133 lines
3.2 KiB
C++
133 lines
3.2 KiB
C++
|
|
#pragma once
|
|
|
|
#if !defined(MIJIN_UTIL_BITFLAGS_HPP_INCLUDED)
|
|
#define MIJIN_UTIL_BITFLAGS_HPP_INCLUDED 1
|
|
|
|
#include <bit>
|
|
#include <compare>
|
|
#include <cstddef>
|
|
|
|
#include "../util/traits.hpp"
|
|
|
|
namespace mijin
|
|
{
|
|
|
|
//
|
|
// public defines
|
|
//
|
|
|
|
//
|
|
// public constants
|
|
//
|
|
|
|
//
|
|
// public types
|
|
//
|
|
|
|
template<typename TBits>
|
|
struct BitFlags
|
|
{
|
|
using bits_t = TBits;
|
|
|
|
constexpr TBits& operator |=(const BitFlags& other) {
|
|
for (std::size_t idx = 0; idx < sizeof(TBits); ++idx) {
|
|
*(std::bit_cast<std::byte*>(asBits()) + idx) |= *(std::bit_cast<const std::byte*>(other.asBits()) + idx);
|
|
}
|
|
return *asBits();
|
|
}
|
|
constexpr TBits& operator &=(const BitFlags& other) {
|
|
for (std::size_t idx = 0; idx < sizeof(TBits); ++idx) {
|
|
*(std::bit_cast<std::byte*>(asBits()) + idx) &= *(std::bit_cast<const std::byte*>(other.asBits()) + idx);
|
|
}
|
|
return *asBits();
|
|
}
|
|
|
|
constexpr TBits& operator ^=(const BitFlags& other) {
|
|
for (std::size_t idx = 0; idx < sizeof(TBits); ++idx) {
|
|
*(std::bit_cast<std::byte*>(asBits()) + idx) ^= *(std::bit_cast<const std::byte*>(other.asBits()) + idx);
|
|
}
|
|
return *asBits();
|
|
}
|
|
|
|
constexpr TBits operator& (const BitFlags& other) const
|
|
{
|
|
TBits copy(*asBits());
|
|
copy &= other;
|
|
return copy;
|
|
}
|
|
|
|
constexpr TBits operator| (const BitFlags& other) const
|
|
{
|
|
TBits copy(*asBits());
|
|
copy |= other;
|
|
return copy;
|
|
}
|
|
|
|
constexpr TBits operator^ (const BitFlags& other) const
|
|
{
|
|
TBits copy(*asBits());
|
|
copy ^= other;
|
|
return copy;
|
|
}
|
|
|
|
explicit constexpr operator bool() const {
|
|
for (std::size_t idx = 0; idx < sizeof(TBits); ++idx) {
|
|
if (*(std::bit_cast<const std::byte*>(asBits()) + idx) != std::byte(0)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
constexpr bool operator!() const {
|
|
return !static_cast<bool>(*this);
|
|
}
|
|
|
|
auto operator<=>(const BitFlags&) const noexcept = default;
|
|
private:
|
|
constexpr TBits* asBits() { return static_cast<TBits*>(this); }
|
|
constexpr const TBits* asBits() const { return static_cast<const TBits*>(this); }
|
|
};
|
|
|
|
template<typename T>
|
|
constexpr bool is_bitflags_v = std::is_base_of_v<BitFlags<T>, T>;
|
|
|
|
template<typename T>
|
|
concept BitFlagsType = is_bitflags_v<T>;
|
|
|
|
//
|
|
// public functions
|
|
//
|
|
|
|
template<std::integral TInt, BitFlagsType T>
|
|
TInt bitFlagsToInt(const BitFlags<T>& flags) noexcept
|
|
{
|
|
static constexpr std::size_t BYTES = std::min(sizeof(T), sizeof(TInt));
|
|
TInt result = 0;
|
|
|
|
for (std::size_t off = 0; off < BYTES; ++off)
|
|
{
|
|
result |= static_cast<TInt>(*(std::bit_cast<const std::byte*>(&flags) + off)) << (off * 8);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
template<BitFlagsType T, std::integral TInt>
|
|
T bitFlagsFromInt(TInt intVal) noexcept
|
|
{
|
|
static constexpr std::size_t BYTES = std::min(sizeof(T), sizeof(TInt));
|
|
T result = {};
|
|
|
|
for (std::size_t off = 0; off < BYTES; ++off)
|
|
{
|
|
(*(std::bit_cast<std::byte*>(&result) + off)) = static_cast<std::byte>(intVal >> (off * 8));
|
|
}
|
|
|
|
return result;
|
|
}
|
|
} // namespace mijin
|
|
|
|
#endif // !defined(MIJIN_UTIL_BITFLAGS_HPP_INCLUDED)
|