#pragma once #include #include #include #include #include "utils/total_ordering.hpp" #include "utils/underlying_cast.hpp" // TODO: Revise this // NOTE: Why not just count all the types? enum class Flags : unsigned { // Type | Mask // -----------+---------------------------------------- // Null | 0000 0000 0000 0000 0000 0000 0000 0000 // -----------+---------------------------------------- // Bool | 0000 0000 0000 0000 0000 0000 0000 0001 // + True | 0000 0000 0000 0000 0000 0000 0000 0011 // + False | 0000 0000 0000 0000 0000 0000 0000 0101 // -----------+---------------------------------------- // String | 0000 0000 0000 0000 0000 0000 0000 1000 // -----------+---------------------------------------- // Number | 0000 0000 0000 0000 0000 0000 0001 0000 // + Integral | 0000 0000 0000 0000 0000 0000 0011 0000 // + Int32 | 0000 0000 0000 0000 0000 0000 0111 0000 // + Int64 | 0000 0000 0000 0000 0000 0000 1011 0000 // + Floating | 0000 0000 0000 0000 0000 0001 0001 0000 // + Float | 0000 0000 0000 0000 0000 0011 0001 0000 // + Double | 0000 0000 0000 0000 0000 0101 0001 0000 // -----------+---------------------------------------- // Array | 0000 0000 0000 0000 0001 0000 0000 0000 // -----------+---------------------------------------- Null = 0x0, Bool = 0x1, // TODO remove this two values True = 0x2 | Bool, False = 0x4 | Bool, String = 0x8, Number = 0x10, Integral = 0x20 | Number, Int32 = 0x40 | Integral, Int64 = 0x80 | Integral, Floating = 0x100 | Number, Float = 0x200 | Floating, Double = 0x400 | Floating, Array = 0x1000, ArrayBool = (Bool << 13) | Array, ArrayString = (String << 13) | Array, ArrayInt32 = (Int32 << 13) | Array, ArrayInt64 = (Int64 << 13) | Array, ArrayFloat = (Float << 13) | Array, ArrayDouble = (Double << 13) | Array, type_mask = 0xFFFFFF }; // Mask to turn flags into type. It passes all bits except 0x2 and 0x4 which // correspond // to True and False. const unsigned flags_equal_mask = 0xFF3FF9; class Type : public TotalOrdering { public: constexpr Type(Flags f) : value(underlying_cast(f) & flags_equal_mask) { Flags o = Flags(value); assert(o == Flags::Null || o == Flags::Bool || o == Flags::String || o == Flags::Int32 || o == Flags::Int64 || o == Flags::Float || o == Flags::Double || o == Flags::ArrayBool || o == Flags::ArrayString || o == Flags::ArrayInt32 || o == Flags::ArrayInt64 || o == Flags::ArrayFloat || o == Flags::ArrayDouble); } const std::string to_str() const { switch (flags()) { case Flags::Null: return "null"; case Flags::Bool: return "bool"; case Flags::String: return "str"; case Flags::Int32: return "int32"; case Flags::Int64: return "int64"; case Flags::Float: return "float"; case Flags::Double: return "double"; case Flags::ArrayBool: return "array_bool"; case Flags::ArrayString: return "array_string"; case Flags::ArrayInt64: return "array_int64"; case Flags::ArrayInt32: return "array_int32"; case Flags::ArrayFloat: return "array_float"; case Flags::ArrayDouble: return "array_double"; default: assert(false); return "err_unknown_type_" + std::to_string(value); } } Flags flags() const { return Flags(value); } Type get_type() const { return *this; } bool is_array() const { return (value & underlying_cast(Flags::Array)) != 0; } template bool is() const { return *this == T::type; } bool operator==(Flags other) const { return *this == Type(other); } bool operator!=(Flags other) const { return *this != Type(other); } friend bool operator<(const Type &lhs, const Type &rhs) { return lhs.value < rhs.value; } friend bool operator==(const Type &lhs, const Type &rhs) { return lhs.value == rhs.value; } private: const unsigned value; // TODO: turn this to flags };