From 922adf0576dd8d2935e062f1394dde8651cc80ca Mon Sep 17 00:00:00 2001 From: Daniel Poetzl Date: Mon, 13 May 2019 23:31:14 +0100 Subject: [PATCH] Small shared n-way pointer This replaces small_shared_two_way_ptrt with small_shared_n_way_ptrt. The new shared pointer type allows more than two types for the managed objects. This can be useful e.g. for implementing graph data structures with sharing where there are more than two different node types. --- src/util/sharing_node.h | 28 +- src/util/small_shared_n_way_ptr.h | 393 +++++++++++++++++++++++++ src/util/small_shared_two_way_ptr.h | 302 ------------------- unit/Makefile | 2 +- unit/util/small_shared_n_way_ptr.cpp | 194 ++++++++++++ unit/util/small_shared_two_way_ptr.cpp | 108 ------- 6 files changed, 603 insertions(+), 424 deletions(-) create mode 100644 src/util/small_shared_n_way_ptr.h delete mode 100644 src/util/small_shared_two_way_ptr.h create mode 100644 unit/util/small_shared_n_way_ptr.cpp delete mode 100644 unit/util/small_shared_two_way_ptr.cpp 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)); - } -}