// =====================================================================================================================
// fennec, a free and open source game engine
// Copyright © 2025 Medusa Slockbower
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
// =====================================================================================================================
///
/// \file bitfield.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_CONTAINERS_BITFIELD_H
#define FENNEC_CONTAINERS_BITFIELD_H
#include
#include
#include
namespace fennec
{
///
/// \brief Bitfield Container with basic Bit Ops
///
/// \details
/// | Property | Value |
/// |:-----------:|:------------------------------:|
/// | stable | Elements cannot be referenced. |
/// | dynamic | ⛔ |
/// | homogeneous | ✅ |
/// | distinct | ⛔ |
/// | ordered | ⛔ |
/// | space | \f$O(N)\f$ |
/// | linear | ✅ |
/// | access | \f$O(1)\f$ |
/// | find | \f$O(N)\f$ |
/// | insertion | ⛔ |
/// | deletion | ⛔ |
///
/// \tparam N The number of bits in the bitfield
template
struct bitfield {
// Constants ===========================================================================================================
public:
static constexpr size_t bits = N; //!< The number of bits in the bitfield
static constexpr size_t bytes = (N + 7) / 8; //!< The number of bytes that hold the bitfield
// Constructors ========================================================================================================
public:
///
/// \brief default constructor, initializes with \f$0\f$
constexpr bitfield()
: _bytes() {
}
///
/// \brief boolean array constructor
/// \param arr An array of boolean values resembling each bit.
explicit constexpr bitfield(const bool (&arr)[N])
: _bytes() {
for (size_t i = 0; i < arr; ++i) {
this->store(i, arr[i]);
}
}
///
/// \brief index array constructor
/// \param arr An array of indices values resembling which bits to set.
template
explicit constexpr bitfield(const size_t (&arr)[I])
: _bytes() {
for (size_t i : arr) {
this->set(i);
}
}
///
/// \brief variadic array constructor
/// \param args A set of indices values resembling which bits to set.
template
constexpr bitfield(ArgsT&&...args)
: _bytes() {
(this->store(fennec::forward(args), true), ...);
}
///
/// \param args A set of boolean values resembling each bit.
template requires((is_bool_v or is_convertible_v) and ...)
constexpr bitfield(ArgsT&&...args)
: _bytes() {
size_t i = 0;
(this->store(i++, fennec::forward(args)), ...);
}
///
/// \brief copy constructor
/// \param bf bitfield to copy
bitfield(const bitfield& bf)
: _bytes(bf._bytes) {
}
///
/// \brief move constructor
/// \param bf bitfield to move
bitfield(bitfield&& bf) noexcept
: _bytes(bf._bytes) {
}
///
/// \brief destructor
constexpr ~bitfield() = default;
///
/// \brief copy assignment
/// \param bf bitfield to copy
/// \returns a reference to self
bitfield& operator=(const bitfield& bf) = default;
///
/// \brief move assignment
/// \param bf bitfield to move
/// \returns a reference to self
bitfield& operator=(bitfield&& bf) noexcept = default;
///
/// \brief test a bit
/// \param i the index of the bit
/// \returns the value stored in the bit as a boolean
bool test(size_t i) const {
assertd(i < bits, "Index out of Bounds!");
size_t b = i / 8;
size_t o = i % 8;
return _bytes[b] & (1 << o);
}
///
/// \brief set a bit
/// \param i the index of the bit
void set(size_t i) {
assertd(i < bits, "Index out of Bounds!");
size_t b = i / 8;
size_t o = i % 8;
_bytes[b] |= (1 << o);
}
///
/// \brief clear a bit
/// \param i the index of the bit
void clear(size_t i) {
assertd(i < bits, "Index out of Bounds!");
size_t b = i / 8;
size_t o = i % 8;
_bytes[b] &= ~(1 << o);
}
///
/// \brief toggle a bit
/// \param i the index of the bit
void toggle(size_t i) {
assertd(i < bits, "Index out of Bounds!");
size_t b = i / 8;
size_t o = i % 8;
_bytes[b] ^= (1 << o);
}
///
/// \brief store \f$v\f$ in bit \f$i\f$
/// \param i
/// \param v
void store(size_t i, bool v) {
assertd(i < bits, "Index out of Bounds!");
size_t b = i / 8;
size_t o = i % 8;
(_bytes[b] &= ~((1 << o))) |= ((v << o));
}
///
/// \brief not operator
/// \returns a bitfield containing the bit-wise inverse
bitfield operator~() const {
bitfield res = *this;
res._inv_helper(make_index_metasequence_t{});
return res;
}
private:
array _bytes;
template
void _inv_helper(index_metasequence) {
((_bytes[I] = ~_bytes[I]), ...);
}
};
}
#endif // FENNEC_CONTAINERS_BITFIELD_H