From 24c1457ca9252c2ed35f1308f696ce0c43f0c9e9 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Wed, 21 Sep 2022 17:26:27 +0700 Subject: [PATCH] add single-header version --- .ci/build_singles.py | 114 + .clang-tidy | 5 + CMakeLists.txt | 3 +- headers/meta.hpp/meta_base/bitflags.hpp | 8 +- singles/CMakeLists.txt | 30 + singles/headers/meta.hpp/meta_all.hpp | 8394 +++++++++++++++++++++++ untests/CMakeLists.txt | 99 +- 7 files changed, 8616 insertions(+), 37 deletions(-) create mode 100755 .ci/build_singles.py create mode 100644 singles/CMakeLists.txt create mode 100644 singles/headers/meta.hpp/meta_all.hpp diff --git a/.ci/build_singles.py b/.ci/build_singles.py new file mode 100755 index 0000000..e37d34a --- /dev/null +++ b/.ci/build_singles.py @@ -0,0 +1,114 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import os +import re +import sys + +# +# +# + +EMPTY_MATCHER = re.compile(r'^\s*$') +C_COMMENT_MATCHER = re.compile(r'^/\*.*\*/', re.S) + +USER_INCLUDE_MATCHER = re.compile(r'#\s*include\s*\"(.*)\"') +SYSTEM_INCLUDE_MATCHER = re.compile(r'#\s*include\s*<(.*)>') +PRAGMA_ONCE_MATCHER = re.compile(r'#\s*pragma\s+once') + +# +# +# + +def CollectLicenseComment(headerPath): + with open(headerPath, "r") as headerStream: + headerContent = headerStream.read().strip() + commentMatch = re.match(C_COMMENT_MATCHER, headerContent) + return commentMatch.group() if commentMatch else "" + +def CollectSystemIncludes(headerPath, parsedHeaders = set()): + with open(headerPath, "r") as headerStream: + headerContent = headerStream.read().strip() + + if PRAGMA_ONCE_MATCHER.search(headerContent) and headerPath in parsedHeaders: + return set() + + headerIncludes = set() + + parsedHeaders.add(headerPath) + headerLines = headerContent.split('\n') + + for headerLine in headerLines: + includeMatch = USER_INCLUDE_MATCHER.findall(headerLine) + if includeMatch: + internalHeaderPath = os.path.abspath(os.path.join(os.path.dirname(headerPath), includeMatch[0])) + headerIncludes = headerIncludes.union(CollectSystemIncludes(internalHeaderPath, parsedHeaders)) + includeMatch = SYSTEM_INCLUDE_MATCHER.findall(headerLine) + if includeMatch: + headerIncludes.add(includeMatch[0]) + + return headerIncludes + +def ParseHeader(headerPath, parsedHeaders = set()): + with open(headerPath, "r") as headerStream: + headerContent = headerStream.read().strip() + headerContent = re.sub(C_COMMENT_MATCHER, '', headerContent) + + if PRAGMA_ONCE_MATCHER.search(headerContent) and headerPath in parsedHeaders: + return "" + + parsedHeaders.add(headerPath) + headerLines = headerContent.split('\n') + + outputContent = "" + shouldSkipNextEmptyLines = True + + for headerLine in headerLines: + if EMPTY_MATCHER.match(headerLine) and shouldSkipNextEmptyLines: + continue + + if PRAGMA_ONCE_MATCHER.match(headerLine): + shouldSkipNextEmptyLines = True + continue + + includeMatch = USER_INCLUDE_MATCHER.findall(headerLine) + if includeMatch: + internalHeaderPath = os.path.abspath(os.path.join(os.path.dirname(headerPath), includeMatch[0])) + internalHeaderContent = ParseHeader(internalHeaderPath, parsedHeaders) + + outputContent += internalHeaderContent + shouldSkipNextEmptyLines = True + continue + + includeMatch = SYSTEM_INCLUDE_MATCHER.findall(headerLine) + if includeMatch: + shouldSkipNextEmptyLines = True + continue + + shouldSkipNextEmptyLines = False + outputContent += "{}\n".format(headerLine) + + return "{}\n".format(outputContent) + +# +# +# + +inputHeaderPath = os.path.abspath(sys.argv[1]) +outputHeaderPath = os.path.abspath(sys.argv[2]) + +os.makedirs(os.path.dirname(outputHeaderPath), exist_ok=True) + +with open(outputHeaderPath, "w") as outputHeaderStream: + licenseComment = CollectLicenseComment(inputHeaderPath) + systemIncludes = CollectSystemIncludes(inputHeaderPath) + + outputHeaderStream.write("{}\n".format(licenseComment)) + outputHeaderStream.write("\n") + + for systemInclude in sorted(systemIncludes): + outputHeaderStream.write("#include <{}>\n".format(systemInclude)) + outputHeaderStream.write("\n") + + outputHeaderStream.write(ParseHeader(inputHeaderPath).strip()) + outputHeaderStream.write("\n") diff --git a/.clang-tidy b/.clang-tidy index 10d9d4c..271fe9f 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -4,6 +4,8 @@ Checks: '-*, bugprone-*, -bugprone-easily-swappable-parameters, -bugprone-forwarding-reference-overload, + -bugprone-lambda-function-name, + -bugprone-macro-parentheses, clang-analyzer-*, @@ -11,6 +13,7 @@ Checks: '-*, cppcoreguidelines-*, -cppcoreguidelines-macro-usage, + -cppcoreguidelines-pro-bounds-array-to-pointer-decay, -cppcoreguidelines-pro-bounds-pointer-arithmetic, modernize-*, @@ -22,7 +25,9 @@ Checks: '-*, readability-*, -readability-identifier-length, + -readability-named-parameter, -readability-redundant-access-specifiers, + -readability-simplify-boolean-expr, -readability-use-anyofallof, ' ... diff --git a/CMakeLists.txt b/CMakeLists.txt index cadd0c5..370c88e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,8 +10,6 @@ endif() project(meta.hpp) add_library(${PROJECT_NAME} INTERFACE) -add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) - target_compile_features(${PROJECT_NAME} INTERFACE cxx_std_20) target_include_directories(${PROJECT_NAME} INTERFACE headers) @@ -39,5 +37,6 @@ include(EnableGCov) include(EnableUBSan) add_subdirectory(manuals) +add_subdirectory(singles) add_subdirectory(vendors) add_subdirectory(untests) diff --git a/headers/meta.hpp/meta_base/bitflags.hpp b/headers/meta.hpp/meta_base/bitflags.hpp index 04a9e6e..90edcac 100644 --- a/headers/meta.hpp/meta_base/bitflags.hpp +++ b/headers/meta.hpp/meta_base/bitflags.hpp @@ -37,19 +37,19 @@ namespace meta_hpp::detail swap(flags_, other.flags_); } - constexpr explicit operator bool() const noexcept { + [[nodiscard]] constexpr explicit operator bool() const noexcept { return !!flags_; } - constexpr underlying_type as_raw() const noexcept { + [[nodiscard]] constexpr underlying_type as_raw() const noexcept { return flags_; } - constexpr enum_type as_enum() const noexcept { + [[nodiscard]] constexpr enum_type as_enum() const noexcept { return static_cast(flags_); } - constexpr bool has(bitflags flags) const noexcept { + [[nodiscard]] constexpr bool has(bitflags flags) const noexcept { return flags.flags_ == (flags_ & flags.flags_); } diff --git a/singles/CMakeLists.txt b/singles/CMakeLists.txt new file mode 100644 index 0000000..a58d8fb --- /dev/null +++ b/singles/CMakeLists.txt @@ -0,0 +1,30 @@ +project(meta.hpp.singles) + +# +# generate +# + +find_package(PythonInterp REQUIRED) + +set(META_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/..") +set(META_SINGLES_INPUT "${META_ROOT_DIR}/headers/meta.hpp/meta_all.hpp") +set(META_SINGLES_OUTPUT "${META_ROOT_DIR}/singles/headers/meta.hpp/meta_all.hpp") +file(GLOB_RECURSE META_SINGLES_DEPENDS "${META_ROOT_DIR}/headers/*.hpp") + +add_custom_command(OUTPUT "${META_SINGLES_OUTPUT}" + COMMAND "${PYTHON_EXECUTABLE}" ".ci/build_singles.py" "${META_SINGLES_INPUT}" "${META_SINGLES_OUTPUT}" + DEPENDS ${META_SINGLES_DEPENDS} + WORKING_DIRECTORY "${META_ROOT_DIR}") + +add_custom_target(${PROJECT_NAME}.generate + DEPENDS "${META_SINGLES_OUTPUT}") + +# +# library +# + +add_library(${PROJECT_NAME} INTERFACE) +add_dependencies(${PROJECT_NAME} ${PROJECT_NAME}.generate) +target_compile_features(${PROJECT_NAME} INTERFACE cxx_std_20) +target_include_directories(${PROJECT_NAME} INTERFACE headers) +target_link_libraries(${PROJECT_NAME} INTERFACE Threads::Threads) diff --git a/singles/headers/meta.hpp/meta_all.hpp b/singles/headers/meta.hpp/meta_all.hpp new file mode 100644 index 0000000..0775287 --- /dev/null +++ b/singles/headers/meta.hpp/meta_all.hpp @@ -0,0 +1,8394 @@ +/******************************************************************************* + * This file is part of the "https://github.com/blackmatov/meta.hpp" + * For conditions of distribution and use, see copyright notice in LICENSE.md + * Copyright (C) 2021-2022, by Matvey Cherevko (blackmatov@gmail.com) + ******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace meta_hpp::detail +{ + template < typename Enum > + class bitflags final { + static_assert(std::is_enum_v); + public: + using enum_type = Enum; + using underlying_type = std::underlying_type_t; + + bitflags() = default; + bitflags(const bitflags&) = default; + bitflags& operator=(const bitflags&) = default; + bitflags(bitflags&&) noexcept = default; + bitflags& operator=(bitflags&&) noexcept = default; + ~bitflags() = default; + + constexpr bitflags(enum_type flags) + : flags_(static_cast(flags)) {} + + constexpr explicit bitflags(underlying_type flags) + : flags_(flags) {} + + constexpr void swap(bitflags& other) noexcept { + using std::swap; + swap(flags_, other.flags_); + } + + [[nodiscard]] constexpr explicit operator bool() const noexcept { + return !!flags_; + } + + [[nodiscard]] constexpr underlying_type as_raw() const noexcept { + return flags_; + } + + [[nodiscard]] constexpr enum_type as_enum() const noexcept { + return static_cast(flags_); + } + + [[nodiscard]] constexpr bool has(bitflags flags) const noexcept { + return flags.flags_ == (flags_ & flags.flags_); + } + + constexpr bitflags& set(bitflags flags) noexcept { + flags_ |= flags.flags_; + return *this; + } + + constexpr bitflags& toggle(bitflags flags) noexcept { + flags_ ^= flags.flags_; + return *this; + } + + constexpr bitflags& clear(bitflags flags) noexcept { + flags_ &= ~flags.flags_; + return *this; + } + private: + underlying_type flags_{}; + }; + + template < typename Enum > + constexpr void swap(bitflags& l, bitflags& r) noexcept { + l.swap(r); + } +} + +namespace std +{ + template < typename Enum > + struct hash> { + size_t operator()(meta_hpp::detail::bitflags bf) const noexcept { + return hash{}(bf.as_enum()); + } + }; +} + +namespace meta_hpp::detail +{ + #define META_HPP_DEFINE_BINARY_OPERATOR(op)\ + template < typename Enum >\ + constexpr bool operator op(Enum l, bitflags r) noexcept {\ + return l op r.as_enum();\ + }\ + template < typename Enum >\ + constexpr bool operator op(bitflags l, Enum r) noexcept {\ + return l.as_enum() op r;\ + }\ + template < typename Enum >\ + constexpr bool operator op(std::underlying_type_t l, bitflags r) noexcept {\ + return l op r.as_raw();\ + }\ + template < typename Enum >\ + constexpr bool operator op(bitflags l, std::underlying_type_t r) noexcept {\ + return l.as_raw() op r;\ + }\ + template < typename Enum >\ + constexpr bool operator op(bitflags l, bitflags r) noexcept {\ + return l.as_raw() op r.as_raw();\ + } + META_HPP_DEFINE_BINARY_OPERATOR(<) + META_HPP_DEFINE_BINARY_OPERATOR(>) + META_HPP_DEFINE_BINARY_OPERATOR(<=) + META_HPP_DEFINE_BINARY_OPERATOR(>=) + META_HPP_DEFINE_BINARY_OPERATOR(==) + META_HPP_DEFINE_BINARY_OPERATOR(!=) + #undef META_HPP_DEFINE_BINARY_OPERATOR +} + +namespace meta_hpp::detail +{ + template < typename Enum > + constexpr bitflags operator~(bitflags l) noexcept { + return static_cast(~l.as_raw()); + } + + #define META_HPP_DEFINE_BINARY_OPERATOR(op)\ + template < typename Enum >\ + constexpr bitflags operator op (Enum l, bitflags r) noexcept {\ + return bitflags{l} op r;\ + }\ + template < typename Enum >\ + constexpr bitflags operator op (bitflags l, Enum r) noexcept {\ + return l op bitflags{r};\ + }\ + template < typename Enum >\ + constexpr bitflags operator op (bitflags l, bitflags r) noexcept {\ + return static_cast(l.as_raw() op r.as_raw());\ + }\ + template < typename Enum >\ + constexpr bitflags& operator op##= (bitflags& l, Enum r) noexcept {\ + return l = l op bitflags{r};\ + }\ + template < typename Enum >\ + constexpr bitflags& operator op##= (bitflags& l, bitflags r) noexcept {\ + return l = l op r;\ + } + META_HPP_DEFINE_BINARY_OPERATOR(|) + META_HPP_DEFINE_BINARY_OPERATOR(&) + META_HPP_DEFINE_BINARY_OPERATOR(^) + #undef META_HPP_DEFINE_BINARY_OPERATOR +} + +// +// META_HPP_BITFLAGS_OPERATORS_DECL +// + +#define META_HPP_BITFLAGS_OPERATORS_DECL(Enum)\ + constexpr ::meta_hpp::detail::bitflags operator~ [[maybe_unused]] (Enum l) noexcept {\ + return ~::meta_hpp::detail::bitflags(l);\ + }\ + constexpr ::meta_hpp::detail::bitflags operator| [[maybe_unused]] (Enum l, Enum r) noexcept {\ + return ::meta_hpp::detail::bitflags(l) | ::meta_hpp::detail::bitflags(r);\ + }\ + constexpr ::meta_hpp::detail::bitflags operator& [[maybe_unused]] (Enum l, Enum r) noexcept {\ + return ::meta_hpp::detail::bitflags(l) & ::meta_hpp::detail::bitflags(r);\ + }\ + constexpr ::meta_hpp::detail::bitflags operator^ [[maybe_unused]] (Enum l, Enum r) noexcept {\ + return ::meta_hpp::detail::bitflags(l) ^ ::meta_hpp::detail::bitflags(r);\ + } + +namespace meta_hpp::detail +{ + template < typename From > + struct cvref_traits { + static constexpr bool is_lvalue = std::is_lvalue_reference_v; + static constexpr bool is_rvalue = std::is_rvalue_reference_v; + static constexpr bool is_const = std::is_const_v>; + static constexpr bool is_volatile = std::is_volatile_v>; + + template < bool yesno, template < typename > typename Q, typename V > + using apply_t_if = std::conditional_t, V>; + + template < typename To > + using copy_to = + apply_t_if>>>>; + }; + + template < typename From, typename To > + struct copy_cvref { + using type = typename cvref_traits::template copy_to; + }; + + template < typename From, typename To > + using copy_cvref_t = typename copy_cvref::type; +} + +namespace meta_hpp::detail +{ + template < typename Function, std::size_t MaxFunctorSize = sizeof(void*) * 2 > + class fixed_function; + + template < typename R, typename... Args, std::size_t MaxFunctorSize > + class fixed_function final { + public: + using result_type = R; + + fixed_function() = default; + ~fixed_function() { reset(); } + + fixed_function(const fixed_function& other) = delete; + fixed_function& operator=(const fixed_function& other) = delete; + + fixed_function(fixed_function&& other) noexcept { + if ( other.vtable_ ) { + other.vtable_->move(other, *this); + } + } + + fixed_function& operator=(fixed_function&& other) noexcept { + if ( this != &other ) { + fixed_function{std::move(other)}.swap(*this); + } + return *this; + } + + template < typename Functor > + fixed_function(Functor&& functor) { + vtable_t::construct(*this, std::forward(functor)); + } + + template < typename Functor > + fixed_function& operator=(Functor&& functor) { + fixed_function{std::forward(functor)}.swap(*this); + return *this; + } + + [[nodiscard]] bool is_valid() const noexcept { + return !!vtable_; + } + + [[nodiscard]] explicit operator bool() const noexcept { + return is_valid(); + } + + R operator()(Args... args) const { + assert(vtable_ && "bad function call"); + return vtable_->call(*this, std::forward(args)...); + } + + void reset() noexcept { + if ( vtable_ ) { + vtable_->destroy(*this); + } + } + + void swap(fixed_function& other) noexcept { + vtable_t::swap(*this, other); + } + private: + struct vtable_t; + vtable_t* vtable_{}; + private: + using storage_t = std::aligned_storage_t; + storage_t storage_{}; + }; + + template < typename Function, std::size_t MaxFunctorSize > + inline void swap(fixed_function& l, fixed_function& r) noexcept { + l.swap(r); + } +} + +namespace meta_hpp::detail +{ + template < typename R, typename... Args, std::size_t MaxFunctorSize > + struct fixed_function::vtable_t final { + R (*const call)(const fixed_function& self, Args... args); + void (*const move)(fixed_function& from, fixed_function& to) noexcept; + void (*const destroy)(fixed_function& self); + + template < typename T > + static T* storage_cast(storage_t& storage) noexcept { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + return reinterpret_cast(&storage); + } + + template < typename T > + static const T* storage_cast(const storage_t& storage) noexcept { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + return reinterpret_cast(&storage); + } + + template < typename FunctionType > + static vtable_t* get() { + static vtable_t table{ + .call = +[](const fixed_function& self, Args... args) -> R { + assert(self); + + const FunctionType& src = *storage_cast(self.storage_); + return std::invoke(src, std::forward(args)...); + }, + .move = +[](fixed_function& from, fixed_function& to) noexcept { + assert(from && !to); + + FunctionType& src = *storage_cast(from.storage_); + ::new (&to.storage_) FunctionType(std::move(src)); + + to.vtable_ = from.vtable_; + from.vtable_->destroy(from); + }, + .destroy = +[](fixed_function& self){ + assert(self); + + FunctionType& src = *storage_cast(self.storage_); + src.~FunctionType(); + + self.vtable_ = nullptr; + }, + }; + return &table; + } + + template < typename Functor > + static void construct(fixed_function& dst, Functor&& functor) { + using Fp = std::decay_t; + + static_assert(sizeof(Fp) <= MaxFunctorSize); + static_assert(alignof(Fp) <= alignof(storage_t)); + static_assert(std::is_invocable_r_v); + static_assert(std::is_nothrow_move_constructible_v); + + ::new (&dst.storage_) Fp(std::forward(functor)); + dst.vtable_ = vtable_t::get(); + } + + static void swap(fixed_function& l, fixed_function& r) noexcept { + if ( (&l == &r) || (!l && !r) ) { + return; + } + + if ( l && r ) { + fixed_function temp; + r.vtable_->move(r, temp); + l.vtable_->move(l, r); + temp.vtable_->move(temp, l); + } else { + if ( l ) { + l.vtable_->move(l, r); + } else { + r.vtable_->move(r, l); + } + } + } + }; +} + +namespace meta_hpp::detail +{ + namespace impl + { + template < typename F > + struct strip_signature_impl; + + template < typename R, typename C, typename... Args > + struct strip_signature_impl { using type = R(Args...); }; + template < typename R, typename C, typename... Args > + struct strip_signature_impl { using type = R(Args...); }; + template < typename R, typename C, typename... Args > + struct strip_signature_impl { using type = R(Args...); }; + template < typename R, typename C, typename... Args > + struct strip_signature_impl { using type = R(Args...); }; + + template < typename R, typename C, typename... Args > + struct strip_signature_impl { using type = R(Args...); }; + template < typename R, typename C, typename... Args > + struct strip_signature_impl { using type = R(Args...); }; + template < typename R, typename C, typename... Args > + struct strip_signature_impl { using type = R(Args...); }; + template < typename R, typename C, typename... Args > + struct strip_signature_impl { using type = R(Args...); }; + + template < typename F > + using strip_signature_impl_t = typename strip_signature_impl::type; + } + + template < typename R, typename... Args > + fixed_function(R(*)(Args...)) -> fixed_function; + + template < typename Functor + , typename Signature = impl::strip_signature_impl_t > + fixed_function(Functor) -> fixed_function; +} + +namespace meta_hpp::detail +{ + struct hash_combiner { + template < typename T > + [[nodiscard]] std::size_t operator()(const T& x) noexcept { + return std::hash{}(x); + } + + template < typename T > + [[nodiscard]] std::size_t operator()(std::size_t seed, const T& x) noexcept { + // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers, readability-magic-numbers) + return (seed ^= std::hash{}(x) + 0x9e3779b9 + (seed << 6) + (seed >> 2)); + } + }; +} + +namespace meta_hpp::detail +{ + class noncopyable { + protected: + noncopyable() = default; + ~noncopyable() = default; + public: + noncopyable(noncopyable&&) = delete; + noncopyable(const noncopyable&) = delete; + noncopyable& operator=(noncopyable&&) = delete; + noncopyable& operator=(const noncopyable&) = delete; + }; +} + +namespace meta_hpp::detail +{ + template < typename... Ts > + struct overloaded : Ts... { + using Ts::operator()...; + }; + + template < typename... Ts > + overloaded(Ts...) -> overloaded; +} + +namespace meta_hpp::detail +{ + template < typename C, typename R, typename... Args > + constexpr auto select_const(R (C::*func)(Args...) const) -> decltype(func) { + return func; + } + + template < typename C, typename R, typename... Args > + constexpr auto select_const(R (C::*func)(Args...) const noexcept) -> decltype(func) { + return func; + } + + template < typename C, typename R, typename... Args > + constexpr auto select_non_const(R (C::*func)(Args...)) -> decltype(func) { + return func; + } + + template < typename C, typename R, typename... Args > + constexpr auto select_non_const(R (C::*func)(Args...) noexcept) -> decltype(func) { + return func; + } + + template < typename Signature > + constexpr auto select_overload(Signature* func) noexcept -> decltype(func) { + return func; + } + + template < typename Signature, typename C > + constexpr auto select_overload(Signature C::*func) noexcept -> decltype(func) { + return func; + } +} + +namespace meta_hpp::stdex +{ + template < typename T, typename U > + concept same_as = + std::is_same_v && + std::is_same_v; + + template < typename Derived, typename Base > + concept derived_from = + std::is_base_of_v && + std::is_convertible_v; + + template < typename From, typename To > + concept convertible_to = + std::is_convertible_v && + requires { static_cast(std::declval()); }; + + template < typename T > + concept destructible = + std::is_nothrow_destructible_v; + + template < typename T, typename... Args > + concept constructible_from = + destructible && + std::is_constructible_v; + + template < typename T > + concept move_constructible = + constructible_from && + convertible_to; + + template + concept copy_constructible = + move_constructible && + constructible_from && convertible_to && + constructible_from && convertible_to && + constructible_from && convertible_to; +} + +namespace meta_hpp::stdex +{ + template < typename Enum > + [[nodiscard]] constexpr std::underlying_type_t to_underlying(Enum e) noexcept { + return static_cast>(e); + } +} + +namespace meta_hpp::detail +{ + template < typename... Types > + struct type_list {}; + + template < std::size_t Index, typename TypeList > + struct type_list_at; + + template < std::size_t Index, typename... Types > + struct type_list_at> { + using type = std::tuple_element_t>; + }; + + template < std::size_t Index, typename TypeList > + using type_list_at_t = typename type_list_at::type; +} + +namespace meta_hpp::detail +{ + class type_id final { + public: + template < typename T > + // NOLINTNEXTLINE(readability-named-parameter) + explicit type_id(type_list) noexcept + : id_{type_to_id()} {} + + type_id(type_id&&) = default; + type_id(const type_id&) = default; + + type_id& operator=(type_id&&) = default; + type_id& operator=(const type_id&) = default; + + ~type_id() = default; + + [[nodiscard]] std::size_t get_hash() const noexcept { + return std::hash{}(id_); + } + + [[nodiscard]] friend bool operator<(type_id l, type_id r) noexcept { + return l.id_ < r.id_; + } + + [[nodiscard]] friend bool operator==(type_id l, type_id r) noexcept { + return l.id_ == r.id_; + } + + [[nodiscard]] friend bool operator!=(type_id l, type_id r) noexcept { + return l.id_ != r.id_; + } + private: + using underlying_type = std::uint32_t; + underlying_type id_{}; + private: + [[nodiscard]] static underlying_type next() noexcept { + static std::atomic id{}; + return ++id; + } + + template < typename T > + [[nodiscard]] static underlying_type type_to_id() noexcept { + static const underlying_type id{next()}; + return id; + } + }; +} + +namespace std +{ + template <> + struct hash { + size_t operator()(const meta_hpp::detail::type_id& id) const noexcept { + return id.get_hash(); + } + }; +} + +namespace meta_hpp::detail +{ + template < typename T > + concept array_kind = std::is_array_v; + + template < typename T > + concept class_kind = std::is_class_v; + + template < typename T > + concept enum_kind = std::is_enum_v; + + template < typename T > + concept function_kind = std::is_pointer_v && std::is_function_v>; + + template < typename T > + concept member_kind = std::is_member_object_pointer_v; + + template < typename T > + concept method_kind = std::is_member_function_pointer_v; + + template < typename T > + concept nullptr_kind = std::is_null_pointer_v; + + template < typename T > + concept number_kind = std::is_arithmetic_v; + + template < typename T > + concept pointer_kind = std::is_pointer_v && !std::is_function_v>; + + template < typename T > + concept reference_kind = std::is_reference_v; + + template < typename T > + concept void_kind = std::is_void_v; +} + +namespace meta_hpp::detail +{ + enum class type_kind : std::uint32_t { + array_, + class_, + constructor_, + destructor_, + enum_, + function_, + member_, + method_, + nullptr_, + number_, + pointer_, + reference_, + void_, + }; + + template < typename T > + constexpr type_kind make_type_kind() noexcept { + if constexpr ( array_kind ) { return type_kind::array_; } + if constexpr ( class_kind ) { return type_kind::class_; } + if constexpr ( enum_kind ) { return type_kind::enum_; } + if constexpr ( function_kind ) { return type_kind::function_; } + if constexpr ( member_kind ) { return type_kind::member_; } + if constexpr ( method_kind ) { return type_kind::method_; } + if constexpr ( nullptr_kind ) { return type_kind::nullptr_; } + if constexpr ( number_kind ) { return type_kind::number_; } + if constexpr ( pointer_kind ) { return type_kind::pointer_; } + if constexpr ( reference_kind ) { return type_kind::reference_; } + if constexpr ( void_kind ) { return type_kind::void_; } + } +} + +#if !defined(__cpp_exceptions) +# define META_HPP_NO_EXCEPTIONS +#endif + +#if !defined(__cpp_rtti) +# define META_HPP_NO_RTTI +#endif + +namespace meta_hpp +{ + using detail::select_const; + using detail::select_non_const; + using detail::select_overload; + + using detail::type_id; + using detail::type_kind; + using detail::type_list; +} + +namespace meta_hpp +{ + class exception final : public std::runtime_error { + public: + explicit exception(const char* what) + : std::runtime_error(what) {} + }; + + namespace detail + { + inline void throw_exception_with [[noreturn]] (const char* what) { + #ifndef META_HPP_NO_EXCEPTIONS + throw ::meta_hpp::exception(what); + #else + (void)what; + std::abort(); + #endif + } + } +} + +namespace meta_hpp +{ + class uvalue; + + namespace detail + { + class uarg_base; + class uarg; + + class uinst_base; + class uinst; + } +} + +namespace meta_hpp +{ + class argument; + class constructor; + class destructor; + class evalue; + class function; + class member; + class method; + class scope; + class variable; + + namespace detail + { + struct argument_state; + struct constructor_state; + struct destructor_state; + struct evalue_state; + struct function_state; + struct member_state; + struct method_state; + struct scope_state; + struct variable_state; + + using argument_state_ptr = std::shared_ptr; + using constructor_state_ptr = std::shared_ptr; + using destructor_state_ptr = std::shared_ptr; + using evalue_state_ptr = std::shared_ptr; + using function_state_ptr = std::shared_ptr; + using member_state_ptr = std::shared_ptr; + using method_state_ptr = std::shared_ptr; + using scope_state_ptr = std::shared_ptr; + using variable_state_ptr = std::shared_ptr; + } +} + +namespace meta_hpp +{ + class any_type; + class array_type; + class class_type; + class constructor_type; + class destructor_type; + class enum_type; + class function_type; + class member_type; + class method_type; + class nullptr_type; + class number_type; + class pointer_type; + class reference_type; + class void_type; + + namespace detail + { + struct type_data_base; + struct array_type_data; + struct class_type_data; + struct constructor_type_data; + struct destructor_type_data; + struct enum_type_data; + struct function_type_data; + struct member_type_data; + struct method_type_data; + struct nullptr_type_data; + struct number_type_data; + struct pointer_type_data; + struct reference_type_data; + struct void_type_data; + } +} + +namespace meta_hpp +{ + class argument_index; + class constructor_index; + class destructor_index; + class evalue_index; + class function_index; + class member_index; + class method_index; + class scope_index; + class variable_index; +} + +namespace meta_hpp +{ + using argument_list = std::vector; + using metadata_map = std::map>; + using typedef_map = std::map>; + + using class_set = std::set>; + using class_map = std::map>; + + using enum_set = std::set>; + using enum_map = std::map>; + + using constructor_map = std::map>; + using destructor_map = std::map>; + using evalue_map = std::map>; + using function_map = std::map>; + using member_map = std::map>; + using method_map = std::map>; + using scope_map = std::map>; + using variable_map = std::map>; +} + +namespace meta_hpp::detail +{ + template < typename T > + inline constexpr bool is_type_family_v = + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v; + + template < typename T > + concept type_family = is_type_family_v; + + template < type_family T > + [[nodiscard]] auto type_access(const T& type) { + return type.data_; + } +} + +namespace meta_hpp::detail +{ + enum class array_flags : std::uint32_t { + is_bounded = 1 << 0, + is_unbounded = 1 << 1, + }; + + META_HPP_BITFLAGS_OPERATORS_DECL(array_flags) + using array_bitflags = bitflags; +} + +namespace meta_hpp::detail +{ + template < array_kind Array > + struct array_traits { + static constexpr std::size_t extent{std::extent_v}; + + using data_type = std::remove_extent_t; + + [[nodiscard]] static constexpr array_bitflags make_flags() noexcept { + array_bitflags flags{}; + + if constexpr ( std::is_bounded_array_v ) { + flags.set(array_flags::is_bounded); + } + + if constexpr ( std::is_unbounded_array_v ) { + flags.set(array_flags::is_unbounded); + } + + return flags; + } + }; +} + +namespace meta_hpp::detail +{ + enum class class_flags : std::uint32_t { + is_empty = 1 << 0, + is_final = 1 << 1, + is_abstract = 1 << 2, + is_polymorphic = 1 << 3, + is_template_instantiation = 1 << 4, + }; + + META_HPP_BITFLAGS_OPERATORS_DECL(class_flags) + using class_bitflags = bitflags; +} + +namespace meta_hpp::detail +{ + namespace impl + { + template < class_kind Class > + struct class_traits_base { + static constexpr std::size_t arity{0}; + + using argument_types = type_list<>; + + [[nodiscard]] static constexpr class_bitflags make_flags() noexcept { + return {}; + } + }; + + template < template < typename... > typename Class, typename... Args > + struct class_traits_base> { + static constexpr std::size_t arity{sizeof...(Args)}; + + using argument_types = type_list; + + [[nodiscard]] static constexpr class_bitflags make_flags() noexcept { + return class_flags::is_template_instantiation; + } + }; + } + + template < class_kind Class > + struct class_traits : impl::class_traits_base { + static constexpr std::size_t size{sizeof(Class)}; + static constexpr std::size_t align{alignof(Class)}; + + [[nodiscard]] static constexpr class_bitflags make_flags() noexcept { + class_bitflags flags{}; + + if constexpr ( std::is_empty_v ) { + flags.set(class_flags::is_empty); + } + + if constexpr ( std::is_final_v ) { + flags.set(class_flags::is_final); + } + + if constexpr ( std::is_abstract_v ) { + flags.set(class_flags::is_abstract); + } + + if constexpr ( std::is_polymorphic_v ) { + flags.set(class_flags::is_polymorphic); + } + + return flags | impl::class_traits_base::make_flags(); + } + }; +} + +namespace meta_hpp::detail +{ + enum class constructor_flags : std::uint32_t { + is_noexcept = 1 << 0, + }; + + META_HPP_BITFLAGS_OPERATORS_DECL(constructor_flags) + using constructor_bitflags = bitflags; +} + +namespace meta_hpp::detail +{ + template < class_kind Class, typename... Args > + struct constructor_traits { + static constexpr std::size_t arity{sizeof...(Args)}; + + using class_type = Class; + using argument_types = type_list; + + [[nodiscard]] static constexpr constructor_bitflags make_flags() noexcept { + constructor_bitflags flags{}; + + if constexpr ( std::is_nothrow_constructible_v ) { + flags.set(constructor_flags::is_noexcept); + } + + return flags; + } + }; +} + +namespace meta_hpp::detail +{ + enum class destructor_flags : std::uint32_t { + is_noexcept = 1 << 0, + }; + + META_HPP_BITFLAGS_OPERATORS_DECL(destructor_flags) + using destructor_bitflags = bitflags; +} + +namespace meta_hpp::detail +{ + template < class_kind Class > + struct destructor_traits { + using class_type = Class; + + [[nodiscard]] static constexpr destructor_bitflags make_flags() noexcept { + destructor_bitflags flags{}; + + if constexpr ( std::is_nothrow_destructible_v ) { + flags.set(destructor_flags::is_noexcept); + } + + return flags; + } + }; +} + +namespace meta_hpp::detail +{ + enum class enum_flags : std::uint32_t { + is_scoped = 1 << 0, + }; + + META_HPP_BITFLAGS_OPERATORS_DECL(enum_flags) + using enum_bitflags = bitflags; +} + +namespace meta_hpp::detail +{ + template < enum_kind Enum > + struct enum_traits { + using underlying_type = std::underlying_type_t; + + [[nodiscard]] static constexpr enum_bitflags make_flags() noexcept { + enum_bitflags flags{}; + + if constexpr ( !std::is_convertible_v ) { + flags.set(enum_flags::is_scoped); + } + + return flags; + } + }; +} + +namespace meta_hpp::detail +{ + enum class function_flags : std::uint32_t { + is_noexcept = 1 << 0, + }; + + META_HPP_BITFLAGS_OPERATORS_DECL(function_flags) + using function_bitflags = bitflags; +} + +namespace meta_hpp::detail +{ + template < function_kind Function > + struct function_traits; + + template < typename R, typename... Args > + struct function_traits { + static constexpr std::size_t arity{sizeof...(Args)}; + + using return_type = R; + using argument_types = type_list; + + [[nodiscard]] static constexpr function_bitflags make_flags() noexcept { + return {}; + } + }; + + template < typename R, typename... Args > + struct function_traits : function_traits { + [[nodiscard]] static constexpr function_bitflags make_flags() noexcept { + return function_flags::is_noexcept; + } + }; +} + +namespace meta_hpp::detail +{ + enum class member_flags : std::uint32_t { + is_readonly = 1 << 0, + }; + + META_HPP_BITFLAGS_OPERATORS_DECL(member_flags) + using member_bitflags = bitflags; +} + +namespace meta_hpp::detail +{ + template < member_kind Member > + struct member_traits; + + template < typename V, typename C > + struct member_traits { + using class_type = C; + using value_type = V; + + [[nodiscard]] static constexpr member_bitflags make_flags() noexcept { + member_bitflags flags{}; + + if constexpr ( std::is_const_v ) { + flags.set(member_flags::is_readonly); + } + + return flags; + } + }; +} + +namespace meta_hpp::detail +{ + enum class method_flags : std::uint32_t { + is_const = 1 << 0, + is_noexcept = 1 << 1, + is_lvalue_qualified = 1 << 2, + is_rvalue_qualified = 1 << 3, + }; + + META_HPP_BITFLAGS_OPERATORS_DECL(method_flags) + using method_bitflags = bitflags; +} + +namespace meta_hpp::detail +{ + template < method_kind Method > + struct method_traits; + + template < typename R, typename C, typename... Args > + struct method_traits { + static constexpr std::size_t arity{sizeof...(Args)}; + + using class_type = C; + using return_type = R; + using qualified_type = C; + using argument_types = type_list; + + [[nodiscard]] static constexpr method_bitflags make_flags() noexcept { + return {}; + } + }; + + template < typename R, typename C, typename... Args > + struct method_traits : method_traits { + using qualified_type = const C; + + [[nodiscard]] static constexpr method_bitflags make_flags() noexcept { + return method_flags::is_const; + } + }; + + template < typename R, typename C, typename... Args > + struct method_traits : method_traits { + using qualified_type = C; + + [[nodiscard]] static constexpr method_bitflags make_flags() noexcept { + return method_flags::is_noexcept; + } + }; + + template < typename R, typename C, typename... Args > + struct method_traits : method_traits { + using qualified_type = const C; + + [[nodiscard]] static constexpr method_bitflags make_flags() noexcept { + return method_flags::is_const | method_flags::is_noexcept; + } + }; + + template < typename R, typename C, typename... Args > + struct method_traits : method_traits { + using qualified_type = C&; + + [[nodiscard]] static constexpr method_bitflags make_flags() noexcept { + return method_flags::is_lvalue_qualified; + } + }; + + template < typename R, typename C, typename... Args > + struct method_traits : method_traits { + using qualified_type = C&; + + [[nodiscard]] static constexpr method_bitflags make_flags() noexcept { + return method_flags::is_noexcept | method_flags::is_lvalue_qualified; + } + }; + + template < typename R, typename C, typename... Args > + struct method_traits : method_traits { + using qualified_type = const C&; + + [[nodiscard]] static constexpr method_bitflags make_flags() noexcept { + return method_flags::is_const | method_flags::is_lvalue_qualified; + } + }; + + template < typename R, typename C, typename... Args > + struct method_traits : method_traits { + using qualified_type = const C&; + + [[nodiscard]] static constexpr method_bitflags make_flags() noexcept { + return method_flags::is_const | method_flags::is_noexcept | method_flags::is_lvalue_qualified; + } + }; + + template < typename R, typename C, typename... Args > + struct method_traits : method_traits { + using qualified_type = C&&; + + [[nodiscard]] static constexpr method_bitflags make_flags() noexcept { + return method_flags::is_rvalue_qualified; + } + }; + + template < typename R, typename C, typename... Args > + struct method_traits : method_traits { + using qualified_type = C&&; + + [[nodiscard]] static constexpr method_bitflags make_flags() noexcept { + return method_flags::is_noexcept | method_flags::is_rvalue_qualified; + } + }; + + template < typename R, typename C, typename... Args > + struct method_traits : method_traits { + using qualified_type = const C&&; + + [[nodiscard]] static constexpr method_bitflags make_flags() noexcept { + return method_flags::is_const | method_flags::is_rvalue_qualified; + } + }; + + template < typename R, typename C, typename... Args > + struct method_traits : method_traits { + using qualified_type = const C&&; + + [[nodiscard]] static constexpr method_bitflags make_flags() noexcept { + return method_flags::is_const | method_flags::is_noexcept | method_flags::is_rvalue_qualified; + } + }; +} + +namespace meta_hpp::detail +{ + enum class number_flags : std::uint32_t { + is_signed = 1 << 0, + is_unsigned = 1 << 1, + is_integral = 1 << 2, + is_floating_point = 1 << 3, + }; + + META_HPP_BITFLAGS_OPERATORS_DECL(number_flags) + using number_bitflags = bitflags; +} + +namespace meta_hpp::detail +{ + template < number_kind Number > + struct number_traits { + static constexpr std::size_t size{sizeof(Number)}; + static constexpr std::size_t align{alignof(Number)}; + + [[nodiscard]] static constexpr number_bitflags make_flags() noexcept { + number_bitflags flags{}; + + if constexpr ( std::is_signed_v ) { + flags.set(number_flags::is_signed); + } + + if constexpr ( std::is_unsigned_v ) { + flags.set(number_flags::is_unsigned); + } + + if constexpr ( std::is_integral_v ) { + flags.set(number_flags::is_integral); + } + + if constexpr ( std::is_floating_point_v ) { + flags.set(number_flags::is_floating_point); + } + + return flags; + } + }; +} + +namespace meta_hpp::detail +{ + enum class pointer_flags : std::uint32_t { + is_readonly = 1 << 0, + }; + + META_HPP_BITFLAGS_OPERATORS_DECL(pointer_flags) + using pointer_bitflags = bitflags; +} + +namespace meta_hpp::detail +{ + template < pointer_kind Pointer > + struct pointer_traits { + using data_type = std::remove_pointer_t; + + [[nodiscard]] static constexpr pointer_bitflags make_flags() noexcept { + pointer_bitflags flags{}; + + if constexpr ( std::is_const_v ) { + flags.set(pointer_flags::is_readonly); + } + + return flags; + } + }; +} + +namespace meta_hpp::detail +{ + enum class reference_flags : std::uint32_t { + is_readonly = 1 << 0, + is_lvalue = 1 << 1, + is_rvalue = 1 << 2, + }; + + META_HPP_BITFLAGS_OPERATORS_DECL(reference_flags) + using reference_bitflags = bitflags; +} + +namespace meta_hpp::detail +{ + template < reference_kind Reference > + struct reference_traits { + using data_type = std::remove_reference_t; + + [[nodiscard]] static constexpr reference_bitflags make_flags() noexcept { + reference_bitflags flags{}; + + if constexpr ( std::is_const_v ) { + flags.set(reference_flags::is_readonly); + } + + if constexpr ( std::is_lvalue_reference_v ) { + flags.set(reference_flags::is_lvalue); + } + + if constexpr ( std::is_rvalue_reference_v ) { + flags.set(reference_flags::is_rvalue); + } + + return flags; + } + }; +} + +namespace meta_hpp +{ + using array_flags = detail::array_flags; + using array_bitflags = detail::array_bitflags; + + using class_flags = detail::class_flags; + using class_bitflags = detail::class_bitflags; + + using constructor_flags = detail::constructor_flags; + using constructor_bitflags = detail::constructor_bitflags; + + using destructor_flags = detail::destructor_flags; + using destructor_bitflags = detail::destructor_bitflags; + + using enum_flags = detail::enum_flags; + using enum_bitflags = detail::enum_bitflags; + + using function_flags = detail::function_flags; + using function_bitflags = detail::function_bitflags; + + using member_flags = detail::member_flags; + using member_bitflags = detail::member_bitflags; + + using method_flags = detail::method_flags; + using method_bitflags = detail::method_bitflags; + + using number_flags = detail::number_flags; + using number_bitflags = detail::number_bitflags; + + using pointer_flags = detail::pointer_flags; + using pointer_bitflags = detail::pointer_bitflags; + + using reference_flags = detail::reference_flags; + using reference_bitflags = detail::reference_bitflags; +} + +namespace meta_hpp +{ + class any_type final { + public: + explicit any_type() = default; + + [[nodiscard]] bool is_valid() const noexcept; + [[nodiscard]] explicit operator bool() const noexcept; + + [[nodiscard]] type_id get_id() const noexcept; + [[nodiscard]] type_kind get_kind() const noexcept; + + [[nodiscard]] const metadata_map& get_metadata() const noexcept; + + any_type(const array_type& other) noexcept; + any_type(const class_type& other) noexcept; + any_type(const constructor_type& other) noexcept; + any_type(const destructor_type& other) noexcept; + any_type(const enum_type& other) noexcept; + any_type(const function_type& other) noexcept; + any_type(const member_type& other) noexcept; + any_type(const method_type& other) noexcept; + any_type(const nullptr_type& other) noexcept; + any_type(const number_type& other) noexcept; + any_type(const pointer_type& other) noexcept; + any_type(const reference_type& other) noexcept; + any_type(const void_type& other) noexcept; + + [[nodiscard]] bool is_array() const noexcept; + [[nodiscard]] bool is_class() const noexcept; + [[nodiscard]] bool is_constructor() const noexcept; + [[nodiscard]] bool is_destructor() const noexcept; + [[nodiscard]] bool is_enum() const noexcept; + [[nodiscard]] bool is_function() const noexcept; + [[nodiscard]] bool is_member() const noexcept; + [[nodiscard]] bool is_method() const noexcept; + [[nodiscard]] bool is_nullptr() const noexcept; + [[nodiscard]] bool is_number() const noexcept; + [[nodiscard]] bool is_pointer() const noexcept; + [[nodiscard]] bool is_reference() const noexcept; + [[nodiscard]] bool is_void() const noexcept; + + [[nodiscard]] array_type as_array() const noexcept; + [[nodiscard]] class_type as_class() const noexcept; + [[nodiscard]] constructor_type as_constructor() const noexcept; + [[nodiscard]] destructor_type as_destructor() const noexcept; + [[nodiscard]] enum_type as_enum() const noexcept; + [[nodiscard]] function_type as_function() const noexcept; + [[nodiscard]] member_type as_member() const noexcept; + [[nodiscard]] method_type as_method() const noexcept; + [[nodiscard]] nullptr_type as_nullptr() const noexcept; + [[nodiscard]] number_type as_number() const noexcept; + [[nodiscard]] pointer_type as_pointer() const noexcept; + [[nodiscard]] reference_type as_reference() const noexcept; + [[nodiscard]] void_type as_void() const noexcept; + private: + detail::type_data_base* data_{}; + friend auto detail::type_access(const any_type&); + }; + + class array_type final { + public: + array_type() = default; + array_type(detail::array_type_data* data); + + [[nodiscard]] bool is_valid() const noexcept; + [[nodiscard]] explicit operator bool() const noexcept; + + [[nodiscard]] type_id get_id() const noexcept; + [[nodiscard]] array_bitflags get_flags() const noexcept; + [[nodiscard]] const metadata_map& get_metadata() const noexcept; + + [[nodiscard]] std::size_t get_extent() const noexcept; + [[nodiscard]] any_type get_data_type() const noexcept; + private: + detail::array_type_data* data_{}; + friend auto detail::type_access(const array_type&); + }; + + class class_type final { + public: + class_type() = default; + class_type(detail::class_type_data* data); + + [[nodiscard]] bool is_valid() const noexcept; + [[nodiscard]] explicit operator bool() const noexcept; + + [[nodiscard]] type_id get_id() const noexcept; + [[nodiscard]] class_bitflags get_flags() const noexcept; + [[nodiscard]] const metadata_map& get_metadata() const noexcept; + + [[nodiscard]] std::size_t get_size() const noexcept; + [[nodiscard]] std::size_t get_align() const noexcept; + + [[nodiscard]] std::size_t get_arity() const noexcept; + [[nodiscard]] any_type get_argument_type(std::size_t position) const noexcept; + [[nodiscard]] const std::vector& get_argument_types() const noexcept; + + [[nodiscard]] const class_set& get_bases() const noexcept; + [[nodiscard]] const constructor_map& get_constructors() const noexcept; + [[nodiscard]] const destructor_map& get_destructors() const noexcept; + [[nodiscard]] const function_map& get_functions() const noexcept; + [[nodiscard]] const member_map& get_members() const noexcept; + [[nodiscard]] const method_map& get_methods() const noexcept; + [[nodiscard]] const typedef_map& get_typedefs() const noexcept; + [[nodiscard]] const variable_map& get_variables() const noexcept; + + template < typename... Args > + [[nodiscard]] uvalue create(Args&&... args) const; + + template < typename... Args > + [[nodiscard]] uvalue operator()(Args&&... args) const; + + template < typename Arg > + bool destroy(Arg&& ptr) const; + + template < detail::class_kind Derived > + [[nodiscard]] bool is_base_of() const noexcept; + [[nodiscard]] bool is_base_of(const class_type& derived) const noexcept; + + template < detail::class_kind Base > + [[nodiscard]] bool is_derived_from() const noexcept; + [[nodiscard]] bool is_derived_from(const class_type& base) const noexcept; + + [[nodiscard]] function get_function(std::string_view name) const noexcept; + [[nodiscard]] member get_member(std::string_view name) const noexcept; + [[nodiscard]] method get_method(std::string_view name) const noexcept; + [[nodiscard]] any_type get_typedef(std::string_view name) const noexcept; + [[nodiscard]] variable get_variable(std::string_view name) const noexcept; + + template < typename... Args > + [[nodiscard]] constructor get_constructor_with() const noexcept; + template < typename Iter > + [[nodiscard]] constructor get_constructor_with(Iter first, Iter last) const noexcept; + [[nodiscard]] constructor get_constructor_with(const std::vector& args) const noexcept; + [[nodiscard]] constructor get_constructor_with(std::initializer_list args) const noexcept; + + template < typename... Args > + [[nodiscard]] function get_function_with(std::string_view name) const noexcept; + template < typename Iter > + [[nodiscard]] function get_function_with(std::string_view name, Iter first, Iter last) const noexcept; + [[nodiscard]] function get_function_with(std::string_view name, const std::vector& args) const noexcept; + [[nodiscard]] function get_function_with(std::string_view name, std::initializer_list args) const noexcept; + + template < typename... Args > + [[nodiscard]] method get_method_with(std::string_view name) const noexcept; + template < typename Iter > + [[nodiscard]] method get_method_with(std::string_view name, Iter first, Iter last) const noexcept; + [[nodiscard]] method get_method_with(std::string_view name, const std::vector& args) const noexcept; + [[nodiscard]] method get_method_with(std::string_view name, std::initializer_list args) const noexcept; + private: + detail::class_type_data* data_{}; + friend auto detail::type_access(const class_type&); + }; + + class constructor_type final { + public: + constructor_type() = default; + constructor_type(detail::constructor_type_data* data); + + [[nodiscard]] bool is_valid() const noexcept; + [[nodiscard]] explicit operator bool() const noexcept; + + [[nodiscard]] type_id get_id() const noexcept; + [[nodiscard]] constructor_bitflags get_flags() const noexcept; + [[nodiscard]] const metadata_map& get_metadata() const noexcept; + + [[nodiscard]] std::size_t get_arity() const noexcept; + [[nodiscard]] any_type get_class_type() const noexcept; + [[nodiscard]] any_type get_argument_type(std::size_t position) const noexcept; + [[nodiscard]] const std::vector& get_argument_types() const noexcept; + private: + detail::constructor_type_data* data_{}; + friend auto detail::type_access(const constructor_type&); + }; + + class destructor_type final { + public: + destructor_type() = default; + destructor_type(detail::destructor_type_data* data); + + [[nodiscard]] bool is_valid() const noexcept; + [[nodiscard]] explicit operator bool() const noexcept; + + [[nodiscard]] type_id get_id() const noexcept; + [[nodiscard]] destructor_bitflags get_flags() const noexcept; + [[nodiscard]] const metadata_map& get_metadata() const noexcept; + + [[nodiscard]] any_type get_class_type() const noexcept; + private: + detail::destructor_type_data* data_{}; + friend auto detail::type_access(const destructor_type&); + }; + + class enum_type final { + public: + enum_type() = default; + enum_type(detail::enum_type_data* data); + + [[nodiscard]] bool is_valid() const noexcept; + [[nodiscard]] explicit operator bool() const noexcept; + + [[nodiscard]] type_id get_id() const noexcept; + [[nodiscard]] enum_bitflags get_flags() const noexcept; + [[nodiscard]] const metadata_map& get_metadata() const noexcept; + + [[nodiscard]] number_type get_underlying_type() const noexcept; + + [[nodiscard]] const evalue_map& get_evalues() const noexcept; + + [[nodiscard]] evalue get_evalue(std::string_view name) const noexcept; + + template < typename Value > + [[nodiscard]] std::string_view value_to_name(Value&& value) const noexcept; + [[nodiscard]] uvalue name_to_value(std::string_view name) const noexcept; + private: + detail::enum_type_data* data_{}; + friend auto detail::type_access(const enum_type&); + }; + + class function_type final { + public: + function_type() = default; + function_type(detail::function_type_data* data); + + [[nodiscard]] bool is_valid() const noexcept; + [[nodiscard]] explicit operator bool() const noexcept; + + [[nodiscard]] type_id get_id() const noexcept; + [[nodiscard]] function_bitflags get_flags() const noexcept; + [[nodiscard]] const metadata_map& get_metadata() const noexcept; + + [[nodiscard]] std::size_t get_arity() const noexcept; + [[nodiscard]] any_type get_return_type() const noexcept; + [[nodiscard]] any_type get_argument_type(std::size_t position) const noexcept; + [[nodiscard]] const std::vector& get_argument_types() const noexcept; + private: + detail::function_type_data* data_{}; + friend auto detail::type_access(const function_type&); + }; + + class member_type final { + public: + member_type() = default; + member_type(detail::member_type_data* data); + + [[nodiscard]] bool is_valid() const noexcept; + [[nodiscard]] explicit operator bool() const noexcept; + + [[nodiscard]] type_id get_id() const noexcept; + [[nodiscard]] member_bitflags get_flags() const noexcept; + [[nodiscard]] const metadata_map& get_metadata() const noexcept; + + [[nodiscard]] class_type get_owner_type() const noexcept; + [[nodiscard]] any_type get_value_type() const noexcept; + private: + detail::member_type_data* data_{}; + friend auto detail::type_access(const member_type&); + }; + + class method_type final { + public: + method_type() = default; + method_type(detail::method_type_data* data); + + [[nodiscard]] bool is_valid() const noexcept; + [[nodiscard]] explicit operator bool() const noexcept; + + [[nodiscard]] type_id get_id() const noexcept; + [[nodiscard]] method_bitflags get_flags() const noexcept; + [[nodiscard]] const metadata_map& get_metadata() const noexcept; + + [[nodiscard]] std::size_t get_arity() const noexcept; + [[nodiscard]] class_type get_owner_type() const noexcept; + [[nodiscard]] any_type get_return_type() const noexcept; + [[nodiscard]] any_type get_argument_type(std::size_t position) const noexcept; + [[nodiscard]] const std::vector& get_argument_types() const noexcept; + private: + detail::method_type_data* data_{}; + friend auto detail::type_access(const method_type&); + }; + + class nullptr_type final { + public: + nullptr_type() = default; + nullptr_type(detail::nullptr_type_data* data); + + [[nodiscard]] bool is_valid() const noexcept; + [[nodiscard]] explicit operator bool() const noexcept; + + [[nodiscard]] type_id get_id() const noexcept; + [[nodiscard]] const metadata_map& get_metadata() const noexcept; + private: + detail::nullptr_type_data* data_{}; + friend auto detail::type_access(const nullptr_type&); + }; + + class number_type final { + public: + number_type() = default; + number_type(detail::number_type_data* data); + + [[nodiscard]] bool is_valid() const noexcept; + [[nodiscard]] explicit operator bool() const noexcept; + + [[nodiscard]] type_id get_id() const noexcept; + [[nodiscard]] number_bitflags get_flags() const noexcept; + [[nodiscard]] const metadata_map& get_metadata() const noexcept; + + [[nodiscard]] std::size_t get_size() const noexcept; + [[nodiscard]] std::size_t get_align() const noexcept; + private: + detail::number_type_data* data_{}; + friend auto detail::type_access(const number_type&); + }; + + class pointer_type final { + public: + pointer_type() = default; + pointer_type(detail::pointer_type_data* data); + + [[nodiscard]] bool is_valid() const noexcept; + [[nodiscard]] explicit operator bool() const noexcept; + + [[nodiscard]] type_id get_id() const noexcept; + [[nodiscard]] pointer_bitflags get_flags() const noexcept; + [[nodiscard]] const metadata_map& get_metadata() const noexcept; + + [[nodiscard]] any_type get_data_type() const noexcept; + private: + detail::pointer_type_data* data_{}; + friend auto detail::type_access(const pointer_type&); + }; + + class reference_type final { + public: + reference_type() = default; + reference_type(detail::reference_type_data* data); + + [[nodiscard]] bool is_valid() const noexcept; + [[nodiscard]] explicit operator bool() const noexcept; + + [[nodiscard]] type_id get_id() const noexcept; + [[nodiscard]] reference_bitflags get_flags() const noexcept; + [[nodiscard]] const metadata_map& get_metadata() const noexcept; + + [[nodiscard]] any_type get_data_type() const noexcept; + private: + detail::reference_type_data* data_{}; + friend auto detail::type_access(const reference_type&); + }; + + class void_type final { + public: + void_type() = default; + void_type(detail::void_type_data* data); + + [[nodiscard]] bool is_valid() const noexcept; + [[nodiscard]] explicit operator bool() const noexcept; + + [[nodiscard]] type_id get_id() const noexcept; + [[nodiscard]] const metadata_map& get_metadata() const noexcept; + private: + detail::void_type_data* data_{}; + friend auto detail::type_access(const void_type&); + }; +} + +namespace std +{ + template < meta_hpp::detail::type_family T > + struct hash { + size_t operator()(const T& t) const noexcept { + return meta_hpp::detail::hash_combiner{}(t.get_id()); + } + }; +} + +namespace meta_hpp +{ + template < detail::type_family T, detail::type_family U > + [[nodiscard]] bool operator<(const T& l, const U& r) noexcept { + if ( !static_cast(r) ) { + return false; + } + + if ( !static_cast(l) ) { + return true; + } + + return l.get_id() < r.get_id(); + } + + template < detail::type_family T, detail::type_family U > + [[nodiscard]] bool operator==(const T& l, const U& r) noexcept { + if ( static_cast(l) != static_cast(r) ) { + return false; + } + + if ( !static_cast(l) ) { + return true; + } + + return l.get_id() == r.get_id(); + } + + template < detail::type_family T, detail::type_family U > + [[nodiscard]] bool operator!=(const T& l, const U& r) noexcept { + return !(l == r); + } +} + +namespace meta_hpp::detail +{ + struct type_data_base { + const type_id id; + const type_kind kind; + + metadata_map metadata; + + explicit type_data_base(type_id nid, type_kind nkind) + : id{nid} + , kind{nkind} {} + }; + + struct array_type_data final : type_data_base { + const array_bitflags flags; + const std::size_t extent; + const any_type data_type; + + template < array_kind Array > + explicit array_type_data(type_list); + }; + + struct class_type_data final : type_data_base { + const class_bitflags flags; + const std::size_t size; + const std::size_t align; + const std::vector argument_types; + + class_set bases; + constructor_map constructors; + destructor_map destructors; + function_map functions; + member_map members; + method_map methods; + typedef_map typedefs; + variable_map variables; + + struct base_info final { + using upcast_fptr = void*(*)(void*); + const upcast_fptr upcast; + }; + + using base_info_map = std::map>; + base_info_map bases_info; + + template < class_kind Class > + explicit class_type_data(type_list); + }; + + struct constructor_type_data final : type_data_base { + const constructor_bitflags flags; + const any_type class_type; + const std::vector argument_types; + + template < class_kind Class, typename... Args > + explicit constructor_type_data(type_list, type_list); + }; + + struct destructor_type_data final : type_data_base { + const destructor_bitflags flags; + const any_type class_type; + + template < class_kind Class > + explicit destructor_type_data(type_list); + }; + + struct enum_type_data final : type_data_base { + const enum_bitflags flags; + const number_type underlying_type; + + evalue_map evalues; + + template < enum_kind Enum > + explicit enum_type_data(type_list); + }; + + struct function_type_data final : type_data_base { + const function_bitflags flags; + const any_type return_type; + const std::vector argument_types; + + template < function_kind Function > + explicit function_type_data(type_list); + }; + + struct member_type_data final : type_data_base { + const member_bitflags flags; + const class_type owner_type; + const any_type value_type; + + template < member_kind Member > + explicit member_type_data(type_list); + }; + + struct method_type_data final : type_data_base { + const method_bitflags flags; + const class_type owner_type; + const any_type return_type; + const std::vector argument_types; + + template < method_kind Method > + explicit method_type_data(type_list); + }; + + struct nullptr_type_data final : type_data_base { + template < nullptr_kind Nullptr > + explicit nullptr_type_data(type_list); + }; + + struct number_type_data final : type_data_base { + const number_bitflags flags; + const std::size_t size; + const std::size_t align; + + template < number_kind Number > + explicit number_type_data(type_list); + }; + + struct pointer_type_data final : type_data_base { + const pointer_bitflags flags; + const any_type data_type; + + template < pointer_kind Pointer > + explicit pointer_type_data(type_list); + }; + + struct reference_type_data final : type_data_base { + const reference_bitflags flags; + const any_type data_type; + + template < reference_kind Reference > + explicit reference_type_data(type_list); + }; + + struct void_type_data final : type_data_base { + template < void_kind Void > + explicit void_type_data(type_list); + }; +} + +namespace meta_hpp::detail +{ + template < typename T > + inline constexpr bool is_index_family_v = + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v; + + template < typename T > + concept index_family = is_index_family_v; +} + +namespace meta_hpp +{ + class argument_index final { + public: + argument_index() = delete; + [[nodiscard]] std::size_t get_hash() const noexcept; + [[nodiscard]] const any_type& get_type() const noexcept; + [[nodiscard]] std::size_t get_position() const noexcept; + private: + friend detail::argument_state; + template < typename Argument > + [[nodiscard]] static argument_index make(std::size_t position); + private: + explicit argument_index(any_type type, std::size_t position); + friend bool operator<(const argument_index& l, const argument_index& r) noexcept; + friend bool operator==(const argument_index& l, const argument_index& r) noexcept; + private: + any_type type_; + std::size_t position_{}; + }; + + class constructor_index final { + public: + constructor_index() = delete; + [[nodiscard]] std::size_t get_hash() const noexcept; + [[nodiscard]] const constructor_type& get_type() const noexcept; + private: + friend detail::constructor_state; + template < detail::class_kind Class, typename... Args > + [[nodiscard]] static constructor_index make(); + private: + explicit constructor_index(constructor_type type); + friend bool operator<(const constructor_index& l, const constructor_index& r) noexcept; + friend bool operator==(const constructor_index& l, const constructor_index& r) noexcept; + private: + constructor_type type_; + }; + + class destructor_index final { + public: + destructor_index() = delete; + [[nodiscard]] std::size_t get_hash() const noexcept; + [[nodiscard]] const destructor_type& get_type() const noexcept; + private: + friend detail::destructor_state; + template < detail::class_kind Class > + [[nodiscard]] static destructor_index make(); + private: + explicit destructor_index(destructor_type type); + friend bool operator<(const destructor_index& l, const destructor_index& r) noexcept; + friend bool operator==(const destructor_index& l, const destructor_index& r) noexcept; + private: + destructor_type type_; + }; + + class evalue_index final { + public: + evalue_index() = delete; + [[nodiscard]] std::size_t get_hash() const noexcept; + [[nodiscard]] const enum_type& get_type() const noexcept; + [[nodiscard]] const std::string& get_name() const noexcept; + private: + friend detail::evalue_state; + template < detail::enum_kind Enum > + [[nodiscard]] static evalue_index make(std::string name); + private: + explicit evalue_index(enum_type type, std::string name); + friend bool operator<(const evalue_index& l, const evalue_index& r) noexcept; + friend bool operator==(const evalue_index& l, const evalue_index& r) noexcept; + private: + enum_type type_; + std::string name_; + }; + + class function_index final { + public: + function_index() = delete; + [[nodiscard]] std::size_t get_hash() const noexcept; + [[nodiscard]] const function_type& get_type() const noexcept; + [[nodiscard]] const std::string& get_name() const noexcept; + private: + friend detail::function_state; + template < detail::function_kind Function > + [[nodiscard]] static function_index make(std::string name); + private: + explicit function_index(function_type type, std::string name); + friend bool operator<(const function_index& l, const function_index& r) noexcept; + friend bool operator==(const function_index& l, const function_index& r) noexcept; + private: + function_type type_; + std::string name_; + }; + + class member_index final { + public: + member_index() = delete; + [[nodiscard]] std::size_t get_hash() const noexcept; + [[nodiscard]] const member_type& get_type() const noexcept; + [[nodiscard]] const std::string& get_name() const noexcept; + private: + friend detail::member_state; + template < detail::member_kind Member > + [[nodiscard]] static member_index make(std::string name); + private: + explicit member_index(member_type type, std::string name); + friend bool operator<(const member_index& l, const member_index& r) noexcept; + friend bool operator==(const member_index& l, const member_index& r) noexcept; + private: + member_type type_; + std::string name_; + }; + + class method_index final { + public: + method_index() = delete; + [[nodiscard]] std::size_t get_hash() const noexcept; + [[nodiscard]] const method_type& get_type() const noexcept; + [[nodiscard]] const std::string& get_name() const noexcept; + private: + friend detail::method_state; + template < detail::method_kind Method > + [[nodiscard]] static method_index make(std::string name); + private: + explicit method_index(method_type type, std::string name); + friend bool operator<(const method_index& l, const method_index& r) noexcept; + friend bool operator==(const method_index& l, const method_index& r) noexcept; + private: + method_type type_; + std::string name_; + }; + + class scope_index final { + public: + scope_index() = delete; + [[nodiscard]] std::size_t get_hash() const noexcept; + [[nodiscard]] const std::string& get_name() const noexcept; + private: + friend detail::scope_state; + [[nodiscard]] static scope_index make(std::string name); + private: + explicit scope_index(std::string name); + friend bool operator<(const scope_index& l, const scope_index& r) noexcept; + friend bool operator==(const scope_index& l, const scope_index& r) noexcept; + private: + std::string name_; + }; + + class variable_index final { + public: + variable_index() = delete; + [[nodiscard]] std::size_t get_hash() const noexcept; + [[nodiscard]] const pointer_type& get_type() const noexcept; + [[nodiscard]] const std::string& get_name() const noexcept; + private: + friend detail::variable_state; + template < detail::pointer_kind Pointer > + [[nodiscard]] static variable_index make(std::string name); + private: + explicit variable_index(pointer_type type, std::string name); + friend bool operator<(const variable_index& l, const variable_index& r) noexcept; + friend bool operator==(const variable_index& l, const variable_index& r) noexcept; + private: + pointer_type type_; + std::string name_; + }; +} + +namespace std +{ + template < meta_hpp::detail::index_family T > + struct hash { + size_t operator()(const T& t) const noexcept { + return t.get_hash(); + } + }; +} + +namespace meta_hpp::detail +{ + template < typename T > + inline constexpr bool is_value_kind_v = std::is_same_v; + + template < typename T > + concept value_kind = is_value_kind_v; + + template < typename T > + concept decay_value_kind = value_kind>; + + template < typename T > + concept decay_non_value_kind = !decay_value_kind; +} + +namespace meta_hpp +{ + class uvalue final { + public: + uvalue() = default; + ~uvalue(); + + uvalue(uvalue&& other) noexcept; + uvalue(const uvalue& other); + + uvalue& operator=(uvalue&& other) noexcept; + uvalue& operator=(const uvalue& other); + + template < detail::decay_non_value_kind T > + requires stdex::copy_constructible> + explicit uvalue(T&& val); + + template < detail::decay_non_value_kind T > + requires stdex::copy_constructible> + uvalue& operator=(T&& val); + + [[nodiscard]] bool is_valid() const noexcept; + [[nodiscard]] explicit operator bool() const noexcept; + + void reset(); + void swap(uvalue& other) noexcept; + + [[nodiscard]] const any_type& get_type() const noexcept; + + [[nodiscard]] void* data() noexcept; + [[nodiscard]] const void* data() const noexcept; + [[nodiscard]] const void* cdata() const noexcept; + + [[nodiscard]] uvalue operator*() const; + [[nodiscard]] uvalue operator[](std::size_t index) const; + + template < typename T > + [[nodiscard]] std::decay_t& cast() &; + + template < typename T > + [[nodiscard]] std::decay_t&& cast() &&; + + template < typename T > + [[nodiscard]] const std::decay_t& cast() const &; + + template < typename T > + [[nodiscard]] const std::decay_t&& cast() const &&; + + template < typename T > + [[nodiscard]] std::decay_t* try_cast() noexcept; + + template < typename T > + [[nodiscard]] const std::decay_t* try_cast() const noexcept; + + friend bool operator<(const uvalue& l, const uvalue& r); + friend bool operator==(const uvalue& l, const uvalue& r); + friend std::istream& operator>>(std::istream& is, uvalue& v); + friend std::ostream& operator<<(std::ostream& os, const uvalue& v); + private: + struct vtable_t; + vtable_t* vtable_{}; + private: + using buffer_t = std::aligned_storage_t; + using storage_u = std::variant; + storage_u storage_{}; + }; + + inline void swap(uvalue& l, uvalue& r) noexcept { + l.swap(r); + } +} + +namespace meta_hpp::detail +{ + template < typename T > + inline constexpr bool is_state_family_v = + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v; + + template < typename T > + concept state_family = is_state_family_v; + + template < state_family T > + [[nodiscard]] auto state_access(const T& state) { + return state.state_; + } +} + +namespace meta_hpp +{ + namespace constructor_policy + { + struct as_object final {}; + struct as_raw_pointer final {}; + struct as_shared_pointer final {}; + } + + namespace function_policy + { + struct as_copy final {}; + struct discard_return final {}; + struct return_reference_as_pointer final {}; + } + + namespace member_policy + { + struct as_copy final {}; + struct as_pointer final {}; + struct as_reference_wrapper final {}; + } + + namespace method_policy + { + struct as_copy final {}; + struct discard_return final {}; + struct return_reference_as_pointer final {}; + } + + namespace variable_policy + { + struct as_copy final {}; + struct as_pointer final {}; + struct as_reference_wrapper final {}; + } + + template < typename Policy > + inline constexpr bool is_constructor_policy_v = + std::is_same_v || + std::is_same_v || + std::is_same_v; + + template < typename Policy > + inline constexpr bool is_function_policy_v = + std::is_same_v || + std::is_same_v || + std::is_same_v; + + template < typename Policy > + inline constexpr bool is_member_policy_v = + std::is_same_v || + std::is_same_v || + std::is_same_v; + + template < typename Policy > + inline constexpr bool is_method_policy_v = + std::is_same_v || + std::is_same_v || + std::is_same_v; + + template < typename Policy > + inline constexpr bool is_variable_policy_v = + std::is_same_v || + std::is_same_v || + std::is_same_v; + + template < typename Policy > + concept constructor_policy_kind = is_constructor_policy_v; + + template < typename Policy > + concept function_policy_kind = is_function_policy_v; + + template < typename Policy > + concept member_policy_kind = is_member_policy_v; + + template < typename Policy > + concept method_policy_kind = is_method_policy_v; + + template < typename Policy > + concept variable_policy_kind = is_variable_policy_v; +} + +namespace meta_hpp +{ + class argument final { + public: + explicit argument() = default; + explicit argument(detail::argument_state_ptr state) noexcept; + argument& operator=(detail::argument_state_ptr state) noexcept; + + [[nodiscard]] bool is_valid() const noexcept; + [[nodiscard]] explicit operator bool() const noexcept; + + [[nodiscard]] const argument_index& get_index() const noexcept; + [[nodiscard]] const metadata_map& get_metadata() const noexcept; + + [[nodiscard]] const any_type& get_type() const noexcept; + [[nodiscard]] std::size_t get_position() const noexcept; + + [[nodiscard]] const std::string& get_name() const noexcept; + private: + detail::argument_state_ptr state_; + friend auto detail::state_access(const argument&); + }; + + class constructor final { + public: + explicit constructor() = default; + explicit constructor(detail::constructor_state_ptr state) noexcept; + constructor& operator=(detail::constructor_state_ptr state) noexcept; + + [[nodiscard]] bool is_valid() const noexcept; + [[nodiscard]] explicit operator bool() const noexcept; + + [[nodiscard]] const constructor_index& get_index() const noexcept; + [[nodiscard]] const metadata_map& get_metadata() const noexcept; + + [[nodiscard]] const constructor_type& get_type() const noexcept; + + template < typename... Args > + uvalue invoke(Args&&... args) const; + + template < typename... Args > + uvalue operator()(Args&&... args) const; + + template < typename... Args > + [[nodiscard]] bool is_invocable_with() const noexcept; + + template < typename... Args > + [[nodiscard]] bool is_invocable_with(Args&&... args) const noexcept; + + [[nodiscard]] argument get_argument(std::size_t position) const noexcept; + [[nodiscard]] const argument_list& get_arguments() const noexcept; + private: + detail::constructor_state_ptr state_; + friend auto detail::state_access(const constructor&); + }; + + class destructor final { + public: + explicit destructor() = default; + explicit destructor(detail::destructor_state_ptr state) noexcept; + destructor& operator=(detail::destructor_state_ptr state) noexcept; + + [[nodiscard]] bool is_valid() const noexcept; + [[nodiscard]] explicit operator bool() const noexcept; + + [[nodiscard]] const destructor_index& get_index() const noexcept; + [[nodiscard]] const metadata_map& get_metadata() const noexcept; + + [[nodiscard]] const destructor_type& get_type() const noexcept; + + template < typename Arg > + void invoke(Arg&& ptr) const; + + template < typename Arg > + void operator()(Arg&& ptr) const; + + template < typename Arg > + [[nodiscard]] bool is_invocable_with() const noexcept; + + template < typename Arg > + [[nodiscard]] bool is_invocable_with(Arg&& ptr) const noexcept; + private: + detail::destructor_state_ptr state_; + friend auto detail::state_access(const destructor&); + }; + + class evalue final { + public: + explicit evalue() = default; + explicit evalue(detail::evalue_state_ptr state) noexcept; + evalue& operator=(detail::evalue_state_ptr state) noexcept; + + [[nodiscard]] bool is_valid() const noexcept; + [[nodiscard]] explicit operator bool() const noexcept; + + [[nodiscard]] const evalue_index& get_index() const noexcept; + [[nodiscard]] const metadata_map& get_metadata() const noexcept; + + [[nodiscard]] const enum_type& get_type() const noexcept; + [[nodiscard]] const std::string& get_name() const noexcept; + + [[nodiscard]] const uvalue& get_value() const noexcept; + [[nodiscard]] const uvalue& get_underlying_value() const noexcept; + private: + detail::evalue_state_ptr state_; + friend auto detail::state_access(const evalue&); + }; + + class function final { + public: + explicit function() = default; + explicit function(detail::function_state_ptr state) noexcept; + function& operator=(detail::function_state_ptr state) noexcept; + + [[nodiscard]] bool is_valid() const noexcept; + [[nodiscard]] explicit operator bool() const noexcept; + + [[nodiscard]] const function_index& get_index() const noexcept; + [[nodiscard]] const metadata_map& get_metadata() const noexcept; + + [[nodiscard]] const function_type& get_type() const noexcept; + [[nodiscard]] const std::string& get_name() const noexcept; + + template < typename... Args > + uvalue invoke(Args&&... args) const; + + template < typename... Args > + uvalue operator()(Args&&... args) const; + + template < typename... Args > + [[nodiscard]] bool is_invocable_with() const noexcept; + + template < typename... Args > + [[nodiscard]] bool is_invocable_with(Args&&... args) const noexcept; + + [[nodiscard]] argument get_argument(std::size_t position) const noexcept; + [[nodiscard]] const argument_list& get_arguments() const noexcept; + private: + detail::function_state_ptr state_; + friend auto detail::state_access(const function&); + }; + + class member final { + public: + explicit member() = default; + explicit member(detail::member_state_ptr state) noexcept; + member& operator=(detail::member_state_ptr state) noexcept; + + [[nodiscard]] bool is_valid() const noexcept; + [[nodiscard]] explicit operator bool() const noexcept; + + [[nodiscard]] const member_index& get_index() const noexcept; + [[nodiscard]] const metadata_map& get_metadata() const noexcept; + + [[nodiscard]] const member_type& get_type() const noexcept; + [[nodiscard]] const std::string& get_name() const noexcept; + + template < typename Instance > + [[nodiscard]] uvalue get(Instance&& instance) const; + + template < typename Instance, typename Value > + void set(Instance&& instance, Value&& value) const; + + template < typename Instance > + [[nodiscard]] uvalue operator()(Instance&& instance) const; + + template < typename Instance, typename Value > + void operator()(Instance&& instance, Value&& value) const; + + template < typename Instance > + [[nodiscard]] bool is_gettable_with() const noexcept; + + template < typename Instance > + [[nodiscard]] bool is_gettable_with(Instance&& instance) const noexcept; + + template < typename Instance, typename Value > + [[nodiscard]] bool is_settable_with() const noexcept; + + template < typename Instance, typename Value > + [[nodiscard]] bool is_settable_with(Instance&& instance, Value&& value) const noexcept; + private: + detail::member_state_ptr state_; + friend auto detail::state_access(const member&); + }; + + class method final { + public: + explicit method() = default; + explicit method(detail::method_state_ptr state) noexcept; + method& operator=(detail::method_state_ptr state) noexcept; + + [[nodiscard]] bool is_valid() const noexcept; + [[nodiscard]] explicit operator bool() const noexcept; + + [[nodiscard]] const method_index& get_index() const noexcept; + [[nodiscard]] const metadata_map& get_metadata() const noexcept; + + [[nodiscard]] const method_type& get_type() const noexcept; + [[nodiscard]] const std::string& get_name() const noexcept; + + template < typename Instance, typename... Args > + uvalue invoke(Instance&& instance, Args&&... args) const; + + template < typename Instance, typename... Args > + uvalue operator()(Instance&& instance, Args&&... args) const; + + template < typename Instance, typename... Args > + [[nodiscard]] bool is_invocable_with() const noexcept; + + template < typename Instance, typename... Args > + [[nodiscard]] bool is_invocable_with(Instance&& instance, Args&&... args) const noexcept; + + [[nodiscard]] argument get_argument(std::size_t position) const noexcept; + [[nodiscard]] const argument_list& get_arguments() const noexcept; + private: + detail::method_state_ptr state_; + friend auto detail::state_access(const method&); + }; + + class scope final { + public: + explicit scope() = default; + explicit scope(detail::scope_state_ptr state) noexcept; + scope& operator=(detail::scope_state_ptr state) noexcept; + + [[nodiscard]] bool is_valid() const noexcept; + [[nodiscard]] explicit operator bool() const noexcept; + + [[nodiscard]] const scope_index& get_index() const noexcept; + [[nodiscard]] const metadata_map& get_metadata() const noexcept; + + [[nodiscard]] const std::string& get_name() const noexcept; + + [[nodiscard]] const function_map& get_functions() const noexcept; + [[nodiscard]] const typedef_map& get_typedefs() const noexcept; + [[nodiscard]] const variable_map& get_variables() const noexcept; + + [[nodiscard]] function get_function(std::string_view name) const noexcept; + [[nodiscard]] any_type get_typedef(std::string_view name) const noexcept; + [[nodiscard]] variable get_variable(std::string_view name) const noexcept; + + template < typename... Args > + [[nodiscard]] function get_function_with(std::string_view name) const noexcept; + template < typename Iter > + [[nodiscard]] function get_function_with(std::string_view name, Iter first, Iter last) const noexcept; + [[nodiscard]] function get_function_with(std::string_view name, const std::vector& args) const noexcept; + [[nodiscard]] function get_function_with(std::string_view name, std::initializer_list args) const noexcept; + private: + detail::scope_state_ptr state_; + friend auto detail::state_access(const scope&); + }; + + class variable final { + public: + explicit variable() = default; + explicit variable(detail::variable_state_ptr state) noexcept; + variable& operator=(detail::variable_state_ptr state) noexcept; + + [[nodiscard]] bool is_valid() const noexcept; + [[nodiscard]] explicit operator bool() const noexcept; + + [[nodiscard]] const variable_index& get_index() const noexcept; + [[nodiscard]] const metadata_map& get_metadata() const noexcept; + + [[nodiscard]] const pointer_type& get_type() const noexcept; + [[nodiscard]] const std::string& get_name() const noexcept; + + [[nodiscard]] uvalue get() const; + + template < typename Value > + void set(Value&& value) const; + + [[nodiscard]] uvalue operator()() const; + + template < typename Value > + void operator()(Value&& value) const; + + template < typename Value > + [[nodiscard]] bool is_settable_with() const noexcept; + + template < typename Value > + [[nodiscard]] bool is_settable_with(Value&& value) const noexcept; + private: + detail::variable_state_ptr state_; + friend auto detail::state_access(const variable&); + }; +} + +namespace meta_hpp +{ + template < detail::state_family T, detail::state_family U > + [[nodiscard]] bool operator<(const T& l, const U& r) noexcept { + if ( !static_cast(r) ) { + return false; + } + + if ( !static_cast(l) ) { + return true; + } + + return l.get_index() < r.get_index(); + } + + template < detail::state_family T, detail::state_family U > + [[nodiscard]] bool operator==(const T& l, const U& r) noexcept { + if ( static_cast(l) != static_cast(r) ) { + return false; + } + + if ( !static_cast(l) ) { + return true; + } + + return l.get_index() == r.get_index(); + } + + template < detail::state_family T, detail::state_family U > + [[nodiscard]] bool operator!=(const T& l, const U& r) noexcept { + return !(l == r); + } +} + +namespace meta_hpp::detail +{ + struct argument_state final { + argument_index index; + metadata_map metadata; + + std::string name{}; + + template < typename Argument > + [[nodiscard]] static argument_state_ptr make(std::size_t position, metadata_map metadata); + }; + + struct constructor_state final { + using invoke_impl = fixed_function)>; + using is_invocable_with_impl = fixed_function)>; + + constructor_index index; + metadata_map metadata; + + invoke_impl invoke; + is_invocable_with_impl is_invocable_with; + + argument_list arguments; + + template < constructor_policy_kind Policy, class_kind Class, typename... Args > + [[nodiscard]] static constructor_state_ptr make(metadata_map metadata); + }; + + struct destructor_state final { + using invoke_impl = fixed_function; + using is_invocable_with_impl = fixed_function; + + destructor_index index; + metadata_map metadata; + + invoke_impl invoke; + is_invocable_with_impl is_invocable_with; + + template < class_kind Class > + [[nodiscard]] static destructor_state_ptr make(metadata_map metadata); + }; + + struct evalue_state final { + evalue_index index; + metadata_map metadata; + + uvalue enum_value; + uvalue underlying_value; + + template < enum_kind Enum > + [[nodiscard]] static evalue_state_ptr make(std::string name, Enum evalue, metadata_map metadata); + }; + + struct function_state final { + using invoke_impl = fixed_function)>; + using is_invocable_with_impl = fixed_function)>; + + function_index index; + metadata_map metadata; + + invoke_impl invoke; + is_invocable_with_impl is_invocable_with; + + argument_list arguments; + + template < function_policy_kind Policy, function_kind Function > + [[nodiscard]] static function_state_ptr make(std::string name, Function function, metadata_map metadata); + }; + + struct member_state final { + using getter_impl = fixed_function; + using setter_impl = fixed_function; + + using is_gettable_with_impl = fixed_function; + using is_settable_with_impl = fixed_function; + + member_index index; + metadata_map metadata; + + getter_impl getter; + setter_impl setter; + is_gettable_with_impl is_gettable_with; + is_settable_with_impl is_settable_with; + + + template < member_policy_kind Policy, member_kind Member > + [[nodiscard]] static member_state_ptr make(std::string name, Member member, metadata_map metadata); + }; + + struct method_state final { + using invoke_impl = fixed_function)>; + using is_invocable_with_impl = fixed_function)>; + + method_index index; + metadata_map metadata; + + invoke_impl invoke; + is_invocable_with_impl is_invocable_with; + + argument_list arguments; + + template < method_policy_kind Policy, method_kind Method > + [[nodiscard]] static method_state_ptr make(std::string name, Method method, metadata_map metadata); + }; + + struct scope_state final { + scope_index index; + metadata_map metadata; + + function_map functions{}; + typedef_map typedefs{}; + variable_map variables{}; + + [[nodiscard]] static scope_state_ptr make(std::string name, metadata_map metadata); + }; + + struct variable_state final { + using getter_impl = fixed_function; + using setter_impl = fixed_function; + using is_settable_with_impl = fixed_function; + + variable_index index; + metadata_map metadata; + + getter_impl getter; + setter_impl setter; + is_settable_with_impl is_settable_with; + + template < variable_policy_kind Policy, pointer_kind Pointer > + [[nodiscard]] static variable_state_ptr make(std::string name, Pointer pointer, metadata_map metadata); + }; +} + +namespace meta_hpp::detail +{ + class state_registry final { + public: + class locker final : noncopyable { + public: + explicit locker() + : lock_{instance().mutex_} {} + private: + std::lock_guard lock_; + }; + + [[nodiscard]] static state_registry& instance() { + static state_registry instance; + return instance; + } + public: + [[nodiscard]] scope get_scope_by_name(std::string_view name) const noexcept { + const locker lock; + + if ( auto iter = scopes_.find(name); iter != scopes_.end() ) { + return iter->second; + } + + return scope{}; + } + + [[nodiscard]] scope resolve_scope(std::string_view name) { + const locker lock; + + if ( auto iter = scopes_.find(name); iter != scopes_.end() ) { + return iter->second; + } + + auto state = scope_state::make(std::string{name}, metadata_map{}); + return scopes_.insert_or_assign(std::string{name}, std::move(state)).first->second; + } + private: + state_registry() = default; + private: + std::recursive_mutex mutex_; + std::map> scopes_; + }; +} + +namespace meta_hpp::detail +{ + class type_registry final { + public: + class locker final : noncopyable { + public: + explicit locker() + : lock_{instance().mutex_} {} + private: + std::lock_guard lock_; + }; + + [[nodiscard]] static type_registry& instance() { + static type_registry instance; + return instance; + } + public: + [[nodiscard]] any_type get_type_by_id(type_id id) const noexcept { + const locker lock; + + if ( auto iter = type_by_id_.find(id); iter != type_by_id_.end() ) { + return iter->second; + } + + return any_type{}; + } + + [[nodiscard]] any_type get_type_by_rtti(const std::type_index& index) const noexcept { + const locker lock; + + if ( auto iter = type_by_rtti_.find(index); iter != type_by_rtti_.end() ) { + return iter->second; + } + + return any_type{}; + } + public: + template < array_kind Array > + [[nodiscard]] array_type resolve_type() { return resolve_array_type(); } + + template < class_kind Class > + [[nodiscard]] class_type resolve_type() { return resolve_class_type(); } + + template < enum_kind Enum > + [[nodiscard]] enum_type resolve_type() { return resolve_enum_type(); } + + template < function_kind Function > + [[nodiscard]] function_type resolve_type() { return resolve_function_type(); } + + template < member_kind Member > + [[nodiscard]] member_type resolve_type() { return resolve_member_type(); } + + template < method_kind Method > + [[nodiscard]] method_type resolve_type() { return resolve_method_type(); } + + template < nullptr_kind Nullptr > + [[nodiscard]] nullptr_type resolve_type() { return resolve_nullptr_type(); } + + template < number_kind Number > + [[nodiscard]] number_type resolve_type() { return resolve_number_type(); } + + template < pointer_kind Pointer > + [[nodiscard]] pointer_type resolve_type() { return resolve_pointer_type(); } + + template < reference_kind Reference > + [[nodiscard]] reference_type resolve_type() { return resolve_reference_type(); } + + template < void_kind Void > + [[nodiscard]] void_type resolve_type() { return resolve_void_type(); } + public: + template < array_kind Array > + [[nodiscard]] array_type resolve_array_type() { return array_type{resolve_array_type_data()}; } + + template < class_kind Class > + [[nodiscard]] class_type resolve_class_type() { return class_type{resolve_class_type_data()}; } + + template < class_kind Class, typename... Args > + [[nodiscard]] constructor_type resolve_constructor_type() { return constructor_type{resolve_constructor_type_data()}; } + + template < class_kind Class > + [[nodiscard]] destructor_type resolve_destructor_type() { return destructor_type{resolve_destructor_type_data()}; } + + template < enum_kind Enum > + [[nodiscard]] enum_type resolve_enum_type() { return enum_type{resolve_enum_type_data()}; } + + template < function_kind Function > + [[nodiscard]] function_type resolve_function_type() { return function_type{resolve_function_type_data()}; } + + template < member_kind Member > + [[nodiscard]] member_type resolve_member_type() { return member_type{resolve_member_type_data()}; } + + template < method_kind Method > + [[nodiscard]] method_type resolve_method_type() { return method_type{resolve_method_type_data()}; } + + template < nullptr_kind Nullptr > + [[nodiscard]] nullptr_type resolve_nullptr_type() { return nullptr_type{resolve_nullptr_type_data()}; } + + template < number_kind Number > + [[nodiscard]] number_type resolve_number_type() { return number_type{resolve_number_type_data()}; } + + template < pointer_kind Pointer > + [[nodiscard]] pointer_type resolve_pointer_type() { return pointer_type{resolve_pointer_type_data()}; } + + template < reference_kind Reference > + [[nodiscard]] reference_type resolve_reference_type() { return reference_type{resolve_reference_type_data()}; } + + template < void_kind Void > + [[nodiscard]] void_type resolve_void_type() { return void_type{resolve_void_type_data()}; } + private: + template < array_kind Array > + [[nodiscard]] array_type_data* resolve_array_type_data() { + static array_type_data data{type_list{}}; + ensure_type(data); + return &data; + } + + template < class_kind Class > + [[nodiscard]] class_type_data* resolve_class_type_data() { + static class_type_data data{type_list{}}; + ensure_type(data); + return &data; + } + + template < class_kind Class, typename... Args > + [[nodiscard]] constructor_type_data* resolve_constructor_type_data() { + static constructor_type_data data{type_list{}, type_list{}}; + return &data; + } + + template < class_kind Class > + [[nodiscard]] destructor_type_data* resolve_destructor_type_data() { + static destructor_type_data data{type_list{}}; + return &data; + } + + template < enum_kind Enum > + [[nodiscard]] enum_type_data* resolve_enum_type_data() { + static enum_type_data data{type_list{}}; + ensure_type(data); + return &data; + } + + template < function_kind Function > + [[nodiscard]] function_type_data* resolve_function_type_data() { + static function_type_data data{type_list{}}; + ensure_type(data); + return &data; + } + + template < member_kind Member > + [[nodiscard]] member_type_data* resolve_member_type_data() { + static member_type_data data{type_list{}}; + ensure_type(data); + return &data; + } + + template < method_kind Method > + [[nodiscard]] method_type_data* resolve_method_type_data() { + static method_type_data data{type_list{}}; + ensure_type(data); + return &data; + } + + template < nullptr_kind Nullptr > + [[nodiscard]] nullptr_type_data* resolve_nullptr_type_data() { + static nullptr_type_data data{type_list{}}; + ensure_type(data); + return &data; + } + + template < number_kind Number > + [[nodiscard]] number_type_data* resolve_number_type_data() { + static number_type_data data{type_list{}}; + ensure_type(data); + return &data; + } + + template < pointer_kind Pointer > + [[nodiscard]] pointer_type_data* resolve_pointer_type_data() { + static pointer_type_data data{type_list{}}; + ensure_type(data); + return &data; + } + + template < reference_kind Reference > + [[nodiscard]] reference_type_data* resolve_reference_type_data() { + static reference_type_data data{type_list{}}; + ensure_type(data); + return &data; + } + + template < void_kind Void > + [[nodiscard]] void_type_data* resolve_void_type_data() { + static void_type_data data{type_list{}}; + ensure_type(data); + return &data; + } + private: + type_registry() = default; + + template < typename Type, typename TypeData > + void ensure_type(TypeData& type_data) { + static std::once_flag init_flag{}; + std::call_once(init_flag, [this, &type_data](){ + const locker lock; + type_by_id_.emplace(type_data.id, any_type{&type_data}); + #ifndef META_HPP_NO_RTTI + type_by_rtti_.emplace(typeid(Type), any_type{&type_data}); + #endif + }); + } + private: + std::recursive_mutex mutex_; + std::map> type_by_id_; + std::map> type_by_rtti_; + }; +} + +namespace meta_hpp::detail +{ + template < typename Class, typename... Args > + concept class_bind_constructor_kind = + class_kind && + requires(Args&&... args) { { Class{std::forward(args)...} }; }; + + template < typename Class > + concept class_bind_destructor_kind = + class_kind && + requires(Class&& inst) { { inst.~Class() }; }; + + template < typename Class, typename Base > + concept class_bind_base_kind = + class_kind && class_kind && + stdex::derived_from; + + template < typename Class, typename Member > + concept class_bind_member_kind = + class_kind && member_kind && + stdex::same_as::class_type>; + + template < typename Class, typename Method > + concept class_bind_method_kind = + class_kind && method_kind && + stdex::same_as::class_type>; +} + +namespace meta_hpp +{ + struct argument_opts final { + std::string name{}; + metadata_map metadata{}; + }; + + struct constructor_opts final { + std::vector arguments{}; + metadata_map metadata{}; + }; + + struct destructor_opts final { + metadata_map metadata{}; + }; + + struct evalue_opts final { + metadata_map metadata{}; + }; + + struct function_opts final { + std::vector arguments{}; + metadata_map metadata{}; + }; + + struct member_opts final { + metadata_map metadata{}; + }; + + struct method_opts final { + std::vector arguments{}; + metadata_map metadata{}; + }; + + struct variable_opts final { + metadata_map metadata{}; + }; +} + +namespace meta_hpp +{ + template < detail::array_kind Array > + class array_bind final { + public: + explicit array_bind(metadata_map metadata); + operator array_type() const noexcept; + private: + detail::array_type_data* data_{}; + detail::type_registry::locker locker_{}; + }; +} + +namespace meta_hpp +{ + template < detail::class_kind Class > + class class_bind final { + public: + explicit class_bind(metadata_map metadata); + operator class_type() const noexcept; + + // base_ + + template < detail::class_kind Base > + class_bind& base_() + requires detail::class_bind_base_kind; + + // constructor_ + + template < typename... Args + , constructor_policy_kind Policy = constructor_policy::as_object > + class_bind& constructor_(Policy = Policy{}) + requires detail::class_bind_constructor_kind; + + template < typename... Args + , constructor_policy_kind Policy = constructor_policy::as_object > + class_bind& constructor_(constructor_opts opts, Policy = Policy{}) + requires detail::class_bind_constructor_kind; + + // destructor_ + + class_bind& destructor_() + requires detail::class_bind_destructor_kind; + + class_bind& destructor_(destructor_opts opts) + requires detail::class_bind_destructor_kind; + + // function_ + + template < detail::function_kind Function + , function_policy_kind Policy = function_policy::as_copy > + class_bind& function_( + std::string name, + Function function, + Policy = Policy{}); + + template < detail::function_kind Function + , function_policy_kind Policy = function_policy::as_copy > + class_bind& function_( + std::string name, + Function function, + function_opts opts, + Policy = Policy{}); + + template < detail::function_kind Function + , function_policy_kind Policy = function_policy::as_copy > + class_bind& function_( + std::string name, + Function function, + std::initializer_list arguments, + Policy = Policy{}); + + // member_ + + template < detail::member_kind Member + , member_policy_kind Policy = member_policy::as_copy > + class_bind& member_( + std::string name, + Member member, + Policy = Policy{}) + requires detail::class_bind_member_kind; + + template < detail::member_kind Member + , member_policy_kind Policy = member_policy::as_copy > + class_bind& member_( + std::string name, + Member member, + member_opts opts, + Policy = Policy{}) + requires detail::class_bind_member_kind; + + // method_ + + template < detail::method_kind Method + , method_policy_kind Policy = method_policy::as_copy > + class_bind& method_( + std::string name, + Method method, + Policy = Policy{}) + requires detail::class_bind_method_kind; + + template < detail::method_kind Method + , method_policy_kind Policy = method_policy::as_copy > + class_bind& method_( + std::string name, + Method method, + method_opts opts, + Policy = Policy{}) + requires detail::class_bind_method_kind; + + template < detail::method_kind Method + , method_policy_kind Policy = method_policy::as_copy > + class_bind& method_( + std::string name, + Method method, + std::initializer_list arguments, + Policy = Policy{}) + requires detail::class_bind_method_kind; + + // typdef_ + + template < typename Type > + class_bind& typedef_(std::string name); + + // variable_ + + template < detail::pointer_kind Pointer + , variable_policy_kind Policy = variable_policy::as_copy > + class_bind& variable_( + std::string name, + Pointer pointer, + Policy = Policy{}); + + template < detail::pointer_kind Pointer + , variable_policy_kind Policy = variable_policy::as_copy > + class_bind& variable_( + std::string name, + Pointer pointer, + variable_opts opts, + Policy = Policy{}); + private: + detail::class_type_data* data_{}; + detail::type_registry::locker locker_{}; + }; +} + +namespace meta_hpp +{ + template < detail::enum_kind Enum > + class enum_bind final { + public: + explicit enum_bind(metadata_map metadata); + operator enum_type() const noexcept; + + enum_bind& evalue_(std::string name, Enum value); + enum_bind& evalue_(std::string name, Enum value, evalue_opts opts); + private: + detail::enum_type_data* data_{}; + detail::type_registry::locker locker_{}; + }; +} + +namespace meta_hpp +{ + template < detail::function_kind Function > + class function_bind final { + public: + explicit function_bind(metadata_map metadata); + operator function_type() const noexcept; + private: + detail::function_type_data* data_{}; + detail::type_registry::locker locker_{}; + }; +} + +namespace meta_hpp +{ + template < detail::member_kind Member > + class member_bind final { + public: + explicit member_bind(metadata_map metadata); + operator member_type() const noexcept; + private: + detail::member_type_data* data_{}; + detail::type_registry::locker locker_{}; + }; +} + +namespace meta_hpp +{ + template < detail::method_kind Method > + class method_bind final { + public: + explicit method_bind(metadata_map metadata); + operator method_type() const noexcept; + private: + detail::method_type_data* data_{}; + detail::type_registry::locker locker_{}; + }; +} + +namespace meta_hpp +{ + template < detail::nullptr_kind Nullptr > + class nullptr_bind final { + public: + explicit nullptr_bind(metadata_map metadata); + operator nullptr_type() const noexcept; + private: + detail::nullptr_type_data* data_{}; + detail::type_registry::locker locker_{}; + }; +} + +namespace meta_hpp +{ + template < detail::number_kind Number > + class number_bind final { + public: + explicit number_bind(metadata_map metadata); + operator number_type() const noexcept; + private: + detail::number_type_data* data_{}; + detail::type_registry::locker locker_{}; + }; +} + +namespace meta_hpp +{ + template < detail::pointer_kind Pointer > + class pointer_bind final { + public: + explicit pointer_bind(metadata_map metadata); + operator pointer_type() const noexcept; + private: + detail::pointer_type_data* data_{}; + detail::type_registry::locker locker_{}; + }; +} + +namespace meta_hpp +{ + template < detail::reference_kind Reference > + class reference_bind final { + public: + explicit reference_bind(metadata_map metadata); + operator reference_type() const noexcept; + private: + detail::reference_type_data* data_{}; + detail::type_registry::locker locker_{}; + }; +} + +namespace meta_hpp +{ + template < detail::void_kind Void > + class void_bind final { + public: + explicit void_bind(metadata_map metadata); + operator void_type() const noexcept; + private: + detail::void_type_data* data_{}; + detail::type_registry::locker locker_{}; + }; +} + +namespace meta_hpp +{ + class scope_bind final { + public: + struct local_tag {}; + struct static_tag {}; + + explicit scope_bind(std::string name, metadata_map metadata, local_tag); + explicit scope_bind(std::string_view name, metadata_map metadata, static_tag); + operator scope() const noexcept; + + // function_ + + template < detail::function_kind Function + , function_policy_kind Policy = function_policy::as_copy > + scope_bind& function_( + std::string name, + Function function, + Policy = Policy{}); + + template < detail::function_kind Function + , function_policy_kind Policy = function_policy::as_copy > + scope_bind& function_( + std::string name, + Function function, + function_opts opts, + Policy = Policy{}); + + template < detail::function_kind Function + , function_policy_kind Policy = function_policy::as_copy > + scope_bind& function_( + std::string name, + Function function, + std::initializer_list arguments, + Policy = Policy{}); + + // typedef_ + + template < typename Type > + scope_bind& typedef_(std::string name); + + // variable_ + + template < detail::pointer_kind Pointer + , variable_policy_kind Policy = variable_policy::as_copy > + scope_bind& variable_( + std::string name, + Pointer pointer, + Policy = Policy{}); + + template < detail::pointer_kind Pointer + , variable_policy_kind Policy = variable_policy::as_copy > + scope_bind& variable_( + std::string name, + Pointer pointer, + variable_opts opts, + Policy = Policy{}); + private: + detail::scope_state_ptr state_; + detail::state_registry::locker locker_{}; + }; +} + +namespace meta_hpp +{ + template < detail::array_kind Array > + array_bind array_(metadata_map metadata = {}) { + return array_bind{std::move(metadata)}; + } + + template < detail::class_kind Class > + class_bind class_(metadata_map metadata = {}) { + return class_bind{std::move(metadata)}; + } + + template < detail::enum_kind Enum > + enum_bind enum_(metadata_map metadata = {}) { + return enum_bind{std::move(metadata)}; + } + + template < detail::function_kind Function > + function_bind function_(metadata_map metadata = {}) { + return function_bind{std::move(metadata)}; + } + + template < detail::member_kind Member > + member_bind member_(metadata_map metadata = {}) { + return member_bind{std::move(metadata)}; + } + + template < detail::method_kind Method > + method_bind method_(metadata_map metadata = {}) { + return method_bind{std::move(metadata)}; + } + + template < detail::nullptr_kind Nullptr > + nullptr_bind nullptr_(metadata_map metadata = {}) { + return nullptr_bind{std::move(metadata)}; + } + + template < detail::number_kind Number > + number_bind number_(metadata_map metadata = {}) { + return number_bind{std::move(metadata)}; + } + + template < detail::pointer_kind Pointer > + pointer_bind pointer_(metadata_map metadata = {}) { + return pointer_bind{std::move(metadata)}; + } + + template < detail::reference_kind Reference > + reference_bind reference_(metadata_map metadata = {}) { + return reference_bind{std::move(metadata)}; + } + + template < detail::void_kind Void > + void_bind void_(metadata_map metadata = {}) { + return void_bind{std::move(metadata)}; + } +} + +namespace meta_hpp +{ + inline scope_bind local_scope_(std::string name, metadata_map metadata = {}) { + return scope_bind{std::move(name), std::move(metadata), scope_bind::local_tag()}; + } + + inline scope_bind static_scope_(std::string_view name, metadata_map metadata = {}) { + return scope_bind{name, std::move(metadata), scope_bind::static_tag()}; + } +} + +namespace meta_hpp +{ + template < typename T > + [[nodiscard]] auto resolve_type() { + using namespace detail; + type_registry& registry = type_registry::instance(); + return registry.resolve_type>(); + } + + template < typename... Ts > + [[nodiscard]] std::vector resolve_types() { + return { resolve_type()... }; + } +} + +namespace meta_hpp +{ + template < typename T > + // NOLINTNEXTLINE(readability-named-parameter) + [[nodiscard]] auto resolve_type(T&&) { + return resolve_type>(); + } + + template < typename... Ts > + // NOLINTNEXTLINE(readability-named-parameter) + [[nodiscard]] std::vector resolve_types(type_list) { + return { resolve_type()... }; + } +} + +namespace meta_hpp +{ + template < detail::class_kind Class, typename... Args > + constructor_type resolve_constructor_type() { + using namespace detail; + type_registry& registry = type_registry::instance(); + return registry.resolve_constructor_type(); + } + + template < detail::class_kind Class > + destructor_type resolve_destructor_type() { + using namespace detail; + type_registry& registry = type_registry::instance(); + return registry.resolve_destructor_type(); + } +} + +namespace meta_hpp +{ + template < typename T > + [[nodiscard]] any_type resolve_polymorphic_type(T&& v) noexcept { + #ifndef META_HPP_NO_RTTI + using namespace detail; + type_registry& registry = type_registry::instance(); + return registry.get_type_by_rtti(typeid(v)); + #else + (void)v; + return any_type{}; + #endif + } +} + +namespace meta_hpp +{ + [[nodiscard]] inline scope resolve_scope(std::string_view name) { + using namespace detail; + state_registry& registry = state_registry::instance(); + return registry.resolve_scope(name); + } +} + +namespace meta_hpp +{ + template < detail::array_kind Array > + array_bind::array_bind(metadata_map metadata) + : data_{detail::type_access(resolve_type())} { + data_->metadata.swap(metadata); + data_->metadata.merge(metadata); + } + + template < detail::array_kind Array > + array_bind::operator array_type() const noexcept { + return array_type{data_}; + } +} + +namespace meta_hpp +{ + template < detail::class_kind Class > + class_bind::class_bind(metadata_map metadata) + : data_{detail::type_access(resolve_type())} { + data_->metadata.swap(metadata); + data_->metadata.merge(metadata); + } + + template < detail::class_kind Class > + class_bind::operator class_type() const noexcept { + return class_type{data_}; + } + + // + // base_ + // + + template < detail::class_kind Class > + template < detail::class_kind Base > + class_bind& class_bind::base_() + requires detail::class_bind_base_kind + { + const class_type base_type = resolve_type(); + if ( data_->bases.contains(base_type) ) { + return *this; + } + + data_->bases.emplace(base_type); + data_->bases_info.emplace(base_type, detail::class_type_data::base_info{ + .upcast = +[](void* derived) -> void* { + return static_cast(static_cast(derived)); + } + }); + + return *this; + } + + // + // constructor_ + // + + template < detail::class_kind Class > + template < typename... Args, constructor_policy_kind Policy > + class_bind& class_bind::constructor_(Policy policy) + requires detail::class_bind_constructor_kind + { + return constructor_({}, policy); + } + + template < detail::class_kind Class > + template < typename... Args, constructor_policy_kind Policy > + class_bind& class_bind::constructor_( + constructor_opts opts, + [[maybe_unused]] Policy policy) + requires detail::class_bind_constructor_kind + { + auto state = detail::constructor_state::make(std::move(opts.metadata)); + + if ( opts.arguments.size() > state->arguments.size() ) { + detail::throw_exception_with("provided argument names don't match constructor argument count"); + } + + for ( std::size_t i = 0; i < opts.arguments.size(); ++i ) { + argument& arg = state->arguments[i]; + detail::state_access(arg)->name = std::move(opts.arguments[i].name); + detail::state_access(arg)->metadata = std::move(opts.arguments[i].metadata); + } + + data_->constructors.insert_or_assign(state->index, std::move(state)); + return *this; + } + + // + // destructor_ + // + + template < detail::class_kind Class > + class_bind& class_bind::destructor_() + requires detail::class_bind_destructor_kind + { + return destructor_({}); + } + + template < detail::class_kind Class > + class_bind& class_bind::destructor_(destructor_opts opts) + requires detail::class_bind_destructor_kind + { + auto state = detail::destructor_state::make(std::move(opts.metadata)); + data_->destructors.insert_or_assign(state->index, std::move(state)); + return *this; + } + + // + // function_ + // + + template < detail::class_kind Class > + template < detail::function_kind Function, function_policy_kind Policy > + class_bind& class_bind::function_( + std::string name, + Function function, + Policy policy) + { + return function_(std::move(name), std::move(function), {}, policy); + } + + template < detail::class_kind Class > + template < detail::function_kind Function, function_policy_kind Policy > + class_bind& class_bind::function_( + std::string name, + Function function, + function_opts opts, + [[maybe_unused]] Policy policy) + { + auto state = detail::function_state::make( + std::move(name), + std::move(function), + std::move(opts.metadata)); + + if ( opts.arguments.size() > state->arguments.size() ) { + detail::throw_exception_with("provided arguments don't match function argument count"); + } + + for ( std::size_t i = 0; i < opts.arguments.size(); ++i ) { + argument& arg = state->arguments[i]; + detail::state_access(arg)->name = std::move(opts.arguments[i].name); + detail::state_access(arg)->metadata = std::move(opts.arguments[i].metadata); + } + + data_->functions.insert_or_assign(state->index, std::move(state)); + return *this; + } + + template < detail::class_kind Class > + template < detail::function_kind Function, function_policy_kind Policy > + class_bind& class_bind::function_( + std::string name, + Function function, + std::initializer_list arguments, + [[maybe_unused]] Policy policy) + { + auto state = detail::function_state::make( + std::move(name), + std::move(function), + {}); + + if ( arguments.size() > state->arguments.size() ) { + detail::throw_exception_with("provided argument names don't match function argument count"); + } + + for ( std::size_t i = 0; i < arguments.size(); ++i ) { + argument& arg = state->arguments[i]; + detail::state_access(arg)->name = std::data(arguments)[i]; + } + + data_->functions.insert_or_assign(state->index, std::move(state)); + return *this; + } + + // + // member_ + // + + template < detail::class_kind Class > + template < detail::member_kind Member, member_policy_kind Policy > + class_bind& class_bind::member_( + std::string name, + Member member, + Policy policy) + requires detail::class_bind_member_kind + { + return member_(std::move(name), std::move(member), {}, policy); + } + + template < detail::class_kind Class > + template < detail::member_kind Member, member_policy_kind Policy > + class_bind& class_bind::member_( + std::string name, + Member member, + member_opts opts, + [[maybe_unused]] Policy policy) + requires detail::class_bind_member_kind + { + auto state = detail::member_state::make( + std::move(name), + std::move(member), + std::move(opts.metadata)); + data_->members.insert_or_assign(state->index, std::move(state)); + return *this; + } + + // + // method_ + // + + template < detail::class_kind Class > + template < detail::method_kind Method, method_policy_kind Policy > + class_bind& class_bind::method_( + std::string name, + Method method, + Policy policy) + requires detail::class_bind_method_kind + { + return method_(std::move(name), std::move(method), {}, policy); + } + + template < detail::class_kind Class > + template < detail::method_kind Method, method_policy_kind Policy > + class_bind& class_bind::method_( + std::string name, + Method method, + method_opts opts, + [[maybe_unused]] Policy policy) + requires detail::class_bind_method_kind + { + auto state = detail::method_state::make( + std::move(name), + std::move(method), + std::move(opts.metadata)); + + if ( opts.arguments.size() > state->arguments.size() ) { + detail::throw_exception_with("provided arguments don't match method argument count"); + } + + for ( std::size_t i = 0; i < opts.arguments.size(); ++i ) { + argument& arg = state->arguments[i]; + detail::state_access(arg)->name = std::move(opts.arguments[i].name); + detail::state_access(arg)->metadata = std::move(opts.arguments[i].metadata); + } + + data_->methods.insert_or_assign(state->index, std::move(state)); + return *this; + } + + template < detail::class_kind Class > + template < detail::method_kind Method, method_policy_kind Policy > + class_bind& class_bind::method_( + std::string name, + Method method, + std::initializer_list arguments, + [[maybe_unused]] Policy policy) + requires detail::class_bind_method_kind + { + auto state = detail::method_state::make( + std::move(name), + std::move(method), + {}); + + if ( arguments.size() > state->arguments.size() ) { + detail::throw_exception_with("provided argument names don't match method argument count"); + } + + for ( std::size_t i = 0; i < arguments.size(); ++i ) { + argument& arg = state->arguments[i]; + detail::state_access(arg)->name = std::data(arguments)[i]; + } + + data_->methods.insert_or_assign(state->index, std::move(state)); + return *this; + } + + // + // typedef_ + // + + template < detail::class_kind Class > + template < typename Type > + class_bind& class_bind::typedef_(std::string name) { + data_->typedefs.insert_or_assign(std::move(name), resolve_type()); + return *this; + } + + // + // variable_ + // + + template < detail::class_kind Class > + template < detail::pointer_kind Pointer, variable_policy_kind Policy > + class_bind& class_bind::variable_( + std::string name, + Pointer pointer, + Policy policy) + { + return variable_(std::move(name), std::move(pointer), {}, policy); + } + + template < detail::class_kind Class > + template < detail::pointer_kind Pointer, variable_policy_kind Policy > + class_bind& class_bind::variable_( + std::string name, + Pointer pointer, + variable_opts opts, + [[maybe_unused]] Policy policy) + { + auto state = detail::variable_state::make( + std::move(name), + std::move(pointer), + std::move(opts.metadata)); + data_->variables.insert_or_assign(state->index, std::move(state)); + return *this; + } +} + +namespace meta_hpp +{ + template < detail::enum_kind Enum > + enum_bind::enum_bind(metadata_map metadata) + : data_{detail::type_access(resolve_type())} { + data_->metadata.swap(metadata); + data_->metadata.merge(metadata); + } + + template < detail::enum_kind Enum > + enum_bind::operator enum_type() const noexcept { + return enum_type{data_}; + } + + template < detail::enum_kind Enum > + enum_bind& enum_bind::evalue_(std::string name, Enum value) { + return evalue_(std::move(name), std::move(value), {}); + } + + template < detail::enum_kind Enum > + enum_bind& enum_bind::evalue_(std::string name, Enum value, evalue_opts opts) { + auto state = detail::evalue_state::make( + std::move(name), + std::move(value), + std::move(opts.metadata)); + data_->evalues.insert_or_assign(state->index, std::move(state)); + return *this; + } +} + +namespace meta_hpp +{ + template < detail::function_kind Function > + function_bind::function_bind(metadata_map metadata) + : data_{detail::type_access(resolve_type())} { + data_->metadata.swap(metadata); + data_->metadata.merge(metadata); + } + + template < detail::function_kind Function > + function_bind::operator function_type() const noexcept { + return function_type{data_}; + } +} + +namespace meta_hpp +{ + template < detail::member_kind Member > + member_bind::member_bind(metadata_map metadata) + : data_{detail::type_access(resolve_type())} { + data_->metadata.swap(metadata); + data_->metadata.merge(metadata); + } + + template < detail::member_kind Member > + member_bind::operator member_type() const noexcept { + return member_type{data_}; + } +} + +namespace meta_hpp +{ + template < detail::method_kind Method > + method_bind::method_bind(metadata_map metadata) + : data_{detail::type_access(resolve_type())} { + data_->metadata.swap(metadata); + data_->metadata.merge(metadata); + } + + template < detail::method_kind Method > + method_bind::operator method_type() const noexcept { + return method_type{data_}; + } +} + +namespace meta_hpp +{ + template < detail::nullptr_kind Nullptr > + nullptr_bind::nullptr_bind(metadata_map metadata) + : data_{detail::type_access(resolve_type())} { + data_->metadata.swap(metadata); + data_->metadata.merge(metadata); + } + + template < detail::nullptr_kind Nullptr > + nullptr_bind::operator nullptr_type() const noexcept { + return nullptr_type{data_}; + } +} + +namespace meta_hpp +{ + template < detail::number_kind Number > + number_bind::number_bind(metadata_map metadata) + : data_{detail::type_access(resolve_type())} { + data_->metadata.swap(metadata); + data_->metadata.merge(metadata); + } + + template < detail::number_kind Number > + number_bind::operator number_type() const noexcept { + return number_type{data_}; + } +} + +namespace meta_hpp +{ + template < detail::pointer_kind Pointer > + pointer_bind::pointer_bind(metadata_map metadata) + : data_{detail::type_access(resolve_type())} { + data_->metadata.swap(metadata); + data_->metadata.merge(metadata); + } + + template < detail::pointer_kind Pointer > + pointer_bind::operator pointer_type() const noexcept { + return pointer_type{data_}; + } +} + +namespace meta_hpp +{ + template < detail::reference_kind Reference > + reference_bind::reference_bind(metadata_map metadata) + : data_{detail::type_access(resolve_type())} { + data_->metadata.swap(metadata); + data_->metadata.merge(metadata); + } + + template < detail::reference_kind Reference > + reference_bind::operator reference_type() const noexcept { + return reference_type{data_}; + } +} + +namespace meta_hpp +{ + // NOLINTNEXTLINE(readability-named-parameter) + inline scope_bind::scope_bind(std::string name, metadata_map metadata, local_tag) + : state_{detail::scope_state::make(std::move(name), std::move(metadata))} {} + + // NOLINTNEXTLINE(readability-named-parameter) + inline scope_bind::scope_bind(std::string_view name, metadata_map metadata, static_tag) + : state_{detail::state_access(resolve_scope(name))} { + state_->metadata.swap(metadata); + state_->metadata.merge(metadata); + } + + inline scope_bind::operator scope() const noexcept { + return scope{state_}; + } + + // + // function_ + // + + template < detail::function_kind Function, function_policy_kind Policy > + scope_bind& scope_bind::function_( + std::string name, + Function function, + Policy policy) + { + return function_(std::move(name), std::move(function), {}, policy); + } + + template < detail::function_kind Function, function_policy_kind Policy > + scope_bind& scope_bind::function_( + std::string name, + Function function, + function_opts opts, + [[maybe_unused]] Policy policy) + { + auto state = detail::function_state::make( + std::move(name), + std::move(function), + std::move(opts.metadata)); + + if ( opts.arguments.size() > state->arguments.size() ) { + detail::throw_exception_with("provided arguments don't match function argument count"); + } + + for ( std::size_t i = 0; i < opts.arguments.size(); ++i ) { + argument& arg = state->arguments[i]; + detail::state_access(arg)->name = std::move(opts.arguments[i].name); + detail::state_access(arg)->metadata = std::move(opts.arguments[i].metadata); + } + + state_->functions.insert_or_assign(state->index, std::move(state)); + return *this; + } + + template < detail::function_kind Function, function_policy_kind Policy > + scope_bind& scope_bind::function_( + std::string name, + Function function, + std::initializer_list arguments, + [[maybe_unused]] Policy policy) + { + auto state = detail::function_state::make( + std::move(name), + std::move(function), + {}); + + if ( arguments.size() > state->arguments.size() ) { + detail::throw_exception_with("provided argument names don't match function argument count"); + } + + for ( std::size_t i = 0; i < arguments.size(); ++i ) { + argument& arg = state->arguments[i]; + detail::state_access(arg)->name = std::data(arguments)[i]; + } + + state_->functions.insert_or_assign(state->index, std::move(state)); + return *this; + } + + // + // typedef_ + // + + template < typename Type > + scope_bind& scope_bind::typedef_(std::string name) { + state_->typedefs.insert_or_assign(std::move(name), resolve_type()); + return *this; + } + + // + // variable_ + // + + template < detail::pointer_kind Pointer, variable_policy_kind Policy > + scope_bind& scope_bind::variable_( + std::string name, + Pointer pointer, + Policy policy) + { + return variable_(std::move(name), std::move(pointer), {}, policy); + } + + template < detail::pointer_kind Pointer, variable_policy_kind Policy > + scope_bind& scope_bind::variable_( + std::string name, + Pointer pointer, + variable_opts opts, + [[maybe_unused]] Policy policy) + { + auto state = detail::variable_state::make( + std::move(name), + std::move(pointer), + std::move(opts.metadata)); + state_->variables.insert_or_assign(state->index, std::move(state)); + return *this; + } +} + +namespace meta_hpp +{ + template < detail::void_kind Void > + void_bind::void_bind(metadata_map metadata) + : data_{detail::type_access(resolve_type())} { + data_->metadata.swap(metadata); + data_->metadata.merge(metadata); + } + + template < detail::void_kind Void > + void_bind::operator void_type() const noexcept { + return void_type{data_}; + } +} + +namespace meta_hpp +{ + inline argument_index::argument_index(any_type type, std::size_t position) + : type_{type} + , position_{position} {} + + template < typename Argument > + inline argument_index argument_index::make(std::size_t position) { + return argument_index{resolve_type(), position}; + } + + inline std::size_t argument_index::get_hash() const noexcept { + return detail::hash_combiner{}(detail::hash_combiner{}(type_), position_); + } + + inline const any_type& argument_index::get_type() const noexcept { + return type_; + } + + inline std::size_t argument_index::get_position() const noexcept { + return position_; + } + + inline bool operator<(const argument_index& l, const argument_index& r) noexcept { + return l.type_ < r.type_ || (l.type_ == r.type_ && l.position_ < r.position_); + } + + inline bool operator==(const argument_index& l, const argument_index& r) noexcept { + return l.type_ == r.type_ && l.position_ == r.position_; + } +} + +namespace meta_hpp +{ + inline constructor_index::constructor_index(constructor_type type) + : type_{type} {} + + template < detail::class_kind Class, typename... Args > + constructor_index constructor_index::make() { + return constructor_index{resolve_constructor_type()}; + } + + inline std::size_t constructor_index::get_hash() const noexcept { + return detail::hash_combiner{}(type_); + } + + inline const constructor_type& constructor_index::get_type() const noexcept { + return type_; + } + + inline bool operator<(const constructor_index& l, const constructor_index& r) noexcept { + return l.type_ < r.type_; + } + + inline bool operator==(const constructor_index& l, const constructor_index& r) noexcept { + return l.type_ == r.type_; + } +} + +namespace meta_hpp +{ + inline destructor_index::destructor_index(destructor_type type) + : type_{type} {} + + template < detail::class_kind Class > + destructor_index destructor_index::make() { + return destructor_index{resolve_destructor_type()}; + } + + inline std::size_t destructor_index::get_hash() const noexcept { + return detail::hash_combiner{}(type_); + } + + inline const destructor_type& destructor_index::get_type() const noexcept { + return type_; + } + + inline bool operator<(const destructor_index& l, const destructor_index& r) noexcept { + return l.type_ < r.type_; + } + + inline bool operator==(const destructor_index& l, const destructor_index& r) noexcept { + return l.type_ == r.type_; + } +} + +namespace meta_hpp +{ + inline evalue_index::evalue_index(enum_type type, std::string name) + : type_{type} + , name_{std::move(name)} {} + + template < detail::enum_kind Enum > + evalue_index evalue_index::make(std::string name) { + return evalue_index{resolve_type(), std::move(name)}; + } + + inline std::size_t evalue_index::get_hash() const noexcept { + return detail::hash_combiner{}(detail::hash_combiner{}(type_), name_); + } + + inline const enum_type& evalue_index::get_type() const noexcept { + return type_; + } + + inline const std::string& evalue_index::get_name() const noexcept { + return name_; + } + + inline bool operator<(const evalue_index& l, const evalue_index& r) noexcept { + return l.type_ < r.type_ || (l.type_ == r.type_ && std::less<>{}(l.name_, r.name_)); + } + + inline bool operator==(const evalue_index& l, const evalue_index& r) noexcept { + return l.type_ == r.type_ && std::equal_to<>{}(l.name_, r.name_); + } +} + +namespace meta_hpp +{ + inline function_index::function_index(function_type type, std::string name) + : type_{type} + , name_{std::move(name)} {} + + template < detail::function_kind Function > + function_index function_index::make(std::string name) { + return function_index{resolve_type(), std::move(name)}; + } + + inline std::size_t function_index::get_hash() const noexcept { + return detail::hash_combiner{}(detail::hash_combiner{}(type_), name_); + } + + inline const function_type& function_index::get_type() const noexcept { + return type_; + } + + inline const std::string& function_index::get_name() const noexcept { + return name_; + } + + inline bool operator<(const function_index& l, const function_index& r) noexcept { + return l.type_ < r.type_ || (l.type_ == r.type_ && std::less<>{}(l.name_, r.name_)); + } + + inline bool operator==(const function_index& l, const function_index& r) noexcept { + return l.type_ == r.type_ && std::equal_to<>{}(l.name_, r.name_); + } +} + +namespace meta_hpp +{ + inline member_index::member_index(member_type type, std::string name) + : type_{type} + , name_{std::move(name)} {} + + template < detail::member_kind Member > + member_index member_index::make(std::string name) { + return member_index{resolve_type(), std::move(name)}; + } + + inline std::size_t member_index::get_hash() const noexcept { + return detail::hash_combiner{}(detail::hash_combiner{}(type_), name_); + } + + inline const member_type& member_index::get_type() const noexcept { + return type_; + } + + inline const std::string& member_index::get_name() const noexcept { + return name_; + } + + inline bool operator<(const member_index& l, const member_index& r) noexcept { + return l.type_ < r.type_ || (l.type_ == r.type_ && std::less<>{}(l.name_, r.name_)); + } + + inline bool operator==(const member_index& l, const member_index& r) noexcept { + return l.type_ == r.type_ && std::equal_to<>{}(l.name_, r.name_); + } +} + +namespace meta_hpp +{ + inline method_index::method_index(method_type type, std::string name) + : type_{type} + , name_{std::move(name)} {} + + template < detail::method_kind Method > + method_index method_index::make(std::string name) { + return method_index{resolve_type(), std::move(name)}; + } + + inline std::size_t method_index::get_hash() const noexcept { + return detail::hash_combiner{}(detail::hash_combiner{}(type_), name_); + } + + inline const method_type& method_index::get_type() const noexcept { + return type_; + } + + inline const std::string& method_index::get_name() const noexcept { + return name_; + } + + inline bool operator<(const method_index& l, const method_index& r) noexcept { + return l.type_ < r.type_ || (l.type_ == r.type_ && std::less<>{}(l.name_, r.name_)); + } + + inline bool operator==(const method_index& l, const method_index& r) noexcept { + return l.type_ == r.type_ && std::equal_to<>{}(l.name_, r.name_); + } +} + +namespace meta_hpp +{ + inline scope_index::scope_index(std::string name) + : name_{std::move(name)} {} + + inline scope_index scope_index::make(std::string name) { + return scope_index{std::move(name)}; + } + + inline std::size_t scope_index::get_hash() const noexcept { + return detail::hash_combiner{}(name_); + } + + inline const std::string& scope_index::get_name() const noexcept { + return name_; + } + + inline bool operator<(const scope_index& l, const scope_index& r) noexcept { + return std::less<>{}(l.name_, r.name_); + } + + inline bool operator==(const scope_index& l, const scope_index& r) noexcept { + return std::equal_to<>{}(l.name_, r.name_); + } +} + +namespace meta_hpp +{ + inline variable_index::variable_index(pointer_type type, std::string name) + : type_{type} + , name_{std::move(name)} {} + + template < detail::pointer_kind Pointer > + variable_index variable_index::make(std::string name) { + return variable_index{resolve_type(), std::move(name)}; + } + + inline std::size_t variable_index::get_hash() const noexcept { + return detail::hash_combiner{}(detail::hash_combiner{}(type_), name_); + } + + inline const pointer_type& variable_index::get_type() const noexcept { + return type_; + } + + inline const std::string& variable_index::get_name() const noexcept { + return name_; + } + + inline bool operator<(const variable_index& l, const variable_index& r) noexcept { + return l.type_ < r.type_ || (l.type_ == r.type_ && std::less<>{}(l.name_, r.name_)); + } + + inline bool operator==(const variable_index& l, const variable_index& r) noexcept { + return l.type_ == r.type_ && std::equal_to<>{}(l.name_, r.name_); + } +} + +namespace meta_hpp::detail +{ + template < typename Argument > + inline argument_state_ptr argument_state::make(std::size_t position, metadata_map metadata) { + return std::make_shared(argument_state{ + .index{argument_index::make(position)}, + .metadata{std::move(metadata)}, + }); + } +} + +namespace meta_hpp +{ + + inline argument::argument(detail::argument_state_ptr state) noexcept + : state_{std::move(state)} {} + + inline argument& argument::operator=(detail::argument_state_ptr state) noexcept { + state_ = std::move(state); + return *this; + } + + inline bool argument::is_valid() const noexcept { + return !!state_; + } + + inline argument::operator bool() const noexcept { + return is_valid(); + } + + inline const argument_index& argument::get_index() const noexcept { + return state_->index; + } + + inline const metadata_map& argument::get_metadata() const noexcept { + return state_->metadata; + } + + inline const any_type& argument::get_type() const noexcept { + return state_->index.get_type(); + } + + inline std::size_t argument::get_position() const noexcept { + return state_->index.get_position(); + } + + inline const std::string& argument::get_name() const noexcept { + return state_->name; + } +} + +namespace meta_hpp::detail +{ + template < class_kind Class, typename... Args > + struct constructor_tag {}; + + template < class_kind Class, typename... Args > + // NOLINTNEXTLINE(readability-named-parameter) + constructor_type_data::constructor_type_data(type_list, type_list) + : type_data_base{type_id{type_list>{}}, type_kind::constructor_} + , flags{constructor_traits::make_flags()} + , class_type{resolve_type::class_type>()} + , argument_types{resolve_types(typename constructor_traits::argument_types{})} {} +} + +namespace meta_hpp +{ + inline constructor_type::constructor_type(detail::constructor_type_data* data) + : data_{data} {} + + inline bool constructor_type::is_valid() const noexcept { + return data_ != nullptr; + } + + inline constructor_type::operator bool() const noexcept { + return is_valid(); + } + + inline type_id constructor_type::get_id() const noexcept { + return data_->id; + } + + inline constructor_bitflags constructor_type::get_flags() const noexcept { + return data_->flags; + } + + inline const metadata_map& constructor_type::get_metadata() const noexcept { + return data_->metadata; + } + + inline std::size_t constructor_type::get_arity() const noexcept { + return data_->argument_types.size(); + } + + inline any_type constructor_type::get_class_type() const noexcept { + return data_->class_type; + } + + inline any_type constructor_type::get_argument_type(std::size_t position) const noexcept { + return position < data_->argument_types.size() ? data_->argument_types[position] : any_type{}; + } + + inline const std::vector& constructor_type::get_argument_types() const noexcept { + return data_->argument_types; + } +} + +namespace meta_hpp::detail +{ + template < typename T > + inline constexpr bool is_uvalue_kind_v = + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v; + + template < typename T > + concept uvalue_kind = is_uvalue_kind_v; + + template < typename T > + concept decay_uvalue_kind = uvalue_kind>; + + template < typename T > + concept decay_non_uvalue_kind = !decay_uvalue_kind; +} + +namespace meta_hpp::detail +{ + template < typename T > + concept arg_lvalue_ref_kind = + (decay_non_uvalue_kind) && + (std::is_lvalue_reference_v); + + template < typename T > + concept arg_rvalue_ref_kind = + (decay_non_uvalue_kind) && + (!std::is_reference_v || std::is_rvalue_reference_v); +} + +namespace meta_hpp::detail +{ + template < typename T > + concept inst_class_ref_kind = + (std::is_class_v) || + (std::is_reference_v && std::is_class_v>); + + template < typename T > + concept inst_class_lvalue_ref_kind = + (decay_non_uvalue_kind) && + (std::is_lvalue_reference_v && std::is_class_v>); + + template < typename T > + concept inst_class_rvalue_ref_kind = + (decay_non_uvalue_kind) && + (std::is_class_v || (std::is_rvalue_reference_v && std::is_class_v>)); +} + +namespace meta_hpp::detail +{ + namespace impl + { + template < inst_class_ref_kind Q, bool is_const, bool is_lvalue, bool is_rvalue > + struct inst_traits_impl; + + template < inst_class_ref_kind Q > + struct inst_traits_impl { + using class_type = std::remove_cvref_t; + using method_type = void(class_type::*)(); + }; + + template < inst_class_ref_kind Q > + struct inst_traits_impl { + using class_type = std::remove_cvref_t; + using method_type = void(class_type::*)() &; + }; + + template < inst_class_ref_kind Q > + struct inst_traits_impl { + using class_type = std::remove_cvref_t; + using method_type = void(class_type::*)() &&; + }; + + template < inst_class_ref_kind Q > + struct inst_traits_impl { + using class_type = std::remove_cvref_t; + using method_type = void(class_type::*)() const; + }; + + template < inst_class_ref_kind Q > + struct inst_traits_impl { + using class_type = std::remove_cvref_t; + using method_type = void(class_type::*)() const &; + }; + + template < inst_class_ref_kind Q > + struct inst_traits_impl { + using class_type = std::remove_cvref_t; + using method_type = void(class_type::*)() const &&; + }; + } + + template < inst_class_ref_kind Q > + struct inst_traits final : impl::inst_traits_impl::is_const, + cvref_traits::is_lvalue, + cvref_traits::is_rvalue> {}; +} + +namespace meta_hpp::detail +{ + [[nodiscard]] inline void* pointer_upcast(void* ptr, const class_type& from, const class_type& to) { + if ( nullptr == ptr || !from || !to ) { + return nullptr; + } + + if ( from == to ) { + return ptr; + } + + for ( auto&& [base, base_info] : type_access(from)->bases_info ) { + if ( base == to ) { + return base_info.upcast(ptr); + } + + if ( base.is_derived_from(to) ) { + return pointer_upcast(base_info.upcast(ptr), base, to); + } + } + + return nullptr; + } + + template < class_kind To, class_kind From > + [[nodiscard]] To* pointer_upcast(From* ptr) { + return static_cast(pointer_upcast(ptr, resolve_type(), resolve_type())); + } + + template < class_kind To, class_kind From > + [[nodiscard]] const To* pointer_upcast(const From* ptr) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) + return pointer_upcast(const_cast(ptr)); + } +} + +namespace meta_hpp::detail +{ + class uarg_base { + public: + enum class ref_types { + lvalue, + const_lvalue, + rvalue, + const_rvalue, + }; + public: + uarg_base() = delete; + + uarg_base(uarg_base&&) = default; + uarg_base(const uarg_base&) = default; + + uarg_base& operator=(uarg_base&&) = delete; + uarg_base& operator=(const uarg_base&) = delete; + + virtual ~uarg_base() = default; + + template < decay_value_kind T > + // NOLINTNEXTLINE(readability-named-parameter) + explicit uarg_base(T&&) + : uarg_base{type_list{}} {} + + template < decay_non_uvalue_kind T > + // NOLINTNEXTLINE(readability-named-parameter) + explicit uarg_base(T&&) + : uarg_base{type_list{}} {} + + template < arg_lvalue_ref_kind T > + // NOLINTNEXTLINE(readability-named-parameter) + explicit uarg_base(type_list) + : ref_type_{std::is_const_v> + ? ref_types::const_lvalue + : ref_types::lvalue} + , raw_type_{resolve_type>()} {} + + template < arg_rvalue_ref_kind T > + // NOLINTNEXTLINE(readability-named-parameter) + explicit uarg_base(type_list) + : ref_type_{std::is_const_v> + ? ref_types::const_rvalue + : ref_types::rvalue} + , raw_type_{resolve_type>()} {} + + explicit uarg_base(uvalue& v) + : ref_type_{ref_types::lvalue} + , raw_type_{v.get_type()} {} + + explicit uarg_base(const uvalue& v) + : ref_type_{ref_types::const_lvalue} + , raw_type_{v.get_type()} {} + + explicit uarg_base(uvalue&& v) + : ref_type_{ref_types::rvalue} + , raw_type_{v.get_type()} {} + + explicit uarg_base(const uvalue&& v) + : ref_type_{ref_types::const_rvalue} + , raw_type_{v.get_type()} {} + + [[nodiscard]] bool is_const() const noexcept { + return ref_type_ == ref_types::const_lvalue + || ref_type_ == ref_types::const_rvalue; + } + + [[nodiscard]] bool is_lvalue() const noexcept { + return ref_type_ == ref_types::lvalue + || ref_type_ == ref_types::const_lvalue; + } + + [[nodiscard]] bool is_rvalue() const noexcept { + return ref_type_ == ref_types::rvalue + || ref_type_ == ref_types::const_rvalue; + } + + [[nodiscard]] ref_types get_ref_type() const noexcept { + return ref_type_; + } + + [[nodiscard]] const any_type& get_raw_type() const noexcept { + return raw_type_; + } + + template < typename To > + [[nodiscard]] bool can_cast_to() const noexcept; + private: + ref_types ref_type_{}; + any_type raw_type_{}; + }; +} + +namespace meta_hpp::detail +{ + class uarg final : public uarg_base { + public: + uarg() = delete; + + uarg(uarg&&) = default; + uarg(const uarg&) = default; + + uarg& operator=(uarg&&) = delete; + uarg& operator=(const uarg&) = delete; + + ~uarg() override = default; + + template < decay_value_kind T > + explicit uarg(T&& v) + : uarg_base{std::forward(v)} + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) + , data_{const_cast(v.data())} {} + + template < decay_non_uvalue_kind T > + explicit uarg(T&& v) + : uarg_base{std::forward(v)} + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) + , data_{const_cast*>(std::addressof(v))} {} + + template < typename To > + [[nodiscard]] To cast() const; + private: + void* data_{}; + }; +} + +namespace meta_hpp::detail +{ + template < typename To > + // NOLINTNEXTLINE(readability-function-cognitive-complexity) + bool uarg_base::can_cast_to() const noexcept { + using to_raw_type_cv = std::remove_reference_t; + using to_raw_type = std::remove_cv_t; + + static_assert( + !(std::is_reference_v && std::is_pointer_v), + "references to pointers are not supported yet"); + + const any_type& from_type = get_raw_type(); + const any_type& to_type = resolve_type(); + + const auto is_a = [](const any_type& base, const any_type& derived){ + return (base == derived) + || (base.is_class() && derived.is_class() && base.as_class().is_base_of(derived.as_class())); + }; + + if constexpr ( std::is_pointer_v ) { + if ( to_type.is_pointer() && from_type.is_nullptr() ) { + return true; + } + + if ( to_type.is_pointer() && from_type.is_array() ) { + const pointer_type& to_type_ptr = to_type.as_pointer(); + const bool to_type_ptr_readonly = to_type_ptr.get_flags().has(pointer_flags::is_readonly); + + const array_type& from_type_array = from_type.as_array(); + const bool from_type_array_readonly = is_const(); + + const any_type& to_data_type = to_type_ptr.get_data_type(); + const any_type& from_data_type = from_type_array.get_data_type(); + + if ( to_type_ptr_readonly >= from_type_array_readonly ) { + if ( to_data_type.is_void() || is_a(to_data_type, from_data_type) ) { + return true; + } + } + } + + if ( to_type.is_pointer() && from_type.is_pointer() ) { + const pointer_type& to_type_ptr = to_type.as_pointer(); + const bool to_type_ptr_readonly = to_type_ptr.get_flags().has(pointer_flags::is_readonly); + + const pointer_type& from_type_ptr = from_type.as_pointer(); + const bool from_type_ptr_readonly = from_type_ptr.get_flags().has(pointer_flags::is_readonly); + + const any_type& to_data_type = to_type_ptr.get_data_type(); + const any_type& from_data_type = from_type_ptr.get_data_type(); + + if ( to_type_ptr_readonly >= from_type_ptr_readonly ) { + if ( to_data_type.is_void() || is_a(to_data_type, from_data_type) ) { + return true; + } + } + } + } + + if constexpr ( std::is_reference_v ) { + const auto is_convertible = [this](){ + switch ( get_ref_type() ) { + case ref_types::lvalue: + return std::is_convertible_v>; + case ref_types::const_lvalue: + return std::is_convertible_v>; + case ref_types::rvalue: + return std::is_convertible_v>; + case ref_types::const_rvalue: + return std::is_convertible_v>; + } + return false; + }; + + if ( is_a(to_type, from_type) && is_convertible() ) { + return true; + } + } + + if constexpr ( !std::is_pointer_v && !std::is_reference_v ) { + const auto is_constructible = [this](){ + switch ( get_ref_type() ) { + case ref_types::lvalue: + return std::is_constructible_v && can_cast_to(); + case ref_types::const_lvalue: + return std::is_constructible_v && can_cast_to(); + case ref_types::rvalue: + return std::is_constructible_v && can_cast_to(); + case ref_types::const_rvalue: + return std::is_constructible_v && can_cast_to(); + } + return false; + }; + + if ( is_a(to_type, from_type) && is_constructible() ) { + return true; + } + } + + return false; + } +} + +namespace meta_hpp::detail +{ + template < typename To > + // NOLINTNEXTLINE(readability-function-cognitive-complexity) + To uarg::cast() const { + if ( !can_cast_to() ) { + throw_exception_with("bad argument cast"); + } + + using to_raw_type_cv = std::remove_reference_t; + using to_raw_type = std::remove_cv_t; + + const any_type& from_type = get_raw_type(); + const any_type& to_type = resolve_type(); + + if constexpr ( std::is_pointer_v ) { + if ( to_type.is_pointer() && from_type.is_nullptr() ) { + return static_cast(nullptr); + } + + if ( to_type.is_pointer() && from_type.is_array() ) { + const pointer_type& to_type_ptr = to_type.as_pointer(); + const array_type& from_type_array = from_type.as_array(); + + const any_type& to_data_type = to_type_ptr.get_data_type(); + const any_type& from_data_type = from_type_array.get_data_type(); + + if ( to_data_type.is_void() || to_data_type == from_data_type ) { + return static_cast(data_); + } + + if ( to_data_type.is_class() && from_data_type.is_class() ) { + const class_type& to_data_class = to_data_type.as_class(); + const class_type& from_data_class = from_data_type.as_class(); + + void* to_ptr = pointer_upcast(data_, from_data_class, to_data_class); + return static_cast(to_ptr); + } + } + + if ( to_type.is_pointer() && from_type.is_pointer() ) { + const pointer_type& to_type_ptr = to_type.as_pointer(); + const pointer_type& from_type_ptr = from_type.as_pointer(); + + const any_type& to_data_type = to_type_ptr.get_data_type(); + const any_type& from_data_type = from_type_ptr.get_data_type(); + + void** from_data_ptr = static_cast(data_); + + if ( to_data_type.is_void() || to_data_type == from_data_type ) { + return static_cast(*from_data_ptr); + } + + if ( to_data_type.is_class() && from_data_type.is_class() ) { + const class_type& to_data_class = to_data_type.as_class(); + const class_type& from_data_class = from_data_type.as_class(); + + void* to_ptr = pointer_upcast(*from_data_ptr, from_data_class, to_data_class); + return static_cast(to_ptr); + } + } + } + + if constexpr ( std::is_reference_v ) { + if ( to_type == from_type ) { + if constexpr ( std::is_lvalue_reference_v ) { + return *static_cast(data_); + } + + if constexpr ( std::is_rvalue_reference_v ) { + return std::move(*static_cast(data_)); + } + } + + if ( to_type.is_class() && from_type.is_class() ) { + const class_type& to_class = to_type.as_class(); + const class_type& from_class = from_type.as_class(); + + void* to_ptr = pointer_upcast(data_, from_class, to_class); + + if constexpr ( std::is_lvalue_reference_v ) { + return *static_cast(to_ptr); + } + + if constexpr ( std::is_rvalue_reference_v ) { + return std::move(*static_cast(to_ptr)); + } + } + } + + if constexpr ( !std::is_pointer_v && !std::is_reference_v ) { + if constexpr ( std::is_constructible_v ) { + if ( get_ref_type() == ref_types::lvalue ) { + return To{cast()}; + } + } + + if constexpr ( std::is_constructible_v ) { + if ( get_ref_type() == ref_types::const_lvalue ) { + return To{cast()}; + } + } + + if constexpr ( std::is_constructible_v ) { + if ( get_ref_type() == ref_types::rvalue ) { + return To{cast()}; + } + } + + if constexpr ( std::is_constructible_v ) { + if ( get_ref_type() == ref_types::const_rvalue ) { + return To{cast()}; + } + } + } + + throw_exception_with("bad argument cast"); + } +} + +namespace meta_hpp::detail +{ + template < constructor_policy_kind Policy, class_kind Class, typename... Args > + uvalue raw_constructor_invoke(std::span args) { + using ct = constructor_traits; + using class_type = typename ct::class_type; + using argument_types = typename ct::argument_types; + + constexpr bool as_object = + stdex::copy_constructible && + stdex::same_as; + + constexpr bool as_raw_ptr = + stdex::same_as; + + constexpr bool as_shared_ptr = + stdex::same_as; + + static_assert(as_object || as_raw_ptr || as_shared_ptr); + + if ( args.size() != ct::arity ) { + throw_exception_with("an attempt to call a constructor with an incorrect arity"); + } + + // NOLINTNEXTLINE(readability-named-parameter) + return [args](std::index_sequence) -> uvalue { + if ( !(... && args[Is].can_cast_to>()) ) { + throw_exception_with("an attempt to call a constructor with incorrect argument types"); + } + + if constexpr ( as_object ) { + class_type return_value{args[Is].cast>()...}; + return uvalue{std::move(return_value)}; + } + + if constexpr ( as_raw_ptr ) { + auto return_value{std::make_unique(args[Is].cast>()...)}; + return uvalue{return_value.release()}; + } + + if constexpr ( as_shared_ptr ) { + auto return_value{std::make_shared(args[Is].cast>()...)}; + return uvalue{std::move(return_value)}; + } + }(std::make_index_sequence()); + } + + template < class_kind Class, typename... Args > + bool raw_constructor_is_invocable_with(std::span args) { + using ct = constructor_traits; + using argument_types = typename ct::argument_types; + + if ( args.size() != ct::arity ) { + return false; + } + + // NOLINTNEXTLINE(readability-named-parameter) + return [args](std::index_sequence){ + return (... && args[Is].can_cast_to>()); + }(std::make_index_sequence()); + } +} + +namespace meta_hpp::detail +{ + template < constructor_policy_kind Policy, class_kind Class, typename... Args > + constructor_state::invoke_impl make_constructor_invoke() { + return &raw_constructor_invoke; + } + + template < class_kind Class, typename... Args > + constructor_state::is_invocable_with_impl make_constructor_is_invocable_with() { + return &raw_constructor_is_invocable_with; + } + + template < class_kind Class, typename... Args > + argument_list make_constructor_arguments() { + using ct = detail::constructor_traits; + + argument_list arguments; + arguments.reserve(ct::arity); + + // NOLINTNEXTLINE(readability-named-parameter) + [&arguments](std::index_sequence) mutable { + (arguments.push_back([](){ + using P = detail::type_list_at_t; + return argument{detail::argument_state::make

