mijin2/source/mijin/util/flag.hpp
2023-05-29 14:51:44 +02:00

162 lines
3.6 KiB
C++

#pragma once
#if !defined(MIJIN_UTIL_FLAG_HPP_INCLUDED)
#define MIJIN_UTIL_FLAG_HPP_INCLUDED 1
#include <cstdint>
#include "./traits.hpp"
#include "./types.hpp"
namespace mijin
{
//
// public defines
//
#define MIJIN_DEFINE_FLAG(name) \
struct name : Flag \
{ \
private: \
struct Proxy_ { \
uint8_t value; \
}; \
public: \
constexpr name() = default; \
constexpr name(const name&) = default; \
constexpr name(Proxy_ proxy) \
: Flag(proxy.value) {} \
constexpr explicit name(bool value) noexcept \
: Flag(value) {} \
name& operator=(const name&) = default; \
static constexpr Proxy_ YES{1}; \
static constexpr Proxy_ NO{0}; \
}
//
// public constants
//
//
// public types
//
struct Flag
{
std::uint8_t value;
Flag() = default;
Flag(const Flag&) = default;
explicit constexpr Flag(uint8_t value) noexcept : value(value) {}
Flag& operator=(const Flag&) = default;
constexpr bool operator ==(const Flag& other) const noexcept
{
return value == other.value;
}
constexpr bool operator !=(const Flag& other) const noexcept
{
return value != other.value;
}
constexpr bool operator !() const noexcept
{
return !value;
}
constexpr operator bool() const noexcept
{
return value != 0;
}
};
template<typename T>
concept FlagType = requires (T& value)
{
value = T::YES;
value = T::NO;
};
namespace impl
{
template<std::size_t offset, FlagType... TFlags>
class FlagSetStorage;
template<std::size_t offset, FlagType TFirst, FlagType... TMore>
class FlagSetStorage<offset, TFirst, TMore...> : public FlagSetStorage<offset + 1, TMore...>
{
private:
using base_t = FlagSetStorage<offset + 1, TMore...>;
static constexpr typename base_t::data_t BIT = (1 << offset);
public:
constexpr void set(TFirst value) noexcept
{
if (value)
{
base_t::data_ |= BIT;
}
else
{
base_t::data_ &= ~BIT;
}
}
constexpr bool get(TFirst) noexcept
{
return (base_t::data_ & BIT) != 0;
}
};
template<std::size_t offset>
class FlagSetStorage<offset>
{
protected:
using data_t = uint_next_t<offset>;
protected:
data_t data_ = data_t(0);
};
} // namespace impl
template<FlagType... TFlags>
class FlagSet
{
private:
using storage_t = impl::FlagSetStorage<0, TFlags...>;
private:
storage_t storage_;
public:
FlagSet() = default;
FlagSet(const FlagSet&) = default;
template<FlagType... TFlags2>
constexpr FlagSet(TFlags2... flags)
{
(set(flags), ...);
}
public:
FlagSet& operator=(const FlagSet&) = default;
template<FlagType T> requires is_any_type_v<T, TFlags...>
FlagSet& operator=(T flag) noexcept
{
reset(flag);
return *this;
}
template<FlagType T> requires is_any_type_v<T, TFlags...>
FlagSet& operator|=(T flag) noexcept
{
set(flag);
return *this;
}
template<FlagType T> requires is_any_type_v<T, TFlags...>
FlagSet& operator&=(T flag) noexcept
{
unset(flag);
}
};
//
// public functions
//
} // namespace mijin
#endif // !defined(MIJIN_UTIL_FLAG_HPP_INCLUDED)