#pragma once #include #include #include #include #include "exopt.h" #include "optional.h" #define _EO_CONSTANT_VALUE(X) ([]() { \ struct { \ typedef decltype(X) comptime_constant_t; \ consteval operator comptime_constant_t() const noexcept { return (X); } \ } inner; \ return inner; \ })() namespace exopt { namespace util [[gnu::visibility("internal")]] { template concept comptime = std::convertible_to and requires{ typename T::comptime_constant_t; }; template concept is_complete = requires{ { sizeof(T) == sizeof(T) }; }; constexpr auto comptime_value(auto value) noexcept { using U = decltype(value); struct inner { typedef U comptime_constant_t; consteval operator comptime_constant_t() const noexcept { return std::move(value); } U value; constexpr inner(std::add_rvalue_reference_t m) noexcept : value(std::move(m)) {} constexpr ~inner() = default; }; return inner{ std::move(value) }; } static_assert(comptime_value(std::string_view{"hello"}.size()) == 5, "Bad comptime_value()"); static_assert(_EO_CONSTANT_VALUE(std::string_view{"hello world"}) == std::string_view{"hello world"}, "Bad CONSTANT_VALUE()"); template, typename _I = std::make_index_sequence> constexpr auto array_literal(const T (&a)[N]) noexcept -> Array { constexpr decltype(auto) _array_create = [](auto const& a, std::index_sequence) noexcept { return Array { a[I]... }; }; return _array_create(std::move(a), _I{}); } template, typename _I = std::make_index_sequence> constexpr auto array_literal(T (&&a)[N]) noexcept -> Array { constexpr decltype(auto) _array_create = [](auto&& a, std::index_sequence) noexcept { return Array { std::move(a[I])... }; }; return _array_create(std::move(a), _I{}); } struct [[gnu::visibility("internal")]] CTInternalFatalError { constexpr CTInternalFatalError() noexcept = default; constexpr CTInternalFatalError(CTInternalFatalError const&) noexcept = default; constexpr CTInternalFatalError(CTInternalFatalError &&) noexcept = default; constexpr CTInternalFatalError& operator=(CTInternalFatalError const&) noexcept = default; constexpr CTInternalFatalError& operator=(CTInternalFatalError&&) noexcept = default; constexpr virtual ~CTInternalFatalError() noexcept = default; constexpr operator std::string_view() const noexcept { return message(); } consteval virtual std::string_view message() const noexcept =0; }; [[noreturn, gnu::noinline, gnu::cold]] void throw_runtime(std::string_view&&); [[noreturn]]//, gnu::noinline, gnu::cold]] constexpr void throw_runtime(std::convertible_to auto&& msg) { std::string_view view{msg}; if consteval { using CTE = CTInternalFatalError; struct CTIFRuntimeError : public CTE { using CTE::CTE; consteval CTIFRuntimeError(std::string_view&& view) noexcept : CTE(), m_message(std::move(view)) {} consteval std::string_view message() const noexcept override { return m_message; } constexpr virtual ~CTIFRuntimeError() noexcept {} private: std::string_view m_message; }; throw CTIFRuntimeError(std::move(view)); } else { throw_runtime(std::move(view)); } __builtin_unreachable(); } } }