intial commit
This commit is contained in:
161
source/mijin/util/flag.hpp
Normal file
161
source/mijin/util/flag.hpp
Normal file
@@ -0,0 +1,161 @@
|
||||
|
||||
#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)
|
||||
Reference in New Issue
Block a user