typeindices.hpp: upgrade with size and align info

This allows contiguous allocation (as in an aggregate).
This commit is contained in:
Nekotekina 2021-02-03 17:05:31 +03:00
parent aa7e2376ec
commit 5cc9bd7702

View File

@ -1,5 +1,14 @@
#pragma once #pragma once
#include "util/types.hpp"
#include "util/shared_ptr.hpp"
#ifndef _MSC_VER
#define ATTR_PURE __attribute__((pure))
#else
#define ATTR_PURE /* nothing available */
#endif
namespace stx namespace stx
{ {
template <typename Info> template <typename Info>
@ -10,12 +19,19 @@ namespace stx
class type_info final : public Info class type_info final : public Info
{ {
// Current type id (starts from 0) // Current type id (starts from 0)
unsigned type = 0u - 1; u32 type = UINT32_MAX;
u32 size = 1;
u32 align = 1;
u32 begin = 0;
// Next typeinfo in linked list // Next typeinfo in linked list
type_info* next = nullptr; type_info* next = nullptr;
type_info(Info info, decltype(sizeof(int))) noexcept; // Auxiliary pointer to base type
const type_info* base = nullptr;
type_info(Info info, u32 size, u32 align, const type_info* base = nullptr) noexcept;
friend type_counter<Info>; friend type_counter<Info>;
@ -25,10 +41,20 @@ namespace stx
{ {
} }
unsigned index() const ATTR_PURE u32 index() const
{ {
return type; return type;
} }
ATTR_PURE u32 pos() const
{
return begin;
}
ATTR_PURE u32 end() const
{
return begin + size;
}
}; };
// Class for automatic type registration for given Info type // Class for automatic type registration for given Info type
@ -46,11 +72,37 @@ namespace stx
public: public:
constexpr type_counter() noexcept = default; constexpr type_counter() noexcept = default;
unsigned count() const u32 count() const
{ {
return next->index() + 1; 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 class const_iterator
{ {
const type_info<Info>* ptr; const type_info<Info>* ptr;
@ -107,7 +159,11 @@ namespace stx
// Global type info instance // Global type info instance
template <typename T> template <typename T>
static inline const type_info<Info> type{Info::template make_typeinfo<T>(), sizeof(T)}; static const type_info<Info> type;
// Helper for dynamic types
template <typename T, typename As>
static const type_info<Info> dyn_type;
}; };
// Global typecounter instance // Global typecounter instance
@ -118,28 +174,110 @@ namespace stx
return typelist_v; return typelist_v;
} }
// Helper for dynamic types
template <typename Info> template <typename Info>
type_info<Info>::type_info(Info info, decltype(sizeof(int))) noexcept auto& dyn_typelist()
: Info(info) {
, type(typelist<Info>().count()) static type_counter<Info> typelist_v;
return typelist_v;
}
template <typename Info> template <typename T>
const type_info<Info> type_counter<Info>::type{Info::template make_typeinfo<T>(), sizeof(T), alignof(T)};
template <typename Info> template <typename T, typename As>
const type_info<Info> type_counter<Info>::dyn_type{Info::template make_typeinfo<As>(), sizeof(As), alignof(As), &type_counter<Info>::template type<T>};
template <typename Info>
type_info<Info>::type_info(Info info, u32 _size, u32 _align, const type_info<Info>* cbase) noexcept
: Info(info)
{ {
// Update linked list
auto& tl = typelist<Info>(); auto& tl = typelist<Info>();
// Update type info
this->size = _size > this->size ? _size : this->size;
this->align = _align > this->align ? _align : this->align;
this->base = cbase;
// Update global max alignment
tl.first.align = _align > tl.first.align ? _align : tl.first.align;
auto& dl = dyn_typelist<Info>();
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->next = this;
tl.next = this; tl.next = this;
} }
// Type index accessor // Type index accessor
template <typename Info, typename T> template <typename Info, typename T, typename As = T>
inline unsigned typeindex() noexcept ATTR_PURE inline u32 typeindex() noexcept
{ {
return type_counter<Info>::template type<T>.index(); static_assert(sizeof(T) > 0);
if constexpr (std::is_same_v<T, As>)
{
return type_counter<Info>::template type<T>.index();
}
else
{
static_assert(sizeof(As) > 0);
static_assert(is_same_ptr<T, As>());
return type_counter<Info>::template dyn_type<T, As>.index();
}
}
// Type global offset
template <typename Info, typename T>
ATTR_PURE inline u32 typeoffset() noexcept
{
static_assert(sizeof(T) > 0);
return type_counter<Info>::template type<T>.pos();
} }
// Type info accessor // Type info accessor
template <typename Info, typename T> template <typename Info, typename T, typename As = T>
inline const Info& typedata() noexcept ATTR_PURE inline const Info& typedata() noexcept
{ {
return type_counter<Info>::template type<T>; static_assert(sizeof(T) > 0 && sizeof(As) > 0);
static_assert(is_same_ptr<T, As>());
return type_counter<Info>::template dyn_type<T, As>;
} }
} }
#undef ATTR_PURE