@ -8,26 +8,15 @@
# include <bitset>
# include <climits>
# include <cstddef>
# include <concepts>
# include <bit>
# include "common/common_types.h"
# include "common/assert.h"
namespace mcl {
namespace detail {
template < typename T , typename U >
concept SameHelper = std : : is_same_v < T , U > ;
} // namespace detail
template < typename T , typename U >
concept SameAs = detail : : SameHelper < T , U > & & detail : : SameHelper < U , T > ;
template < typename T , typename . . . U >
concept IsAnyOf = ( SameAs < T , U > | | . . . ) ;
/// Integral upon which bit operations can be safely performed.
template < typename T >
concept BitIntegral = IsAnyOf < T , u8 , u16 , u32 , u64 , std : : uintptr_t , size_t > ;
template < typename T >
constexpr std : : size_t bitsizeof = CHAR_BIT * sizeof ( T ) ;
} // namespace mcl
namespace mcl : : bit {
@ -71,58 +60,37 @@ constexpr u64 swap_words_64(u64 value) {
| ( ( value & 0x00000000ffffffffull ) < < 32 ) ;
}
template < BitIntegral T >
constexpr T rotate_right ( T x , size_t amount ) {
amount % = bitsizeof < T > ;
if ( amount = = 0 ) {
return x ;
}
return static_cast < T > ( ( x > > amount ) | ( x < < ( bitsizeof < T > - amount ) ) ) ;
}
template < BitIntegral T >
constexpr T rotate_left ( T x , size_t amount ) {
amount % = bitsizeof < T > ;
if ( amount = = 0 ) {
return x ;
}
return static_cast < T > ( ( x < < amount ) | ( x > > ( bitsizeof < T > - amount ) ) ) ;
}
/// Create a mask with `count` number of one bits.
template < size_t count , BitI ntegral T >
template < size_t count , std : : integral T >
constexpr T ones ( ) {
static_assert ( count < = bitsizeof < T > , " count larger than bitsize of T " ) ;
if constexpr ( count = = 0 ) {
return 0 ;
} else {
return static_cast < T > ( ~ static_cast < T > ( 0 ) ) > > ( bitsizeof < T > - count ) ;
return T ( ~ T ( 0 ) ) > > ( bitsizeof < T > - count ) ;
}
}
/// Create a mask with `count` number of one bits.
template < BitI ntegral T >
template < std : : integral T >
constexpr T ones ( size_t count ) {
ASSERT ( count < = bitsizeof < T > & & " count larger than bitsize of T " ) ;
if ( count = = 0 ) {
if ( count = = 0 )
return 0 ;
}
return static_cast < T > ( ~ static_cast < T > ( 0 ) ) > > ( bitsizeof < T > - count ) ;
return T ( ~ T ( 0 ) ) > > ( bitsizeof < T > - count ) ;
}
/// Create a mask of type T for bits [begin_bit, end_bit] inclusive.
template < size_t begin_bit , size_t end_bit , BitI ntegral T >
template < size_t begin_bit , size_t end_bit , std : : i ntegral T >
constexpr T mask ( ) {
static_assert ( begin_bit < = end_bit , " invalid bit range (position of beginning bit cannot be greater than that of end bit) " ) ;
static_assert ( begin_bit < bitsizeof < T > , " begin_bit must be smaller than size of T " ) ;
static_assert ( end_bit < bitsizeof < T > , " end_bit must be smaller than size of T " ) ;
return ones < end_bit - begin_bit + 1 , T > ( ) < < begin_bit ;
}
/// Create a mask of type T for bits [begin_bit, end_bit] inclusive.
template < BitI ntegral T >
template < std : : i ntegral T >
constexpr T mask ( size_t begin_bit , size_t end_bit ) {
ASSERT ( begin_bit < = end_bit & & " invalid bit range (position of beginning bit cannot be greater than that of end bit) " ) ;
ASSERT ( begin_bit < bitsizeof < T > & & " begin_bit must be smaller than size of T " ) ;
@ -131,101 +99,100 @@ constexpr T mask(size_t begin_bit, size_t end_bit) {
}
/// Extract bits [begin_bit, end_bit] inclusive from value of type T.
template < size_t begin_bit , size_t end_bit , BitI ntegral T >
template < size_t begin_bit , size_t end_bit , std : : i ntegral T >
constexpr T get_bits ( T value ) {
constexpr T m = mask < begin_bit , end_bit , T > ( ) ;
return ( value & m ) > > begin_bit ;
}
/// Extract bits [begin_bit, end_bit] inclusive from value of type T.
template < BitI ntegral T >
template < std : : i ntegral T >
constexpr T get_bits ( size_t begin_bit , size_t end_bit , T value ) {
const T m = mask < T > ( begin_bit , end_bit ) ;
return ( value & m ) > > begin_bit ;
}
/// Clears bits [begin_bit, end_bit] inclusive of value of type T.
template < size_t begin_bit , size_t end_bit , BitI ntegral T >
template < size_t begin_bit , size_t end_bit , std : : i ntegral T >
constexpr T clear_bits ( T value ) {
constexpr T m = mask < begin_bit , end_bit , T > ( ) ;
return value & ~ m ;
}
/// Clears bits [begin_bit, end_bit] inclusive of value of type T.
template < BitI ntegral T >
template < std : : i ntegral T >
constexpr T clear_bits ( size_t begin_bit , size_t end_bit , T value ) {
const T m = mask < T > ( begin_bit , end_bit ) ;
return value & ~ m ;
}
/// Modifies bits [begin_bit, end_bit] inclusive of value of type T.
template < size_t begin_bit , size_t end_bit , BitI ntegral T >
template < size_t begin_bit , size_t end_bit , std : : i ntegral T >
constexpr T set_bits ( T value , T new_bits ) {
constexpr T m = mask < begin_bit , end_bit , T > ( ) ;
return ( value & ~ m ) | ( ( new_bits < < begin_bit ) & m ) ;
}
/// Modifies bits [begin_bit, end_bit] inclusive of value of type T.
template < BitI ntegral T >
template < std : : i ntegral T >
constexpr T set_bits ( size_t begin_bit , size_t end_bit , T value , T new_bits ) {
const T m = mask < T > ( begin_bit , end_bit ) ;
return ( value & ~ m ) | ( ( new_bits < < begin_bit ) & m ) ;
}
/// Extract bit at bit_position from value of type T.
template < size_t bit_position , BitI ntegral T >
template < size_t bit_position , std : : i ntegral T >
constexpr bool get_bit ( T value ) {
constexpr T m = mask < bit_position , bit_position , T > ( ) ;
return ( value & m ) ! = 0 ;
}
/// Extract bit at bit_position from value of type T.
template < BitI ntegral T >
template < std : : i ntegral T >
constexpr bool get_bit ( size_t bit_position , T value ) {
const T m = mask < T > ( bit_position , bit_position ) ;
return ( value & m ) ! = 0 ;
}
/// Clears bit at bit_position of value of type T.
template < size_t bit_position , BitI ntegral T >
template < size_t bit_position , std : : i ntegral T >
constexpr T clear_bit ( T value ) {
constexpr T m = mask < bit_position , bit_position , T > ( ) ;
return value & ~ m ;
}
/// Clears bit at bit_position of value of type T.
template < BitI ntegral T >
template < std : : i ntegral T >
constexpr T clear_bit ( size_t bit_position , T value ) {
const T m = mask < T > ( bit_position , bit_position ) ;
return value & ~ m ;
}
/// Modifies bit at bit_position of value of type T.
template < size_t bit_position , BitI ntegral T >
template < size_t bit_position , std : : i ntegral T >
constexpr T set_bit ( T value , bool new_bit ) {
constexpr T m = mask < bit_position , bit_position , T > ( ) ;
return ( value & ~ m ) | ( new_bit ? m : static_cast < T > ( 0 ) ) ;
return ( value & ~ m ) | ( new_bit ? m : T ( 0 ) ) ;
}
/// Modifies bit at bit_position of value of type T.
template < BitI ntegral T >
template < std : : i ntegral T >
constexpr T set_bit ( size_t bit_position , T value , bool new_bit ) {
const T m = mask < T > ( bit_position , bit_position ) ;
return ( value & ~ m ) | ( new_bit ? m : static_cast < T > ( 0 ) ) ;
return ( value & ~ m ) | ( new_bit ? m : T ( 0 ) ) ;
}
/// Sign-extends a value that has bit_count bits to the full bitwidth of type T.
template < size_t bit_count , BitI ntegral T >
template < size_t bit_count , std : : i ntegral T >
constexpr T sign_extend ( T value ) {
static_assert ( bit_count ! = 0 , " cannot sign-extend zero-sized value " ) ;
using S = std : : make_signed_t < T > ;
constexpr size_t shift_amount = bitsizeof < T > - bit_count ;
return static_cast < T > ( static_cast < S > ( value < < shift_amount ) > > shift_amount ) ;
return T ( S ( value < < shift_amount ) > > shift_amount ) ;
}
/// Sign-extends a value that has bit_count bits to the full bitwidth of type T.
template < BitI ntegral T >
template < std : : i ntegral T >
constexpr T sign_extend ( size_t bit_count , T value ) {
ASSERT ( bit_count ! = 0 & & " cannot sign-extend zero-sized value " ) ;
using S = std : : make_signed_t < T > ;
@ -234,78 +201,42 @@ constexpr T sign_extend(size_t bit_count, T value) {
}
/// Replicate an element across a value of type T.
template < size_t element_size , BitI ntegral T >
template < size_t element_size , std : : i ntegral T >
constexpr T replicate_element ( T value ) {
static_assert ( element_size < = bitsizeof < T > , " element_size is too large " ) ;
static_assert ( bitsizeof < T > % element_size = = 0 , " bitsize of T not divisible by element_size " ) ;
if constexpr ( element_size = = bitsizeof < T > ) {
return value ;
} else {
return replicate_element < element_size * 2 , T > ( static_cast < T > ( value | ( value < < element_size ) ) ) ;
return replicate_element < element_size * 2 , T > ( T ( value | ( value < < element_size ) ) ) ;
}
}
/// Replicate an element of type U across a value of type T.
template < BitIntegral U , BitI ntegral T >
template < std : : integral U , std : : i ntegral T >
constexpr T replicate_element ( T value ) {
static_assert ( bitsizeof < U > < = bitsizeof < T > , " element_size is too large " ) ;
return replicate_element < bitsizeof < U > , T > ( value ) ;
}
/// Replicate an element across a value of type T.
template < BitI ntegral T >
template < std : : i ntegral T >
constexpr T replicate_element ( size_t element_size , T value ) {
ASSERT ( element_size < = bitsizeof < T > & & " element_size is too large " ) ;
ASSERT ( bitsizeof < T > % element_size = = 0 & & " bitsize of T not divisible by element_size " ) ;
if ( element_size = = bitsizeof < T > )
return value ;
return replicate_element < T > ( element_size * 2 , static_cast < T > ( value | ( value < < element_size ) ) ) ;
return replicate_element < T > ( element_size * 2 , T ( value | ( value < < element_size ) ) ) ;
}
template < BitI ntegral T >
template < std : : i ntegral T >
constexpr bool most_significant_bit ( T value ) {
return get_bit < bitsizeof < T > - 1 , T > ( value ) ;
}
template < BitIntegral T >
inline size_t count_ones ( T x ) {
return std : : bitset < bitsizeof < T > > ( x ) . count ( ) ;
}
template < BitIntegral T >
constexpr size_t count_leading_zeros ( T x ) {
size_t result = bitsizeof < T > ;
while ( x ! = 0 ) {
x > > = 1 ;
result - - ;
}
return result ;
}
template < BitIntegral T >
template < std : : integral T >
constexpr int highest_set_bit ( T x ) {
int result = - 1 ;
while ( x ! = 0 ) {
x > > = 1 ;
result + + ;
}
return result ;
}
template < BitIntegral T >
constexpr size_t lowest_set_bit ( T x ) {
if ( x = = 0 ) {
return bitsizeof < T > ;
}
size_t result = 0 ;
while ( ( x & 1 ) = = 0 ) {
x > > = 1 ;
result + + ;
}
return result ;
return std : : bit_width ( x ) - 1 ;
}
} // namespace mcl::bit