226 lines
6.4 KiB
C++
226 lines
6.4 KiB
C++
/*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* Copyright 2011-2018 Danny Robson <danny@nerdcruft.net>
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "debug/assert.hpp"
|
|
|
|
#include <type_traits>
|
|
#include <cstdint>
|
|
|
|
|
|
namespace cruft {
|
|
///////////////////////////////////////////////////////////////////////////
|
|
/// Rotate `value` left by `magnitude` bits.
|
|
///
|
|
/// `magnitude` must not be greater than the bit count of `value`.
|
|
template <typename T>
|
|
constexpr T
|
|
rotatel [[gnu::pure]] (const T value, std::size_t magnitude)
|
|
{
|
|
CHECK_LT (magnitude, sizeof (value) * 8u);
|
|
|
|
return (value << magnitude) | (value >> (sizeof (value) * 8 - magnitude));
|
|
}
|
|
|
|
|
|
///------------------------------------------------------------------------
|
|
/// Rotate `value` right by `magnitude` bits.
|
|
///
|
|
/// `magnitude` must not be greater than the bit count of `value`.
|
|
template <typename T>
|
|
constexpr T
|
|
rotater [[gnu::pure]] (const T value, std::size_t magnitude)
|
|
{
|
|
CHECK_LT (magnitude, sizeof (value) * 8);
|
|
|
|
return (value >> magnitude) | (value << (sizeof (value) * 8 - magnitude));
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
/// Reverse the order of bits in the supplied value.
|
|
///
|
|
/// Adapted from 'bit twiddling hacks'
|
|
template <typename T>
|
|
constexpr
|
|
std::enable_if_t<std::is_integral<T>::value, T>
|
|
reverse (T src)
|
|
{
|
|
T dst = src; // dst will be reversed bits of v; first get LSB of v
|
|
|
|
int bits = sizeof (src) * 8 - 1; // extra shift needed at end
|
|
for (src >>= 1; src; src >>= 1) {
|
|
dst <<= 1;
|
|
dst |= src & 1;
|
|
bits--;
|
|
}
|
|
|
|
dst <<= bits; // shift when src's highest bits are zero
|
|
return dst;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
/// Reverse the order of bits in the supplied value.
|
|
///
|
|
/// Adapted from 'bit twiddling hacks'
|
|
template <>
|
|
constexpr
|
|
uint8_t
|
|
reverse (uint8_t val)
|
|
{
|
|
return ((val * 0x80200802ULL) & 0x0884422110ULL) * 0x0101010101ULL >> 32;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
/// Calculates the number of bits that are set.
|
|
constexpr unsigned
|
|
popcount (unsigned char t)
|
|
{
|
|
return __builtin_popcount (t);
|
|
}
|
|
|
|
|
|
///------------------------------------------------------------------------
|
|
/// Calculates the number of bits that are set.
|
|
constexpr unsigned
|
|
popcount (unsigned short t)
|
|
{
|
|
return __builtin_popcount (t);
|
|
}
|
|
|
|
|
|
///------------------------------------------------------------------------
|
|
/// Calculates the number of bits that are set.
|
|
constexpr unsigned
|
|
popcount (unsigned t)
|
|
{
|
|
return __builtin_popcount (t);
|
|
}
|
|
|
|
|
|
///------------------------------------------------------------------------
|
|
/// Calculates the number of bits that are set.
|
|
constexpr unsigned long
|
|
popcount (unsigned long t)
|
|
{
|
|
return __builtin_popcountl (t);
|
|
}
|
|
|
|
|
|
///------------------------------------------------------------------------
|
|
/// Calculates the number of bits that are set.
|
|
constexpr unsigned long long
|
|
popcount (unsigned long long t)
|
|
{
|
|
return __builtin_popcountll (t);
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
/// Count trailing zeroes
|
|
constexpr unsigned int
|
|
ctz (unsigned int x) noexcept
|
|
{
|
|
return __builtin_ctz (x);
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------
|
|
constexpr unsigned long
|
|
ctz (unsigned long x) noexcept
|
|
{
|
|
return __builtin_ctzl (x);
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------
|
|
constexpr unsigned long long
|
|
ctz (unsigned long long x) noexcept
|
|
{
|
|
return __builtin_ctzll (x);
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
/// returns the integral value composed of the bits from `val' in the
|
|
/// inclusive range [lo, hi].
|
|
template <typename ValueT, typename IndexT>
|
|
constexpr ValueT
|
|
from_bits (ValueT val, IndexT hi, IndexT lo)
|
|
{
|
|
CHECK_LT (hi, IndexT (sizeof (ValueT) * 8));
|
|
CHECK_LT (lo, IndexT (sizeof (ValueT) * 8));
|
|
CHECK_GE (hi, 0);
|
|
CHECK_GE (lo, 1);
|
|
CHECK_GE (hi, lo);
|
|
|
|
ValueT zero = 0;
|
|
ValueT ones = ~zero;
|
|
|
|
return (val >> lo) & (ones >> (sizeof (ValueT) * 8 - (hi - lo + 1)));
|
|
}
|
|
|
|
|
|
/// A convenience wrapper that provides access to a range of bits in an
|
|
/// underlying integral value.
|
|
///
|
|
/// This class is most useful as part of a union where each has differing
|
|
/// offsets and sizes that cover the underlying type.
|
|
///
|
|
/// A conversion operator is supplied for accessing the bit value.
|
|
///
|
|
/// ValueT must support bit shifting and bitwise operators (primarily
|
|
/// bitwise and).
|
|
///
|
|
/// \tparam ValueT the underlying integral type
|
|
/// \tparam OffsetV the index of the first bit of the range (where 0 is
|
|
/// least significant)
|
|
/// \tparam SizeV the number of bits in the range. Must be strictly
|
|
/// positive.
|
|
template <
|
|
typename ValueT,
|
|
size_t OffsetV,
|
|
size_t SizeV
|
|
>
|
|
class [[gnu::packed]] bitfield {
|
|
public:
|
|
static_assert (SizeV > 0);
|
|
static_assert (OffsetV + SizeV <= sizeof (ValueT) * 8);
|
|
|
|
constexpr ValueT get (void) const
|
|
{
|
|
auto const MASK = ~(~0u << SizeV);
|
|
ValueT shifted = value >> OffsetV;
|
|
ValueT masked = shifted & MASK;
|
|
return masked;
|
|
}
|
|
|
|
operator ValueT () const { return get (); }
|
|
|
|
auto operator+ () const { return +get (); }
|
|
|
|
ValueT value;
|
|
};
|
|
|
|
template <typename OperandT, typename BitfieldT, size_t OffsetV, size_t SizeV>
|
|
bool operator== (bitfield<BitfieldT,OffsetV,SizeV> const &a, OperandT const &b)
|
|
{
|
|
return a.get () == b;
|
|
}
|
|
|
|
|
|
template <typename ValueT, size_t Offset, size_t Size>
|
|
std::ostream& operator<< (std::ostream &os, bitfield<ValueT,Offset,Size> const &val)
|
|
{
|
|
return os << +ValueT(val);
|
|
}
|
|
}
|