Last active
December 16, 2023 01:55
-
-
Save komiga/5219355 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <cassert> | |
| #include <new> | |
| #include <iostream> | |
| namespace { | |
| template<typename... P> | |
| struct sizeof_max_impl; | |
| template<> | |
| struct sizeof_max_impl<> { | |
| static constexpr std::size_t g(std::size_t const size) { | |
| return size; | |
| } | |
| }; | |
| template<typename I, typename... P> | |
| struct sizeof_max_impl<I, P...> { | |
| static constexpr std::size_t g(std::size_t const size) { | |
| return sizeof_max_impl<P...>::g( | |
| size < sizeof(I) | |
| ? sizeof(I) | |
| : size | |
| ); | |
| } | |
| }; | |
| } | |
| template<typename... P> | |
| constexpr std::size_t sizeof_max() { | |
| return sizeof_max_impl<P...>::g(0u); | |
| } | |
| enum class ElementType : unsigned { | |
| // Primitives | |
| uint8, int8, | |
| uint16, int16, | |
| uint32, int32, | |
| uint64, int64, | |
| float32, float64, | |
| zstring, | |
| // Complex | |
| string, | |
| array, | |
| ref, | |
| // Sentinels | |
| terminate | |
| }; | |
| static char const | |
| s_element_invalid[]{"INVALID"}, | |
| * const s_element_names[]{ | |
| "uint8", "int8", | |
| "uint16", "int16", | |
| "uint32", "int32", | |
| "uint64", "int64", | |
| "float32", "float64", | |
| "zstring", | |
| "string", | |
| "array", | |
| "ref", | |
| "terminate" | |
| }; | |
| char const* get_element_name(ElementType const element_type) noexcept { | |
| std::size_t const index=static_cast<std::size_t>(element_type); | |
| if (index<std::extent<decltype(s_element_names)>::value) { | |
| return s_element_names[index]; | |
| } else { | |
| return s_element_invalid; | |
| } | |
| } | |
| template<class EDesc> | |
| struct desc_traits { | |
| using type=void; | |
| static constexpr ElementType element_type=ElementType::terminate; | |
| static constexpr bool is_desc=false; | |
| }; | |
| #define DECLARE_DESC(T, E) \ | |
| template<> \ | |
| struct desc_traits<T> { \ | |
| using type=T; \ | |
| static constexpr ElementType element_type=E; \ | |
| static constexpr bool is_desc=true; \ | |
| }; | |
| #define ASSERT_IS_A_DESC(T) \ | |
| static_assert( \ | |
| desc_traits<T>::is_desc, \ | |
| "type is not an element descriptor" \ | |
| ); | |
| class Desc; | |
| struct StringDesc; | |
| struct ArrayDesc; | |
| struct RefDesc; | |
| struct StringDesc final { | |
| std::size_t size; | |
| }; | |
| struct ArrayDesc final { | |
| std::size_t size; | |
| ElementType elem; | |
| }; | |
| struct RefDesc final { | |
| Desc* ref; | |
| }; | |
| DECLARE_DESC(StringDesc, ElementType::string); | |
| DECLARE_DESC(ArrayDesc, ElementType::array); | |
| DECLARE_DESC(RefDesc, ElementType::ref); | |
| class Desc final { | |
| private: | |
| ElementType m_type; | |
| uint8_t m_data[ | |
| sizeof_max< | |
| StringDesc, | |
| ArrayDesc, | |
| RefDesc | |
| >() | |
| ]; | |
| Desc()=delete; | |
| public: | |
| Desc(Desc const&)=default; | |
| Desc(Desc&&)=default; | |
| Desc& operator=(Desc const&)=default; | |
| Desc& operator=(Desc&&)=default; | |
| Desc(ElementType const type) | |
| : m_type{type} | |
| {} | |
| template<class EDesc> | |
| Desc(EDesc&& desc) noexcept { | |
| set_desc(std::move(desc)); | |
| } | |
| ElementType get_type() const noexcept { return m_type; } | |
| template<class EDesc> | |
| void set_desc(EDesc&& desc) noexcept { | |
| ASSERT_IS_A_DESC(EDesc); | |
| m_type=desc_traits<EDesc>::element_type; | |
| ::new (m_data) EDesc(std::move(desc)); | |
| } | |
| template<class EDesc> | |
| EDesc& get_desc() noexcept { | |
| ASSERT_IS_A_DESC(EDesc); | |
| assert(desc_traits<EDesc>::element_type==m_type); | |
| return reinterpret_cast<EDesc&>(m_data); | |
| } | |
| }; | |
| Desc s_comp[]{ | |
| ArrayDesc{10, ElementType::uint8}, | |
| ElementType::terminate | |
| }; | |
| Desc s_comp_bukkit[]{ | |
| RefDesc{s_comp}, | |
| ElementType::terminate | |
| }; | |
| signed main() { | |
| std::cout | |
| <<"EDesc max size: " | |
| <<sizeof_max< | |
| StringDesc, | |
| ArrayDesc, | |
| RefDesc | |
| >() | |
| <<std::endl; | |
| ArrayDesc& ad=s_comp[0].get_desc<ArrayDesc>(); | |
| std::cout | |
| <<get_element_name(s_comp[0].get_type())<<": " | |
| <<ad.size<<", "<<get_element_name(ad.elem) | |
| <<std::endl; | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment