// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details #pragma once #include #include #include namespace Luau::EqSat { #define LUAU_EQSAT_ATOM(name, t) LUAU_EQSAT_ATOM_CUSTOM(name, #name, t) #define LUAU_EQSAT_ATOM_CUSTOM(name, custom, t) \ struct name : public ::Luau::EqSat::Atom \ { \ static constexpr const char* tag = custom; \ } template struct Atom { T value; bool operator==(const Atom& rhs) const { return value == rhs.value; } bool operator!=(const Atom& rhs) const { return !(*this == rhs); } }; // `Language` is very similar to `Luau::Variant` with enough differences warranting a different type altogether. // // Firstly, where `Luau::Variant` uses an `int` to decide which type the variant currently holds, we use // a `const char*` instead. We use the pointer address for tag checking, and the string buffer for stringification. // // Secondly, we need `Language` to have additional methods such as: // - `children()` to get child operands, // - `operator==` to decide equality, and // - `hash()` function. // // And finally, each `T` in `Ts` have additional requirements which `Luau::Variant` doesn't need. template class Language { const char* tag; char buffer[std::max({sizeof(Ts)...})]; template using WithinDomain = std::disjunction, Ts>...>; using FnCopy = void (*)(void*, const void*); using FnMove = void (*)(void*, void*); using FnDtor = void (*)(void*); using FnPred = bool (*)(const void*, const void*); template static void fnCopy(void* dst, const void* src) { new (dst) T(*static_cast(src)); } template static void fnMove(void* dst, void* src) { // static_cast is equivalent to std::move() but faster in Debug new (dst) T(static_cast(*static_cast(src))); } template static void fnDtor(void* dst) { static_cast(dst)->~T(); } template static bool fnPred(const void* lhs, const void* rhs) { return *static_cast(lhs) == *static_cast(rhs); } static constexpr FnCopy tableCopy[sizeof...(Ts)] = {&fnCopy...}; static constexpr FnMove tableMove[sizeof...(Ts)] = {&fnMove...}; static constexpr FnDtor tableDtor[sizeof...(Ts)] = {&fnDtor...}; static constexpr FnPred tablePred[sizeof...(Ts)] = {&fnPred...}; static constexpr int getIndexFromTag(const char* tag) { constexpr int N = sizeof...(Ts); constexpr const char* is[N] = {Ts::tag...}; for (int i = 0; i < N; ++i) if (is[i] == tag) return i; return -1; } public: template Language(T&& t, std::enable_if_t::value>* = 0) { tag = T::tag; new (&buffer) std::decay_t(std::forward(t)); } Language(const Language& other) { tag = other.tag; tableCopy[getIndexFromTag(tag)](&buffer, &other.buffer); } Language(Language&& other) { tag = other.tag; tableMove[getIndexFromTag(tag)](&buffer, &other.buffer); } ~Language() { tableDtor[getIndexFromTag(tag)](&buffer); } Language& operator=(const Language& other) { Language copy{other}; *this = static_cast(copy); return *this; } Language& operator=(Language&& other) { if (this != &other) { tableDtor[getIndexFromTag(tag)](&buffer); tag = other.tag; tableMove[getIndexFromTag(tag)](&buffer, &other.buffer); // nothrow } return *this; } template const T* get() const { static_assert(WithinDomain::value); return tag == T::tag ? reinterpret_cast(&buffer) : nullptr; } bool operator==(const Language& rhs) const { return tag == rhs.tag && tablePred[getIndexFromTag(tag)](&buffer, &rhs.buffer); } bool operator!=(const Language& rhs) const { return !(*this == rhs); } public: struct Hash { size_t operator()(const Language& lang) { // TODO. Currently here so I can build and test this project. return 0; } }; }; } // namespace Luau::EqSat