2424// Layout:
2525// Used to plan which objects are needed.
2626// Reserves handles that can later be resolved against Data.
27- // Defines the Data and DataUP types used to access the data.
2827//
2928// Data:
3029// Owns the packed storage for all objects planned by Layout.
31- // Inherits from the Base class specified in Layout .
30+ // This class can be extended by the user to add custom data and API .
3231//
3332// Handle:
3433// Reserved by Layout for a single object.
@@ -81,8 +80,6 @@ template <size_t I, typename H, typename... Ts> constexpr auto get_type_at() {
8180 }
8281}
8382
84- struct EmptyBase {};
85-
8683} // namespace detail
8784
8885template <typename H, typename ... Ts> struct Domain {
@@ -107,23 +104,23 @@ template <typename T, domain D> constexpr size_t type_id() {
107104
108105namespace detail {
109106
110- template <domain D, typename Base > constexpr std::align_val_t full_align () {
111- return std::align_val_t (std::max (D::max_align, alignof (Base )));
107+ template <domain D, typename Target > constexpr std::align_val_t full_align () {
108+ return std::align_val_t (std::max (D::max_align, alignof (Target )));
112109}
113110
114- template <domain D, typename Base > struct DataDeleter ;
111+ template <domain D, typename Target > struct DataDeleter ;
115112
116113} // namespace detail
117114
118- template <domain D, typename Base > class Data ;
119- template <domain D, typename Base = detail::EmptyBase > class Layout ;
115+ template <domain D> class Data ;
116+ template <domain D, typename Target = Data<D> > class Layout ;
120117class ArrayHandle ;
121118
122119class Handle {
123120private:
124121 friend class ArrayHandle ;
125122 friend class HandleIterator ;
126- template <domain D, typename Base > friend class Layout ;
123+ template <domain D, typename Target > friend class Layout ;
127124 uint32_t _value;
128125 static constexpr uint32_t invalid_handle = 0xffffffff ;
129126 static constexpr uint32_t offset_bits = 24 ;
@@ -165,8 +162,8 @@ class HandleIterator {
165162
166163class ArrayHandle {
167164private:
168- template <domain D, typename Base > friend class Layout ;
169- template <domain D, typename Base > friend class Data ;
165+ template <domain D, typename Target > friend class Layout ;
166+ template <domain D> friend class Data ;
170167 Handle _base;
171168 uint32_t _size;
172169
@@ -189,25 +186,32 @@ class ArrayHandle {
189186 constexpr auto end () const noexcept { return HandleIterator (_base._value + _size); }
190187};
191188
192- template <typename ... Ts, typename Base> class Data <Domain<Ts...>, Base> : public Base {
189+ class DataKey {
190+ private:
191+ template <domain D, typename Target> friend class Layout ;
192+ constexpr DataKey () noexcept = default;
193+ };
194+
195+ template <typename ... Ts> class Data <Domain<Ts...>> {
193196private:
194197 using MyDomain = Domain<Ts...>;
195- friend class Layout <MyDomain, Base> ;
196- friend struct detail ::DataDeleter<MyDomain, Base> ;
198+ template <domain D, typename Target> friend class Layout ;
199+ template <domain D, typename Target> friend struct detail ::DataDeleter;
197200 struct VectorRef {
198201 uint32_t pos;
199202 uint32_t len;
200203 constexpr VectorRef () noexcept : pos(0 ), len(0 ) {}
201204 };
202205 size_t _allocated;
203206 std::array<VectorRef, MyDomain::num_types> _header;
204- constexpr Data (size_t need_size) noexcept : _allocated(need_size), _header{} {}
205207 Data (const Data&) = delete ;
206208 Data (Data&&) = delete ;
207209 Data& operator =(const Data&) = delete ;
208210 Data& operator =(Data&&) = delete ;
209211
210212public:
213+ constexpr Data (DataKey) noexcept : _allocated{}, _header{} {}
214+
211215 template <typename T> std::span<T> all_of () noexcept {
212216 static constexpr size_t I = type_id<T, MyDomain>();
213217 if (_header[I].len == 0 ) {
@@ -252,31 +256,31 @@ template <typename... Ts, typename Base> class Data<Domain<Ts...>, Base> : publi
252256
253257namespace detail {
254258
255- template <typename ... Ts, typename Base > struct DataDeleter <Domain<Ts...>, Base > {
259+ template <typename ... Ts, typename Target > struct DataDeleter <Domain<Ts...>, Target > {
256260 using MyDomain = Domain<Ts...>;
257- using MyData = Data<MyDomain, Base> ;
258- void operator ()(MyData * ptr) noexcept {
261+ static_assert (std::derived_from<Target, Data<MyDomain>>) ;
262+ void operator ()(Target * ptr) noexcept {
259263 auto destruct_array = [&]<typename T>() {
260264 for (auto & obj : ptr->template all_of <T>()) {
261265 obj.~T ();
262266 }
263267 };
264268 (destruct_array.template operator ()<Ts>(), ...);
265- ptr->~MyData ();
266- ::operator delete (ptr, full_align<MyDomain, Base >());
269+ ptr->~Target ();
270+ ::operator delete (ptr, full_align<MyDomain, Target >());
267271 }
268272};
269273
270274} // namespace detail
271275
272- template <typename ... Ts, typename Base > class Layout <Domain<Ts...>, Base > {
276+ template <typename ... Ts, typename Target > class Layout <Domain<Ts...>, Target > {
273277private:
274278 using MyDomain = Domain<Ts...>;
275279 std::array<uint32_t , MyDomain::num_types> counts{};
280+ static_assert (std::derived_from<Target, Data<MyDomain>>);
276281
277282public:
278- using MyData = Data<MyDomain, Base>;
279- using DataUP = std::unique_ptr<MyData, detail::DataDeleter<MyDomain, Base>>;
283+ using DataUP = std::unique_ptr<Target, detail::DataDeleter<MyDomain, Target>>;
280284 template <typename T> Handle reserve () {
281285 static constexpr size_t I = type_id<T, MyDomain>();
282286 return Handle::make<I>(counts[I]++);
@@ -292,7 +296,7 @@ template <typename... Ts, typename Base> class Layout<Domain<Ts...>, Base> {
292296 return ArrayHandle::make<I>(0 , counts[I]);
293297 }
294298 DataUP create_data () const {
295- size_t need_size = sizeof (MyData );
299+ size_t need_size = sizeof (Target );
296300 [&]<size_t ... Is>(std::index_sequence<Is...>) {
297301 auto handle_array = [&]<typename T, size_t I>() {
298302 if (counts[I] > 0 ) {
@@ -303,11 +307,12 @@ template <typename... Ts, typename Base> class Layout<Domain<Ts...>, Base> {
303307 (handle_array.template operator ()<Ts, Is>(), ...);
304308 }(typename MyDomain::index_sequence{});
305309 assert (need_size <= UINT32_MAX);
306- constexpr auto align = detail::full_align<MyDomain, Base >();
310+ constexpr auto align = detail::full_align<MyDomain, Target >();
307311 char * mem = static_cast <char *>(::operator new (need_size, align));
308- DataUP result (new (mem) MyData (need_size ));
312+ DataUP result (new (mem) Target (DataKey{} ));
309313 auto & obj = *result;
310- size_t offset = sizeof (MyData);
314+ size_t offset = sizeof (Target);
315+ obj._allocated = need_size;
311316 [&]<size_t ... Is>(std::index_sequence<Is...>) {
312317 auto construct_array = [&]<typename T, size_t I>() {
313318 if (counts[I] > 0 ) {
0 commit comments