diff --git a/docs/md/poly.md b/docs/md/poly.md index dc151533e..cbcfc0be3 100644 --- a/docs/md/poly.md +++ b/docs/md/poly.md @@ -13,6 +13,7 @@ * [Fullfill a concept](#fullfill-a-concept) * [Inheritance](#inheritance) * [Static polymorphism in the wild](#static-polymorphism-in-the-wild) +* [Configurable storage size](#configurable-storage-size) @@ -236,7 +237,7 @@ For a deduced concept, inheritance is achieved in a few steps: ```cpp struct DrawableAndErasable: entt::type_list<> { template - struct type: typename Drawable::type { + struct type: typename Drawable::template type { static constexpr auto base = std::tuple_size_v::type>; void erase() { entt::poly_call(*this); } }; @@ -336,3 +337,22 @@ This allows users to decouple the API of the wrapper from that of the concept. Therefore, where `instance.data()` will invoke the `data` member function of the poly object, `instance->data()` will map directly to the functionality exposed by the underlying concept. + +# Configurable storage size + +Under the hood, the `poly` class template makes use of `entt::any`. Therefore, +it can take advantage of the possibility of defining at compile-time the size of +the storage suitable for the small buffer optimization.
+To do this, it will be sufficient to provide the desired size as a second +template parameter: + +```cpp +entt::poly +``` + +The default value is `sizeof(double[2])`, which seems like a good compromise +between a buffer that is too large and one unable to hold anything larger than +an integer.
+It's worth noting that providing a size of 0 (which is an accepted value in all +respects) will force the system to dynamically allocate the contained objects in +all cases. diff --git a/src/entt/poly/poly.hpp b/src/entt/poly/poly.hpp index 17c98f0c3..feba60908 100644 --- a/src/entt/poly/poly.hpp +++ b/src/entt/poly/poly.hpp @@ -171,17 +171,18 @@ decltype(auto) poly_call(Poly &&self, Args &&... args) { * Moreover, the `poly` class template also works with unmanaged objects. * * @tparam Concept Concept descriptor. + * @tparam Len Size of the storage reserved for the small buffer optimization. */ -template -class poly: private Concept::template type>> { +template +class poly: private Concept::template type>> { /*! @brief A poly base is allowed to snoop into a poly object. */ - friend struct poly_base>; + friend struct poly_base; using vtable_type = typename poly_vtable::type; public: /*! @brief Concept type. */ - using concept_type = typename Concept::template type>>; + using concept_type = typename Concept::template type>; /*! @brief Default constructor. */ poly() ENTT_NOEXCEPT @@ -336,7 +337,7 @@ public: } private: - any storage; + basic_any storage; const vtable_type *vtable; }; diff --git a/test/entt/poly/poly_deduced.cpp b/test/entt/poly/poly_deduced.cpp index 24c366a21..323c44739 100644 --- a/test/entt/poly/poly_deduced.cpp +++ b/test/entt/poly/poly_deduced.cpp @@ -208,3 +208,17 @@ TEST(PolyDeduced, AsRef) { ASSERT_NE(ref.data(), nullptr); ASSERT_NE(cref.data(), nullptr); } + +TEST(PolyDeduced, SBOVsZeroedSBOSize) { + entt::poly sbo{impl{}}; + const auto broken = sbo.data(); + entt::poly other = std::move(sbo); + + ASSERT_NE(broken, other.data()); + + entt::poly dyn{impl{}}; + const auto valid = dyn.data(); + entt::poly same = std::move(dyn); + + ASSERT_EQ(valid, same.data()); +} diff --git a/test/entt/poly/poly_defined.cpp b/test/entt/poly/poly_defined.cpp index e8e6e2cc4..450b2c5fa 100644 --- a/test/entt/poly/poly_defined.cpp +++ b/test/entt/poly/poly_defined.cpp @@ -214,3 +214,17 @@ TEST(PolyDefined, AsRef) { ASSERT_NE(ref.data(), nullptr); ASSERT_NE(cref.data(), nullptr); } + +TEST(PolyDefined, SBOVsZeroedSBOSize) { + entt::poly sbo{impl{}}; + const auto broken = sbo.data(); + entt::poly other = std::move(sbo); + + ASSERT_NE(broken, other.data()); + + entt::poly dyn{impl{}}; + const auto valid = dyn.data(); + entt::poly same = std::move(dyn); + + ASSERT_EQ(valid, same.data()); +}