diff --git a/include/boost/core/bit.hpp b/include/boost/core/bit.hpp new file mode 100644 index 0000000..22f098d --- /dev/null +++ b/include/boost/core/bit.hpp @@ -0,0 +1,134 @@ +#ifndef BOOST_CORE_BIT_HPP_INCLUDED +#define BOOST_CORE_BIT_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// boost/core/bit.hpp +// +// A portable version of the C++20 standard header +// +// Copyright 2020 Peter Dimov +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include +#include + +#define BOOST_CORE_BIT_CONSTEXPR + +namespace boost +{ +namespace core +{ + +// bit_cast +template +To bit_cast( From const & from) BOOST_NOEXCEPT +{ + BOOST_STATIC_ASSERT( sizeof(To) == sizeof(From) ); + + To to; + std::memcpy( &to, &from, sizeof(To) ); + return to; +} + +// counting +template +BOOST_CORE_BIT_CONSTEXPR int countl_zero( T x ) BOOST_NOEXCEPT; + +template +BOOST_CORE_BIT_CONSTEXPR int countl_one( T x ) BOOST_NOEXCEPT +{ + return boost::core::countl_zero( ~x ); +} + +template +BOOST_CORE_BIT_CONSTEXPR int countr_zero( T x ) BOOST_NOEXCEPT; + +template +BOOST_CORE_BIT_CONSTEXPR int countr_one( T x ) BOOST_NOEXCEPT +{ + return boost::core::countr_zero( ~x ); +} + +template +BOOST_CORE_BIT_CONSTEXPR int popcount( T x ) BOOST_NOEXCEPT; + +// rotating +template +BOOST_CXX14_CONSTEXPR T rotl( T x, int s ) BOOST_NOEXCEPT +{ + unsigned const mask = std::numeric_limits::digits - 1; + return x << (s & mask) | x >> ((-s) & mask); +} + +template +BOOST_CXX14_CONSTEXPR T rotr( T x, int s ) BOOST_NOEXCEPT +{ + unsigned const mask = std::numeric_limits::digits - 1; + return x >> (s & mask) | x << ((-s) & mask); +} + +// integral powers of 2 +template +BOOST_CONSTEXPR bool has_single_bit( T x ) BOOST_NOEXCEPT +{ + return x != 0 && ( x & ( x - 1 ) ) == 0; +} + +template +BOOST_CONSTEXPR T bit_width( T x ) BOOST_NOEXCEPT +{ + return std::numeric_limits::digits - boost::core::countl_zero( x ); +} + +template +BOOST_CONSTEXPR T bit_ceil( T x ) BOOST_NOEXCEPT; + +template +BOOST_CONSTEXPR T bit_floor( T x ) BOOST_NOEXCEPT +{ + return x == 0? 0: T(1) << ( boost::core::bit_width( x ) - 1 ); +} + +// endian + +#if !defined(BOOST_NO_CXX11_SCOPED_ENUMS) + +enum class endian +{ + little, + big, + // native = /* see description */ +}; + +typedef endian endian_type; + +#else + +namespace endian +{ + +enum type +{ + little, + big, + // native = /* see description */ +}; + +} // namespace endian + +typedef endian::type endian_type; + +#endif + +} // namespace core +} // namespace boost + +#endif // #ifndef BOOST_CORE_BIT_HPP_INCLUDED diff --git a/include/boost/core/detail/splitmix64.hpp b/include/boost/core/detail/splitmix64.hpp new file mode 100644 index 0000000..a7dc532 --- /dev/null +++ b/include/boost/core/detail/splitmix64.hpp @@ -0,0 +1,54 @@ +#ifndef BOOST_CORE_DETAIL_SPLITMIX64_HPP_INCLUDED +#define BOOST_CORE_DETAIL_SPLITMIX64_HPP_INCLUDED + +// Copyright 2020 Peter Dimov +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt +// +// An implementation of splitmix64 for testing purposes, +// derived from Sebastiano Vigna's public domain implementation +// http://xorshift.di.unimi.it/splitmix64.c + +#include + +namespace boost +{ +namespace detail +{ + +class splitmix64 +{ +private: + + boost::uint64_t x_; + +public: + + splitmix64(): x_( 0 ) + { + } + + explicit splitmix64( boost::uint64_t seed ): x_( seed ) + { + } + + boost::uint64_t operator()() + { + x_ += 0x9e3779b97f4a7c15; + + boost::uint64_t z = x_; + + z ^= z >> 30; + z *= 0xbf58476d1ce4e5b9; + z ^= z >> 27; + z *= 0x94d049bb133111eb; + z ^= z >> 31; + + return z; + } +}; + +} // namespace detail +} // namespace boost + +#endif // #ifndef BOOST_CORE_DETAIL_SPLITMIX64_HPP_INCLUDED diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 6aa1bf2..18856f7 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -222,5 +222,8 @@ run no_exceptions_support_test.cpp : : : off : no_exceptions run cmath_test.cpp ; +run bit_cast_test.cpp ; +run bit_rotate_test.cpp ; + use-project /boost/core/swap : ./swap ; build-project ./swap ; diff --git a/test/bit_cast_test.cpp b/test/bit_cast_test.cpp new file mode 100644 index 0000000..c9fba44 --- /dev/null +++ b/test/bit_cast_test.cpp @@ -0,0 +1,29 @@ +// Test for boost/core/bit.hpp +// +// Copyright 2020 Peter Dimov +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include +#include + +int main() +{ + { + float x = 0.89f; + boost::uint32_t y = boost::core::bit_cast( x ); + + BOOST_TEST( std::memcmp( &x, &y, sizeof(x) ) == 0 ); + } + + { + double x = 0.89; + boost::uint64_t y = boost::core::bit_cast( x ); + + BOOST_TEST( std::memcmp( &x, &y, sizeof(x) ) == 0 ); + } + + return boost::report_errors(); +} diff --git a/test/bit_rotate_test.cpp b/test/bit_rotate_test.cpp new file mode 100644 index 0000000..a81ea04 --- /dev/null +++ b/test/bit_rotate_test.cpp @@ -0,0 +1,168 @@ +// Test for boost/core/bit.hpp +// +// Copyright 2020 Peter Dimov +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include +#include +#include + +int const M = 256; + +template void test_rotate( T x ) +{ + for( int i = 0; i < M; ++i ) + { + BOOST_TEST_EQ( +boost::core::rotl( x, i ), +boost::core::rotr( x, -i ) ); + BOOST_TEST_EQ( +boost::core::rotl( x, -i ), +boost::core::rotr( x, i ) ); + + unsigned const width = std::numeric_limits::digits; + unsigned r = i & ( width - 1 ); + + if( r == 0 ) + { + BOOST_TEST_EQ( +boost::core::rotl( x, i ), +x ); + BOOST_TEST_EQ( +boost::core::rotr( x, i ), +x ); + } + else + { + BOOST_TEST_EQ( +boost::core::rotl( x, i ), +static_cast( (x << r) | (x >> (width - r)) ) ); + BOOST_TEST_EQ( +boost::core::rotr( x, i ), +static_cast( (x >> r) | (x << (width - r)) ) ); + } + } +} + +int main() +{ + { + boost::uint8_t x = 0x11; + + BOOST_TEST_EQ( +boost::core::rotl( x, 1 ), 0x22 ); + BOOST_TEST_EQ( +boost::core::rotr( x, 1 ), 0x88 ); + + x = 0x22; + + BOOST_TEST_EQ( +boost::core::rotl( x, 1 ), 0x44 ); + BOOST_TEST_EQ( +boost::core::rotr( x, 1 ), 0x11 ); + + x = 0x44; + + BOOST_TEST_EQ( +boost::core::rotl( x, 1 ), 0x88 ); + BOOST_TEST_EQ( +boost::core::rotr( x, 1 ), 0x22 ); + + x = 0x88; + + BOOST_TEST_EQ( +boost::core::rotl( x, 1 ), 0x11 ); + BOOST_TEST_EQ( +boost::core::rotr( x, 1 ), 0x44 ); + } + + { + boost::uint16_t x = 0x1111; + + BOOST_TEST_EQ( +boost::core::rotl( x, 1 ), 0x2222 ); + BOOST_TEST_EQ( +boost::core::rotr( x, 1 ), 0x8888 ); + + x = 0x2222; + + BOOST_TEST_EQ( +boost::core::rotl( x, 1 ), 0x4444 ); + BOOST_TEST_EQ( +boost::core::rotr( x, 1 ), 0x1111 ); + + x = 0x4444; + + BOOST_TEST_EQ( +boost::core::rotl( x, 1 ), 0x8888 ); + BOOST_TEST_EQ( +boost::core::rotr( x, 1 ), 0x2222 ); + + x = 0x8888; + + BOOST_TEST_EQ( +boost::core::rotl( x, 1 ), 0x1111 ); + BOOST_TEST_EQ( +boost::core::rotr( x, 1 ), 0x4444 ); + } + + { + boost::uint32_t x = 0x11111111; + + BOOST_TEST_EQ( +boost::core::rotl( x, 1 ), 0x22222222 ); + BOOST_TEST_EQ( +boost::core::rotr( x, 1 ), 0x88888888 ); + + x = 0x22222222; + + BOOST_TEST_EQ( +boost::core::rotl( x, 1 ), 0x44444444 ); + BOOST_TEST_EQ( +boost::core::rotr( x, 1 ), 0x11111111 ); + + x = 0x44444444; + + BOOST_TEST_EQ( +boost::core::rotl( x, 1 ), 0x88888888 ); + BOOST_TEST_EQ( +boost::core::rotr( x, 1 ), 0x22222222 ); + + x = 0x88888888; + + BOOST_TEST_EQ( +boost::core::rotl( x, 1 ), 0x11111111 ); + BOOST_TEST_EQ( +boost::core::rotr( x, 1 ), 0x44444444 ); + } + + { + boost::uint64_t x = 0x1111111111111111; + + BOOST_TEST_EQ( +boost::core::rotl( x, 1 ), 0x2222222222222222 ); + BOOST_TEST_EQ( +boost::core::rotr( x, 1 ), 0x8888888888888888 ); + + x = 0x2222222222222222; + + BOOST_TEST_EQ( +boost::core::rotl( x, 1 ), 0x4444444444444444 ); + BOOST_TEST_EQ( +boost::core::rotr( x, 1 ), 0x1111111111111111 ); + + x = 0x4444444444444444; + + BOOST_TEST_EQ( +boost::core::rotl( x, 1 ), 0x8888888888888888 ); + BOOST_TEST_EQ( +boost::core::rotr( x, 1 ), 0x2222222222222222 ); + + x = 0x8888888888888888; + + BOOST_TEST_EQ( +boost::core::rotl( x, 1 ), 0x1111111111111111 ); + BOOST_TEST_EQ( +boost::core::rotr( x, 1 ), 0x4444444444444444 ); + } + + for( int i = -M; i <= M; ++i ) + { + { + unsigned char x = 0; + BOOST_TEST_EQ( +boost::core::rotl( x, i ), +x ); + BOOST_TEST_EQ( +boost::core::rotr( x, i ), +x ); + } + + { + unsigned int x = 0; + BOOST_TEST_EQ( boost::core::rotl( x, i ), x ); + BOOST_TEST_EQ( boost::core::rotr( x, i ), x ); + } + + { + unsigned long x = 0; + BOOST_TEST_EQ( boost::core::rotl( x, i ), x ); + BOOST_TEST_EQ( boost::core::rotr( x, i ), x ); + } + + { + unsigned long long x = 0; + BOOST_TEST_EQ( boost::core::rotl( x, i ), x ); + BOOST_TEST_EQ( boost::core::rotr( x, i ), x ); + } + } + + boost::detail::splitmix64 rng; + + for( int i = 0; i < 1000; ++i ) + { + boost::uint64_t x = rng(); + + test_rotate( static_cast( x ) ); + test_rotate( static_cast( x ) ); + test_rotate( static_cast( x ) ); + test_rotate( static_cast( x ) ); + } + + return boost::report_errors(); +}