(I, metadata_map{})}; + }.template operator()()), ...); + }(std::make_index_sequence()); + + return arguments; + } +} + +namespace meta_hpp::detail +{ + template < constructor_policy_kind Policy, class_kind Class, typename... Args > + constructor_state_ptr constructor_state::make(metadata_map metadata) { + return std::make_shared(constructor_state{ + .index{constructor_index::make()}, + .metadata{std::move(metadata)}, + .invoke{make_constructor_invoke()}, + .is_invocable_with{make_constructor_is_invocable_with()}, + .arguments{make_constructor_arguments()}, + }); + } +} + +namespace meta_hpp +{ + inline constructor::constructor(detail::constructor_state_ptr state) noexcept + : state_{std::move(state)} {} + + inline constructor& constructor::operator=(detail::constructor_state_ptr state) noexcept { + state_ = std::move(state); + return *this; + } + + inline bool constructor::is_valid() const noexcept { + return !!state_; + } + + inline constructor::operator bool() const noexcept { + return is_valid(); + } + + inline const constructor_index& constructor::get_index() const noexcept { + return state_->index; + } + + inline const metadata_map& constructor::get_metadata() const noexcept { + return state_->metadata; + } + + inline const constructor_type& constructor::get_type() const noexcept { + return state_->index.get_type(); + } + + template < typename... Args > + uvalue constructor::invoke(Args&&... args) const { + if constexpr ( sizeof...(Args) > 0 ) { + using namespace detail; + const std::array vargs{uarg{std::forward(args)}...}; + return state_->invoke(vargs); + } else { + return state_->invoke({}); + } + } + + template < typename... Args > + uvalue constructor::operator()(Args&&... args) const { + return invoke(std::forward(args)...); + } + + template < typename... Args > + bool constructor::is_invocable_with() const noexcept { + if constexpr ( sizeof...(Args) > 0 ) { + using namespace detail; + const std::array vargs{uarg_base{type_list{}}...}; + return state_->is_invocable_with(vargs); + } else { + return state_->is_invocable_with({}); + } + } + + template < typename... Args > + bool constructor::is_invocable_with(Args&&... args) const noexcept { + if constexpr ( sizeof...(Args) > 0 ) { + using namespace detail; + const std::array vargs{uarg_base{std::forward(args)}...}; + return state_->is_invocable_with(vargs); + } else { + return state_->is_invocable_with({}); + } + } + + inline argument constructor::get_argument(std::size_t position) const noexcept { + return position < state_->arguments.size() ? state_->arguments[position] : argument{}; + } + + inline const argument_list& constructor::get_arguments() const noexcept { + return state_->arguments; + } +} + +namespace meta_hpp::detail +{ + template < class_kind Class > + struct destructor_tag {}; + + template < class_kind Class > + // NOLINTNEXTLINE(readability-named-parameter) + destructor_type_data::destructor_type_data(type_list) + : type_data_base{type_id{type_list>{}}, type_kind::destructor_} + , flags{destructor_traits::make_flags()} + , class_type{resolve_type::class_type>()} {} +} + +namespace meta_hpp +{ + inline destructor_type::destructor_type(detail::destructor_type_data* data) + : data_{data} {} + + inline bool destructor_type::is_valid() const noexcept { + return data_ != nullptr; + } + + inline destructor_type::operator bool() const noexcept { + return is_valid(); + } + + inline type_id destructor_type::get_id() const noexcept { + return data_->id; + } + + inline destructor_bitflags destructor_type::get_flags() const noexcept { + return data_->flags; + } + + inline const metadata_map& destructor_type::get_metadata() const noexcept { + return data_->metadata; + } + + inline any_type destructor_type::get_class_type() const noexcept { + return data_->class_type; + } +} + +namespace meta_hpp::detail +{ + template < class_kind Class > + void raw_destructor_invoke(const uarg& ptr) { + using dt = destructor_traits; + using class_type = typename dt::class_type; + + if ( !ptr.can_cast_to() ) { + throw_exception_with("an attempt to call a destructor with an incorrect argument type"); + } + + class_type* raw_ptr = ptr.cast(); + if ( raw_ptr ) { + std::unique_ptr{raw_ptr}.reset(); + } + } + + template < class_kind Class > + bool raw_destructor_is_invocable_with(const uarg_base& ptr) { + using dt = destructor_traits; + using class_type = typename dt::class_type; + + return ptr.can_cast_to(); + } +} + +namespace meta_hpp::detail +{ + template < class_kind Class > + destructor_state::invoke_impl make_destructor_invoke() { + return &raw_destructor_invoke; + } + + template < class_kind Class > + destructor_state::is_invocable_with_impl make_destructor_is_invocable_with() { + return &raw_destructor_is_invocable_with; + } +} + +namespace meta_hpp::detail +{ + template < class_kind Class > + destructor_state_ptr destructor_state::make(metadata_map metadata) { + return std::make_shared(destructor_state{ + .index{destructor_index::make()}, + .metadata{std::move(metadata)}, + .invoke{make_destructor_invoke()}, + .is_invocable_with{make_destructor_is_invocable_with()}, + }); + } +} + +namespace meta_hpp +{ + inline destructor::destructor(detail::destructor_state_ptr state) noexcept + : state_{std::move(state)} {} + + inline destructor& destructor::operator=(detail::destructor_state_ptr state) noexcept { + state_ = std::move(state); + return *this; + } + + inline bool destructor::is_valid() const noexcept { + return !!state_; + } + + inline destructor::operator bool() const noexcept { + return is_valid(); + } + + inline const destructor_index& destructor::get_index() const noexcept { + return state_->index; + } + + inline const metadata_map& destructor::get_metadata() const noexcept { + return state_->metadata; + } + + inline const destructor_type& destructor::get_type() const noexcept { + return state_->index.get_type(); + } + + template < typename Arg > + void destructor::invoke(Arg&& ptr) const { + using namespace detail; + const uarg varg{std::forward(ptr)}; + state_->invoke(varg); + } + + template < typename Arg > + void destructor::operator()(Arg&& ptr) const { + invoke(std::forward(ptr)); + } + + template < typename Arg > + bool destructor::is_invocable_with() const noexcept { + using namespace detail; + const uarg_base varg{type_list{}}; + return state_->is_invocable_with(varg); + } + + template < typename Arg > + bool destructor::is_invocable_with(Arg&& ptr) const noexcept { + using namespace detail; + const uarg_base varg{std::forward(ptr)}; + return state_->is_invocable_with(varg); + } +} + +namespace meta_hpp::detail +{ + template < enum_kind Enum > + struct enum_tag {}; + + template < enum_kind Enum > + // NOLINTNEXTLINE(readability-named-parameter) + enum_type_data::enum_type_data(type_list) + : type_data_base{type_id{type_list>{}}, type_kind::enum_} + , flags{enum_traits::make_flags()} + , underlying_type{resolve_type::underlying_type>()} {} +} + +namespace meta_hpp +{ + inline enum_type::enum_type(detail::enum_type_data* data) + : data_{data} {} + + inline bool enum_type::is_valid() const noexcept { + return data_ != nullptr; + } + + inline enum_type::operator bool() const noexcept { + return is_valid(); + } + + inline type_id enum_type::get_id() const noexcept { + return data_->id; + } + + inline enum_bitflags enum_type::get_flags() const noexcept { + return data_->flags; + } + + inline const metadata_map& enum_type::get_metadata() const noexcept { + return data_->metadata; + } + + inline number_type enum_type::get_underlying_type() const noexcept { + return data_->underlying_type; + } + + inline const evalue_map& enum_type::get_evalues() const noexcept { + return data_->evalues; + } + + inline evalue enum_type::get_evalue(std::string_view name) const noexcept { + for ( auto&& [index, evalue] : data_->evalues ) { + if ( index.get_name() == name ) { + return evalue; + } + } + return evalue{}; + } + + template < typename Value > + std::string_view enum_type::value_to_name(Value&& value) const noexcept { + const detail::uarg value_arg{std::forward(value)}; + + if ( value_arg.get_raw_type() != *this ) { + return std::string_view{}; + } + + for ( auto&& evalue : data_->evalues ) { + if ( evalue.second.get_value() == value ) { + return evalue.second.get_index().get_name(); + } + } + + return std::string_view{}; + } + + inline uvalue enum_type::name_to_value(std::string_view name) const noexcept { + if ( const evalue value = get_evalue(name); value ) { + return value.get_value(); + } + + return uvalue{}; + } +} + +namespace meta_hpp::detail +{ + template < enum_kind Enum > + evalue_state_ptr evalue_state::make(std::string name, Enum evalue, metadata_map metadata) { + return std::make_shared(evalue_state{ + .index{evalue_index::make(std::move(name))}, + .metadata{std::move(metadata)}, + .enum_value{uvalue{evalue}}, + .underlying_value{uvalue{stdex::to_underlying(evalue)}}, + }); + } +} + +namespace meta_hpp +{ + inline evalue::evalue(detail::evalue_state_ptr state) noexcept + : state_{std::move(state)} {} + + inline evalue& evalue::operator=(detail::evalue_state_ptr state) noexcept { + state_ = std::move(state); + return *this; + } + + inline bool evalue::is_valid() const noexcept { + return !!state_; + } + + inline evalue::operator bool() const noexcept { + return is_valid(); + } + + inline const evalue_index& evalue::get_index() const noexcept { + return state_->index; + } + + inline const metadata_map& evalue::get_metadata() const noexcept { + return state_->metadata; + } + + inline const enum_type& evalue::get_type() const noexcept { + return state_->index.get_type(); + } + + inline const std::string& evalue::get_name() const noexcept { + return state_->index.get_name(); + } + + inline const uvalue& evalue::get_value() const noexcept { + return state_->enum_value; + } + + inline const uvalue& evalue::get_underlying_value() const noexcept { + return state_->underlying_value; + } +} + +namespace meta_hpp::detail +{ + template < function_kind Function > + struct function_tag {}; + + template < function_kind Function > + // NOLINTNEXTLINE(readability-named-parameter) + function_type_data::function_type_data(type_list) + : type_data_base{type_id{type_list>{}}, type_kind::function_} + , flags{function_traits::make_flags()} + , return_type{resolve_type::return_type>()} + , argument_types{resolve_types(typename function_traits::argument_types{})} {} +} + +namespace meta_hpp +{ + inline function_type::function_type(detail::function_type_data* data) + : data_{data} {} + + inline bool function_type::is_valid() const noexcept { + return data_ != nullptr; + } + + inline function_type::operator bool() const noexcept { + return is_valid(); + } + + inline type_id function_type::get_id() const noexcept { + return data_->id; + } + + inline function_bitflags function_type::get_flags() const noexcept { + return data_->flags; + } + + inline const metadata_map& function_type::get_metadata() const noexcept { + return data_->metadata; + } + + inline std::size_t function_type::get_arity() const noexcept { + return data_->argument_types.size(); + } + + inline any_type function_type::get_return_type() const noexcept { + return data_->return_type; + } + + inline any_type function_type::get_argument_type(std::size_t position) const noexcept { + return position < data_->argument_types.size() ? data_->argument_types[position] : any_type{}; + } + + inline const std::vector& function_type::get_argument_types() const noexcept { + return data_->argument_types; + } +} + +namespace meta_hpp::detail +{ + template < function_policy_kind Policy, function_kind Function > + uvalue raw_function_invoke(const Function& function, std::span args) { + using ft = function_traits; + using return_type = typename ft::return_type; + using argument_types = typename ft::argument_types; + + constexpr bool as_copy = + stdex::copy_constructible && + stdex::same_as; + + constexpr bool as_void = + std::is_void_v || + stdex::same_as; + + constexpr bool ref_as_ptr = + std::is_reference_v && + stdex::same_as; + + static_assert(as_copy || as_void || ref_as_ptr); + + if ( args.size() != ft::arity ) { + throw_exception_with("an attempt to call a function with an incorrect arity"); + } + + // NOLINTNEXTLINE(readability-named-parameter) + return [&function, args](std::index_sequence) -> uvalue { + if ( !(... && args[Is].can_cast_to>()) ) { + throw_exception_with("an attempt to call a function with incorrect argument types"); + } + + if constexpr ( as_void ) { + std::ignore = function( + args[Is].cast>()...); + return uvalue{}; + } else { + return_type&& return_value = function( + args[Is].cast>()...); + + if constexpr ( ref_as_ptr ) { + return uvalue{std::addressof(return_value)}; + } else { + return uvalue{std::forward(return_value)}; + } + } + }(std::make_index_sequence()); + } + + template < function_kind Function > + bool raw_function_is_invocable_with(std::span args) { + using ft = function_traits; + using argument_types = typename ft::argument_types; + + if ( args.size() != ft::arity ) { + return false; + } + + // NOLINTNEXTLINE(readability-named-parameter) + return [args](std::index_sequence){ + return (... && args[Is].can_cast_to>()); + }(std::make_index_sequence()); + } +} + +namespace meta_hpp::detail +{ + template < function_policy_kind Policy, function_kind Function > + function_state::invoke_impl make_function_invoke(Function function) { + return [function = std::move(function)](std::span args){ + return raw_function_invoke(function, args); + }; + } + + template < function_kind Function > + function_state::is_invocable_with_impl make_function_is_invocable_with() { + return &raw_function_is_invocable_with; + } + + template < function_kind Function > + argument_list make_function_arguments() { + using ft = detail::function_traits; + + argument_list arguments; + arguments.reserve(ft::arity); + + // NOLINTNEXTLINE(readability-named-parameter) + [&arguments](std::index_sequence) mutable { + (arguments.push_back([](){ + using P = detail::type_list_at_t; + return argument{detail::argument_state::make

(I, metadata_map{})}; + }.template operator()()), ...); + }(std::make_index_sequence()); + + return arguments; + } +} + +namespace meta_hpp::detail +{ + template < function_policy_kind Policy, function_kind Function > + function_state_ptr function_state::make(std::string name, Function function, metadata_map metadata) { + return std::make_shared(function_state{ + .index{function_index::make(std::move(name))}, + .metadata{std::move(metadata)}, + .invoke{make_function_invoke(std::move(function))}, + .is_invocable_with{make_function_is_invocable_with()}, + .arguments{make_function_arguments()}, + }); + } +} + +namespace meta_hpp +{ + inline function::function(detail::function_state_ptr state) noexcept + : state_{std::move(state)} {} + + inline function& function::operator=(detail::function_state_ptr state) noexcept { + state_ = std::move(state); + return *this; + } + + inline bool function::is_valid() const noexcept { + return !!state_; + } + + inline function::operator bool() const noexcept { + return is_valid(); + } + + inline const function_index& function::get_index() const noexcept { + return state_->index; + } + + inline const metadata_map& function::get_metadata() const noexcept { + return state_->metadata; + } + + inline const function_type& function::get_type() const noexcept { + return state_->index.get_type(); + } + + inline const std::string& function::get_name() const noexcept { + return state_->index.get_name(); + } + + template < typename... Args > + uvalue function::invoke(Args&&... args) const { + if constexpr ( sizeof...(Args) > 0 ) { + using namespace detail; + const std::array vargs{uarg{std::forward(args)}...}; + return state_->invoke(vargs); + } else { + return state_->invoke({}); + } + } + + template < typename... Args > + uvalue function::operator()(Args&&... args) const { + return invoke(std::forward(args)...); + } + + template < typename... Args > + bool function::is_invocable_with() const noexcept { + if constexpr ( sizeof...(Args) > 0 ) { + using namespace detail; + const std::array vargs{uarg_base{type_list{}}...}; + return state_->is_invocable_with(vargs); + } else { + return state_->is_invocable_with({}); + } + } + + template < typename... Args > + bool function::is_invocable_with(Args&&... args) const noexcept { + if constexpr ( sizeof...(Args) > 0 ) { + using namespace detail; + const std::array vargs{uarg_base{std::forward(args)}...}; + return state_->is_invocable_with(vargs); + } else { + return state_->is_invocable_with({}); + } + } + + inline argument function::get_argument(std::size_t position) const noexcept { + return position < state_->arguments.size() ? state_->arguments[position] : argument{}; + } + + inline const argument_list& function::get_arguments() const noexcept { + return state_->arguments; + } +} + +namespace meta_hpp::detail +{ + template < member_kind Member > + struct member_tag {}; + + template < member_kind Member > + // NOLINTNEXTLINE(readability-named-parameter) + member_type_data::member_type_data(type_list) + : type_data_base{type_id{type_list>{}}, type_kind::member_} + , flags{member_traits::make_flags()} + , owner_type{resolve_type::class_type>()} + , value_type{resolve_type::value_type>()} {} +} + +namespace meta_hpp +{ + inline member_type::member_type(detail::member_type_data* data) + : data_{data} {} + + inline bool member_type::is_valid() const noexcept { + return data_ != nullptr; + } + + inline member_type::operator bool() const noexcept { + return is_valid(); + } + + inline type_id member_type::get_id() const noexcept { + return data_->id; + } + + inline member_bitflags member_type::get_flags() const noexcept { + return data_->flags; + } + + inline const metadata_map& member_type::get_metadata() const noexcept { + return data_->metadata; + } + + inline class_type member_type::get_owner_type() const noexcept { + return data_->owner_type; + } + + inline any_type member_type::get_value_type() const noexcept { + return data_->value_type; + } +} + +namespace meta_hpp::detail +{ + class uinst_base { + public: + enum class ref_types { + lvalue, + const_lvalue, + rvalue, + const_rvalue, + }; + public: + uinst_base() = delete; + + uinst_base(uinst_base&&) = default; + uinst_base(const uinst_base&) = default; + + uinst_base& operator=(uinst_base&&) = delete; + uinst_base& operator=(const uinst_base&) = delete; + + virtual ~uinst_base() = default; + + template < decay_value_kind T > + // NOLINTNEXTLINE(readability-named-parameter) + explicit uinst_base(T&&) + : uinst_base{type_list{}} {} + + template < decay_non_uvalue_kind T > + // NOLINTNEXTLINE(readability-named-parameter) + explicit uinst_base(T&&) + : uinst_base{type_list{}} {} + + template < inst_class_lvalue_ref_kind T > + // NOLINTNEXTLINE(readability-named-parameter) + explicit uinst_base(type_list) + : ref_type_{std::is_const_v> + ? ref_types::const_lvalue + : ref_types::lvalue} + , raw_type_{resolve_type>()} {} + + template < inst_class_rvalue_ref_kind T > + // NOLINTNEXTLINE(readability-named-parameter) + explicit uinst_base(type_list) + : ref_type_{std::is_const_v> + ? ref_types::const_rvalue + : ref_types::rvalue} + , raw_type_{resolve_type>()} {} + + explicit uinst_base(uvalue& v) + : ref_type_{ref_types::lvalue} + , raw_type_{v.get_type()} {} + + explicit uinst_base(const uvalue& v) + : ref_type_{ref_types::const_lvalue} + , raw_type_{v.get_type()} {} + + explicit uinst_base(uvalue&& v) + : ref_type_{ref_types::rvalue} + , raw_type_{v.get_type()} {} + + explicit uinst_base(const uvalue&& v) + : ref_type_{ref_types::const_rvalue} + , raw_type_{v.get_type()} {} + + [[nodiscard]] bool is_const() const noexcept { + return ref_type_ == ref_types::const_lvalue + || ref_type_ == ref_types::const_rvalue; + } + + [[nodiscard]] bool is_lvalue() const noexcept { + return ref_type_ == ref_types::lvalue + || ref_type_ == ref_types::const_lvalue; + } + + [[nodiscard]] bool is_rvalue() const noexcept { + return ref_type_ == ref_types::rvalue + || ref_type_ == ref_types::const_rvalue; + } + + [[nodiscard]] ref_types get_ref_type() const noexcept { + return ref_type_; + } + + [[nodiscard]] const any_type& get_raw_type() const noexcept { + return raw_type_; + } + + template < inst_class_ref_kind Q > + [[nodiscard]] bool can_cast_to() const noexcept; + private: + ref_types ref_type_{}; + any_type raw_type_{}; + }; +} + +namespace meta_hpp::detail +{ + class uinst final : public uinst_base { + public: + uinst() = delete; + + uinst(uinst&&) = default; + uinst(const uinst&) = default; + + uinst& operator=(uinst&&) = delete; + uinst& operator=(const uinst&) = delete; + + ~uinst() override = default; + + template < decay_value_kind T > + explicit uinst(T&& v) + : uinst_base{std::forward(v)} + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) + , data_{const_cast(v.data())} {} + + template < decay_non_uvalue_kind T > + explicit uinst(T&& v) + : uinst_base{std::forward(v)} + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) + , data_{const_cast*>(std::addressof(v))} {} + + template < inst_class_ref_kind Q > + [[nodiscard]] decltype(auto) cast() const; + private: + void* data_{}; + }; +} + +namespace meta_hpp::detail +{ + template < inst_class_ref_kind Q > + bool uinst_base::can_cast_to() const noexcept { + using inst_class = typename inst_traits::class_type; + using inst_method = typename inst_traits::method_type; + + const any_type& from_type = get_raw_type(); + const any_type& to_type = resolve_type(); + + const auto is_a = [](const any_type& base, const any_type& derived){ + return (base == derived) + || (base.is_class() && derived.is_class() && base.as_class().is_base_of(derived.as_class())); + }; + + const auto is_invocable = [this](){ + switch ( get_ref_type() ) { + case ref_types::lvalue: + return std::is_invocable_v; + case ref_types::const_lvalue: + return std::is_invocable_v; + case ref_types::rvalue: + return std::is_invocable_v; + case ref_types::const_rvalue: + return std::is_invocable_v; + } + return false; + }; + + return is_a(to_type, from_type) && is_invocable(); + } +} + +namespace meta_hpp::detail +{ + template < inst_class_ref_kind Q > + decltype(auto) uinst::cast() const { + if ( !can_cast_to() ) { + throw_exception_with("bad instance cast"); + } + + using inst_class_cv = std::remove_reference_t; + using inst_class = std::remove_cv_t; + + const any_type& from_type = get_raw_type(); + const any_type& to_type = resolve_type(); + + if ( from_type.is_class() && to_type.is_class() ) { + const class_type& from_class = from_type.as_class(); + const class_type& to_class = to_type.as_class(); + + void* to_ptr = pointer_upcast(data_, from_class, to_class); + + if constexpr ( !std::is_reference_v ) { + return *static_cast(to_ptr); + } + + if constexpr ( std::is_lvalue_reference_v ) { + return *static_cast(to_ptr); + } + + if constexpr ( std::is_rvalue_reference_v ) { + return std::move(*static_cast(to_ptr)); + } + } + + throw_exception_with("bad instance cast"); + } +} + +namespace meta_hpp::detail +{ + template < member_policy_kind Policy, member_kind Member > + uvalue raw_member_getter(const Member& member, const uinst& inst) { + using mt = member_traits; + using class_type = typename mt::class_type; + using value_type = typename mt::value_type; + + constexpr bool as_copy = + stdex::copy_constructible && + stdex::same_as; + + constexpr bool as_ptr = + stdex::same_as; + + constexpr bool as_ref_wrap = + stdex::same_as; + + static_assert(as_copy || as_ptr || as_ref_wrap); + + if ( !inst.can_cast_to() ) { + throw_exception_with("an attempt to get a member with an incorrect instance type"); + } + + if ( inst.is_const() ) { + auto&& return_value = inst.cast().*member; + + if constexpr ( as_copy ) { + return uvalue{std::forward(return_value)}; + } + + if constexpr ( as_ptr ) { + return uvalue{std::addressof(return_value)}; + } + + if constexpr ( as_ref_wrap ) { + return uvalue{std::ref(return_value)}; + } + } else { + auto&& return_value = inst.cast().*member; + + if constexpr ( as_copy ) { + return uvalue{std::forward(return_value)}; + } + + if constexpr ( as_ptr ) { + return uvalue{std::addressof(return_value)}; + } + + if constexpr ( as_ref_wrap ) { + return uvalue{std::ref(return_value)}; + } + } + } + + template < member_kind Member > + bool raw_member_is_gettable_with(const uinst_base& inst) { + using mt = member_traits; + using class_type = typename mt::class_type; + + return inst.can_cast_to(); + } +} + +namespace meta_hpp::detail +{ + template < member_kind Member > + void raw_member_setter([[maybe_unused]] const Member& member, const uinst& inst, const uarg& arg) { + using mt = member_traits; + using class_type = typename mt::class_type; + using value_type = typename mt::value_type; + + if constexpr ( std::is_const_v ) { + throw_exception_with("an attempt to set a constant member"); + } else { + if ( inst.is_const() ) { + throw_exception_with("an attempt to set a member with an const instance type"); + } + + if ( !inst.can_cast_to() ) { + throw_exception_with("an attempt to set a member with an incorrect instance type"); + } + + if ( !arg.can_cast_to() ) { + throw_exception_with("an attempt to set a member with an incorrect argument type"); + } + + inst.cast().*member = arg.cast(); + } + } + + template < member_kind Member > + bool raw_member_is_settable_with(const uinst_base& inst, const uarg_base& arg) { + using mt = member_traits; + using class_type = typename mt::class_type; + using value_type = typename mt::value_type; + + return !std::is_const_v + && !inst.is_const() + && inst.can_cast_to() + && arg.can_cast_to(); + } +} + +namespace meta_hpp::detail +{ + template < member_policy_kind Policy, member_kind Member > + member_state::getter_impl make_member_getter(Member member) { + return [member = std::move(member)](const uinst& inst){ + return raw_member_getter(member, inst); + }; + } + + template < member_kind Member > + member_state::is_gettable_with_impl make_member_is_gettable_with() { + return &raw_member_is_gettable_with; + } + + template < member_kind Member > + member_state::setter_impl make_member_setter(Member member) { + return [member = std::move(member)](const uinst& inst, const uarg& arg){ + return raw_member_setter(member, inst, arg); + }; + } + + template < member_kind Member > + member_state::is_settable_with_impl make_member_is_settable_with() { + return &raw_member_is_settable_with; + } +} + +namespace meta_hpp::detail +{ + template < member_policy_kind Policy, member_kind Member > + member_state_ptr member_state::make(std::string name, Member member, metadata_map metadata) { + return std::make_shared(member_state{ + .index{member_index::make(std::move(name))}, + .metadata{std::move(metadata)}, + .getter{make_member_getter(member)}, + .setter{make_member_setter(member)}, + .is_gettable_with{make_member_is_gettable_with()}, + .is_settable_with{make_member_is_settable_with()}, + }); + } +} + +namespace meta_hpp +{ + inline member::member(detail::member_state_ptr state) noexcept + : state_{std::move(state)} {} + + inline member& member::operator=(detail::member_state_ptr state) noexcept { + state_ = std::move(state); + return *this; + } + + inline bool member::is_valid() const noexcept { + return !!state_; + } + + inline member::operator bool() const noexcept { + return is_valid(); + } + + inline const member_index& member::get_index() const noexcept { + return state_->index; + } + + inline const metadata_map& member::get_metadata() const noexcept { + return state_->metadata; + } + + inline const member_type& member::get_type() const noexcept { + return state_->index.get_type(); + } + + inline const std::string& member::get_name() const noexcept { + return state_->index.get_name(); + } + + template < typename Instance > + uvalue member::get(Instance&& instance) const { + using namespace detail; + const uinst vinst{std::forward(instance)}; + return state_->getter(vinst); + } + + template < typename Instance, typename Value > + void member::set(Instance&& instance, Value&& value) const { + using namespace detail; + const uinst vinst{std::forward(instance)}; + const uarg vvalue{std::forward(value)}; + state_->setter(vinst, vvalue); + } + + template < typename Instance > + uvalue member::operator()(Instance&& instance) const { + return get(std::forward(instance)); + } + + template < typename Instance, typename Value > + void member::operator()(Instance&& instance, Value&& value) const { + set(std::forward(instance), std::forward(value)); + } + + template < typename Instance > + [[nodiscard]] bool member::is_gettable_with() const noexcept { + using namespace detail; + const uinst_base vinst{type_list{}}; + return state_->is_gettable_with(vinst); + } + + template < typename Instance > + [[nodiscard]] bool member::is_gettable_with(Instance&& instance) const noexcept { + using namespace detail; + const uinst_base vinst{std::forward(instance)}; + return state_->is_gettable_with(vinst); + } + + template < typename Instance, typename Value > + [[nodiscard]] bool member::is_settable_with() const noexcept { + using namespace detail; + const uinst_base vinst{type_list{}}; + const uarg_base vvalue{type_list{}}; + return state_->is_settable_with(vinst, vvalue); + } + + template < typename Instance, typename Value > + [[nodiscard]] bool member::is_settable_with(Instance&& instance, Value&& value) const noexcept { + using namespace detail; + const uinst_base vinst{std::forward(instance)}; + const uarg_base vvalue{std::forward(value)}; + return state_->is_settable_with(vinst, vvalue); + } +} + +namespace meta_hpp::detail +{ + template < method_kind Method > + struct method_tag {}; + + template < method_kind Method > + // NOLINTNEXTLINE(readability-named-parameter) + method_type_data::method_type_data(type_list) + : type_data_base{type_id{type_list>{}}, type_kind::method_} + , flags{method_traits::make_flags()} + , owner_type{resolve_type::class_type>()} + , return_type{resolve_type::return_type>()} + , argument_types{resolve_types(typename method_traits::argument_types{})} {} +} + +namespace meta_hpp +{ + inline method_type::method_type(detail::method_type_data* data) + : data_{data} {} + + inline bool method_type::is_valid() const noexcept { + return data_ != nullptr; + } + + inline method_type::operator bool() const noexcept { + return is_valid(); + } + + inline type_id method_type::get_id() const noexcept { + return data_->id; + } + + inline method_bitflags method_type::get_flags() const noexcept { + return data_->flags; + } + + inline const metadata_map& method_type::get_metadata() const noexcept { + return data_->metadata; + } + + inline std::size_t method_type::get_arity() const noexcept { + return data_->argument_types.size(); + } + + inline class_type method_type::get_owner_type() const noexcept { + return data_->owner_type; + } + + inline any_type method_type::get_return_type() const noexcept { + return data_->return_type; + } + + inline any_type method_type::get_argument_type(std::size_t position) const noexcept { + return position < data_->argument_types.size() ? data_->argument_types[position] : any_type{}; + } + + inline const std::vector& method_type::get_argument_types() const noexcept { + return data_->argument_types; + } +} + +namespace meta_hpp::detail +{ + template < method_policy_kind Policy, method_kind Method > + uvalue raw_method_invoke(const Method& method, const uinst& inst, std::span args) { + using mt = method_traits; + using return_type = typename mt::return_type; + using qualified_type = typename mt::qualified_type; + using argument_types = typename mt::argument_types; + + constexpr bool as_copy = + stdex::copy_constructible && + stdex::same_as; + + constexpr bool as_void = + std::is_void_v || + stdex::same_as; + + constexpr bool ref_as_ptr = + std::is_reference_v && + stdex::same_as; + + static_assert(as_copy || as_void || ref_as_ptr); + + if ( args.size() != mt::arity ) { + throw_exception_with("an attempt to call a method with an incorrect arity"); + } + + if ( !inst.can_cast_to() ) { + throw_exception_with("an attempt to call a method with an incorrect instance type"); + } + + // NOLINTNEXTLINE(readability-named-parameter) + return [&method, &inst, args](std::index_sequence) -> uvalue { + if ( !(... && args[Is].can_cast_to>()) ) { + throw_exception_with("an attempt to call a method with incorrect argument types"); + } + + if constexpr ( as_void ) { + std::ignore = (inst.cast().*method)( + inst.cast(), + args[Is].cast>()...); + return uvalue{}; + } else { + return_type&& return_value = (inst.cast().*method)( + args[Is].cast>()...); + + if constexpr ( ref_as_ptr ) { + return uvalue{std::addressof(return_value)}; + } else { + return uvalue{std::forward(return_value)}; + } + } + }(std::make_index_sequence()); + } + + template < method_kind Method > + bool raw_method_is_invocable_with(const uinst_base& inst, std::span args) { + using mt = method_traits; + using qualified_type = typename mt::qualified_type; + using argument_types = typename mt::argument_types; + + if ( args.size() != mt::arity ) { + return false; + } + + if ( !inst.can_cast_to() ) { + return false; + } + + // NOLINTNEXTLINE(readability-named-parameter) + return [args](std::index_sequence){ + return (... && args[Is].can_cast_to>()); + }(std::make_index_sequence()); + } +} + +namespace meta_hpp::detail +{ + template < method_policy_kind Policy, method_kind Method > + method_state::invoke_impl make_method_invoke(Method method) { + return [method = std::move(method)](const uinst& inst, std::span args){ + return raw_method_invoke(method, inst, args); + }; + } + + template < method_kind Method > + method_state::is_invocable_with_impl make_method_is_invocable_with() { + return &raw_method_is_invocable_with; + } + + template < method_kind Method > + argument_list make_method_arguments() { + using mt = detail::method_traits; + + argument_list arguments; + arguments.reserve(mt::arity); + + // NOLINTNEXTLINE(readability-named-parameter) + [&arguments](std::index_sequence) mutable { + (arguments.push_back([](){ + using P = detail::type_list_at_t; + return argument{detail::argument_state::make

(I, metadata_map{})}; + }.template operator()()), ...); + }(std::make_index_sequence()); + + return arguments; + } +} + +namespace meta_hpp::detail +{ + template < method_policy_kind Policy, method_kind Method > + method_state_ptr method_state::make(std::string name, Method method, metadata_map metadata) { + return std::make_shared(method_state{ + .index{method_index::make(std::move(name))}, + .metadata{std::move(metadata)}, + .invoke{make_method_invoke(std::move(method))}, + .is_invocable_with{make_method_is_invocable_with()}, + .arguments{make_method_arguments()}, + }); + } +} + +namespace meta_hpp +{ + inline method::method(detail::method_state_ptr state) noexcept + : state_{std::move(state)} {} + + inline method& method::operator=(detail::method_state_ptr state) noexcept { + state_ = std::move(state); + return *this; + } + + inline bool method::is_valid() const noexcept { + return !!state_; + } + + inline method::operator bool() const noexcept { + return is_valid(); + } + + inline const method_index& method::get_index() const noexcept { + return state_->index; + } + + inline const metadata_map& method::get_metadata() const noexcept { + return state_->metadata; + } + + inline const method_type& method::get_type() const noexcept { + return state_->index.get_type(); + } + + inline const std::string& method::get_name() const noexcept { + return state_->index.get_name(); + } + + template < typename Instance, typename... Args > + uvalue method::invoke(Instance&& instance, Args&&... args) const { + using namespace detail; + const uinst vinst{std::forward(instance)}; + if constexpr ( sizeof...(Args) > 0 ) { + const std::array vargs{uarg{std::forward(args)}...}; + return state_->invoke(vinst, vargs); + } else { + return state_->invoke(vinst, {}); + } + } + + template < typename Instance, typename... Args > + uvalue method::operator()(Instance&& instance, Args&&... args) const { + return invoke(std::forward(instance), std::forward(args)...); + } + + template < typename Instance, typename... Args > + bool method::is_invocable_with() const noexcept { + using namespace detail; + const uinst_base vinst{type_list{}}; + if constexpr ( sizeof...(Args) > 0 ) { + const std::array vargs{uarg_base{type_list{}}...}; + return state_->is_invocable_with(vinst, vargs); + } else { + return state_->is_invocable_with(vinst, {}); + } + } + + template < typename Instance, typename... Args > + bool method::is_invocable_with(Instance&& instance, Args&&... args) const noexcept { + using namespace detail; + const uinst_base vinst{std::forward(instance)}; + if constexpr ( sizeof...(Args) > 0 ) { + const std::array vargs{uarg_base{std::forward(args)}...}; + return state_->is_invocable_with(vinst, vargs); + } else { + return state_->is_invocable_with(vinst, {}); + } + } + + inline argument method::get_argument(std::size_t position) const noexcept { + return position < state_->arguments.size() ? state_->arguments[position] : argument{}; + } + + inline const argument_list& method::get_arguments() const noexcept { + return state_->arguments; + } +} + +namespace meta_hpp::detail +{ + template < pointer_kind Pointer > + struct pointer_tag {}; + + template < pointer_kind Pointer > + // NOLINTNEXTLINE(readability-named-parameter) + pointer_type_data::pointer_type_data(type_list) + : type_data_base{type_id{type_list>{}}, type_kind::pointer_} + , flags{pointer_traits::make_flags()} + , data_type{resolve_type::data_type>()} {} +} + +namespace meta_hpp +{ + inline pointer_type::pointer_type(detail::pointer_type_data* data) + : data_{data} {} + + inline bool pointer_type::is_valid() const noexcept { + return data_ != nullptr; + } + + inline pointer_type::operator bool() const noexcept { + return is_valid(); + } + + inline type_id pointer_type::get_id() const noexcept { + return data_->id; + } + + inline pointer_bitflags pointer_type::get_flags() const noexcept { + return data_->flags; + } + + inline const metadata_map& pointer_type::get_metadata() const noexcept { + return data_->metadata; + } + + inline any_type pointer_type::get_data_type() const noexcept { + return data_->data_type; + } +} + +namespace meta_hpp::detail +{ + template < variable_policy_kind Policy, pointer_kind Pointer > + uvalue raw_variable_getter(const Pointer& pointer) { + using pt = pointer_traits; + using data_type = typename pt::data_type; + + constexpr bool as_copy = + stdex::copy_constructible && + stdex::same_as; + + constexpr bool as_ptr = + stdex::same_as; + + constexpr bool as_ref_wrap = + stdex::same_as; + + static_assert(as_copy || as_ptr || as_ref_wrap); + + auto&& return_value = *pointer; + + if constexpr ( as_copy ) { + return uvalue{std::forward(return_value)}; + } + + if constexpr ( as_ptr ) { + return uvalue{std::addressof(return_value)}; + } + + if constexpr ( as_ref_wrap) { + return uvalue{std::ref(return_value)}; + } + } + + template < pointer_kind Pointer > + void raw_variable_setter([[maybe_unused]] const Pointer& pointer, const uarg& arg) { + using pt = pointer_traits; + using data_type = typename pt::data_type; + + if constexpr ( std::is_const_v ) { + throw_exception_with("an attempt to set a constant variable"); + } else { + if ( !arg.can_cast_to() ) { + throw_exception_with("an attempt to set a variable with an incorrect argument type"); + } + *pointer = arg.cast(); + } + } + + template < pointer_kind Pointer > + bool raw_variable_is_settable_with(const uarg_base& arg) { + using pt = pointer_traits; + using data_type = typename pt::data_type; + + return !std::is_const_v + && arg.can_cast_to(); + } +} + +namespace meta_hpp::detail +{ + template < variable_policy_kind Policy, pointer_kind Pointer > + variable_state::getter_impl make_variable_getter(Pointer pointer) { + return [pointer = std::move(pointer)](){ + return raw_variable_getter(pointer); + }; + } + + template < pointer_kind Pointer > + variable_state::setter_impl make_variable_setter(Pointer pointer) { + return [pointer = std::move(pointer)](const uarg& arg){ + return raw_variable_setter(pointer, arg); + }; + } + + template < pointer_kind Pointer > + variable_state::is_settable_with_impl make_variable_is_settable_with() { + return &raw_variable_is_settable_with; + } +} + +namespace meta_hpp::detail +{ + template < variable_policy_kind Policy, pointer_kind Pointer > + variable_state_ptr variable_state::make(std::string name, Pointer pointer, metadata_map metadata) { + return std::make_shared(variable_state{ + .index{variable_index::make(std::move(name))}, + .metadata{std::move(metadata)}, + .getter{make_variable_getter(pointer)}, + .setter{make_variable_setter(pointer)}, + .is_settable_with{make_variable_is_settable_with()}, + }); + } +} + +namespace meta_hpp +{ + inline variable::variable(detail::variable_state_ptr state) noexcept + : state_{std::move(state)} {} + + inline variable& variable::operator=(detail::variable_state_ptr state) noexcept { + state_ = std::move(state); + return *this; + } + + inline bool variable::is_valid() const noexcept { + return !!state_; + } + + inline variable::operator bool() const noexcept { + return is_valid(); + } + + inline const variable_index& variable::get_index() const noexcept { + return state_->index; + } + + inline const metadata_map& variable::get_metadata() const noexcept { + return state_->metadata; + } + + inline const pointer_type& variable::get_type() const noexcept { + return state_->index.get_type(); + } + + inline const std::string& variable::get_name() const noexcept { + return state_->index.get_name(); + } + + inline uvalue variable::get() const { + return state_->getter(); + } + + template < typename Value > + void variable::set(Value&& value) const { + using namespace detail; + const uarg vvalue{std::forward(value)}; + state_->setter(vvalue); + } + + inline uvalue variable::operator()() const { + return get(); + } + + template < typename Value > + void variable::operator()(Value&& value) const { + set(std::forward(value)); + } + + template < typename Value > + bool variable::is_settable_with() const noexcept { + using namespace detail; + const uarg_base vvalue{type_list{}}; + return state_->is_settable_with(vvalue); + } + + template < typename Value > + bool variable::is_settable_with(Value&& value) const noexcept { + using namespace detail; + const uarg vvalue{std::forward(value)}; + return state_->is_settable_with(vvalue); + } +} + +namespace meta_hpp::detail +{ + template < class_kind Class > + struct class_tag {}; + + template < class_kind Class > + // NOLINTNEXTLINE(readability-named-parameter) + class_type_data::class_type_data(type_list) + : type_data_base{type_id{type_list>{}}, type_kind::class_} + , flags{class_traits::make_flags()} + , size{class_traits::size} + , align{class_traits::align} + , argument_types{resolve_types(typename class_traits::argument_types{})} {} +} + +namespace meta_hpp +{ + inline class_type::class_type(detail::class_type_data* data) + : data_{data} {} + + inline bool class_type::is_valid() const noexcept { + return data_ != nullptr; + } + + inline class_type::operator bool() const noexcept { + return is_valid(); + } + + inline type_id class_type::get_id() const noexcept { + return data_->id; + } + + inline class_bitflags class_type::get_flags() const noexcept { + return data_->flags; + } + + inline const metadata_map& class_type::get_metadata() const noexcept { + return data_->metadata; + } + + inline std::size_t class_type::get_size() const noexcept { + return data_->size; + } + + inline std::size_t class_type::get_align() const noexcept { + return data_->align; + } + + inline std::size_t class_type::get_arity() const noexcept { + return data_->argument_types.size(); + } + + inline any_type class_type::get_argument_type(std::size_t position) const noexcept { + return position < data_->argument_types.size() ? data_->argument_types[position] : any_type{}; + } + + inline const std::vector& class_type::get_argument_types() const noexcept { + return data_->argument_types; + } + + inline const class_set& class_type::get_bases() const noexcept { + return data_->bases; + } + + inline const constructor_map& class_type::get_constructors() const noexcept { + return data_->constructors; + } + + inline const destructor_map& class_type::get_destructors() const noexcept { + return data_->destructors; + } + + inline const function_map& class_type::get_functions() const noexcept { + return data_->functions; + } + + inline const member_map& class_type::get_members() const noexcept { + return data_->members; + } + + inline const method_map& class_type::get_methods() const noexcept { + return data_->methods; + } + + inline const typedef_map& class_type::get_typedefs() const noexcept { + return data_->typedefs; + } + + inline const variable_map& class_type::get_variables() const noexcept { + return data_->variables; + } + + template < typename... Args > + uvalue class_type::create(Args&&... args) const { + for ( auto&& ctor : data_->constructors ) { + if ( ctor.second.is_invocable_with(std::forward(args)...) ) { + return ctor.second.invoke(std::forward(args)...); + } + } + return uvalue{}; + } + + template < typename... Args > + uvalue class_type::operator()(Args&&... args) const { + return create(std::forward(args)...); + } + + template < typename Arg > + bool class_type::destroy(Arg&& ptr) const { + for ( auto&& dtor : data_->destructors ) { + if ( dtor.second.is_invocable_with(std::forward(ptr)) ) { + dtor.second.invoke(std::forward(ptr)); + return true; + } + } + return false; + } + + template < detail::class_kind Derived > + bool class_type::is_base_of() const noexcept { + return is_base_of(resolve_type()); + } + + inline bool class_type::is_base_of(const class_type& derived) const noexcept { + if ( !is_valid() || !derived.is_valid() ) { + return false; + } + + if ( derived.data_->bases.contains(*this) ) { + return true; + } + + for ( auto&& derived_base : derived.data_->bases ) { + if ( is_base_of(derived_base) ) { + return true; + } + } + + return false; + } + + template < detail::class_kind Base > + bool class_type::is_derived_from() const noexcept { + return is_derived_from(resolve_type()); + } + + inline bool class_type::is_derived_from(const class_type& base) const noexcept { + if ( !is_valid() || !base.is_valid() ) { + return false; + } + + if ( data_->bases.contains(base) ) { + return true; + } + + for ( auto&& self_base : data_->bases ) { + if ( self_base.is_derived_from(base) ) { + return true; + } + } + + return false; + } + + inline function class_type::get_function(std::string_view name) const noexcept { + for ( auto&& [index, function] : data_->functions ) { + if ( index.get_name() == name ) { + return function; + } + } + + for ( auto&& base : data_->bases ) { + if ( function function = base.get_function(name); function ) { + return function; + } + } + + return function{}; + } + + inline member class_type::get_member(std::string_view name) const noexcept { + for ( auto&& [index, member] : data_->members ) { + if ( index.get_name() == name ) { + return member; + } + } + + for ( auto&& base : data_->bases ) { + if ( member member = base.get_member(name); member ) { + return member; + } + } + + return member{}; + } + + inline method class_type::get_method(std::string_view name) const noexcept { + for ( auto&& [index, method] : data_->methods ) { + if ( index.get_name() == name ) { + return method; + } + } + + for ( auto&& base : data_->bases ) { + if ( method method = base.get_method(name); method ) { + return method; + } + } + + return method{}; + } + + inline any_type class_type::get_typedef(std::string_view name) const noexcept { + for ( auto&& [index, type] : data_->typedefs ) { + if ( index == name ) { + return type; + } + } + + for ( auto&& base : data_->bases ) { + if ( any_type type = base.get_typedef(name); type ) { + return type; + } + } + + return any_type{}; + } + + inline variable class_type::get_variable(std::string_view name) const noexcept { + for ( auto&& [index, variable] : data_->variables ) { + if ( index.get_name() == name ) { + return variable; + } + } + + for ( auto&& base : data_->bases ) { + if ( variable variable = base.get_variable(name); variable ) { + return variable; + } + } + + return variable{}; + } + + // + // get_constructor_with + // + + template < typename... Args > + constructor class_type::get_constructor_with() const noexcept { + return get_constructor_with({resolve_type()...}); + } + + template < typename Iter > + constructor class_type::get_constructor_with(Iter first, Iter last) const noexcept { + for ( auto&& [index, ctor] : data_->constructors ) { + const std::vector& args = ctor.get_type().get_argument_types(); + if ( std::equal(first, last, args.begin(), args.end()) ) { + return ctor; + } + } + return constructor{}; + } + + inline constructor class_type::get_constructor_with(const std::vector& args) const noexcept { + return get_constructor_with(args.begin(), args.end()); + } + + inline constructor class_type::get_constructor_with(std::initializer_list args) const noexcept { + return get_constructor_with(args.begin(), args.end()); + } + + // + // get_function_with + // + + template < typename... Args > + function class_type::get_function_with(std::string_view name) const noexcept { + return get_function_with(name, {resolve_type()...}); + } + + template < typename Iter > + function class_type::get_function_with(std::string_view name, Iter first, Iter last) const noexcept { + for ( auto&& [index, function] : data_->functions ) { + if ( index.get_name() != name ) { + continue; + } + + const std::vector& args = function.get_type().get_argument_types(); + if ( std::equal(first, last, args.begin(), args.end()) ) { + return function; + } + } + + for ( auto&& base : data_->bases ) { + if ( function function = base.get_function_with(name, first, last); function ) { + return function; + } + } + + return function{}; + } + + inline function class_type::get_function_with(std::string_view name, const std::vector& args) const noexcept { + return get_function_with(name, args.begin(), args.end()); + } + + inline function class_type::get_function_with(std::string_view name, std::initializer_list args) const noexcept { + return get_function_with(name, args.begin(), args.end()); + } + + // + // get_method_with + // + + template < typename... Args > + method class_type::get_method_with(std::string_view name) const noexcept { + return get_method_with(name, {resolve_type()...}); + } + + template < typename Iter > + method class_type::get_method_with(std::string_view name, Iter first, Iter last) const noexcept { + for ( auto&& [index, method] : data_->methods ) { + if ( index.get_name() != name ) { + continue; + } + + const std::vector& args = method.get_type().get_argument_types(); + if ( std::equal(first, last, args.begin(), args.end()) ) { + return method; + } + } + + for ( auto&& base : data_->bases ) { + if ( method method = base.get_method_with(name, first, last); method ) { + return method; + } + } + + return method{}; + } + + inline method class_type::get_method_with(std::string_view name, const std::vector& args) const noexcept { + return get_method_with(name, args.begin(), args.end()); + } + + inline method class_type::get_method_with(std::string_view name, std::initializer_list args) const noexcept { + return get_method_with(name, args.begin(), args.end()); + } +} + +namespace meta_hpp::detail +{ + inline scope_state_ptr scope_state::make(std::string name, metadata_map metadata) { + return std::make_shared(scope_state{ + .index{scope_index::make(std::move(name))}, + .metadata{std::move(metadata)}, + }); + } +} + +namespace meta_hpp +{ + inline scope::scope(detail::scope_state_ptr state) noexcept + : state_{std::move(state)} {} + + inline scope& scope::operator=(detail::scope_state_ptr state) noexcept { + state_ = std::move(state); + return *this; + } + + inline bool scope::is_valid() const noexcept { + return !!state_; + } + + inline scope::operator bool() const noexcept { + return is_valid(); + } + + inline const scope_index& scope::get_index() const noexcept { + return state_->index; + } + + inline const metadata_map& scope::get_metadata() const noexcept { + return state_->metadata; + } + + inline const std::string& scope::get_name() const noexcept { + return state_->index.get_name(); + } + + inline const function_map& scope::get_functions() const noexcept { + return state_->functions; + } + + inline const typedef_map& scope::get_typedefs() const noexcept { + return state_->typedefs; + } + + inline const variable_map& scope::get_variables() const noexcept { + return state_->variables; + } + + inline function scope::get_function(std::string_view name) const noexcept { + for ( auto&& [index, function] : state_->functions ) { + if ( index.get_name() == name ) { + return function; + } + } + return function{}; + } + + inline any_type scope::get_typedef(std::string_view name) const noexcept { + for ( auto&& [index, type] : state_->typedefs ) { + if ( index == name ) { + return type; + } + } + return any_type{}; + } + + inline variable scope::get_variable(std::string_view name) const noexcept { + for ( auto&& [index, variable] : state_->variables ) { + if ( index.get_name() == name ) { + return variable; + } + } + return variable{}; + } + + template < typename... Args > + function scope::get_function_with(std::string_view name) const noexcept { + return get_function_with(name, {resolve_type()...}); + } + + template < typename Iter > + function scope::get_function_with(std::string_view name, Iter first, Iter last) const noexcept { + for ( auto&& [index, function] : state_->functions ) { + if ( index.get_name() != name ) { + continue; + } + + const std::vector& args = function.get_type().get_argument_types(); + if ( std::equal(first, last, args.begin(), args.end()) ) { + return function; + } + } + return function{}; + } + + inline function scope::get_function_with(std::string_view name, const std::vector& args) const noexcept { + return get_function_with(name, args.begin(), args.end()); + } + + inline function scope::get_function_with(std::string_view name, std::initializer_list args) const noexcept { + return get_function_with(name, args.begin(), args.end()); + } +} + +namespace meta_hpp +{ + inline bool any_type::is_valid() const noexcept { + return data_ != nullptr; + } + + inline any_type::operator bool() const noexcept { + return is_valid(); + } + + inline type_id any_type::get_id() const noexcept { + return data_->id; + } + + inline type_kind any_type::get_kind() const noexcept { + return data_->kind; + } + + inline const metadata_map& any_type::get_metadata() const noexcept { + return data_->metadata; + } + + inline any_type::any_type(const array_type& other) noexcept + : data_{detail::type_access(other)} {} + + inline any_type::any_type(const class_type& other) noexcept + : data_{detail::type_access(other)} {} + + inline any_type::any_type(const constructor_type& other) noexcept + : data_{detail::type_access(other)} {} + + inline any_type::any_type(const destructor_type& other) noexcept + : data_{detail::type_access(other)} {} + + inline any_type::any_type(const enum_type& other) noexcept + : data_{detail::type_access(other)} {} + + inline any_type::any_type(const function_type& other) noexcept + : data_{detail::type_access(other)} {} + + inline any_type::any_type(const member_type& other) noexcept + : data_{detail::type_access(other)} {} + + inline any_type::any_type(const method_type& other) noexcept + : data_{detail::type_access(other)} {} + + inline any_type::any_type(const nullptr_type& other) noexcept + : data_{detail::type_access(other)} {} + + inline any_type::any_type(const number_type& other) noexcept + : data_{detail::type_access(other)} {} + + inline any_type::any_type(const pointer_type& other) noexcept + : data_{detail::type_access(other)} {} + + inline any_type::any_type(const reference_type& other) noexcept + : data_{detail::type_access(other)} {} + + inline any_type::any_type(const void_type& other) noexcept + : data_{detail::type_access(other)} {} + + inline bool any_type::is_array() const noexcept { + return is_valid() && data_->kind == type_kind::array_; + } + + inline bool any_type::is_class() const noexcept { + return is_valid() && data_->kind == type_kind::class_; + } + + inline bool any_type::is_constructor() const noexcept { + return is_valid() && data_->kind == type_kind::constructor_; + } + + inline bool any_type::is_destructor() const noexcept { + return is_valid() && data_->kind == type_kind::destructor_; + } + + inline bool any_type::is_enum() const noexcept { + return is_valid() && data_->kind == type_kind::enum_; + } + + inline bool any_type::is_function() const noexcept { + return is_valid() && data_->kind == type_kind::function_; + } + + inline bool any_type::is_member() const noexcept { + return is_valid() && data_->kind == type_kind::member_; + } + + inline bool any_type::is_method() const noexcept { + return is_valid() && data_->kind == type_kind::method_; + } + + inline bool any_type::is_nullptr() const noexcept { + return is_valid() && data_->kind == type_kind::nullptr_; + } + + inline bool any_type::is_number() const noexcept { + return is_valid() && data_->kind == type_kind::number_; + } + + inline bool any_type::is_pointer() const noexcept { + return is_valid() && data_->kind == type_kind::pointer_; + } + + inline bool any_type::is_reference() const noexcept { + return is_valid() && data_->kind == type_kind::reference_; + } + + inline bool any_type::is_void() const noexcept { + return is_valid() && data_->kind == type_kind::void_; + } + + inline array_type any_type::as_array() const noexcept { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-static-cast-downcast) + return is_array() ? array_type{static_cast(data_)} : array_type{}; + } + + inline class_type any_type::as_class() const noexcept { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-static-cast-downcast) + return is_class() ? class_type{static_cast(data_)} : class_type{}; + } + + inline constructor_type any_type::as_constructor() const noexcept { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-static-cast-downcast) + return is_constructor() ? constructor_type{static_cast(data_)} : constructor_type{}; + } + + inline destructor_type any_type::as_destructor() const noexcept { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-static-cast-downcast) + return is_destructor() ? destructor_type{static_cast(data_)} : destructor_type{}; + } + + inline enum_type any_type::as_enum() const noexcept { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-static-cast-downcast) + return is_enum() ? enum_type{static_cast(data_)} : enum_type{}; + } + + inline function_type any_type::as_function() const noexcept { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-static-cast-downcast) + return is_function() ? function_type{static_cast(data_)} : function_type{}; + } + + inline member_type any_type::as_member() const noexcept { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-static-cast-downcast) + return is_member() ? member_type{static_cast(data_)} : member_type{}; + } + + inline method_type any_type::as_method() const noexcept { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-static-cast-downcast) + return is_method() ? method_type{static_cast(data_)} : method_type{}; + } + + inline nullptr_type any_type::as_nullptr() const noexcept { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-static-cast-downcast) + return is_nullptr() ? nullptr_type{static_cast(data_)} : nullptr_type{}; + } + + inline number_type any_type::as_number() const noexcept { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-static-cast-downcast) + return is_number() ? number_type{static_cast(data_)} : number_type{}; + } + + inline pointer_type any_type::as_pointer() const noexcept { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-static-cast-downcast) + return is_pointer() ? pointer_type{static_cast(data_)} : pointer_type{}; + } + + inline reference_type any_type::as_reference() const noexcept { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-static-cast-downcast) + return is_reference() ? reference_type{static_cast(data_)} : reference_type{}; + } + + inline void_type any_type::as_void() const noexcept { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-static-cast-downcast) + return is_void() ? void_type{static_cast(data_)} : void_type{}; + } +} + +namespace meta_hpp::detail +{ + template < array_kind Array > + struct array_tag {}; + + template < array_kind Array > + // NOLINTNEXTLINE(readability-named-parameter) + array_type_data::array_type_data(type_list) + : type_data_base{type_id{type_list>{}}, type_kind::array_} + , flags{array_traits::make_flags()} + , extent{array_traits::extent} + , data_type{resolve_type::data_type>()} {} +} + +namespace meta_hpp +{ + inline array_type::array_type(detail::array_type_data* data) + : data_{data} {} + + inline bool array_type::is_valid() const noexcept { + return data_ != nullptr; + } + + inline array_type::operator bool() const noexcept { + return is_valid(); + } + + inline type_id array_type::get_id() const noexcept { + return data_->id; + } + + inline array_bitflags array_type::get_flags() const noexcept { + return data_->flags; + } + + inline const metadata_map& array_type::get_metadata() const noexcept { + return data_->metadata; + } + + inline std::size_t array_type::get_extent() const noexcept { + return data_->extent; + } + + inline any_type array_type::get_data_type() const noexcept { + return data_->data_type; + } +} + +namespace meta_hpp::detail +{ + template < nullptr_kind Nullptr > + struct nullptr_tag {}; + + template < nullptr_kind Nullptr > + // NOLINTNEXTLINE(readability-named-parameter) + nullptr_type_data::nullptr_type_data(type_list) + : type_data_base{type_id{type_list>{}}, type_kind::nullptr_} {} +} + +namespace meta_hpp +{ + inline nullptr_type::nullptr_type(detail::nullptr_type_data* data) + : data_{data} {} + + inline bool nullptr_type::is_valid() const noexcept { + return data_ != nullptr; + } + + inline nullptr_type::operator bool() const noexcept { + return is_valid(); + } + + inline type_id nullptr_type::get_id() const noexcept { + return data_->id; + } + + inline const metadata_map& nullptr_type::get_metadata() const noexcept { + return data_->metadata; + } +} + +namespace meta_hpp::detail +{ + template < number_kind Number > + struct number_tag {}; + + template < number_kind Number > + // NOLINTNEXTLINE(readability-named-parameter) + number_type_data::number_type_data(type_list) + : type_data_base{type_id{type_list>{}}, type_kind::number_} + , flags{number_traits::make_flags()} + , size{number_traits::size} + , align{number_traits::align} {} +} + +namespace meta_hpp +{ + inline number_type::number_type(detail::number_type_data* data) + : data_{data} {} + + inline bool number_type::is_valid() const noexcept { + return data_ != nullptr; + } + + inline number_type::operator bool() const noexcept { + return is_valid(); + } + + inline type_id number_type::get_id() const noexcept { + return data_->id; + } + + inline number_bitflags number_type::get_flags() const noexcept { + return data_->flags; + } + + inline const metadata_map& number_type::get_metadata() const noexcept { + return data_->metadata; + } + + inline std::size_t number_type::get_size() const noexcept { + return data_->size; + } + + inline std::size_t number_type::get_align() const noexcept { + return data_->align; + } +} + +namespace meta_hpp::detail +{ + template < reference_kind Reference > + struct reference_tag {}; + + template < reference_kind Reference > + // NOLINTNEXTLINE(readability-named-parameter) + reference_type_data::reference_type_data(type_list) + : type_data_base{type_id{type_list>{}}, type_kind::reference_} + , flags{reference_traits::make_flags()} + , data_type{resolve_type::data_type>()} {} +} + +namespace meta_hpp +{ + inline reference_type::reference_type(detail::reference_type_data* data) + : data_{data} {} + + inline bool reference_type::is_valid() const noexcept { + return data_ != nullptr; + } + + inline reference_type::operator bool() const noexcept { + return is_valid(); + } + + inline type_id reference_type::get_id() const noexcept { + return data_->id; + } + + inline reference_bitflags reference_type::get_flags() const noexcept { + return data_->flags; + } + + inline const metadata_map& reference_type::get_metadata() const noexcept { + return data_->metadata; + } + + inline any_type reference_type::get_data_type() const noexcept { + return data_->data_type; + } +} + +namespace meta_hpp::detail +{ + template < void_kind Void > + struct void_tag {}; + + template < void_kind Void > + // NOLINTNEXTLINE(readability-named-parameter) + void_type_data::void_type_data(type_list) + : type_data_base{type_id{type_list>{}}, type_kind::void_} {} +} + +namespace meta_hpp +{ + inline void_type::void_type(detail::void_type_data* data) + : data_{data} {} + + inline bool void_type::is_valid() const noexcept { + return data_ != nullptr; + } + + inline void_type::operator bool() const noexcept { + return is_valid(); + } + + inline type_id void_type::get_id() const noexcept { + return data_->id; + } + + inline const metadata_map& void_type::get_metadata() const noexcept { + return data_->metadata; + } +} + +namespace meta_hpp +{ + template < typename... Args > + uvalue invoke(const function& function, Args&&... args) { + return function.invoke(std::forward(args)...); + } + + template < detail::function_kind Function, typename... Args > + uvalue invoke(Function&& function, Args&&... args) { + using namespace detail; + if constexpr ( sizeof...(Args) > 0 ) { + const std::array vargs{uarg{std::forward(args)}...}; + return raw_function_invoke(std::forward(function), vargs); + } else { + return raw_function_invoke(std::forward(function), {}); + } + } +} + +namespace meta_hpp +{ + template < typename Instance > + uvalue invoke(const member& member, Instance&& instance) { + return member.get(std::forward(instance)); + } + + template < detail::member_kind Member, typename Instance > + uvalue invoke(Member&& member, Instance&& instance) { + using namespace detail; + const uinst vinst{std::forward(instance)}; + return raw_member_getter(std::forward(member), vinst); + } +} + +namespace meta_hpp +{ + template < typename Instance, typename... Args > + uvalue invoke(const method& method, Instance&& instance, Args&&... args) { + return method.invoke(std::forward(instance), std::forward(args)...); + } + + template < detail::method_kind Method, typename Instance, typename... Args > + uvalue invoke(Method&& method, Instance&& instance, Args&&... args) { + using namespace detail; + const uinst vinst{std::forward(instance)}; + if constexpr ( sizeof...(Args) > 0 ) { + const std::array vargs{uarg{std::forward(args)}...}; + return raw_method_invoke(std::forward(method), vinst, vargs); + } else { + return raw_method_invoke(std::forward(method), vinst, {}); + } + } +} + +namespace meta_hpp +{ + template < typename... Args > + bool is_invocable_with(const function& function) { + return function.is_invocable_with(); + } + + template < typename... Args > + bool is_invocable_with(const function& function, Args&&... args) { + return function.is_invocable_with(std::forward(args)...); + } + + template < detail::function_kind Function, typename... Args > + bool is_invocable_with() { + if constexpr ( sizeof...(Args) > 0 ) { + using namespace detail; + const std::array vargs{uarg_base{type_list{}}...}; + return raw_function_is_invocable_with(vargs); + } else { + return raw_function_is_invocable_with({}); + } + } + + template < detail::function_kind Function, typename... Args > + bool is_invocable_with(Args&&... args) { + if constexpr ( sizeof...(Args) > 0 ) { + using namespace detail; + const std::array vargs{uarg_base{std::forward(args)}...}; + return raw_function_is_invocable_with(vargs); + } else { + return raw_function_is_invocable_with({}); + } + } +} + +namespace meta_hpp +{ + template < typename Instance > + bool is_invocable_with(const member& member) { + return member.is_gettable_with(); + } + + template < typename Instance > + bool is_invocable_with(const member& member, Instance&& instance) { + return member.is_gettable_with(std::forward(instance)); + } +} + +namespace meta_hpp +{ + template < typename Instance, typename... Args > + bool is_invocable_with(const method& method) { + return method.is_invocable_with(); + } + + template < typename Instance, typename... Args > + bool is_invocable_with(const method& method, Instance&& instance, Args&&... args) { + return method.is_invocable_with(std::forward(instance), std::forward(args)...); + } +} + +namespace meta_hpp +{ + template < detail::member_kind Member, typename Instance > + bool is_invocable_with() { + using namespace detail; + const uinst_base vinst{type_list{}}; + return raw_member_is_gettable_with(vinst); + } + + template < detail::member_kind Member, typename Instance > + bool is_invocable_with(Instance&& instance) { + using namespace detail; + const uinst_base vinst{std::forward(instance)}; + return raw_member_is_gettable_with(vinst); + } +} + +namespace meta_hpp +{ + template < detail::method_kind Method, typename Instance, typename... Args > + bool is_invocable_with() { + using namespace detail; + const uinst_base vinst{type_list{}}; + if constexpr ( sizeof...(Args) > 0 ) { + const std::array vargs{uarg_base{type_list{}}...}; + return raw_method_is_invocable_with(vinst, vargs); + } else { + return raw_method_is_invocable_with(vinst, {}); + } + } + + template < detail::method_kind Method, typename Instance, typename... Args > + bool is_invocable_with(Instance&& instance, Args&&... args) { + using namespace detail; + const uinst_base vinst{std::forward(instance)}; + if constexpr ( sizeof...(Args) > 0 ) { + const std::array vargs{uarg_base{std::forward(args)}...}; + return raw_method_is_invocable_with(vinst, vargs); + } else { + return raw_method_is_invocable_with(vinst, {}); + } + } +} + +namespace meta_hpp::detail +{ + template < typename T > + struct deref_traits; + + template < typename T > + concept has_deref_traits = requires(const T& v) { + { deref_traits{}(v) } -> stdex::convertible_to; + }; +} + +namespace meta_hpp::detail +{ + template < stdex::copy_constructible T > + struct deref_traits { + uvalue operator()(T* v) const { + return uvalue{*v}; + } + }; + + template < stdex::copy_constructible T > + struct deref_traits { + uvalue operator()(const T* v) const { + return uvalue{*v}; + } + }; + + template < stdex::copy_constructible T > + struct deref_traits> { + uvalue operator()(const std::shared_ptr& v) const { + return uvalue{*v}; + } + }; + + template < stdex::copy_constructible T > + struct deref_traits> { + uvalue operator()(const std::unique_ptr& v) const { + return uvalue{*v}; + } + }; +} + +namespace meta_hpp::detail +{ + template < typename T > + struct equals_traits; + + template < typename T > + concept has_equals_traits = requires(const T& l, const T& r) { + { equals_traits{}(l, r) } -> stdex::convertible_to; + }; +} + +namespace meta_hpp::detail +{ + template < typename T > + requires requires(const T& l, const T& r) { + { std::equal_to<>{}(l, r) } -> stdex::convertible_to; + } + struct equals_traits { + bool operator()(const T& l, const T& r) const { + return std::equal_to<>{}(l, r); + } + }; +} + +namespace meta_hpp::detail +{ + template < typename T > + struct index_traits; + + template < typename T > + concept has_index_traits = requires(const T& v, std::size_t i) { + { index_traits{}(v, i) } -> stdex::convertible_to; + }; +} + +namespace meta_hpp::detail +{ + template < stdex::copy_constructible T > + struct index_traits { + uvalue operator()(T* v, std::size_t i) const { + return uvalue{v[i]}; + } + }; + + template < stdex::copy_constructible T > + struct index_traits { + uvalue operator()(const T* v, std::size_t i) const { + return uvalue{v[i]}; + } + }; + + template < stdex::copy_constructible T, std::size_t Size > + struct index_traits> { + uvalue operator()(const std::array& v, std::size_t i) const { + return uvalue{v[i]}; + } + }; + + template < stdex::copy_constructible T, std::size_t Extent > + struct index_traits> { + uvalue operator()(const std::span& v, std::size_t i) const { + return uvalue{v[i]}; + } + }; + + template < stdex::copy_constructible T, typename Traits, typename Allocator > + struct index_traits> { + uvalue operator()(const std::basic_string& v, std::size_t i) const { + return uvalue{v[i]}; + } + }; + + template < stdex::copy_constructible T, typename Allocator > + struct index_traits> { + uvalue operator()(const std::vector& v, std::size_t i) { + return uvalue{v[i]}; + } + }; +} + +namespace meta_hpp::detail +{ + template < typename T > + struct istream_traits; + + template < typename T > + concept has_istream_traits = requires(std::istream& is, T& v) { + { istream_traits{}(is, v) } -> stdex::convertible_to; + }; +} + +namespace meta_hpp::detail +{ + template < typename T > + requires requires(std::istream& is, T& v) { + { is >> v } -> stdex::convertible_to; + } + struct istream_traits { + std::istream& operator()(std::istream& is, T& v) const { + return is >> v; + } + }; +} + +namespace meta_hpp::detail +{ + template < typename T > + struct less_traits; + + template < typename T > + concept has_less_traits = requires(const T& l, const T& r) { + { less_traits{}(l, r) } -> stdex::convertible_to; + }; +} + +namespace meta_hpp::detail +{ + template < typename T > + requires requires(const T& l, const T& r) { + { std::less<>{}(l, r) } -> stdex::convertible_to; + } + struct less_traits { + bool operator()(const T& l, const T& r) const { + return std::less<>{}(l, r); + } + }; +} + +namespace meta_hpp::detail +{ + template < typename T > + struct ostream_traits; + + template < typename T > + concept has_ostream_traits = requires(std::ostream& os, const T& v) { + { ostream_traits{}(os, v) } -> stdex::convertible_to; + }; +} + +namespace meta_hpp::detail +{ + template < typename T > + requires requires(std::ostream& os, const T& v) { + { os << v } -> stdex::convertible_to; + } + struct ostream_traits { + std::ostream& operator()(std::ostream& os, const T& v) const { + return os << v; + } + }; +} + +namespace meta_hpp +{ + struct uvalue::vtable_t final { + const any_type type; + + void* (*const data)(storage_u& from) noexcept; + const void* (*const cdata)(const storage_u& from) noexcept; + + void (*const move)(uvalue& from, uvalue& to) noexcept; + void (*const copy)(const uvalue& from, uvalue& to); + void (*const destroy)(uvalue& self) noexcept; + + uvalue (*const deref)(const uvalue& from); + uvalue (*const index)(const uvalue& from, std::size_t); + + bool (*const less)(const uvalue&, const uvalue&); + bool (*const equals)(const uvalue&, const uvalue&); + + std::istream& (*const istream)(std::istream&, uvalue&); + std::ostream& (*const ostream)(std::ostream&, const uvalue&); + + template < typename T > + static T* buffer_cast(buffer_t& buffer) noexcept { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + return reinterpret_cast(&buffer); + } + + template < typename T > + static const T* buffer_cast(const buffer_t& buffer) noexcept { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + return reinterpret_cast(&buffer); + } + + template < typename T > + static T* storage_cast(storage_u& storage) noexcept { + return std::visit(detail::overloaded { + [](void* ptr) { return static_cast(ptr); }, + [](buffer_t& buffer) { return buffer_cast(buffer); }, + [](...) -> T* { return nullptr; }, + }, storage); + } + + template < typename T > + static const T* storage_cast(const storage_u& storage) noexcept { + return std::visit(detail::overloaded { + [](const void* ptr) { return static_cast(ptr); }, + [](const buffer_t& buffer) { return buffer_cast(buffer); }, + [](...) -> const T* { return nullptr; }, + }, storage); + } + + template < typename T > + static void construct(uvalue& dst, T&& val) { + using Tp = std::decay_t; + + constexpr bool in_buffer = + sizeof(Tp) <= sizeof(buffer_t) && + alignof(Tp) <= alignof(buffer_t) && + std::is_nothrow_move_constructible_v; + + if constexpr ( in_buffer ) { + dst.storage_.emplace(); + ::new (storage_cast(dst.storage_)) Tp(std::forward(val)); + } else { + dst.storage_.emplace(std::make_unique(std::forward(val)).release()); + } + + dst.vtable_ = vtable_t::get(); + } + + static void swap(uvalue& l, uvalue& r) noexcept { + if ( (&l == &r) || (!l && !r) ) { + return; + } + + if ( l && r ) { + if ( std::holds_alternative(l.storage_) ) { + uvalue temp; + r.vtable_->move(r, temp); + l.vtable_->move(l, r); + temp.vtable_->move(temp, l); + } else { + uvalue temp; + l.vtable_->move(l, temp); + r.vtable_->move(r, l); + temp.vtable_->move(temp, r); + } + } else { + if ( l ) { + l.vtable_->move(l, r); + } else { + r.vtable_->move(r, l); + } + } + } + + template < typename Tp > + // NOLINTNEXTLINE(readability-function-cognitive-complexity) + static vtable_t* get() { + static vtable_t table{ + .type = resolve_type(), + + .data = [](storage_u& from) noexcept -> void* { + return storage_cast(from); + }, + + .cdata = [](const storage_u& from) noexcept -> const void* { + return storage_cast(from); + }, + + .move = [](uvalue& from, uvalue& to) noexcept { + assert(from && !to); + + std::visit(detail::overloaded { + [&to](void* ptr) { + Tp* src = static_cast(ptr); + to.storage_.emplace(src); + }, + [&to](buffer_t& buffer) { + Tp& src = *buffer_cast(buffer); + ::new (&to.storage_.emplace()) Tp(std::move(src)); + src.~Tp(); + }, + [](...){} + }, from.storage_); + + to.vtable_ = from.vtable_; + from.vtable_ = nullptr; + }, + + .copy = [](const uvalue& from, uvalue& to){ + assert(from && !to); + + std::visit(detail::overloaded { + [&to](void* ptr) { + const Tp& src = *static_cast(ptr); + to.storage_.emplace(new Tp(src)); + }, + [&to](const buffer_t& buffer) { + const Tp& src = *buffer_cast(buffer); + ::new (&to.storage_.emplace()) Tp(src); + }, + [](...){} + }, from.storage_); + + to.vtable_ = from.vtable_; + }, + + .destroy = [](uvalue& self) noexcept { + assert(self); + + std::visit(detail::overloaded { + [](void* ptr) { + Tp* src = static_cast(ptr); + std::unique_ptr{src}.reset(); + }, + [](buffer_t& buffer) { + Tp& src = *buffer_cast(buffer); + src.~Tp(); + }, + [](...){} + }, self.storage_); + + self.vtable_ = nullptr; + }, + + .deref = +[]([[maybe_unused]] const uvalue& v) -> uvalue { + if constexpr ( detail::has_deref_traits ) { + return detail::deref_traits{}(v.cast()); + } else { + detail::throw_exception_with("value type doesn't have value deref traits"); + } + }, + + .index = +[]([[maybe_unused]] const uvalue& v, [[maybe_unused]] std::size_t i) -> uvalue { + if constexpr ( detail::has_index_traits ) { + return detail::index_traits{}(v.cast(), i); + } else { + detail::throw_exception_with("value type doesn't have value index traits"); + } + }, + + .less = +[]([[maybe_unused]] const uvalue& l, [[maybe_unused]] const uvalue& r) -> bool { + if constexpr ( detail::has_less_traits ) { + return detail::less_traits{}(l.cast(), r.cast()); + } else { + detail::throw_exception_with("value type doesn't have value less traits"); + } + }, + + .equals = +[]([[maybe_unused]] const uvalue& l, [[maybe_unused]] const uvalue& r) -> bool { + if constexpr ( detail::has_equals_traits ) { + return detail::equals_traits{}(l.cast(), r.cast()); + } else { + detail::throw_exception_with("value type doesn't have value equals traits"); + } + }, + + .istream = +[]([[maybe_unused]] std::istream& is, [[maybe_unused]] uvalue& v) -> std::istream& { + if constexpr ( detail::has_istream_traits ) { + return detail::istream_traits{}(is, v.cast()); + } else { + detail::throw_exception_with("value type doesn't have value istream traits"); + } + }, + + .ostream = +[]([[maybe_unused]] std::ostream& os, [[maybe_unused]] const uvalue& v) -> std::ostream& { + if constexpr ( detail::has_ostream_traits ) { + return detail::ostream_traits{}(os, v.cast()); + } else { + detail::throw_exception_with("value type doesn't have value ostream traits"); + } + }, + }; + + return &table; + } + }; +} + +namespace meta_hpp +{ + inline uvalue::~uvalue() { + reset(); + } + + inline uvalue::uvalue(uvalue&& other) noexcept { + if ( other.vtable_ != nullptr ) { + other.vtable_->move(other, *this); + } + } + + inline uvalue::uvalue(const uvalue& other) { + if ( other.vtable_ != nullptr ) { + other.vtable_->copy(other, *this); + } + } + + inline uvalue& uvalue::operator=(uvalue&& other) noexcept { + if ( this != &other ) { + uvalue{std::move(other)}.swap(*this); + } + return *this; + } + + inline uvalue& uvalue::operator=(const uvalue& other) { + if ( this != &other ) { + uvalue{other}.swap(*this); + } + return *this; + } + + template < detail::decay_non_value_kind T > + requires stdex::copy_constructible> + uvalue::uvalue(T&& val) { + vtable_t::construct(*this, std::forward(val)); + } + + template < detail::decay_non_value_kind T > + requires stdex::copy_constructible> + uvalue& uvalue::operator=(T&& val) { + uvalue{std::forward(val)}.swap(*this); + return *this; + } + + inline bool uvalue::is_valid() const noexcept { + return vtable_ != nullptr; + } + + inline uvalue::operator bool() const noexcept { + return is_valid(); + } + + inline void uvalue::reset() { + if ( vtable_ != nullptr ) { + vtable_->destroy(*this); + } + } + + inline void uvalue::swap(uvalue& other) noexcept { + vtable_t::swap(*this, other); + } + + inline const any_type& uvalue::get_type() const noexcept { + static any_type void_type = resolve_type(); + return vtable_ != nullptr ? vtable_->type : void_type; + } + + inline void* uvalue::data() noexcept { + return vtable_ != nullptr ? vtable_->data(storage_) : nullptr; + } + + inline const void* uvalue::data() const noexcept { + return vtable_ != nullptr ? vtable_->cdata(storage_) : nullptr; + } + + inline const void* uvalue::cdata() const noexcept { + return vtable_ != nullptr ? vtable_->cdata(storage_) : nullptr; + } + + inline uvalue uvalue::operator*() const { + return vtable_ != nullptr ? vtable_->deref(*this) : uvalue{}; + } + + inline uvalue uvalue::operator[](std::size_t index) const { + return vtable_ != nullptr ? vtable_->index(*this, index) : uvalue{}; + } + + template < typename T > + std::decay_t& uvalue::cast() & { + using Tp = std::decay_t; + if ( Tp* ptr = try_cast() ) { + return *ptr; + } + detail::throw_exception_with("bad value cast"); + } + + template < typename T > + std::decay_t&& uvalue::cast() && { + using Tp = std::decay_t; + if ( Tp* ptr = try_cast() ) { + return std::move(*ptr); + } + detail::throw_exception_with("bad value cast"); + } + + template < typename T > + const std::decay_t& uvalue::cast() const & { + using Tp = std::decay_t; + if ( const Tp* ptr = try_cast() ) { + return *ptr; + } + detail::throw_exception_with("bad value cast"); + } + + template < typename T > + const std::decay_t&& uvalue::cast() const && { + using Tp = std::decay_t; + if ( const Tp* ptr = try_cast() ) { + return std::move(*ptr); + } + detail::throw_exception_with("bad value cast"); + } + + template < typename T > + std::decay_t* uvalue::try_cast() noexcept { + using Tp = std::decay_t; + return get_type() == resolve_type() + ? vtable_t::storage_cast(storage_) + : nullptr; + } + + template < typename T > + const std::decay_t* uvalue::try_cast() const noexcept { + using Tp = std::decay_t; + return get_type() == resolve_type() + ? vtable_t::storage_cast(storage_) + : nullptr; + } +} + +namespace meta_hpp +{ + template < typename T > + [[nodiscard]] bool operator<(const uvalue& l, const T& r) { + if ( !static_cast(l) ) { + return true; + } + + const any_type& l_type = l.get_type(); + const any_type& r_type = resolve_type(); + + return (l_type < r_type) || (l_type == r_type && l.cast() < r); + } + + template < typename T > + [[nodiscard]] bool operator<(const T& l, const uvalue& r) { + if ( !static_cast(r) ) { + return false; + } + + const any_type& l_type = resolve_type(); + const any_type& r_type = r.get_type(); + + return (l_type < r_type) || (l_type == r_type && l < r.cast()); + } + + [[nodiscard]] inline bool operator<(const uvalue& l, const uvalue& r) { + if ( !static_cast(r) ) { + return false; + } + + if ( !static_cast(l) ) { + return true; + } + + const any_type& l_type = l.get_type(); + const any_type& r_type = r.get_type(); + + return (l_type < r_type) || (l_type == r_type && l.vtable_->less(l, r)); + } +} + +namespace meta_hpp +{ + template < typename T > + [[nodiscard]] bool operator==(const uvalue& l, const T& r) { + if ( !static_cast(l) ) { + return false; + } + + const any_type& l_type = l.get_type(); + const any_type& r_type = resolve_type(); + + return l_type == r_type && l.cast() == r; + } + + template < typename T > + [[nodiscard]] bool operator==(const T& l, const uvalue& r) { + if ( !static_cast(r) ) { + return false; + } + + const any_type& l_type = resolve_type(); + const any_type& r_type = r.get_type(); + + return l_type == r_type && l == r.cast(); + } + + [[nodiscard]] inline bool operator==(const uvalue& l, const uvalue& r) { + if ( static_cast(l) != static_cast(r) ) { + return false; + } + + if ( !static_cast(l) ) { + return true; + } + + const any_type& l_type = l.get_type(); + const any_type& r_type = r.get_type(); + + return l_type == r_type && l.vtable_->equals(l, r); + } +} + +namespace meta_hpp +{ + inline std::istream& operator>>(std::istream& is, uvalue& v) { + return v.vtable_->istream(is, v); + } + + inline std::ostream& operator<<(std::ostream& os, const uvalue& v) { + return v.vtable_->ostream(os, v); + } +} diff --git a/untests/CMakeLists.txt b/untests/CMakeLists.txt index a60bcbb..c8a425f 100644 --- a/untests/CMakeLists.txt +++ b/untests/CMakeLists.txt @@ -4,40 +4,77 @@ file(GLOB_RECURSE UNTESTS_SOURCES "*.cpp" "*.hpp") source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${UNTESTS_SOURCES}) add_executable(${PROJECT_NAME} ${UNTESTS_SOURCES}) -target_link_libraries(${PROJECT_NAME} PRIVATE meta.hpp doctest_with_main) +target_link_libraries(${PROJECT_NAME} PRIVATE meta.hpp) -if(${BUILD_WITH_COVERAGE}) - target_link_libraries(${PROJECT_NAME} PRIVATE enable_gcov) -endif() +add_executable(${PROJECT_NAME}.singles ${UNTESTS_SOURCES}) +target_link_libraries(${PROJECT_NAME}.singles PRIVATE meta.hpp.singles) -if(${BUILD_WITH_SANITIZERS}) - target_link_libraries(${PROJECT_NAME} PRIVATE enable_asan enable_ubsan) -endif() +# +# setup defines +# -target_compile_options(${PROJECT_NAME} - PRIVATE - $<$: - /WX /W4> - PRIVATE - $<$: - -Werror -Wall -Wextra -Wpedantic> - PRIVATE - $<$,$>: - -Werror -Weverything -Wconversion - -Wno-c++98-compat - -Wno-c++98-compat-pedantic - -Wno-exit-time-destructors - -Wno-global-constructors - -Wno-padded - -Wno-unknown-warning-option - -Wno-unneeded-internal-declaration - -Wno-unneeded-member-function - -Wno-unused-macros - -Wno-weak-vtables - >) +function(setup_defines_for_target TARGET) + target_compile_definitions(${TARGET} PRIVATE + DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS + DOCTEST_CONFIG_USE_STD_HEADERS) +endfunction() -target_compile_definitions(${PROJECT_NAME} PRIVATE - DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS - DOCTEST_CONFIG_USE_STD_HEADERS) +setup_defines_for_target(${PROJECT_NAME}) +setup_defines_for_target(${PROJECT_NAME}.singles) + +# +# setup libraries +# + +function(setup_libraries_for_target TARGET) + target_link_libraries(${TARGET} PRIVATE doctest_with_main) + + if(${BUILD_WITH_COVERAGE}) + target_link_libraries(${TARGET} PRIVATE enable_gcov) + endif() + + if(${BUILD_WITH_SANITIZERS}) + target_link_libraries(${TARGET} PRIVATE enable_asan enable_ubsan) + endif() +endfunction() + +setup_libraries_for_target(${PROJECT_NAME}) +setup_libraries_for_target(${PROJECT_NAME}.singles) + +# +# setup warnings +# + +function(setup_warnings_for_target TARGET) + target_compile_options(${TARGET} + PRIVATE + $<$: + /WX /W4> + PRIVATE + $<$: + -Werror -Wall -Wextra -Wpedantic> + PRIVATE + $<$,$>: + -Werror -Weverything -Wconversion + -Wno-c++98-compat + -Wno-c++98-compat-pedantic + -Wno-exit-time-destructors + -Wno-global-constructors + -Wno-padded + -Wno-unknown-warning-option + -Wno-unneeded-internal-declaration + -Wno-unneeded-member-function + -Wno-unused-macros + -Wno-weak-vtables + >) +endfunction() + +setup_warnings_for_target(${PROJECT_NAME}) +setup_warnings_for_target(${PROJECT_NAME}.singles) + +# +# add tests +# add_test(${PROJECT_NAME} ${PROJECT_NAME}) +add_test(${PROJECT_NAME} ${PROJECT_NAME}.singles)