/* * 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 */ #pragma once #include "types/bits.hpp" #include "debug.hpp" #include #include namespace cruft { /////////////////////////////////////////////////////////////////////////// /// Rotate `value` left by `magnitude` bits. /// /// `magnitude` must not be greater than the bit count of `value`. template constexpr T rotatel [[gnu::pure]] (const T value, std::size_t magnitude) { CHECK_LE (magnitude, sizeof (value) * 8); 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 constexpr T rotater [[gnu::pure]] (const T value, std::size_t magnitude) { CHECK_LE (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 constexpr std::enable_if_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 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); } /////////////////////////////////////////////////////////////////////////// /// returns the integral value composed of the bits from `val' in the /// inclusive range [lo, hi]. template 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); return (value >> OffsetV) & MASK; } operator auto() const { return get (); } decltype(auto) operator+ () const { return +get (); } ValueT value; }; template std::ostream& operator<< (std::ostream &os, bitfield const &val) { return os << +ValueT(val); } }