diff --git a/src/Services/BitsetService.hpp b/src/Services/BitsetService.hpp new file mode 100644 index 00000000..cae9d36e --- /dev/null +++ b/src/Services/BitsetService.hpp @@ -0,0 +1,102 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace Services +{ + class BitsetService + { + public: + struct BitFieldRange + { + std::uint8_t startPosition; + std::uint8_t length; + + constexpr BitFieldRange(std::uint8_t startPosition, std::uint8_t length) + : startPosition(startPosition) + , length(length) + {} + }; + + template + static constexpr std::uint8_t totalBitRangeLength(const std::array& ranges) { + auto output = std::uint8_t{0}; + + for (const auto& range : ranges) { + output += range.length; + } + + return output; + } + + template + requires std::is_integral_v + static constexpr SubjectType extractBitField(SubjectType subject, const BitFieldRange& range) { + const auto mask = BitsetService::setBitField(SubjectType{0}, range); + return (subject & mask) >> (range.startPosition - range.length + 1); + } + + template + requires std::is_integral_v + static constexpr SubjectType extractBitField( + SubjectType subject, + const std::array& ranges + ) { + auto output = SubjectType{0}; + + for (const auto& range : ranges) { + output = (output << range.length) | BitsetService::extractBitField(subject, range); + } + + return output; + } + + template + requires std::is_integral_v + static constexpr SubjectType setBitField(SubjectType subject, const BitFieldRange& range) { + const auto mask = static_cast( + ~(-1LL << range.length) << (range.startPosition - range.length + 1) + ); + return subject | mask; + } + + template + requires std::is_integral_v + static constexpr SubjectType setBitField( + SubjectType subject, + const std::array& ranges + ) { + for (const auto& range : ranges) { + subject = BitsetService::setBitField(subject, range); + } + + return subject; + } + + template + requires std::is_integral_v + static constexpr SubjectType clearBitField(SubjectType subject, const BitFieldRange& range) { + const auto mask = static_cast( + ~(~(-1LL << range.length) << (range.startPosition - range.length + 1)) + ); + return subject & mask; + } + + template + requires std::is_integral_v + static constexpr SubjectType clearBitField( + SubjectType subject, + const std::array& ranges + ) { + for (const auto& range : ranges) { + subject = BitsetService::clearBitField(subject, range); + } + + return subject; + } + }; +}