mijin2/source/mijin/util/bitflags.hpp

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)