163 lines
3.8 KiB
C++
163 lines
3.8 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"
|
|
#include "../internal/common.hpp"
|
|
|
|
namespace mijin
|
|
{
|
|
|
|
//
|
|
// public defines
|
|
//
|
|
|
|
#define MIJIN_DEFINE_FLAG(name) \
|
|
struct name : mijin::Flag \
|
|
{ \
|
|
private: \
|
|
struct Proxy_ { \
|
|
uint8_t value; \
|
|
}; \
|
|
public: \
|
|
constexpr name() = default; \
|
|
constexpr name(const name&) = default; \
|
|
constexpr name(Proxy_ proxy) MIJIN_NOEXCEPT \
|
|
: Flag(proxy.value) {} \
|
|
constexpr explicit name(bool value) MIJIN_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) MIJIN_NOEXCEPT : value(value) {}
|
|
|
|
Flag& operator=(const Flag&) = default;
|
|
|
|
constexpr bool operator ==(const Flag& other) const MIJIN_NOEXCEPT
|
|
{
|
|
return value == other.value;
|
|
}
|
|
constexpr bool operator !=(const Flag& other) const MIJIN_NOEXCEPT
|
|
{
|
|
return value != other.value;
|
|
}
|
|
constexpr bool operator !() const MIJIN_NOEXCEPT
|
|
{
|
|
return !value;
|
|
}
|
|
constexpr operator bool() const MIJIN_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) MIJIN_NOEXCEPT
|
|
{
|
|
if (value)
|
|
{
|
|
base_t::data_ |= BIT;
|
|
}
|
|
else
|
|
{
|
|
base_t::data_ &= ~BIT;
|
|
}
|
|
}
|
|
constexpr bool get(TFirst) MIJIN_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) MIJIN_NOEXCEPT
|
|
{
|
|
reset(flag);
|
|
return *this;
|
|
}
|
|
template<FlagType T> requires is_any_type_v<T, TFlags...>
|
|
FlagSet& operator|=(T flag) MIJIN_NOEXCEPT
|
|
{
|
|
set(flag);
|
|
return *this;
|
|
}
|
|
template<FlagType T> requires is_any_type_v<T, TFlags...>
|
|
FlagSet& operator&=(T flag) MIJIN_NOEXCEPT
|
|
{
|
|
unset(flag);
|
|
}
|
|
};
|
|
|
|
//
|
|
// public functions
|
|
//
|
|
|
|
} // namespace mijin
|
|
|
|
#endif // !defined(MIJIN_UTIL_FLAG_HPP_INCLUDED)
|