Skip to content

Instantly share code, notes, and snippets.

@komiga
Last active December 16, 2023 01:55
Show Gist options
  • Select an option

  • Save komiga/5219355 to your computer and use it in GitHub Desktop.

Select an option

Save komiga/5219355 to your computer and use it in GitHub Desktop.
#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