Compare commits

..

8 Commits

Author SHA1 Message Date
c659255289 Added VS2022 job and C++20 and C++latest jobs to AppVeyor CI. 2022-06-06 02:55:11 +03:00
49195acf60 Enabled testing with GNU extensions in GitHub Actions. 2022-01-16 18:29:54 +03:00
bc9b0e6177 Implemented integer_log2 in terms of countl_zero from Boost.Core.
This allows to use compiler intrinsics and specialized hardware
instructions to compute log2, which results in better performance.

Also, added tests for the generic implementation using Boost.Multiprecision
integers.

Closes https://github.com/boostorg/integer/issues/31.
2022-01-16 15:20:37 +03:00
c6564a2d2b Merge pull request #26 from bernardosulzbach/documentation-typo-fix
Fixed a typo in ::least
2022-01-15 22:19:23 +03:00
16ef530fcf Use up to date includes for lightweight_test.hpp. 2021-12-21 20:45:00 +03:00
c5df07cb21 Simplified integer_log2 implementation.
Removed unnecessary template specializations, removed workaround for
compilers not supporting partial template specializations. Use unsigned
integers for bit counting, which allows to replace the division with
a shift.
2021-12-21 20:39:22 +03:00
a832e8fe65 Added a test for integer_log2. 2021-12-21 20:36:24 +03:00
ba7ea7f846 Fixed a typo in ::least 2021-01-31 14:03:24 +01:00
11 changed files with 317 additions and 95 deletions

View File

@ -98,7 +98,7 @@ jobs:
install:
- g++-10
- toolset: gcc-11
cxxstd: "03,11,14,17,20"
cxxstd: "03-gnu,11-gnu,14-gnu,17-gnu,20-gnu"
os: ubuntu-20.04
install:
- g++-11
@ -106,7 +106,7 @@ jobs:
- "ppa:ubuntu-toolchain-r/test"
- name: UBSAN
toolset: gcc-11
cxxstd: "03,11,14,17,20"
cxxstd: "03-gnu,11-gnu,14-gnu,17-gnu,20-gnu"
ubsan: 1
build_variant: debug
os: ubuntu-20.04
@ -203,13 +203,13 @@ jobs:
- clang-11
- toolset: clang
compiler: clang++-12
cxxstd: "03,11,14,17,20"
cxxstd: "03-gnu,11-gnu,14-gnu,17-gnu,20-gnu"
os: ubuntu-20.04
install:
- clang-12
- toolset: clang
compiler: clang++-12
cxxstd: "03,11,14,17,20"
cxxstd: "03-gnu,11-gnu,14-gnu,17-gnu,20-gnu"
os: ubuntu-20.04
install:
- clang-12
@ -217,10 +217,34 @@ jobs:
- libc++abi-12-dev
cxxflags: -stdlib=libc++
linkflags: -stdlib=libc++
- toolset: clang
compiler: clang++-13
cxxstd: "03-gnu,11-gnu,14-gnu,17-gnu,20-gnu"
os: ubuntu-20.04
install:
- clang-13
sources:
- "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-13 main"
source_keys:
- "https://apt.llvm.org/llvm-snapshot.gpg.key"
- toolset: clang
compiler: clang++-13
cxxstd: "03-gnu,11-gnu,14-gnu,17-gnu,20-gnu"
os: ubuntu-20.04
install:
- clang-13
- libc++-13-dev
- libc++abi-13-dev
sources:
- "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-13 main"
source_keys:
- "https://apt.llvm.org/llvm-snapshot.gpg.key"
cxxflags: -stdlib=libc++
linkflags: -stdlib=libc++
- name: UBSAN
toolset: clang
compiler: clang++-12
cxxstd: "03,11,14,17,20"
cxxstd: "03-gnu,11-gnu,14-gnu,17-gnu,20-gnu"
cxxflags: -stdlib=libc++
linkflags: -stdlib=libc++
ubsan: 1

View File

