Files
clice/include/Support/Enum.h
2024-11-06 21:33:11 +08:00

98 lines
2.7 KiB
C++

#pragma once
#include <format>
#include <llvm/Support/raw_ostream.h>
#include <Support/Reflection.h>
namespace clice {
template <typename T>
requires std::is_enum_v<T>
auto underlying_value(T value) {
return static_cast<std::underlying_type_t<T>>(value);
}
template <typename Enum, bool is_mask = false>
requires std::is_enum_v<Enum>
struct enum_type {
using enum_tag = Enum;
constexpr explicit enum_type() = default;
constexpr explicit enum_type(std::underlying_type_t<Enum> 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<Enum>(static_cast<Enum>(e.value)));
return os;
}
std::underlying_type_t<Enum> value;
};
template <typename Enum>
requires std::is_enum_v<Enum>
struct enum_type<Enum, true> {
public:
using enum_tag = Enum;
constexpr explicit enum_type() = default;
template <typename... Args>
constexpr explicit enum_type(Args... args) : value(((1 << underlying_value(args)) | ...)) {}
constexpr explicit enum_type(std::underlying_type_t<Enum> 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<Enum>) * 8; i++) {
if(value & (1 << i)) {
if(is_first) {
is_first = false;
} else {
masks += " | ";
}
masks += refl::enum_name<Enum>(static_cast<Enum>(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<Enum> value;
};
template <typename T>
requires requires { typename T::enum_tag; }
auto underlying_value(T value) {
return value.value;
}
template <typename T>
constexpr inline bool is_enum_v = std::is_enum_v<T> || requires { typename T::enum_tag; };
} // namespace clice