1#ifndef LIBSBX_UTILITY_ENUM_HPP_
2#define LIBSBX_UTILITY_ENUM_HPP_
10#include <libsbx/utility/string_literal.hpp>
12namespace sbx::utility {
14template<
typename Enum>
15requires (std::is_enum_v<Enum>)
16constexpr auto to_underlying(
const Enum value) -> std::underlying_type_t<Enum> {
17 return static_cast<std::underlying_type_t<Enum>
>(value);
20template<
typename Enum>
21requires (std::is_enum_v<Enum>)
22constexpr auto from_underlying(
const std::underlying_type_t<Enum> value) -> Enum {
23 return static_cast<Enum
>(value);
26template<
auto... Values>
27requires (std::is_enum_v<
decltype(Values)> && ...)
30 inline static constexpr auto values = std::array{Values...};
32 inline static constexpr auto contains(
const typename decltype(values)::value_type value)
noexcept ->
bool {
33 for (
auto entry : values) {
42 inline static constexpr auto size()
noexcept -> std::size_t {
46 inline static constexpr auto is_empty()
noexcept -> std::size_t {
55 template<
typename Type>
56 requires (std::is_enum_v<Type>)
57 inline static constexpr auto contains(
const Type value)
noexcept ->
bool {
61 inline static constexpr auto size()
noexcept -> std::size_t {
65 inline static constexpr auto is_empty()
noexcept -> std::size_t {
71template<
typename Enum>
72requires (std::is_enum_v<Enum>)
75template<
typename Enum>
76requires (std::is_enum_v<Enum>)
79template<std::
size_t Shift>
80struct bit : std::integral_constant<std::size_t, (std::size_t{1} << Shift)> { };
82template<std::size_t Shift>
83inline constexpr auto bit_v = bit<Shift>::value;
85template<typename Enum, typename Underlying = std::underlying_type_t<Enum>>
86requires (std::is_enum_v<Enum>)
91 using value_type = Enum;
92 using underlying_type = Underlying;
94 constexpr bit_field() noexcept
95 : _value{underlying_type{0}} { }
97 constexpr bit_field(const value_type value) noexcept
98 : _value{to_underlying(value)} { }
100 explicit constexpr bit_field(const underlying_type value) noexcept
103 constexpr auto set(const value_type value) noexcept -> void {
104 _value |= static_cast<underlying_type>(value);
107 constexpr auto clear(const value_type value) noexcept -> void {
108 _value &= ~static_cast<underlying_type>(value);
111 constexpr auto has(
const value_type value)
const noexcept ->
bool {
112 return _value &
static_cast<underlying_type
>(value);
115 constexpr auto has_any() const noexcept ->
bool {
116 return _value != underlying_type{0};
119 constexpr auto has_none() const noexcept ->
bool {
120 return _value == underlying_type{0};
123 constexpr auto operator*() const noexcept -> value_type {
124 return from_underlying<value_type>(_value);
127 constexpr auto value() const -> value_type {
128 return static_cast<value_type
>(_value);
131 constexpr auto underlying() const -> underlying_type {
137 underlying_type _value;
141template<
typename Enum>
142requires (std::is_enum_v<Enum>)
145 std::string_view name;
148template<
typename Enum>
149requires (std::is_enum_v<Enum>)
153template<
typename Type>
154concept mapped_enum =
requires() {
155 std::is_enum_v<Type>;
159template<mapped_enum Enum>
160constexpr auto to_string(
const Enum value) -> std::string {
163 if (entry == std::ranges::end(enum_mapping<Enum>::values)) {
170template<mapped_enum Enum>
171constexpr auto from_string(
const std::string& name) -> std::optional<Enum> {
172 auto entry = std::ranges::find_if(enum_mapping<Enum>::values, [&name](
const auto& entry){
return entry.name == name; });
174 if (entry == std::ranges::end(enum_mapping<Enum>::values)) {
183template<
typename Type>
184requires (sbx::utility::is_bit_field_v<Type>)
185constexpr auto operator|(
const Type lhs,
const Type rhs) -> Type {
186 return sbx::utility::from_underlying<Type>(sbx::utility::to_underlying(lhs) | sbx::utility::to_underlying(rhs));
190template<
typename Type>
191requires (sbx::utility::is_bit_field_v<Type>)
192constexpr auto operator&(
const Type lhs,
const Type rhs) -> Type {
193 return sbx::utility::from_underlying<Type>(sbx::utility::to_underlying(lhs) & sbx::utility::to_underlying(rhs));