@ -18,19 +18,24 @@ environment:
ADDRMD: 32
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
- TOOLSET: msvc-14.0
CXXSTD: 14,latest
ADDRMD: 32,64
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
- TOOLSET: msvc-14.1
CXXSTD: 14,17
CXXSTD: 14,17,latest
ADDRMD: 32,64
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
- TOOLSET: msvc-14.2
ADDRMD: 32,64
CXXSTD: 14,17
CXXSTD: 14,17,20,latest
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
- TOOLSET: msvc-14.3
ADDRMD: 32,64
CXXSTD: 14,17,20,latest
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
- TOOLSET: clang-win
ADDRMD: 32,64
CXXSTD: 14,17
CXXSTD: 14,17,latest
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
- TOOLSET: gcc
CXXSTD: 03,11,14,1z

View File

@ -285,7 +285,7 @@ The following table describes each template's criteria.
[*only] if there exists a type with exactly N bits.]
]
[
[[^boost::int_max_value_t<V>::last]]
[[^boost::int_max_value_t<V>::least]]
[The smallest, built-in, signed integral type that can hold all the values in the inclusive range ['0 - V].
The parameter should be a positive number.]
]

View File

@ -4,7 +4,8 @@
// Gives the integer part of the logarithm, in base 2, of a
// given number. Behavior is undefined if the argument is <= 0.
//
// Copyright (c) 2003-2004, 2008 Gennaro Prota
// Copyright (c) 2003-2004, 2008 Gennaro Prota
// Copyright (c) 2022 Andrey Semashev
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
@ -15,98 +16,102 @@
#ifndef BOOST_INTEGER_INTEGER_LOG2_HPP
#define BOOST_INTEGER_INTEGER_LOG2_HPP
#include <boost/limits.hpp>
#include <climits>
#include <limits>
#include <boost/config.hpp>
#include <boost/assert.hpp>
#if defined(BOOST_BORLANDC)
#include <climits>
#endif
#include <boost/cstdint.hpp>
#include <boost/core/bit.hpp>
#include <boost/core/enable_if.hpp>
#include <boost/type_traits/is_integral.hpp>
#include <boost/type_traits/make_unsigned.hpp>
namespace boost {
namespace detail {
namespace detail {
template <typename T>
int integer_log2_impl(T x, int n) {
// helper to find the maximum power of two
// less than p
template< unsigned int p, unsigned int n, bool = ((2u * n) < p) >
struct max_pow2_less :
public max_pow2_less< p, 2u * n >
{
};
int result = 0;
template< unsigned int p, unsigned int n >
struct max_pow2_less< p, n, false >
{
BOOST_STATIC_CONSTANT(unsigned int, value = n);
};
while (x != 1) {
template< typename T >
inline typename boost::disable_if< boost::is_integral< T >, int >::type integer_log2_impl(T x)
{
unsigned int n = detail::max_pow2_less<
std::numeric_limits< T >::digits,
CHAR_BIT / 2u
>::value;
const T t = static_cast<T>(x >> n);
if (t) {
result += n;
x = t;
}
n /= 2;
}
return result;
}
// helper to find the maximum power of two
// less than p (more involved than necessary,
// to avoid PTS)
//
template <int p, int n>
struct max_pow2_less {
enum { c = 2*n < p };
BOOST_STATIC_CONSTANT(int, value =
c ? (max_pow2_less< c*p, 2*c*n>::value) : n);
};
template <>
struct max_pow2_less<0, 0> {
BOOST_STATIC_CONSTANT(int, value = 0);
};
// this template is here just for Borland :(
// we could simply rely on numeric_limits but sometimes
// Borland tries to use numeric_limits<const T>, because
// of its usual const-related problems in argument deduction
// - gps
template <typename T>
struct width {
#ifdef BOOST_BORLANDC
BOOST_STATIC_CONSTANT(int, value = sizeof(T) * CHAR_BIT);
int result = 0;
while (x != 1)
{
T t(x >> n);
if (t)
{
result += static_cast< int >(n);
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
x = static_cast< T&& >(t);
#else
BOOST_STATIC_CONSTANT(int, value = (std::numeric_limits<T>::digits));
x = t;
#endif
}
n >>= 1u;
}
};
} // detail
// ---------
// integer_log2
// ---------------
//
template <typename T>
int integer_log2(T x) {
BOOST_ASSERT(x > 0);
const int n = detail::max_pow2_less<
detail::width<T> :: value, 4
> :: value;
return detail::integer_log2_impl(x, n);
}
return result;
}
template< typename T >
inline typename boost::enable_if< boost::is_integral< T >, int >::type integer_log2_impl(T x)
{
// We could simply rely on numeric_limits but sometimes
// Borland tries to use numeric_limits<const T>, because
// of its usual const-related problems in argument deduction
// - gps
return static_cast< int >((sizeof(T) * CHAR_BIT - 1u) -
boost::core::countl_zero(static_cast< typename boost::make_unsigned< T >::type >(x)));
}
#if defined(BOOST_HAS_INT128)
// We need to provide explicit overloads for __int128 because (a) boost/core/bit.hpp currently does not support it and
// (b) std::numeric_limits are not specialized for __int128 in some standard libraries.
inline int integer_log2_impl(boost::uint128_type x)
{
const boost::uint64_t x_hi = static_cast< boost::uint64_t >(x >> 64u);
if (x_hi != 0u)
return 127 - boost::core::countl_zero(x_hi);
else
return 63 - boost::core::countl_zero(static_cast< boost::uint64_t >(x));
}
inline int integer_log2_impl(boost::int128_type x)
{
return detail::integer_log2_impl(static_cast< boost::uint128_type >(x));
}
#endif // defined(BOOST_HAS_INT128)
} // namespace detail
#endif // include guard
// ------------
// integer_log2
// ------------
template< typename T >
inline int integer_log2(T x)
{
BOOST_ASSERT(x > 0);
return detail::integer_log2_impl(x);
}
} // namespace boost
#endif // BOOST_INTEGER_INTEGER_LOG2_HPP

View File

@ -15,6 +15,7 @@ test-suite integer
[ run integer_traits_test.cpp ]
[ run integer_test.cpp : : : <toolset>gcc:<cxxflags>-Wno-long-long <toolset>darwin:<cxxflags>-Wno-long-long <toolset>sun:<cxxflags>"-Qoption ccfe -tmpldepth=128" ]
[ run integer_mask_test.cpp ]
[ run integer_log2_test.cpp ]
[ run static_log2_test.cpp ]
[ run static_min_max_test.cpp ]
[ run extended_euclidean_test.cpp ]

187
test/integer_log2_test.cpp Normal file
View File

@ -0,0 +1,187 @@
// Boost integer_log2.hpp test program --------------------------------------//
// (C) Copyright Andrey Semashev 2021.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
// See https://www.boost.org for most recent version including documentation.
#include <boost/config.hpp>
#include <boost/cstdint.hpp>
#include <boost/integer/integer_log2.hpp>
#include <boost/core/lightweight_test.hpp>
#include <iostream>
#include "multiprecision_config.hpp"
#if !defined(DISABLE_MP_TESTS)
#include <boost/multiprecision/cpp_int.hpp>
#endif
// Macros to compact code
#define PRIVATE_LB_TEST( v, e ) BOOST_TEST( ::boost::integer_log2((v)) == e )
#define PRIVATE_PRINT_LB( v ) ::std::cout << "boost::integer_log2(" << (v) \
<< ") = " << ::boost::integer_log2((v)) << '.' << ::std::endl
// Control to check for a compile-time error
#ifndef CONTROL_LB_0_TEST
#define PRIVATE_LB_0_TEST
#else
#define PRIVATE_LB_0_TEST PRIVATE_PRINT_LB( 0 )
#endif
// Main testing function
int main()
{
std::cout << "Doing tests on integer_log2." << std::endl;
PRIVATE_LB_0_TEST;
PRIVATE_LB_TEST( (unsigned char)1, 0 );
PRIVATE_LB_TEST( (unsigned char)2, 1 );
PRIVATE_LB_TEST( 1, 0 );
PRIVATE_LB_TEST( 2, 1 );
PRIVATE_LB_TEST( 3, 1 );
PRIVATE_LB_TEST( 4, 2 );
PRIVATE_LB_TEST( 5, 2 );
PRIVATE_LB_TEST( 6, 2 );
PRIVATE_LB_TEST( 7, 2 );
PRIVATE_LB_TEST( 8, 3 );
PRIVATE_LB_TEST( 9, 3 );
PRIVATE_LB_TEST( 10, 3 );
PRIVATE_LB_TEST( 11, 3 );
PRIVATE_LB_TEST( 12, 3 );
PRIVATE_LB_TEST( 13, 3 );
PRIVATE_LB_TEST( 14, 3 );
PRIVATE_LB_TEST( 15, 3 );
PRIVATE_LB_TEST( 16, 4 );
PRIVATE_LB_TEST( 17, 4 );
PRIVATE_LB_TEST( 18, 4 );
PRIVATE_LB_TEST( 19, 4 );
PRIVATE_LB_TEST( 20, 4 );
PRIVATE_LB_TEST( 21, 4 );
PRIVATE_LB_TEST( 22, 4 );
PRIVATE_LB_TEST( 23, 4 );
PRIVATE_LB_TEST( 24, 4 );
PRIVATE_LB_TEST( 25, 4 );
PRIVATE_LB_TEST( 26, 4 );
PRIVATE_LB_TEST( 27, 4 );
PRIVATE_LB_TEST( 28, 4 );
PRIVATE_LB_TEST( 29, 4 );
PRIVATE_LB_TEST( 30, 4 );
PRIVATE_LB_TEST( 31, 4 );
PRIVATE_LB_TEST( 32, 5 );
PRIVATE_LB_TEST( 33, 5 );
PRIVATE_LB_TEST( 34, 5 );
PRIVATE_LB_TEST( 35, 5 );
PRIVATE_LB_TEST( 36, 5 );
PRIVATE_LB_TEST( 37, 5 );
PRIVATE_LB_TEST( 38, 5 );
PRIVATE_LB_TEST( 39, 5 );
PRIVATE_LB_TEST( 40, 5 );
PRIVATE_LB_TEST( 63, 5 );
PRIVATE_LB_TEST( 64, 6 );
PRIVATE_LB_TEST( 65, 6 );
PRIVATE_LB_TEST( 127, 6 );
PRIVATE_LB_TEST( 128, 7 );
PRIVATE_LB_TEST( 129, 7 );
PRIVATE_LB_TEST( 255, 7 );
PRIVATE_LB_TEST( 256, 8 );
PRIVATE_LB_TEST( 257, 8 );
PRIVATE_LB_TEST( 511, 8 );
PRIVATE_LB_TEST( 512, 9 );
PRIVATE_LB_TEST( 513, 9 );
PRIVATE_LB_TEST( 1023, 9 );
PRIVATE_LB_TEST( 1024, 10 );
PRIVATE_LB_TEST( 1025, 10 );
PRIVATE_LB_TEST( 2047, 10 );
PRIVATE_LB_TEST( 2048, 11 );
PRIVATE_LB_TEST( 2049, 11 );
PRIVATE_LB_TEST( 4095, 11 );
PRIVATE_LB_TEST( 4096, 12 );
PRIVATE_LB_TEST( 4097, 12 );
PRIVATE_LB_TEST( 8191, 12 );
PRIVATE_LB_TEST( 8192, 13 );
PRIVATE_LB_TEST( 8193, 13 );
PRIVATE_LB_TEST( 16383, 13 );
PRIVATE_LB_TEST( 16384, 14 );
PRIVATE_LB_TEST( 16385, 14 );
PRIVATE_LB_TEST( 32767, 14 );
PRIVATE_LB_TEST( 32768, 15 );
PRIVATE_LB_TEST( 32769, 15 );
PRIVATE_LB_TEST( 65535, 15 );
PRIVATE_LB_TEST( 65536, 16 );
PRIVATE_LB_TEST( 65537, 16 );
#if defined(UINT32_C)
PRIVATE_LB_TEST( UINT32_C(4294967295), 31 );
#endif
#if defined(UINT64_C) && !defined(BOOST_NO_INT64_T)
PRIVATE_LB_TEST( UINT64_C(4294967296), 32 );
PRIVATE_LB_TEST( UINT64_C(4294967297), 32 );
PRIVATE_LB_TEST( UINT64_C(18446744073709551615), 63 );
#endif
#if defined(BOOST_HAS_INT128)
PRIVATE_LB_TEST( boost::uint128_type(1u) << 64u, 64 );
PRIVATE_LB_TEST( (boost::uint128_type(1u) << 64u) + 1u, 64 );
PRIVATE_LB_TEST( ~boost::uint128_type(0u), 127 );
#endif
#if !defined(DISABLE_MP_TESTS)
PRIVATE_LB_TEST( boost::multiprecision::cpp_int(1), 0 );
PRIVATE_LB_TEST( boost::multiprecision::cpp_int(2), 1 );
PRIVATE_LB_TEST( boost::multiprecision::cpp_int(3), 1 );
PRIVATE_LB_TEST( boost::multiprecision::cpp_int(65535), 15 );
PRIVATE_LB_TEST( boost::multiprecision::cpp_int(65536), 16 );
PRIVATE_LB_TEST( boost::multiprecision::int1024_t(1), 0 );
PRIVATE_LB_TEST( boost::multiprecision::int1024_t(2), 1 );
PRIVATE_LB_TEST( boost::multiprecision::int1024_t(3), 1 );
PRIVATE_LB_TEST( boost::multiprecision::int1024_t(65535), 15 );
PRIVATE_LB_TEST( boost::multiprecision::int1024_t(65536), 16 );
PRIVATE_LB_TEST( boost::multiprecision::uint1024_t(1), 0 );
PRIVATE_LB_TEST( boost::multiprecision::uint1024_t(2), 1 );
PRIVATE_LB_TEST( boost::multiprecision::uint1024_t(3), 1 );
PRIVATE_LB_TEST( boost::multiprecision::uint1024_t(65535), 15 );
PRIVATE_LB_TEST( boost::multiprecision::uint1024_t(65536), 16 );
#endif
return boost::report_errors();
}

View File

@ -10,7 +10,7 @@
// Revision History
// 23 Sep 2001 Initial version (Daryle Walker)
#include <boost/detail/lightweight_test.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/cstdlib.hpp> // for boost::exit_success
#include <boost/integer/integer_mask.hpp> // for boost::high_bit_mask_t, etc.

View File

@ -15,7 +15,7 @@
// 10 Mar 01 Boost Test Library now used for tests (Beman Dawes)
// 31 Aug 99 Initial version
#include <boost/detail/lightweight_test.hpp> // for main, BOOST_TEST
#include <boost/core/lightweight_test.hpp> // for main, BOOST_TEST
#include <boost/integer.hpp> // for boost::int_t, boost::uint_t
#include <boost/type_traits/is_same.hpp>
#include <boost/mpl/bool.hpp> // for mpl::true_ and false_

View File

@ -17,7 +17,7 @@
// use int64_t instead of long long for better portability
#include <boost/cstdint.hpp>
#include <boost/detail/lightweight_test.hpp>
#include <boost/core/lightweight_test.hpp>
/*
* General portability note:

View File

@ -10,7 +10,7 @@
// Revision History
// 01 Oct 2001 Initial version (Daryle Walker)
#include <boost/detail/lightweight_test.hpp> // for main
#include <boost/core/lightweight_test.hpp> // for main
#include <boost/cstdlib.hpp> // for boost::exit_success
#include <boost/integer/static_log2.hpp> // for boost::static_log2

View File

@ -10,7 +10,7 @@
// Revision History
// 23 Sep 2001 Initial version (Daryle Walker)
#include <boost/detail/lightweight_test.hpp> // for main, BOOST_TEST
#include <boost/core/lightweight_test.hpp> // for main, BOOST_TEST
#include <boost/cstdlib.hpp> // for boost::exit_success
#include <boost/integer/static_min_max.hpp> // for boost::static_signed_min, etc.