#pragma once #include "../../Auxiliary/bits.hpp" #include "../../Auxiliary/type_traits.hpp" #include "../../System/IOPorts/gpu_io.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 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 enable_if::value, Link&>::type concat(T& obj) { Link::set_adr(&obj); return *this; } template enable_if::value, const Link&>::type concat(const T& obj) { return concat(const_cast(obj)); } constexpr void terminate() { this->link_value |= TerminationValue; } }; template struct LinkedElement : public Link { T element; static constexpr LinkedElement create(const T& element) { LinkedElement new_element; new_element.element = element; new_element.set_link_identitiy(); return new_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; } static_assert((sizeof(T) >> 2) <= GPU_IO::FIFOWordSize); }; namespace internal { template struct LinkedElementCreator { typedef LinkedElement Linked; constexpr LinkedElement linked() { return LinkedElement::create(*static_cast(this)); } }; } namespace LinkHelper { template static Link* link_array(Link* last_prim, T* elements, size_t length) { for(size_t n = 0; n < length; n++) { last_prim->concat(elements[n]); last_prim = &elements[n]; } last_prim->terminate(); return last_prim; } template static Link* link_array(Link* last_prim, T(&elements)[N]) { return link_array(last_prim, elements, N); } } } }