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)
 |