#pragma once #include #include #include namespace clice { template requires std::is_enum_v auto underlying_value(T value) { return static_cast>(value); } template requires std::is_enum_v struct enum_type { using enum_tag = Enum; constexpr explicit enum_type() = default; constexpr explicit enum_type(std::underlying_type_t value) : value(value) {} constexpr enum_type(Enum enum_) : value(underlying_value(enum_)) {} friend constexpr bool operator== (enum_type lhs, enum_type rhs) = default; friend llvm::raw_ostream& operator<< (llvm::raw_ostream& os, enum_type e) { os << std::format("[normal enum, value: {}, name: {}]", e.value, refl::enum_name(static_cast(e.value))); return os; } std::underlying_type_t value; }; template requires std::is_enum_v struct enum_type { public: using enum_tag = Enum; constexpr explicit enum_type() = default; template constexpr explicit enum_type(Args... args) : value(((1 << underlying_value(args)) | ...)) {} constexpr explicit enum_type(std::underlying_type_t value) : value(value) {} constexpr enum_type(Enum enum_) : value(1 << underlying_value(enum_)) {} constexpr void set(Enum enum_) { value |= (1 << underlying_value(enum_)); } constexpr bool is(Enum enum_) const { return value & (1 << underlying_value(enum_)); } friend constexpr bool operator== (enum_type lhs, enum_type rhs) = default; std::string dump() { std::string masks; bool is_first = true; for(std::size_t i = 0; i < sizeof(std::underlying_type_t) * 8; i++) { if(value & (1 << i)) { if(is_first) { is_first = false; } else { masks += " | "; } masks += refl::enum_name(static_cast(i)); } } return masks; } friend llvm::raw_ostream& operator<< (llvm::raw_ostream& os, enum_type e) { os << std::format("[mask enum, value: {}, masks: {}]", e.value, e.dump()); return os; } std::underlying_type_t value; }; template requires requires { typename T::enum_tag; } auto underlying_value(T value) { return value.value; } template constexpr inline bool is_enum_v = std::is_enum_v || requires { typename T::enum_tag; }; } // namespace clice