diff --git a/src/util/sharing_node.h b/src/util/sharing_node.h index e534749d542..307167be4e5 100644 --- a/src/util/sharing_node.h +++ b/src/util/sharing_node.h @@ -35,8 +35,8 @@ Author: Daniel Poetzl #include "invariant.h" #include "make_unique.h" +#include "small_shared_n_way_ptr.h" #include "small_shared_ptr.h" -#include "small_shared_two_way_ptr.h" #ifdef SN_INTERNAL_CHECKS #define SN_ASSERT(b) INVARIANT(b, "Sharing node internal invariant") @@ -70,7 +70,7 @@ const T *as_const(T *t) // Inner nodes (internal nodes or container nodes) -typedef small_shared_two_way_pointeet d_baset; +typedef small_shared_n_way_pointee_baset<2, unsigned> d_baset; SN_TYPE_PAR_DECL class sharing_node_innert; @@ -105,7 +105,7 @@ class sharing_node_baset SN_TYPE_PAR_DEF class sharing_node_innert : public sharing_node_baset { public: - typedef small_shared_two_way_ptrt datat; + typedef small_shared_n_way_ptrt datat; typedef typename datat::use_countt use_countt; typedef d_internalt d_it; @@ -155,12 +155,12 @@ SN_TYPE_PAR_DEF class sharing_node_innert : public sharing_node_baset bool is_internal() const { - return data.is_derived_u(); + return data.template is_derived<0>(); } bool is_container() const { - return data.is_derived_v(); + return data.template is_derived<1>(); } bool is_defined_internal() const @@ -177,14 +177,14 @@ SN_TYPE_PAR_DEF class sharing_node_innert : public sharing_node_baset { SN_ASSERT(!empty()); - return *data.get_derived_u(); + return *data.template get_derived<0>(); } const d_ct &read_container() const { SN_ASSERT(!empty()); - return *data.get_derived_v(); + return *data.template get_derived<1>(); } // Accessors @@ -334,32 +334,34 @@ SN_TYPE_PAR_DEF class sharing_node_innert : public sharing_node_baset { if(!data) { - data = make_shared_derived_u(); + data = make_shared_2<0, SN_PTR_TYPE_ARGS>(); } else if(data.use_count() > 1) { - data = make_shared_derived_u(*data.get_derived_u()); + data = + make_shared_2<0, SN_PTR_TYPE_ARGS>(*data.template get_derived<0>()); } SN_ASSERT(data.use_count() == 1); - return *data.get_derived_u(); + return *data.template get_derived<0>(); } d_ct &write_container() { if(!data) { - data = make_shared_derived_v(); + data = make_shared_2<1, SN_PTR_TYPE_ARGS>(); } else if(data.use_count() > 1) { - data = make_shared_derived_v(*data.get_derived_v()); + data = + make_shared_2<1, SN_PTR_TYPE_ARGS>(*data.template get_derived<1>()); } SN_ASSERT(data.use_count() == 1); - return *data.get_derived_v(); + return *data.template get_derived<1>(); } datat data; diff --git a/src/util/small_shared_n_way_ptr.h b/src/util/small_shared_n_way_ptr.h new file mode 100644 index 00000000000..6cf2e0d1eaf --- /dev/null +++ b/src/util/small_shared_n_way_ptr.h @@ -0,0 +1,393 @@ +/*******************************************************************\ + +Module: Small shared n-way pointer + +Author: Daniel Poetzl + +\*******************************************************************/ + +#ifndef CPROVER_UTIL_SMALL_SHARED_N_WAY_PTR_H +#define CPROVER_UTIL_SMALL_SHARED_N_WAY_PTR_H + +#include +#include +#include +#include + +#include "invariant.h" + +/// Get the type with the given index in the parameter pack +template +struct get_typet +{ + // NOLINTNEXTLINE(readability/identifiers) + typedef typename std::tuple_element>::type type; +}; + +template +class small_shared_n_way_pointee_baset; + +// Struct to hold the static method destruct() to destruct the pointee of a +// small shared n-way pointer. +// +// Note: This functionality should ideally be in a private static method of +// small_shared_n_way_ptrt, but partial template specializations are not allowed +// within other templates, hence it is defined at global scope. +template +struct destructt +{ + static void destruct(pointee_baset *p) + { + if(p->template is_derived()) + { + typedef typename get_typet::type pointeet; + static_assert( + std::is_base_of::value, + "indexed pointee type must be a subclass of the pointee base"); + + delete static_cast(p); + } + else + { + destructt::destruct(p); + } + } +}; + +template +struct destructt<0, pointee_baset, Ts...> +{ + static void destruct(pointee_baset *p) + { + PRECONDITION(p->template is_derived<0>()); + + typedef typename get_typet<0, Ts...>::type pointeet; + static_assert( + std::is_base_of::value, + "indexed pointee type must be a subclass of the pointee base"); + + delete static_cast(p); + } +}; + +/// This class is similar to small_shared_ptrt and boost's intrusive_ptr. Like +/// those, it stores the use count with the pointed-to object instead of in a +/// separate control block. Additionally, it uses the MSBs of the use count to +/// indicate the type of the managed object (which is of one of the types in the +/// parameter pack Ts). +/// +/// A possible use case is the implementation of data structures with sharing +/// that consist of several different types of nodes (such as a tree with +/// internal nodes and leaf nodes). Storing the type with the use count avoids +/// having to keep a separate `type` member or using `typeid` or `dynamic_cast`. +/// Moreover, since the shared pointer is aware of the concrete type of the +/// object being stored, it can delete it without requiring a virtual destructor +/// or custom delete function (like std::shared_ptr). +/// +/// \tparam Ts parameter pack of the different types the small shared n-way +/// pointer can point to +template +class small_shared_n_way_ptrt final +{ +public: + static const std::size_t num_types = + std::tuple_size>::value; + + static_assert( + num_types >= 2, + "parameter pack should contain at least two types"); + + typedef decltype(std::declval::type>() + .get_use_count()) use_countt; + + typedef small_shared_n_way_pointee_baset pointee_baset; + + small_shared_n_way_ptrt() = default; + + /// Static factory method to construct a small shared n-way pointer, pointing + /// to the given object *p of type Ts[I], which must be a subclass of + /// small_shared_n_way_pointee_baset. + /// + /// \tparam I index of a type in the parameter pack Ts + /// \param p pointer to an object of type Ts[I] + /// \return a small shared n-way pointer pointing to p + template + static small_shared_n_way_ptrt + create_small_shared_n_way_ptr(typename get_typet::type *p) + { + PRECONDITION(p != nullptr); + PRECONDITION(p->get_use_count() == 0); + + p->template set_derived(); + p->increment_use_count(); + + return small_shared_n_way_ptrt(p); + } + + small_shared_n_way_ptrt(const small_shared_n_way_ptrt &rhs) : p(rhs.p) + { + PRECONDITION(is_same_type(rhs)); + + if(p) + { + p->increment_use_count(); + } + } + + small_shared_n_way_ptrt(small_shared_n_way_ptrt &&rhs) + { + PRECONDITION(is_same_type(rhs)); + + swap(rhs); + } + + small_shared_n_way_ptrt &operator=(const small_shared_n_way_ptrt &rhs) + { + PRECONDITION(is_same_type(rhs)); + + small_shared_n_way_ptrt copy(rhs); + swap(copy); + return *this; + } + + small_shared_n_way_ptrt &operator=(small_shared_n_way_ptrt &&rhs) + { + PRECONDITION(is_same_type(rhs)); + + swap(rhs); + return *this; + } + + ~small_shared_n_way_ptrt() + { + destruct(); + } + + /// Clears this shared pointer. Decreases the use count of the pointed-to + /// object (if any) by one. + void reset() + { + destruct(); + p = nullptr; + } + + void swap(small_shared_n_way_ptrt &rhs) + { + PRECONDITION(is_same_type(rhs)); + + std::swap(p, rhs.p); + } + + /// Get the use count of the pointed-to object + /// + /// \return the use count of the pointed-to object + use_countt use_count() const + { + return p ? p->get_use_count() : 0; + } + + /// Check if converting the held raw pointer to type Ts[I] is valid + /// + /// \tparam I index into the parameter pack Ts + template + bool is_derived() const + { + return p == nullptr || p->template is_derived(); + } + + /// Get base type pointer to the managed object + /// + /// \return pointer to the managed object, as type pointer to + /// small_shared_n_way_pointee_baset (the common base type of all types in + /// Ts) + pointee_baset *get() const + { + return p; + } + + /// Get pointer to the managed object + /// + /// \return pointer to the managed object, cast to type pointer to Ts[I] + template + typename get_typet::type *get_derived() const + { + PRECONDITION(is_derived()); + + return static_cast::type *>(p); + } + + /// Checks if the raw pointers held by `*this` and `other` both can be + /// converted to a pointer to the same type (of a type in the parameter pack + /// Ts) + bool is_same_type(const small_shared_n_way_ptrt &other) const + { + if(p == nullptr || other.p == nullptr) + return true; + + return p->is_same_type(*other.p); + } + + explicit operator bool() const + { + return p != nullptr; + } + +private: + template + explicit small_shared_n_way_ptrt(T *p) : p(p) + { + } + + void destruct() + { + if(!p) + { + return; + } + + if(p->get_use_count() > 1) + { + p->decrement_use_count(); + return; + } + + destructt::destruct(p); + } + + pointee_baset *p = nullptr; +}; + +/// Constructs a small shared n-way pointer, with two possible pointee types +/// (i.e., n = 2), and constructs an object of either type U (when I = 0) or +/// type V (when I = 1) pointed to by the shared pointer. Arguments ts are +/// passed to the constructor of U or V. U and V must be subclasses of +/// small_shared_n_way_pointee_baset<2, Num>. +/// +/// \tparam I index of the type of object to construct (0 -> U, 1 -> V) +/// \tparam U first possible pointee type +/// \tparam V second possible pointee type +/// \tparam Ts types of arguments to pass to the constructor of U or V +/// \param ts arguments to pass to the constructor of U or V +template +small_shared_n_way_ptrt make_shared_2(Ts &&... ts) +{ + return small_shared_n_way_ptrt::template create_small_shared_n_way_ptr< + I>(new typename get_typet::type(std::forward(ts)...)); +} + +/// Constructs a small shared n-way pointer, with three possible pointee types +/// (i.e., n = 3), and constructs an object of either type U (when I = 0), type +/// V (when I = 1), or type W (when I = 2), pointed to by the shared pointer. +/// Arguments ts are passed to the constructor of U, V, or W. U, V, and W must +/// be subclasses of small_shared_n_way_pointee_baset<3, Num>. +/// +/// \tparam I index of the type of object to construct (0 -> U, 1 -> V) +/// \tparam U first possible pointee type +/// \tparam V second possible pointee type +/// \tparam W third possible pointee type +/// \tparam Ts types of arguments to pass to the constructor of U or V +/// \param ts arguments to pass to the constructor of U or V +template +small_shared_n_way_ptrt make_shared_3(Ts &&... ts) +{ + return small_shared_n_way_ptrt:: + template create_small_shared_n_way_ptr( + new typename get_typet::type(std::forward(ts)...)); +} + +template +bool operator==( + const small_shared_n_way_ptrt &lhs, + const small_shared_n_way_ptrt &rhs) +{ + return lhs.get() == rhs.get(); +} + +template +bool operator!=( + const small_shared_n_way_ptrt &lhs, + const small_shared_n_way_ptrt &rhs) +{ + return lhs.get() != rhs.get(); +} + +template +class small_shared_n_way_pointee_baset +{ +public: + static_assert(std::is_unsigned::value, "Num must be an unsigned type"); + + small_shared_n_way_pointee_baset() = default; + + // The use count shall be unaffected + small_shared_n_way_pointee_baset(const small_shared_n_way_pointee_baset &) + { + } + + // The use count shall be unaffected + small_shared_n_way_pointee_baset & + operator=(const small_shared_n_way_pointee_baset &) + { + return *this; + } + + Num get_use_count() const + { + return use_count & use_count_mask; + } + + void increment_use_count() + { + PRECONDITION(get_use_count() < use_count_mask); + + ++use_count; + } + + void decrement_use_count() + { + PRECONDITION(get_use_count() > 0); + + --use_count; + } + + template + void set_derived() + { + static_assert(I < N, "type index shall be within bounds"); + + use_count &= use_count_mask; + use_count |= I << use_count_bit_width; + } + + template + bool is_derived() const + { + static_assert(I < N, "type index shall be within bounds"); + + return ((use_count & ~use_count_mask) >> use_count_bit_width) == I; + } + + bool is_same_type(const small_shared_n_way_pointee_baset &other) const + { + return !((use_count ^ other.use_count) & ~use_count_mask); + } + +private: + Num use_count = 0; + + static const int bit_width = std::numeric_limits::digits; + + static constexpr std::size_t num_bits(const std::size_t n) + { + return n < 2 ? 1 : 1 + num_bits(n >> 1); + } + + static const std::size_t type_bit_width = num_bits(N); + + static const std::size_t use_count_bit_width = + (std::size_t)bit_width - type_bit_width; + + static const Num use_count_mask = ((Num)1 << use_count_bit_width) - 1; +}; + +#endif // CPROVER_UTIL_SMALL_SHARED_N_WAY_PTR_H diff --git a/src/util/small_shared_two_way_ptr.h b/src/util/small_shared_two_way_ptr.h deleted file mode 100644 index 89349f16e65..00000000000 --- a/src/util/small_shared_two_way_ptr.h +++ /dev/null @@ -1,302 +0,0 @@ -/*******************************************************************\ - -Module: Small shared two-way pointer - -Author: Daniel Poetzl - -\*******************************************************************/ - -#ifndef CPROVER_UTIL_SMALL_SHARED_TWO_WAY_PTR_H -#define CPROVER_UTIL_SMALL_SHARED_TWO_WAY_PTR_H - -#include -#include -#include - -#include "invariant.h" - -template -class small_shared_two_way_pointeet; - -/// This class is similar to small_shared_ptrt and boost's intrusive_ptr. Like -/// those, it stores the use count with the pointed-to object instead of in a -/// separate control block. Additionally, it uses the MSB of the use count to -/// indicate the type of the managed object (which is either of type U or V). -/// -/// A possible use case is the implementation of data structures with sharing -/// that consist of two different types of objects (such as a tree with internal -/// nodes and leaf nodes). Storing the type with the use count avoids having to -/// keep a separate `type` member or using `typeid` or `dynamic_cast`. Moreover, -/// since the shared pointer is aware of the concrete type of the object being -/// stored, it can delete it without requiring a virtual destructor or custom -/// delete function (like std::shared_ptr). -template -class small_shared_two_way_ptrt final -{ -public: - typedef decltype(std::declval().use_count()) use_countt; - - typedef small_shared_two_way_pointeet pointeet; - - static_assert( - std::is_base_of::value, - "pointeet must be a base of U"); - static_assert( - std::is_base_of::value, - "pointeet must be a base of V"); - - small_shared_two_way_ptrt() = default; - - explicit small_shared_two_way_ptrt(U *u) : p(u) - { - PRECONDITION(u != nullptr); - PRECONDITION(u->use_count() == 0); - - p->set_derived_u(); - p->increment_use_count(); - } - - explicit small_shared_two_way_ptrt(V *v) : p(v) - { - PRECONDITION(v != nullptr); - PRECONDITION(v->use_count() == 0); - - p->set_derived_v(); - p->increment_use_count(); - } - - small_shared_two_way_ptrt(const small_shared_two_way_ptrt &rhs) : p(rhs.p) - { - PRECONDITION(is_same_type(rhs)); - - if(p) - { - p->increment_use_count(); - } - } - - small_shared_two_way_ptrt(small_shared_two_way_ptrt &&rhs) - { - PRECONDITION(is_same_type(rhs)); - - swap(rhs); - } - - small_shared_two_way_ptrt &operator=(const small_shared_two_way_ptrt &rhs) - { - PRECONDITION(is_same_type(rhs)); - - small_shared_two_way_ptrt copy(rhs); - swap(copy); - return *this; - } - - small_shared_two_way_ptrt &operator=(small_shared_two_way_ptrt &&rhs) - { - PRECONDITION(is_same_type(rhs)); - - swap(rhs); - return *this; - } - - ~small_shared_two_way_ptrt() - { - destruct(); - } - - void reset() - { - destruct(); - p = nullptr; - } - - void swap(small_shared_two_way_ptrt &rhs) - { - PRECONDITION(is_same_type(rhs)); - - std::swap(p, rhs.p); - } - - use_countt use_count() const - { - return p ? p->use_count() : 0; - } - - /// Checks if converting the held raw pointer to `U*` is valid - bool is_derived_u() const - { - return p == nullptr || p->is_derived_u(); - } - - /// Checks if converting the held raw pointer to `V*` is valid - bool is_derived_v() const - { - return p == nullptr || p->is_derived_v(); - } - - pointeet *get() const - { - return p; - } - - U *get_derived_u() const - { - PRECONDITION(is_derived_u()); - - return static_cast(p); - } - - V *get_derived_v() const - { - PRECONDITION(is_derived_v()); - - return static_cast(p); - } - - /// Checks if the raw pointers held by `*this` and `other` both can be - /// converted to either U* or V* - bool is_same_type(const small_shared_two_way_ptrt &other) const - { - if(p == nullptr || other.p == nullptr) - return true; - - return p->is_same_type(*other.p); - } - - explicit operator bool() const - { - return p != nullptr; - } - -private: - void destruct() - { - if(!p) - { - return; - } - - auto use_count = p->use_count(); - - if(use_count == 1) - { - if(p->is_derived_u()) - { - U *u = static_cast(p); - delete u; - } - else - { - V *v = static_cast(p); - delete v; - } - } - else - { - p->decrement_use_count(); - } - } - - pointeet *p = nullptr; -}; - -template -small_shared_two_way_ptrt make_shared_derived_u(Ts &&... ts) -{ - return small_shared_two_way_ptrt(new U(std::forward(ts)...)); -} - -template -small_shared_two_way_ptrt make_shared_derived_v(Ts &&... ts) -{ - return small_shared_two_way_ptrt(new V(std::forward(ts)...)); -} - -template -bool operator==( - const small_shared_two_way_ptrt &lhs, - const small_shared_two_way_ptrt &rhs) -{ - return lhs.get() == rhs.get(); -} - -template -bool operator!=( - const small_shared_two_way_ptrt &lhs, - const small_shared_two_way_ptrt &rhs) -{ - return lhs.get() != rhs.get(); -} - -template -class small_shared_two_way_pointeet -{ -public: - static_assert(std::is_unsigned::value, "Num must be an unsigned type"); - - static const int bit_idx = std::numeric_limits::digits - 1; - static const Num mask = ~((Num)1 << bit_idx); - - small_shared_two_way_pointeet() = default; - - // The use count shall be unaffected - small_shared_two_way_pointeet(const small_shared_two_way_pointeet &) - { - } - - // The use count shall be unaffected - small_shared_two_way_pointeet & - operator=(const small_shared_two_way_pointeet &) - { - return *this; - } - - Num use_count() const - { - return use_count_ & mask; - } - - void increment_use_count() - { - PRECONDITION((use_count_ & mask) < mask); - - use_count_++; - } - - void decrement_use_count() - { - PRECONDITION((use_count_ & mask) > 0); - - use_count_--; - } - - void set_derived_u() - { - use_count_ &= mask; - } - - void set_derived_v() - { - use_count_ |= ~mask; - } - - bool is_derived_u() const - { - return !(use_count_ & ~mask); - } - - bool is_derived_v() const - { - return (use_count_ & ~mask) != 0; - } - - bool is_same_type(const small_shared_two_way_pointeet &other) const - { - return !((use_count_ ^ other.use_count_) & ~mask); - } - -private: - Num use_count_ = 0; -}; - -#endif diff --git a/unit/Makefile b/unit/Makefile index 46f8ad567aa..62de5696389 100644 --- a/unit/Makefile +++ b/unit/Makefile @@ -74,7 +74,7 @@ SRC += analyses/ai/ai.cpp \ util/sharing_node.cpp \ util/simplify_expr.cpp \ util/small_map.cpp \ - util/small_shared_two_way_ptr.cpp \ + util/small_shared_n_way_ptr.cpp \ util/std_expr.cpp \ util/string2int.cpp \ util/string_utils/join_string.cpp \ diff --git a/unit/util/small_shared_n_way_ptr.cpp b/unit/util/small_shared_n_way_ptr.cpp new file mode 100644 index 00000000000..00d5a9539a9 --- /dev/null +++ b/unit/util/small_shared_n_way_ptr.cpp @@ -0,0 +1,194 @@ +/// Author: Daniel Poetzl + +/// \file Tests for small shared n-way pointer + +#include +#include + +bool data1_destructed = false; +bool data2_destructed = false; +bool data3_destructed = false; + +class data1t : public small_shared_n_way_pointee_baset<2, unsigned> +{ +public: + data1t() = default; + + explicit data1t(int i) : d1(i) + { + } + + ~data1t() + { + data1_destructed = true; + } + + int d1; +}; + +class data2t : public small_shared_n_way_pointee_baset<2, unsigned> +{ +public: + data2t() = default; + + explicit data2t(int i) : d2(i) + { + } + + ~data2t() + { + data2_destructed = true; + } + + int d2; +}; + +class data3t : public small_shared_n_way_pointee_baset<3, unsigned> +{ +public: + ~data3t() + { + data3_destructed = true; + } +}; + +TEST_CASE("Small shared n-way pointer", "[core][util]") +{ + typedef small_shared_n_way_ptrt spt; + + SECTION("Types") + { + spt sp1; + spt sp2 = spt::create_small_shared_n_way_ptr<0>(new data1t()); + spt sp3 = spt::create_small_shared_n_way_ptr<1>(new data2t()); + + REQUIRE(sp1.is_same_type(sp1)); + REQUIRE(sp2.is_same_type(sp2)); + REQUIRE(sp3.is_same_type(sp3)); + + REQUIRE(sp1.is_same_type(sp2)); + REQUIRE(sp1.is_same_type(sp3)); + + REQUIRE(!sp2.is_same_type(sp3)); + + REQUIRE(sp1.is_derived<0>()); + REQUIRE(sp1.is_derived<1>()); + + REQUIRE(sp2.is_derived<0>()); + REQUIRE(!sp2.is_derived<1>()); + + REQUIRE(sp3.is_derived<1>()); + REQUIRE(!sp3.is_derived<0>()); + } + + SECTION("Basic") + { + spt sp1; + REQUIRE(!sp1); + REQUIRE(sp1.get() == nullptr); + REQUIRE(sp1.use_count() == 0); + + const data1t *p; + + p = sp1.get_derived<0>(); + REQUIRE(p == nullptr); + + spt sp2 = spt::create_small_shared_n_way_ptr<0>(new data1t()); + REQUIRE(sp2.use_count() == 1); + + p = sp2.get_derived<0>(); + REQUIRE(p != nullptr); + + spt sp3(sp2); + REQUIRE(sp3.is_derived<0>()); + REQUIRE(sp2.get_derived<0>() == sp3.get_derived<0>()); + REQUIRE(sp2.use_count() == 2); + REQUIRE(sp3.use_count() == 2); + + sp1 = sp2; + REQUIRE(sp1.is_derived<0>()); + REQUIRE(sp1.get_derived<0>() == sp2.get_derived<0>()); + REQUIRE(sp1.use_count() == 3); + REQUIRE(sp2.use_count() == 3); + REQUIRE(sp3.use_count() == 3); + + sp1.reset(); + REQUIRE(!sp1); + REQUIRE(sp1.use_count() == 0); + REQUIRE(sp2.use_count() == 2); + REQUIRE(sp2.use_count() == 2); + + { + spt sp4(sp2); + REQUIRE(sp4.use_count() == 3); + } + + REQUIRE(sp2.use_count() == 2); + } + + SECTION("Creation") + { + spt sp1 = make_shared_2<0, data1t, data2t>(); + spt sp2 = make_shared_2<1, data1t, data2t>(); + + REQUIRE(!sp1.is_same_type(sp2)); + + sp1 = make_shared_2<0, data1t, data2t>(0); + sp2 = make_shared_2<1, data1t, data2t>(0); + + REQUIRE(!sp1.is_same_type(sp2)); + } + + SECTION("Destruction") + { + data1_destructed = false; + data2_destructed = false; + + { + spt sp = make_shared_2<0, data1t, data2t>(); + REQUIRE(sp); + } + + REQUIRE(data1_destructed); + REQUIRE(!data2_destructed); + + data1_destructed = false; + + { + spt sp1 = make_shared_2<0, data1t, data2t>(); + + { + spt sp2(sp1); + REQUIRE(sp2.use_count() == 2); + } + + REQUIRE(!data1_destructed); + REQUIRE(!data2_destructed); + + REQUIRE(sp1.use_count() == 1); + } + + REQUIRE(data1_destructed); + REQUIRE(!data2_destructed); + } + + SECTION("Three target types") + { + typedef small_shared_n_way_ptrt sp3t; + + sp3t sp1 = make_shared_3<0, data3t, data3t, data3t>(); + REQUIRE(sp1.is_derived<0>()); + REQUIRE(!sp1.is_derived<1>()); + REQUIRE(!sp1.is_derived<2>()); + + sp3t sp2 = make_shared_3<1, data3t, data3t, data3t>(); + REQUIRE(!sp2.is_derived<0>()); + REQUIRE(sp2.is_derived<1>()); + REQUIRE(!sp2.is_derived<2>()); + + sp3t sp3 = make_shared_3<2, data3t, data3t, data3t>(); + REQUIRE(!sp3.is_derived<0>()); + REQUIRE(!sp3.is_derived<1>()); + REQUIRE(sp3.is_derived<2>()); + } +} diff --git a/unit/util/small_shared_two_way_ptr.cpp b/unit/util/small_shared_two_way_ptr.cpp deleted file mode 100644 index a34285db8b3..00000000000 --- a/unit/util/small_shared_two_way_ptr.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/// Author: Daniel Poetzl - -/// \file Tests for small shared two-way pointer - -#include -#include - -class d1t : public small_shared_two_way_pointeet -{ -public: - d1t() = default; - - explicit d1t(int i) : d1(i) - { - } - - int d1; -}; - -class d2t : public small_shared_two_way_pointeet -{ -public: - d2t() = default; - - explicit d2t(int i) : d2(i) - { - } - - int d2; -}; - -TEST_CASE("Small shared two-way pointer") -{ - typedef small_shared_two_way_ptrt spt; - - SECTION("Types") - { - spt sp1; - spt sp2(new d1t()); - spt sp3(new d2t()); - - REQUIRE(sp1.is_same_type(sp1)); - REQUIRE(sp2.is_same_type(sp2)); - REQUIRE(sp3.is_same_type(sp3)); - - REQUIRE(sp1.is_same_type(sp2)); - REQUIRE(sp1.is_same_type(sp3)); - - REQUIRE(!sp2.is_same_type(sp3)); - - REQUIRE(sp1.is_derived_u()); - REQUIRE(sp1.is_derived_v()); - - REQUIRE(sp2.is_derived_u()); - REQUIRE(!sp2.is_derived_v()); - - REQUIRE(sp3.is_derived_v()); - REQUIRE(!sp3.is_derived_u()); - } - - SECTION("Basic") - { - spt sp1; - REQUIRE(!sp1); - REQUIRE(sp1.use_count() == 0); - - const d1t *p; - - p = sp1.get_derived_u(); - REQUIRE(p == nullptr); - - spt sp2(new d1t()); - REQUIRE(sp2.use_count() == 1); - - p = sp2.get_derived_u(); - REQUIRE(p != nullptr); - - spt sp3(sp2); - REQUIRE(sp3.is_derived_u()); - REQUIRE(sp2.get_derived_u() == sp3.get_derived_u()); - REQUIRE(sp2.use_count() == 2); - REQUIRE(sp3.use_count() == 2); - - sp1 = sp2; - REQUIRE(sp1.is_derived_u()); - REQUIRE(sp1.get_derived_u() == sp2.get_derived_u()); - REQUIRE(sp1.use_count() == 3); - REQUIRE(sp2.use_count() == 3); - REQUIRE(sp3.use_count() == 3); - - sp1.reset(); - REQUIRE(!sp1); - REQUIRE(sp1.use_count() == 0); - } - - SECTION("Creation") - { - spt sp1 = make_shared_derived_u(); - spt sp2 = make_shared_derived_v(); - - REQUIRE(!sp1.is_same_type(sp2)); - - sp1 = make_shared_derived_u(0); - sp2 = make_shared_derived_v(0); - - REQUIRE(!sp1.is_same_type(sp2)); - } -}