2023-09-07 23:24:30 +01:00
|
|
|
#pragma once
|
|
|
|
|
|
2023-09-07 23:31:29 +01:00
|
|
|
#include <cstdint>
|
|
|
|
|
#include <cstddef>
|
|
|
|
|
#include <array>
|
|
|
|
|
#include <type_traits>
|
2023-09-07 23:24:30 +01:00
|
|
|
|
|
|
|
|
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 <std::size_t bitFieldRangeCount>
|
|
|
|
|
static constexpr std::uint8_t totalBitRangeLength(const std::array<BitFieldRange, bitFieldRangeCount>& ranges) {
|
|
|
|
|
auto output = std::uint8_t{0};
|
|
|
|
|
|
|
|
|
|
for (const auto& range : ranges) {
|
|
|
|
|
output += range.length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return output;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename SubjectType>
|
|
|
|
|
requires std::is_integral_v<SubjectType>
|
|
|
|
|
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 <typename SubjectType, std::size_t bitFieldRangeCount>
|
|
|
|
|
requires std::is_integral_v<SubjectType>
|
|
|
|
|
static constexpr SubjectType extractBitField(
|
|
|
|
|
SubjectType subject,
|
|
|
|
|
const std::array<BitFieldRange, bitFieldRangeCount>& ranges
|
|
|
|
|
) {
|
|
|
|
|
auto output = SubjectType{0};
|
|
|
|
|
|
|
|
|
|
for (const auto& range : ranges) {
|
2023-09-10 01:19:23 +01:00
|
|
|
output = static_cast<SubjectType>(
|
|
|
|
|
(output << range.length) | BitsetService::extractBitField(subject, range)
|
|
|
|
|
);
|
2023-09-07 23:24:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return output;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename SubjectType>
|
|
|
|
|
requires std::is_integral_v<SubjectType>
|
|
|
|
|
static constexpr SubjectType setBitField(SubjectType subject, const BitFieldRange& range) {
|
|
|
|
|
const auto mask = static_cast<SubjectType>(
|
|
|
|
|
~(-1LL << range.length) << (range.startPosition - range.length + 1)
|
|
|
|
|
);
|
|
|
|
|
return subject | mask;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename SubjectType, std::size_t bitFieldRangeCount>
|
|
|
|
|
requires std::is_integral_v<SubjectType>
|
|
|
|
|
static constexpr SubjectType setBitField(
|
|
|
|
|
SubjectType subject,
|
|
|
|
|
const std::array<BitFieldRange, bitFieldRangeCount>& ranges
|
|
|
|
|
) {
|
|
|
|
|
for (const auto& range : ranges) {
|
|
|
|
|
subject = BitsetService::setBitField(subject, range);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return subject;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename SubjectType>
|
|
|
|
|
requires std::is_integral_v<SubjectType>
|
|
|
|
|
static constexpr SubjectType clearBitField(SubjectType subject, const BitFieldRange& range) {
|
|
|
|
|
const auto mask = static_cast<SubjectType>(
|
|
|
|
|
~(~(-1LL << range.length) << (range.startPosition - range.length + 1))
|
|
|
|
|
);
|
|
|
|
|
return subject & mask;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename SubjectType, std::size_t bitFieldRangeCount>
|
|
|
|
|
requires std::is_integral_v<SubjectType>
|
|
|
|
|
static constexpr SubjectType clearBitField(
|
|
|
|
|
SubjectType subject,
|
|
|
|
|
const std::array<BitFieldRange, bitFieldRangeCount>& ranges
|
|
|
|
|
) {
|
|
|
|
|
for (const auto& range : ranges) {
|
|
|
|
|
subject = BitsetService::clearBitField(subject, range);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return subject;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|