#ifndef __JABYENGINE_LINKED_ELEMENTS_HPP__ #define __JABYENGINE_LINKED_ELEMENTS_HPP__ #include "../../Auxiliary/bits.hpp" namespace JabyEngine { namespace GPU { struct Link { static constexpr auto AdrRange = BitRange::from_to(0, 23); static constexpr auto SizeRange = BitRange::from_to(24, 31); static constexpr uint32_t TerminationValue = 0x00FFFFFF; static constexpr uint32_t default_link_value(size_t size) { return SizeRange.as_value(size >> 2) | TerminationValue; } uint32_t link_value; constexpr Link() = default; constexpr Link(size_t size) : link_value(default_link_value(size)) { } constexpr void set_link_identitiy(size_t size) { this->link_value = default_link_value(size); } void set_adr(const void* adr) { this->link_value = bit::value::set_normalized(this->link_value, AdrRange.with(reinterpret_cast(adr))); } void* get_adr() const { return reinterpret_cast(bit::value::get_normalized(this->link_value, AdrRange)); } template T& insert_after(T& obj) { const auto adr = Link::get_adr(); Link::set_adr(&obj); obj.set_adr(adr); return obj; } template T& concat(T& obj) { Link::set_adr(&obj); return obj; } template const T& concat(const T& obj) { return concat(const_cast(obj)); } constexpr void terminate() { this->link_value |= TerminationValue; } }; template struct LinkedElement : public Link { T element; constexpr LinkedElement() = default; constexpr LinkedElement(const T& element) : Link(sizeof(T)), element(element) { } constexpr void set_link_identitiy() { Link::set_link_identitiy(sizeof(T)); } constexpr const T* operator->() const { return &this->element; } constexpr T* operator->() { return &this->element; } }; namespace internal { template struct LinkedElementCreator { typedef LinkedElement Linked; constexpr LinkedElement linked() { return LinkedElement(*static_cast(this)); } }; } } } #endif // !__JABYENGINE_LINKED_ELEMENTS_HPP__