// ===================================================================================================================== // 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