#pragma once #include "util/types.hpp" #include "util/shared_ptr.hpp" #include #ifndef _MSC_VER #define ATTR_PURE __attribute__((pure)) #else #define ATTR_PURE /* nothing available */ #endif namespace stx { template class type_counter; // Type information for given Info type, also serving as tag template class type_info final : public Info { // Current type id (starts from 0) u32 type = umax; u32 size = 1; u32 align = 1; u32 begin = 0; double order{}; // Next typeinfo in linked list type_info* next = nullptr; // Auxiliary pointer to base type const type_info* base = nullptr; type_info(Info info, u32 size, u32 align, double order, const type_info* base = nullptr) noexcept; friend type_counter; public: constexpr type_info() noexcept : Info() { } ATTR_PURE u32 index() const { return type; } ATTR_PURE u32 pos() const { return begin; } ATTR_PURE u32 end() const { return begin + size; } ATTR_PURE double init_pos() const { return order; } }; // Class for automatic type registration for given Info type template class type_counter final { // Dummy first element to simplify list filling logic type_info first{}; // Linked list built at global initialization time type_info* next = &first; friend type_info; public: constexpr type_counter() noexcept = default; u32 count() const { return next->index() + 1; } u32 align() const { return first.align; } u32 size() const { // Get on first use static const u32 sz = [&]() { u32 result = 0; for (auto* ptr = first.next; ptr; ptr = ptr->next) { result = ((result + ptr->align - 1) & (u32{0} - ptr->align)); ptr->begin = result; result = result + ptr->size; } return result; }(); return sz; } class const_iterator { const type_info* ptr; public: const_iterator(const type_info* ptr) : ptr(ptr) { } const type_info& operator*() const { return *ptr; } const type_info* operator->() const { return ptr; } const_iterator& operator++() { ptr = ptr->next; return *this; } const_iterator operator++(int) { const_iterator r = ptr; ptr = ptr->next; return r; } bool operator==(const const_iterator& r) const { return ptr == r.ptr; } }; const_iterator begin() const { return first.next; } const_iterator end() const { return nullptr; } // Global type info instance template static const type_info type; // Helper for dynamic types template static const type_info dyn_type; }; // Global typecounter instance template auto& typelist() { static type_counter typelist_v; return typelist_v; } // Helper for dynamic types template auto& dyn_typelist() { static type_counter typelist_v; return typelist_v; } template requires requires () { T::savestate_init_pos + 0.; } constexpr double get_savestate_init_pos() { return T::savestate_init_pos; } template requires (!(requires () { T::savestate_init_pos + 0.; })) constexpr double get_savestate_init_pos() { return {}; } template template const type_info type_counter::type{Info::template make_typeinfo(), sizeof(T), alignof(T), get_savestate_init_pos()}; template template const type_info type_counter::dyn_type{Info::template make_typeinfo(), sizeof(As), alignof(As), get_savestate_init_pos(), &type_counter::template type}; template type_info::type_info(Info info, u32 _size, u32 _align, double order, const type_info* cbase) noexcept : Info(info) { auto& tl = typelist(); // Update type info this->size = _size > this->size ? _size : this->size; this->align = _align > this->align ? _align : this->align; this->base = cbase; this->order = order; // Update global max alignment tl.first.align = _align > tl.first.align ? _align : tl.first.align; auto& dl = dyn_typelist(); if (cbase) { dl.next->next = this; dl.next = this; // Update base max size/align for dynamic types for (auto ptr = tl.first.next; ptr; ptr = ptr->next) { if (cbase == ptr) { ptr->size = _size > ptr->size ? _size : ptr->size; ptr->align = _align > ptr->align ? _align : ptr->align; this->type = ptr->type; } } return; } // Update type index this->type = tl.next->type + 1; // Update base max size/align for dynamic types for (auto ptr = dl.first.next; ptr; ptr = ptr->next) { if (ptr->base == this) { this->size = ptr->size > this->size ? ptr->size : this->size; this->align = ptr->align > this->align ? ptr->align : this->align; ptr->type = this->type; } } // Update linked list tl.next->next = this; tl.next = this; } // Type index accessor template ATTR_PURE inline u32 typeindex() noexcept { static_assert(sizeof(T) > 0); if constexpr (std::is_same_v) { return type_counter::template type.index(); } else { static_assert(sizeof(As) > 0); static_assert(PtrSame); return type_counter::template dyn_type.index(); } } // Type global offset template ATTR_PURE inline u32 typeoffset() noexcept { static_assert(sizeof(T) > 0); return type_counter::template type.pos(); } // Type info accessor template ATTR_PURE inline const Info& typedata() noexcept { static_assert(sizeof(T) > 0 && sizeof(As) > 0); static_assert(PtrSame); // TODO return type_counter::template dyn_type; } } #undef ATTR_PURE