diff --git a/xo-alloc2/utest/objectmodel.test.cpp b/xo-alloc2/utest/objectmodel.test.cpp index 19ce1b72..194357c3 100644 --- a/xo-alloc2/utest/objectmodel.test.cpp +++ b/xo-alloc2/utest/objectmodel.test.cpp @@ -34,9 +34,9 @@ * IComplex_DRectCoords IComplex_DPolarCoords IComplex_Any * = IComplex_Specific = IComplex_Specific * - * ^ - * | - * OUniqueBox + * ^ ^ + * | | + * ... OUniqueBox * * ^ * | @@ -104,6 +104,8 @@ namespace xo { virtual double ycoord(void * data) const = 0; virtual double argument(void * data) const = 0; virtual double magnitude(void * data) const = 0; + + virtual void destruct(void * data) const = 0; }; /** type-erased implementation of AComplex, for runtime polymorphism @@ -115,6 +117,8 @@ namespace xo { virtual double ycoord(void *) const final override { assert(false); return 0.0; } virtual double argument(void *) const final override { assert(false); return 0.0; } virtual double magnitude(void *) const final override { assert(false); return 0.0; } + + virtual void destruct(void *) const final override { assert(false); } }; template @@ -123,11 +127,26 @@ namespace xo { static double _ycoord(Repr *); static double _argument(Repr *); static double _magnitude(Repr *); + static void _destruct(Repr *); virtual double xcoord(void * data) const final override { return _xcoord((Repr*)data); } virtual double ycoord(void * data) const final override { return _ycoord((Repr*)data); } virtual double argument(void * data) const final override { return _argument((Repr*)data); } virtual double magnitude(void * data) const final override { return _magnitude((Repr*)data); } + virtual void destruct(void * data) const final override { _destruct((Repr*)data); } + }; + + // ----- Placeholder for opaque data ----- + + // Placeholder used for template specialization + + struct DOpaquePlaceholder {}; + + using IComplex_DOpaquePlaceholder = IComplex_Any; + + template <> + struct ISpecificFor { + using ImplType = IComplex_Any; }; // ----- Polar Coordinates ----- @@ -166,6 +185,12 @@ namespace xo { return data->mag_; } + template <> + void + IComplex_Specific::_destruct(DPolarCoords *) { + /*trivial*/ + } + template <> struct ISpecificFor { using ImplType = IComplex_Specific; @@ -211,6 +236,12 @@ namespace xo { return std::sqrt(x*x + y*y); } + template <> + void + IComplex_Specific::_destruct(DRectCoords * /*data*/) { + /*trivial*/ + } + template <> struct ISpecificFor { using ImplType = IComplex_Specific; @@ -250,8 +281,49 @@ namespace xo { DataBox data_; }; + // ----- polymorphic box ----- + + /** + * Unqiuely-owned instance with runtime polymorphism. + * + * Unlike OUniqueBox can use for variant data + * without additional overhead. Tradeoff is that avoiding such + * overhead excludes std::unique_ptr. + * + * We're going to instead rely on AInterface providing a destruct() method, + * so in practice get the deleter from interface state. + * + * Possibly means we need all abstract interfaces to share a common base + **/ + template + struct OUniqueAny : ISpecificFor::ImplType { + /* note: Data can be void here */ + using DataType = Data; + using DataBox = Data*; + + explicit OUniqueAny() {} + /* unsatisfactory b/c doesn't enforce that @p d is heap-allocated */ + explicit OUniqueAny(DataBox d) : data_{std::move(d)} {} + + ~OUniqueAny() { + if (data_ != nullptr) { + this->destruct(data_); + delete data_; + this->data_ = nullptr; + } + } + + /** note: load-bearing for routing classes such as RComplex **/ + Data * data() const { return data_; } + + DataBox data_ = nullptr; + }; + + // ----- Router; RFoo pairs with AFoo ----- + template struct RComplex : public Object { + RComplex() {} RComplex(Object::DataBox data) : Object{std::move(data)} {} double xcoord() const { return Object::_xcoord(Object::data()); } @@ -271,6 +343,8 @@ namespace xo { template using RoutingType = RoutingFor::RoutingType; + // ----- unique box; coordinates with OUniqueBox ----- + /** boxed object, held by unique pointer * * Example: @@ -283,8 +357,44 @@ namespace xo { explicit ubox(Super::DataBox d) : Super{std::move(d)} {} }; + + // ----- unique any; coordinates with OUniqueAny ----- + + /** boxed object, held by unique-pointer equiavelent. + * + * Example: + * std::unique_ptr z1_in = std::make_unique(1.0, 0.0): + * uany z1{z1_in.release()}; + * + * z1.xcoord(); + **/ + template + struct uany : public RoutingType> { + using Super = RoutingType>; + + uany() {} + explicit uany(Super::DataBox d) : Super(d) {} + + /** move constructor from a different representation. + * allowed given: + * - same abstract interface + * - same strategy (unique / refcounted / ..) + **/ + template + uany(uany && other) + requires (std::is_same_v + || std::is_convertible_v) + : Super(reinterpret_cast 1+0i */ @@ -363,6 +473,32 @@ namespace xo { REQUIRE(box.argument() == 0.0); REQUIRE(box.magnitude() == 1.0); } + + TEST_CASE("uany-1", "[objectmodel]") + { + /* default ctor */ + uany any; + } + + TEST_CASE("uany-2", "[objectmodel]") + { + /* equivalent to ubox, but impl doesn't use std::unique_ptr */ + uany any{new DRectCoords{1.0, 0.0}}; + + REQUIRE(any.xcoord() == 1.0); + REQUIRE(any.ycoord() == 0.0); + REQUIRE(any.argument() == 0.0); + REQUIRE(any.magnitude() == 1.0); + } + + TEST_CASE("uany-3", "[objectmodel]") + { + /* equivalent to ubox, but impl doesn't use std::unique_ptr */ + uany z1{new DRectCoords{1.0, 0.0}}; + + /* should be able to assign to a variant uany */ + uany uany = std::move(z1); + } } /*namespace ut*/ } /*namespace xo*/ diff --git a/xo-ordinaltree/utest/RedBlackTree-gc.test.cpp b/xo-ordinaltree/utest/RedBlackTree-gc.test.cpp index 5322a97c..f3cf204c 100644 --- a/xo-ordinaltree/utest/RedBlackTree-gc.test.cpp +++ b/xo-ordinaltree/utest/RedBlackTree-gc.test.cpp @@ -465,6 +465,7 @@ namespace xo { keys[i] = key_i; } +#ifdef NOT_YET REQUIRE(rbtree.get() != nullptr); REQUIRE(rbtree->verify_ok(debug_flag)); @@ -499,7 +500,6 @@ namespace xo { } -#ifdef NOT_YET if (n > 0) { INFO("insert phase B - random_inserts(1, n+1, ..)"); diff --git a/xo-ordinaltree/utest/random_tree_ops.hpp b/xo-ordinaltree/utest/random_tree_ops.hpp index c0586655..89746a63 100644 --- a/xo-ordinaltree/utest/random_tree_ops.hpp +++ b/xo-ordinaltree/utest/random_tree_ops.hpp @@ -86,6 +86,8 @@ namespace utest { xo::rng::xoshiro256ss * p_rgen, Tree * p_tree) { + using xo::xtag; + bool ok_flag = true; xo::scope log(XO_DEBUG(catch_flag), xtag("n-keys", keys.size())); @@ -96,9 +98,11 @@ namespace utest { std::size_t n = keys.size(); /* permute keys, remembering original position */ std::vector> permuted_keys(n); - uint32_t i = 0; - for (const auto & x : keys) { - permuted_keys[i] = std::make_pair(i, x); + { + uint32_t i = 0; + for (const auto & x : keys) { + permuted_keys[i] = std::make_pair(i, x); + } } /* shuffle to get unpredictable insert order */ std::shuffle(keys.begin(), keys.end(), *p_rgen); @@ -106,26 +110,28 @@ namespace utest { size_t tree_z0 = p_tree->size(); /* insert keys in permuted order */ - uint32_t i = 1; - for(const auto & pr_i : permuted_keys) { - log && log(xtag("i", i), xtag("ord", pr_i.first), xtag("n", n), xtag("key", pr_i.second)); + { + uint32_t i = 1; + for(const auto & pr_i : permuted_keys) { + log && log(xtag("i", i), xtag("ord", pr_i.first), xtag("n", n), xtag("key", pr_i.second)); - /* .first: iterator @ insert position - * .second: true if insert occurred (ịẹ tree size incremented) - */ - auto insert_result = p_tree->insert(typename Tree::value_type(pr_i.second, 10.0 * i)); + /* .first: iterator @ insert position + * .second: true if insert occurred (ịẹ tree size incremented) + */ + auto insert_result = p_tree->insert(typename Tree::value_type(pr_i.second, 10.0 * i)); - REQUIRE_ORFAIL(ok_flag, catch_flag, p_tree->verify_ok(catch_flag)); + REQUIRE_ORFAIL(ok_flag, catch_flag, p_tree->verify_ok(catch_flag)); - REQUIRE_ORFAIL(ok_flag, catch_flag, insert_result.second); + REQUIRE_ORFAIL(ok_flag, catch_flag, insert_result.second); - /* verify: iterator returned by Treẹinsert(), refers to inserted key,value pair */ - log && log(xtag("iter.node", insert_result.first.node())); + /* verify: iterator returned by Treẹinsert(), refers to inserted key,value pair */ + log && log(xtag("iter.node", insert_result.first.node())); - REQUIRE_ORFAIL(ok_flag, catch_flag, insert_result.first->first == pr_i.second); - REQUIRE_ORFAIL(ok_flag, catch_flag, insert_result.first->second == 10.0 * i); + REQUIRE_ORFAIL(ok_flag, catch_flag, insert_result.first->first == pr_i.second); + REQUIRE_ORFAIL(ok_flag, catch_flag, insert_result.first->second == 10.0 * i); - ++i; + ++i; + } } REQUIRE_ORFAIL(ok_flag, catch_flag, p_tree->size() == tree_z0 + n);