162 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			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 : mijin::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)
 |