From 6c75ee1081c4d669fc42219cd747558ea91209b3 Mon Sep 17 00:00:00 2001 From: Eddie Date: Mon, 28 Apr 2025 19:36:53 -0600 Subject: [PATCH 1/9] Comments --- .../inc/demo/type_erasure_shared_pointer_value_manager.hpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/inc/demo/type_erasure_shared_pointer_value_manager.hpp b/test/inc/demo/type_erasure_shared_pointer_value_manager.hpp index d7b0760..23be37d 100644 --- a/test/inc/demo/type_erasure_shared_pointer_value_manager.hpp +++ b/test/inc/demo/type_erasure_shared_pointer_value_manager.hpp @@ -38,8 +38,9 @@ struct UserValueManagement { /// Abbreviation using SPM = SharedPointerManager; - + // not part of the end-user interface VP *sharedPointer() noexcept { return this->space_.template as(); } + // part of the end-user interface V *value() noexcept { return &**sharedPointer(); } const V *value() const noexcept { @@ -65,12 +66,14 @@ struct UserValueManagement { AffordanceSpecifications::template Operation... }; + // not user interface SharedPointerManager(SharedPointerManager &&donor) noexcept: Base(&Operations) { new(sharedPointer()) VP(std::move(*donor.sharedPointer())); } + // not user interface SharedPointerManager(const SharedPointerManager &donor) noexcept: Base(&Operations) { @@ -78,6 +81,7 @@ struct UserValueManagement { } + // internal interface of Builder (important) template SharedPointerManager(Args &&...args): Base(&Operations) @@ -91,6 +95,7 @@ struct UserValueManagement { }; struct AdaptedPolicy: GP::Policy { + // Builders is the old name to refer to what I now call "Value Manager" template using Builder = std::conditional_t< From fcf3d675aa7f64e4cad973145bff42e0cabac90a Mon Sep 17 00:00:00 2001 From: Jamie Pond Date: Mon, 28 Apr 2025 19:51:20 -0700 Subject: [PATCH 2/9] string io affordance working --- ...e_erasure_shared_pointer_value_manager.cpp | 95 ++++++++++++++++++- ...e_erasure_shared_pointer_value_manager.hpp | 7 +- 2 files changed, 98 insertions(+), 4 deletions(-) diff --git a/test/demo/type_erasure_shared_pointer_value_manager.cpp b/test/demo/type_erasure_shared_pointer_value_manager.cpp index a8459db..97e6227 100644 --- a/test/demo/type_erasure_shared_pointer_value_manager.cpp +++ b/test/demo/type_erasure_shared_pointer_value_manager.cpp @@ -1,18 +1,86 @@ #include "demo/type_erasure_shared_pointer_value_manager.hpp" +#include "zoo/Any/VTablePolicy.h" +#include "zoo/AnyContainer.h" #include "zoo/FunctionPolicy.h" #include +#include + + +struct StringInputOutput { + struct VTableEntry { + std::string (*str)(const void *); + void (*fromString)(void *, const std::string &); + }; + + template + constexpr static inline VTableEntry Default = { + [](const void *) { return std::string(); }, + [](void *, const std::string &) {} + }; + + template + constexpr static inline VTableEntry Operation = { + [](const void *container) { + auto c = const_cast(container); + auto cvm = static_cast(c); + std::ostringstream oss; + oss << *cvm->value(); + return oss.str(); + }, + [] (void *container, const std::string &str) { + std::istringstream iss{str}; + auto c = const_cast(container); + auto cvm = static_cast(c); + iss >> *cvm->value(); + }, + }; + + // No extra state/functions needed in the memory layout + template + struct Mixin {}; + + template + struct UserAffordance { + + std::string stringize() const { + auto container = + const_cast(static_cast(this))->container(); + return container->template vTable()->str(container); + } + + auto fromString(const std::string &str) { + auto container = static_cast(this)->container(); + auto vt = container->template vTable(); + vt->fromString(container, str); + } + }; +}; + namespace user { template auto extractSharedPointer(zoo::AnyContainer &a) { using VBuilder = typename Policy::template Builder; - auto downcasted = static_cast(a.container()); - return downcasted->sharedPointer(); + auto valueManager = static_cast(a.container()); + return valueManager->sharedPointer(); } +template +auto isExclusive(zoo::AnyContainer &a) { + if constexpr (SharedPointerOptIn::value) { + using VBuilder = typename Policy::template Builder; + auto valueManager = static_cast(a.container()); + return valueManager->isExclusive(); + } + + return true; +} + + + } using LocalBuffer = void *[4]; @@ -25,9 +93,13 @@ using UAny = zoo::AnyContainer< > >; + TEST_CASE("Shared Pointer Value Manager", "[demo][type-erasure][shared-pointer-policy]") { UAny uAny{9.9}; CHECK(9.9 == *uAny.state()); + + REQUIRE(user::isExclusive(uAny)); + user::ExplicitDestructor ed; REQUIRE(nullptr == user::ExplicitDestructor::last); uAny = ed; @@ -35,12 +107,29 @@ TEST_CASE("Shared Pointer Value Manager", "[demo][type-erasure][shared-pointer-p REQUIRE(typeid(user::ExplicitDestructor) == uAny.type()); auto spp = user::extractSharedPointer(uAny); auto sp = *spp; + REQUIRE(2 == sp.use_count()); + + REQUIRE(! user::isExclusive(uAny)); + CHECK(nullptr == user::ExplicitDestructor::last); const auto oldAddress = uAny.state(); REQUIRE(oldAddress == &*sp); sp.reset(); - REQUIRE(1 == spp->use_count()); + REQUIRE(user::isExclusive(uAny)); + uAny = 5; REQUIRE(oldAddress == user::ExplicitDestructor::last); + + SECTION("roundtrip io affordance") { + using IOType = zoo::AnyContainer>; + IOType io = 8; + REQUIRE("8" == io.stringize()); + io.fromString("42"); + REQUIRE(42 == *io.state()); + } + + SECTION("copy on write") { + + } } diff --git a/test/inc/demo/type_erasure_shared_pointer_value_manager.hpp b/test/inc/demo/type_erasure_shared_pointer_value_manager.hpp index 23be37d..424436b 100644 --- a/test/inc/demo/type_erasure_shared_pointer_value_manager.hpp +++ b/test/inc/demo/type_erasure_shared_pointer_value_manager.hpp @@ -37,7 +37,7 @@ struct UserValueManagement { using VP = std::shared_ptr; /// Abbreviation using SPM = SharedPointerManager; - + // not part of the end-user interface VP *sharedPointer() noexcept { return this->space_.template as(); } // part of the end-user interface @@ -66,6 +66,11 @@ struct UserValueManagement { AffordanceSpecifications::template Operation... }; + auto isExclusive() const noexcept { + auto sp = const_cast(this)->sharedPointer(); + return 1 == sp->use_count(); + } + // not user interface SharedPointerManager(SharedPointerManager &&donor) noexcept: Base(&Operations) From 4d65a2ed0a50bc25e928239ddef49b84fdbc4cc3 Mon Sep 17 00:00:00 2001 From: Jamie Pond Date: Mon, 28 Apr 2025 20:40:12 -0700 Subject: [PATCH 3/9] works --- ...e_erasure_shared_pointer_value_manager.cpp | 67 +++++++++++++------ ...e_erasure_shared_pointer_value_manager.hpp | 9 ++- 2 files changed, 54 insertions(+), 22 deletions(-) diff --git a/test/demo/type_erasure_shared_pointer_value_manager.cpp b/test/demo/type_erasure_shared_pointer_value_manager.cpp index 97e6227..77ead46 100644 --- a/test/demo/type_erasure_shared_pointer_value_manager.cpp +++ b/test/demo/type_erasure_shared_pointer_value_manager.cpp @@ -6,6 +6,24 @@ #include #include +#include + + +// Primary template: defaults to false +template > +struct ExclusiveAwareTrait: std::false_type {}; + +// Specialization: if T has T::ExclusiveAware, this will match and be true +template +struct ExclusiveAwareTrait>: std::true_type {}; + + +struct MyCoolStruct { + struct ExclusiveAware {}; +}; + +static_assert(ExclusiveAwareTrait::value == false); +static_assert(ExclusiveAwareTrait::value); struct StringInputOutput { @@ -30,9 +48,16 @@ struct StringInputOutput { return oss.str(); }, [] (void *container, const std::string &str) { - std::istringstream iss{str}; auto c = const_cast(container); auto cvm = static_cast(c); + + if constexpr (ExclusiveAwareTrait::value) { + if (!cvm->isExclusive()) { + cvm->makeExclusive(); + } + } + + std::istringstream iss{str}; iss >> *cvm->value(); }, }; @@ -95,31 +120,33 @@ using UAny = zoo::AnyContainer< TEST_CASE("Shared Pointer Value Manager", "[demo][type-erasure][shared-pointer-policy]") { - UAny uAny{9.9}; - CHECK(9.9 == *uAny.state()); + SECTION("shared pointer value management basics") { + UAny uAny{9.9}; + CHECK(9.9 == *uAny.state()); - REQUIRE(user::isExclusive(uAny)); + REQUIRE(user::isExclusive(uAny)); - user::ExplicitDestructor ed; - REQUIRE(nullptr == user::ExplicitDestructor::last); - uAny = ed; - CHECK(nullptr == user::ExplicitDestructor::last); - REQUIRE(typeid(user::ExplicitDestructor) == uAny.type()); - auto spp = user::extractSharedPointer(uAny); - auto sp = *spp; + user::ExplicitDestructor ed; + REQUIRE(nullptr == user::ExplicitDestructor::last); + uAny = ed; + CHECK(nullptr == user::ExplicitDestructor::last); + REQUIRE(typeid(user::ExplicitDestructor) == uAny.type()); + auto spp = user::extractSharedPointer(uAny); + auto sp = *spp; - REQUIRE(2 == sp.use_count()); + REQUIRE(2 == sp.use_count()); - REQUIRE(! user::isExclusive(uAny)); + REQUIRE(! user::isExclusive(uAny)); - CHECK(nullptr == user::ExplicitDestructor::last); - const auto oldAddress = uAny.state(); - REQUIRE(oldAddress == &*sp); - sp.reset(); - REQUIRE(user::isExclusive(uAny)); + CHECK(nullptr == user::ExplicitDestructor::last); + const auto oldAddress = uAny.state(); + REQUIRE(oldAddress == &*sp); + sp.reset(); + REQUIRE(user::isExclusive(uAny)); - uAny = 5; - REQUIRE(oldAddress == user::ExplicitDestructor::last); + uAny = 5; + REQUIRE(oldAddress == user::ExplicitDestructor::last); + } SECTION("roundtrip io affordance") { using IOType = zoo::AnyContainer>; diff --git a/test/inc/demo/type_erasure_shared_pointer_value_manager.hpp b/test/inc/demo/type_erasure_shared_pointer_value_manager.hpp index 424436b..5277932 100644 --- a/test/inc/demo/type_erasure_shared_pointer_value_manager.hpp +++ b/test/inc/demo/type_erasure_shared_pointer_value_manager.hpp @@ -38,6 +38,7 @@ struct UserValueManagement { /// Abbreviation using SPM = SharedPointerManager; + struct ExclusiveAware {}; // not part of the end-user interface VP *sharedPointer() noexcept { return this->space_.template as(); } // part of the end-user interface @@ -71,6 +72,10 @@ struct UserValueManagement { return 1 == sp->use_count(); } + auto makeExclusive() { + *sharedPointer() = std::make_shared(*value()); + } + // not user interface SharedPointerManager(SharedPointerManager &&donor) noexcept: Base(&Operations) @@ -79,10 +84,10 @@ struct UserValueManagement { } // not user interface - SharedPointerManager(const SharedPointerManager &donor) noexcept: + SharedPointerManager(const SharedPointerManager &model) noexcept: Base(&Operations) { - new(sharedPointer()) VP(*const_cast(donor).sharedPointer()); + new(sharedPointer()) VP(*const_cast(model).sharedPointer()); } From 0de1da869cdddb805b0d32309cc50a01c189449f Mon Sep 17 00:00:00 2001 From: Jamie Pond Date: Mon, 28 Apr 2025 21:02:13 -0700 Subject: [PATCH 4/9] update copy --- ...e_erasure_shared_pointer_value_manager.cpp | 2 +- ...e_erasure_shared_pointer_value_manager.hpp | 21 ++++++++++++------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/test/demo/type_erasure_shared_pointer_value_manager.cpp b/test/demo/type_erasure_shared_pointer_value_manager.cpp index 77ead46..d9ac6cb 100644 --- a/test/demo/type_erasure_shared_pointer_value_manager.cpp +++ b/test/demo/type_erasure_shared_pointer_value_manager.cpp @@ -114,7 +114,7 @@ static_assert(sizeof(std::shared_ptr) <= sizeof(LocalBuffer)); using UAny = zoo::AnyContainer< user::SharedPointerPolicy< LocalBuffer, - zoo::Destroy, zoo::Move, zoo::Copy, zoo::RTTI + zoo::Destroy, zoo::Move, zoo::RTTI > >; diff --git a/test/inc/demo/type_erasure_shared_pointer_value_manager.hpp b/test/inc/demo/type_erasure_shared_pointer_value_manager.hpp index 5277932..2002add 100644 --- a/test/inc/demo/type_erasure_shared_pointer_value_manager.hpp +++ b/test/inc/demo/type_erasure_shared_pointer_value_manager.hpp @@ -39,6 +39,11 @@ struct UserValueManagement { using SPM = SharedPointerManager; struct ExclusiveAware {}; + + SharedPointerManager(): Base(&Operations) { + new(sharedPointer()) VP; + } + // not part of the end-user interface VP *sharedPointer() noexcept { return this->space_.template as(); } // part of the end-user interface @@ -59,8 +64,9 @@ struct UserValueManagement { } static void copyOp(void *to, const void *from) { - auto downcast = static_cast(from); - new(to) SPM(*downcast); + auto downcast = static_cast(const_cast(from)); + auto destValueManager = new(to) SPM; + *destValueManager->sharedPointer() = *downcast->sharedPointer(); } constexpr static inline typename GP::VTable Operations = { @@ -84,11 +90,12 @@ struct UserValueManagement { } // not user interface - SharedPointerManager(const SharedPointerManager &model) noexcept: - Base(&Operations) - { - new(sharedPointer()) VP(*const_cast(model).sharedPointer()); - } +// SharedPointerManager(const SharedPointerManager &model) noexcept: +// Base(&Operations) +// { +// new(sharedPointer()) VP(*const_cast(model).sharedPointer()); +// } + // internal interface of Builder (important) From b2450559053f7d08b7e6444614910c6283bd327b Mon Sep 17 00:00:00 2001 From: Jamie Pond Date: Mon, 28 Apr 2025 21:22:42 -0700 Subject: [PATCH 5/9] copy on write tests pass --- .../type_erasure_shared_pointer_value_manager.cpp | 14 ++++++++++++++ .../type_erasure_shared_pointer_value_manager.hpp | 6 ++++++ 2 files changed, 20 insertions(+) diff --git a/test/demo/type_erasure_shared_pointer_value_manager.cpp b/test/demo/type_erasure_shared_pointer_value_manager.cpp index d9ac6cb..1aaedfc 100644 --- a/test/demo/type_erasure_shared_pointer_value_manager.cpp +++ b/test/demo/type_erasure_shared_pointer_value_manager.cpp @@ -157,6 +157,20 @@ TEST_CASE("Shared Pointer Value Manager", "[demo][type-erasure][shared-pointer-p } SECTION("copy on write") { + using CopyOnWritable = zoo::AnyContainer>; + CopyOnWritable a = std::string{"foo"}; + auto aState = a.state(); + REQUIRE("foo" == *aState); + auto b = a; + // proves that a and b share the same object + REQUIRE(aState == b.state()); + + b.fromString("bar"); + + auto bState = b.state(); + REQUIRE(aState != bState); + REQUIRE("foo" == *aState); + REQUIRE("bar" == *bState); } } diff --git a/test/inc/demo/type_erasure_shared_pointer_value_manager.hpp b/test/inc/demo/type_erasure_shared_pointer_value_manager.hpp index 2002add..9f32f20 100644 --- a/test/inc/demo/type_erasure_shared_pointer_value_manager.hpp +++ b/test/inc/demo/type_erasure_shared_pointer_value_manager.hpp @@ -13,11 +13,17 @@ struct ExplicitDestructor { template struct SharedPointerOptIn: std::false_type {}; + template<> struct SharedPointerOptIn: std::true_type {}; + template<> struct SharedPointerOptIn: std::true_type {}; +template<> +struct SharedPointerOptIn: std::true_type {}; + + template struct UserValueManagement { /// abbreviation From 06612dd663d96dff6801aa971d8961680af122fb Mon Sep 17 00:00:00 2001 From: Jamie Pond Date: Mon, 28 Apr 2025 21:27:08 -0700 Subject: [PATCH 6/9] update tests --- test/demo/type_erasure_shared_pointer_value_manager.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/test/demo/type_erasure_shared_pointer_value_manager.cpp b/test/demo/type_erasure_shared_pointer_value_manager.cpp index 1aaedfc..989dfde 100644 --- a/test/demo/type_erasure_shared_pointer_value_manager.cpp +++ b/test/demo/type_erasure_shared_pointer_value_manager.cpp @@ -162,12 +162,19 @@ TEST_CASE("Shared Pointer Value Manager", "[demo][type-erasure][shared-pointer-p auto aState = a.state(); REQUIRE("foo" == *aState); + REQUIRE(user::isExclusive(a)); + + auto b = a; + REQUIRE(!user::isExclusive(a)); // proves that a and b share the same object REQUIRE(aState == b.state()); - + // now we're going to write to b! then the copy must happen. b.fromString("bar"); + REQUIRE(user::isExclusive(a)); + REQUIRE(user::isExclusive(b)); + auto bState = b.state(); REQUIRE(aState != bState); REQUIRE("foo" == *aState); From e6b467fcae361b58e87137a6b08cfdbcb9d90671 Mon Sep 17 00:00:00 2001 From: Jamie Pond Date: Mon, 28 Apr 2025 21:30:25 -0700 Subject: [PATCH 7/9] tidy --- test/demo/type_erasure_shared_pointer_value_manager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/demo/type_erasure_shared_pointer_value_manager.cpp b/test/demo/type_erasure_shared_pointer_value_manager.cpp index 989dfde..41f7558 100644 --- a/test/demo/type_erasure_shared_pointer_value_manager.cpp +++ b/test/demo/type_erasure_shared_pointer_value_manager.cpp @@ -158,13 +158,13 @@ TEST_CASE("Shared Pointer Value Manager", "[demo][type-erasure][shared-pointer-p SECTION("copy on write") { using CopyOnWritable = zoo::AnyContainer>; + CopyOnWritable a = std::string{"foo"}; - auto aState = a.state(); + auto aState = a.state(); REQUIRE("foo" == *aState); REQUIRE(user::isExclusive(a)); - auto b = a; REQUIRE(!user::isExclusive(a)); // proves that a and b share the same object From a74aa7e3e39582bcc11e12f7258d6adbb0e88084 Mon Sep 17 00:00:00 2001 From: Jamie Pond Date: Mon, 28 Apr 2025 21:33:09 -0700 Subject: [PATCH 8/9] tidy --- test/demo/type_erasure_shared_pointer_value_manager.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/demo/type_erasure_shared_pointer_value_manager.cpp b/test/demo/type_erasure_shared_pointer_value_manager.cpp index 41f7558..379e1cb 100644 --- a/test/demo/type_erasure_shared_pointer_value_manager.cpp +++ b/test/demo/type_erasure_shared_pointer_value_manager.cpp @@ -1,7 +1,5 @@ #include "demo/type_erasure_shared_pointer_value_manager.hpp" -#include "zoo/Any/VTablePolicy.h" -#include "zoo/AnyContainer.h" #include "zoo/FunctionPolicy.h" #include From ee76478706bd6ed369fd9c1d3ef700a4db154323 Mon Sep 17 00:00:00 2001 From: Jamie Pond Date: Mon, 28 Apr 2025 21:47:13 -0700 Subject: [PATCH 9/9] update template --- test/demo/type_erasure_shared_pointer_value_manager.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/demo/type_erasure_shared_pointer_value_manager.cpp b/test/demo/type_erasure_shared_pointer_value_manager.cpp index 379e1cb..3b39252 100644 --- a/test/demo/type_erasure_shared_pointer_value_manager.cpp +++ b/test/demo/type_erasure_shared_pointer_value_manager.cpp @@ -4,11 +4,9 @@ #include #include -#include - // Primary template: defaults to false -template > +template struct ExclusiveAwareTrait: std::false_type {}; // Specialization: if T has T::ExclusiveAware, this will match and be true