diff --git a/.github/workflows/ci-cell.yml b/.github/workflows/ci-cell.yml index b14fae42..2214d999 100644 --- a/.github/workflows/ci-cell.yml +++ b/.github/workflows/ci-cell.yml @@ -606,4 +606,6 @@ jobs: if [ "${{ inputs.c-compiler }}" = "mingw" ]; then export PATH="/mingw64/bin:$PATH" fi + # Gaps between pattern groups in the bit-functions harness. + export SIS_PERFTESTS_GROUPGAPS=1 SIS_CMAKE_BUILD_DIR="${{ github.workspace }}/build" ./execute_performance_tests.sh -M diff --git a/CHANGES.md b/CHANGES.md index edead870..7a74078a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,17 @@ # STLSoft - CHANGES +## 1.11.1-rc7 - 25th September 2026 + +* Added `count_bits_by_intrinsic()` and `find_highest_bit_by_intrinsic()` (unselected by default; `count_bits()` keeps the 8-bit table; `find_highest_bit()` keeps the scan); +* Added **stlsoft/api/external/bitfns.h** and **stlsoft/api/internal/bitfns.h** — detection and adaptations for `popcount` / `clz` / `_BitScanReverse` intrinsics (GCC/Clang builtins preferred over MSVC when both are visible); +* Clang cccap — `STLSOFT_CLANG_VER`; documented shared `STLSOFT_GCC_VER` (also noted in GCC cccap); +* Fixed `count_bits()` overloads when `STLSOFT_BIT_COUNT_BY_Kernighan` is defined; +* Unit tests for intrinsic popcount / highest-bit helpers; broader width coverage for bit-function overloads; +* Performance suite **test/performance/stlsoft/bit_functions** (density patterns, intrinsic rows, median / ns-per-call reporting); +* Strategy note **strategy/BIT_FUNCTIONS.md** — measurements and default choice (table for `count_bits()`; keep intrinsics unselected pending cross-toolchain evidence); + + ## 1.11.1-rc6 - 21st September 2026 * CMake/CI — optional **ACE** discovery (**cmake/FindACE.cmake**, **NO_ACE** / **prepare_cmake.sh --no-ace**); dedicated **cell-ace** job (**with-ace**); diff --git a/NEWS.md b/NEWS.md index 4c133f6c..911b3a39 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,6 +3,7 @@ | Date | News Item | Details | | ------------------- | ----------------------------------- | ------- | +| 25th September 2026 | Release of [STLSoft 1.11.1-rc7](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc7) | bit-function intrinsics; table default for `count_bits()` | | 21st September 2026 | Release of [STLSoft 1.11.1-rc6](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc6) | ACE/ATL/MFC CI; Clang/macOS `stricmp` aliases | | 4th August 2026 | Release of [STLSoft 1.11.1-rc5](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc5) | `basic_simple_string<>#resize()`; **CHANGES.md**; docs | | 29th July 2026 | Release of [STLSoft 1.11.1-rc4](https://github.com/synesissoftware/STLSoft/releases/tag/1.11.1-rc4) | GitHub Actions CI; VC++ 18.x; MinGW | diff --git a/include/stlsoft/api/external/bitfns.h b/include/stlsoft/api/external/bitfns.h new file mode 100644 index 00000000..5a43fecc --- /dev/null +++ b/include/stlsoft/api/external/bitfns.h @@ -0,0 +1,467 @@ +/* ///////////////////////////////////////////////////////////////////////// + * File: stlsoft/api/external/bitfns.h + * + * Purpose: External adaptations for bit functions. + * + * Created: 24th September 2026 + * Updated: 25th September 2026 + * + * Home: http://stlsoft.org/ + * + * Copyright (c) 2026, Matthew Wilson and Synesis Information Systems + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name(s) of Matthew Wilson and Synesis Information Systems + * nor the names of any contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ////////////////////////////////////////////////////////////////////// */ + + +/* WARNING: this file contains undocumented external features that are + * subject to change at any time, so if you use them it is at your own risk. + */ + +#ifndef STLSOFT_INCL_STLSOFT_API_external_h_bitfns +#define STLSOFT_INCL_STLSOFT_API_external_h_bitfns + + +/* ///////////////////////////////////////////////////////////////////////// + * includes - 1 + */ + +#ifndef STLSOFT_INCL_STLSOFT_H_STLSOFT +# include +#endif /* !STLSOFT_INCL_STLSOFT_H_STLSOFT */ +#ifdef STLSOFT_TRACE_INCLUDE +# pragma message(__FILE__) +#endif /* STLSOFT_TRACE_INCLUDE */ + + +/* ///////////////////////////////////////////////////////////////////////// + * intrinsics support + * + * Detection follows p99/src/p99_portable.h. GCC and Clang builtins are + * preferred over the MSVC intrinsics when both are visible (clang-cl). + * + * Detected features/macros: + * + * 1. "Count leading zeros" + * - discriminated symbols: + * - STLSOFT_CF__BitScanReverse_SUPPORT + * - STLSOFT_CF__BitScanReverse64_SUPPORT + * - STLSOFT_CF__builtin_clz_SUPPORT + * - STLSOFT_CF__builtin_clzll_SUPPORT + * + * - Clang/GCC may provide: + * - int __builtin_clz(unsigned int) + * - int __builtin_clzll(unsigned long long) + * + * - VC++ may provide: + * - unsigned char _BitScanReverse(unsigned long*, unsigned long) + * - unsigned char _BitScanReverse64(unsigned long*, unsigned __int64) + * + * NOTE: _BitScanReverse(64)() have different semantics to clz(ll) in + * that the former find the index of the most significant bit and the + * latter find the number of leading zeros. + * + * 2. "Population count" + * + * - discriminated symbols: + * - STLSOFT_CF__builtin_popcount_SUPPORT + * - STLSOFT_CF__builtin_popcountll_SUPPORT + * - STLSOFT_CF__popcnt16_SUPPORT + * - STLSOFT_CF__popcnt_SUPPORT + * - STLSOFT_CF__popcnt64_SUPPORT + * + * - Clang/GCC may provide: + * - int __builtin_popcount(unsigned int) + * - int __builtin_popcountll(unsigned long long) + * + * - VC++ may provide: + * - unsigned short __popcnt16(unsigned short) + * - unsigned int __popcnt(unsigned int) + * - unsigned __int64 __popcnt64(unsigned __int64) + */ + + +/* ///////////////////////////////////////////////////////// + * reject any other definition of the symbols under purview + */ + +#ifdef STLSOFT_CF__BitScanReverse_SUPPORT +# error STLSOFT_CF__BitScanReverse_SUPPORT may not be defined +#endif /* STLSOFT_CF__BitScanReverse_SUPPORT */ +#ifdef STLSOFT_CF__BitScanReverse64_SUPPORT +# error STLSOFT_CF__BitScanReverse64_SUPPORT may not be defined +#endif /* STLSOFT_CF__BitScanReverse64_SUPPORT */ + +#ifdef STLSOFT_CF__builtin_clz_SUPPORT +# error STLSOFT_CF__builtin_clz_SUPPORT may not be defined +#endif /* STLSOFT_CF__builtin_clz_SUPPORT */ +#ifdef STLSOFT_CF__builtin_clzll_SUPPORT +# error STLSOFT_CF__builtin_clzll_SUPPORT may not be defined +#endif /* STLSOFT_CF__builtin_clzll_SUPPORT */ + +#ifdef STLSOFT_CF__builtin_popcount_SUPPORT +# error STLSOFT_CF__builtin_popcount_SUPPORT may not be defined +#endif /* STLSOFT_CF__builtin_popcount_SUPPORT */ +#ifdef STLSOFT_CF__builtin_popcountll_SUPPORT +# error STLSOFT_CF__builtin_popcountll_SUPPORT may not be defined +#endif /* STLSOFT_CF__builtin_popcountll_SUPPORT */ + +#ifdef STLSOFT_CF__popcnt16_SUPPORT +# error STLSOFT_CF__popcnt16_SUPPORT may not be defined +#endif /* STLSOFT_CF__popcnt16_SUPPORT */ +#ifdef STLSOFT_CF__popcnt_SUPPORT +# error STLSOFT_CF__popcnt_SUPPORT may not be defined +#endif /* STLSOFT_CF__popcnt_SUPPORT */ +#ifdef STLSOFT_CF__popcnt64_SUPPORT +# error STLSOFT_CF__popcnt64_SUPPORT may not be defined +#endif /* STLSOFT_CF__popcnt64_SUPPORT */ + + +/* ///////////////////////////////////////////////////////// + * "Count leading zeros" + * + * - STLSOFT_CF__BitScanReverse_SUPPORT + * - STLSOFT_CF__BitScanReverse64_SUPPORT + * - STLSOFT_CF__builtin_clz_SUPPORT + * - STLSOFT_CF__builtin_clzll_SUPPORT + */ + + +/* STLSOFT_CF__BitScanReverse_SUPPORT, STLSOFT_CF__BitScanReverse64_SUPPORT */ + +#if 0 +#elif defined(_MSC_VER) &&\ + _MSC_VER >= 1400 + +# define STLSOFT_CF__BitScanReverse_SUPPORT +# if 0 ||\ + defined(_M_ARM64) ||\ + defined(_M_ARM64EC) ||\ + defined(_M_X64) ||\ + 0 + +# define STLSOFT_CF__BitScanReverse64_SUPPORT +# endif +#endif + + +/* STLSOFT_CF__builtin_clz_SUPPORT, STLSOFT_CF__builtin_clzll_SUPPORT */ + +#if 0 +#elif defined(__has_builtin) + +# if __has_builtin(__builtin_clz) + +# define STLSOFT_CF__builtin_clz_SUPPORT +# endif + +# if __has_builtin(__builtin_clzll) + +# define STLSOFT_CF__builtin_clzll_SUPPORT +# endif +#endif + +#ifndef STLSOFT_CF__builtin_clz_SUPPORT + +# if 0 +# elif defined(STLSOFT_CLANG_VER) &&\ + STLSOFT_CLANG_VER >= 40000 + +# define STLSOFT_CF__builtin_clz_SUPPORT +# elif defined(STLSOFT_GCC_VER) &&\ + STLSOFT_GCC_VER >= 30400 + +# define STLSOFT_CF__builtin_clz_SUPPORT +# endif +#endif + +#ifndef STLSOFT_CF__builtin_clzll_SUPPORT + +# if 0 +# elif defined(STLSOFT_CLANG_VER) &&\ + STLSOFT_CLANG_VER >= 40000 + +# define STLSOFT_CF__builtin_clzll_SUPPORT +# elif defined(STLSOFT_GCC_VER) &&\ + STLSOFT_GCC_VER >= 30400 + +# define STLSOFT_CF__builtin_clzll_SUPPORT +# endif +#endif + + +/* ///////////////////////////////////////////////////////// + * "Population count" + * + * - STLSOFT_CF__builtin_popcount_SUPPORT + * - STLSOFT_CF__builtin_popcountll_SUPPORT + * - STLSOFT_CF__popcnt16_SUPPORT + * - STLSOFT_CF__popcnt_SUPPORT + * - STLSOFT_CF__popcnt64_SUPPORT + */ + +/* STLSOFT_CF__builtin_popcount_SUPPORT, STLSOFT_CF__builtin_popcountll_SUPPORT */ + +#if 0 +#elif defined(__has_builtin) + +# if __has_builtin(__builtin_popcount) + +# define STLSOFT_CF__builtin_popcount_SUPPORT +# endif + +# if __has_builtin(__builtin_popcountll) + +# define STLSOFT_CF__builtin_popcountll_SUPPORT +# endif +#endif + +#ifndef STLSOFT_CF__builtin_popcount_SUPPORT + +# if 0 +# elif defined(STLSOFT_CLANG_VER) &&\ + STLSOFT_CLANG_VER >= 40000 + +# define STLSOFT_CF__builtin_popcount_SUPPORT +# elif defined(STLSOFT_GCC_VER) &&\ + STLSOFT_GCC_VER >= 30400 + +# define STLSOFT_CF__builtin_popcount_SUPPORT +# endif +#endif + +#ifndef STLSOFT_CF__builtin_popcountll_SUPPORT + +# if 0 +# elif defined(STLSOFT_CLANG_VER) &&\ + STLSOFT_CLANG_VER >= 40000 + +# define STLSOFT_CF__builtin_popcountll_SUPPORT +# elif defined(STLSOFT_GCC_VER) &&\ + STLSOFT_GCC_VER >= 30400 + +# define STLSOFT_CF__builtin_popcountll_SUPPORT +# endif +#endif + + +/* STLSOFT_CF__popcnt16_SUPPORT, STLSOFT_CF__popcnt_SUPPORT + * + * x86 and x64 from MSVC 15.00. ARM64 from Visual Studio 2022 17.11 + * (_MSC_VER 1941). Not 32-bit ARM. Not ARM64EC: those two intrinsics + * are declared for x86, x64, and ARM64 only. + */ + +#if 0 +#elif 1 &&\ + defined(_MSC_VER) &&\ + _MSC_VER >= 1500 &&\ + ( 0 ||\ + defined(_M_IX86) ||\ + defined(_M_X64) ||\ + 0) &&\ + 1 + +# define STLSOFT_CF__popcnt16_SUPPORT +# define STLSOFT_CF__popcnt_SUPPORT +#elif 1 &&\ + defined(_MSC_VER) &&\ + _MSC_VER >= 1941 &&\ + defined(_M_ARM64) &&\ + 1 + +# define STLSOFT_CF__popcnt16_SUPPORT +# define STLSOFT_CF__popcnt_SUPPORT +#endif + + +/* STLSOFT_CF__popcnt64_SUPPORT + * + * x64 from MSVC 15.00. ARM64 and ARM64EC from Visual Studio 2022 17.11 + * (_MSC_VER 1941). + */ + +#if 0 +#elif defined(_MSC_VER) &&\ + _MSC_VER >= 1500 &&\ + defined(_M_X64) + +# define STLSOFT_CF__popcnt64_SUPPORT +#elif defined(_MSC_VER) &&\ + _MSC_VER >= 1941 &&\ + ( 0 ||\ + defined(_M_ARM64) ||\ + defined(_M_ARM64EC) ||\ + 0) + +# define STLSOFT_CF__popcnt64_SUPPORT +#endif + + +/* ///////////////////////////////////////////////////////////////////////// + * includes - 2 + */ + +#if 0 +#elif 0 ||\ + defined(STLSOFT_CF__popcnt16_SUPPORT) ||\ + defined(STLSOFT_CF__popcnt_SUPPORT) ||\ + defined(STLSOFT_CF__popcnt64_SUPPORT) ||\ + defined(STLSOFT_CF__BitScanReverse_SUPPORT) ||\ + defined(STLSOFT_CF__BitScanReverse64_SUPPORT) ||\ + 0 + +# include +#endif + + +/* ///////////////////////////////////////////////////////////////////////// + * bit functions + */ + +#ifndef STLSOFT_API_EXTERNAL_bitfns_BitScanReverse_uint32 + +# if 0 +# elif defined(STLSOFT_CF__BitScanReverse_SUPPORT) + +# define STLSOFT_API_EXTERNAL_bitfns_BitScanReverse_uint32 _BitScanReverse +# else + +# endif +#endif /* !STLSOFT_API_EXTERNAL_bitfns_BitScanReverse_uint32 */ + + +#ifndef STLSOFT_API_EXTERNAL_bitfns_BitScanReverse_uint64 + +# if 0 +# elif defined(STLSOFT_CF__BitScanReverse64_SUPPORT) + +# define STLSOFT_API_EXTERNAL_bitfns_BitScanReverse_uint64 _BitScanReverse64 +# else + +# endif +#endif /* !STLSOFT_API_EXTERNAL_bitfns_BitScanReverse_uint64 */ + + +#ifndef STLSOFT_API_EXTERNAL_bitfns_clz_uint + +# if 0 +# elif defined(STLSOFT_CF__builtin_clz_SUPPORT) + +# define STLSOFT_API_EXTERNAL_bitfns_clz_uint __builtin_clz +# else + +# endif +#endif /* !STLSOFT_API_EXTERNAL_bitfns_clz_uint */ + + +#ifndef STLSOFT_API_EXTERNAL_bitfns_clz_ullong + +# if 0 +# elif defined(STLSOFT_CF__builtin_clzll_SUPPORT) + +# define STLSOFT_API_EXTERNAL_bitfns_clz_ullong __builtin_clzll +# else + +# endif +#endif /* !STLSOFT_API_EXTERNAL_bitfns_clz_ullong */ + + +#ifndef STLSOFT_API_EXTERNAL_bitfns_popcount_uint + +# if 0 +# elif defined(STLSOFT_CF__builtin_popcount_SUPPORT) + +# define STLSOFT_API_EXTERNAL_bitfns_popcount_uint __builtin_popcount +# else + +# endif +#endif /* !STLSOFT_API_EXTERNAL_bitfns_popcount_uint */ + + +#ifndef STLSOFT_API_EXTERNAL_bitfns_popcount_ullong + +# if 0 +# elif defined(STLSOFT_CF__builtin_popcountll_SUPPORT) + +# define STLSOFT_API_EXTERNAL_bitfns_popcount_ullong __builtin_popcountll +# else + +# endif +#endif /* !STLSOFT_API_EXTERNAL_bitfns_popcount_ullong */ + + +#ifndef STLSOFT_API_EXTERNAL_bitfns_popcnt_uint16 + +# if 0 +# elif defined(STLSOFT_CF__popcnt16_SUPPORT) + +# define STLSOFT_API_EXTERNAL_bitfns_popcnt_uint16 __popcnt16 +# else + +# endif +#endif /* !STLSOFT_API_EXTERNAL_bitfns_popcnt_uint16 */ + + +#ifndef STLSOFT_API_EXTERNAL_bitfns_popcnt_uint32 + +# if 0 +# elif defined(STLSOFT_CF__popcnt_SUPPORT) + +# define STLSOFT_API_EXTERNAL_bitfns_popcnt_uint32 __popcnt +# else + +# endif +#endif /* !STLSOFT_API_EXTERNAL_bitfns_popcnt_uint32 */ + + +#ifndef STLSOFT_API_EXTERNAL_bitfns_popcnt_uint64 + +# if 0 +# elif defined(STLSOFT_CF__popcnt64_SUPPORT) + +# define STLSOFT_API_EXTERNAL_bitfns_popcnt_uint64 __popcnt64 +# else + +# endif +#endif /* !STLSOFT_API_EXTERNAL_bitfns_popcnt_uint64 */ + + +/* ///////////////////////////////////////////////////////////////////////// + * inclusion control + */ + +#ifdef STLSOFT_CF_PRAGMA_ONCE_SUPPORT +# pragma once +#endif /* STLSOFT_CF_PRAGMA_ONCE_SUPPORT */ + +#endif /* !STLSOFT_INCL_STLSOFT_API_external_h_bitfns */ + +/* ///////////////////////////// end of file //////////////////////////// */ + diff --git a/include/stlsoft/api/internal/bitfns.h b/include/stlsoft/api/internal/bitfns.h new file mode 100644 index 00000000..206bc323 --- /dev/null +++ b/include/stlsoft/api/internal/bitfns.h @@ -0,0 +1,170 @@ +/* ///////////////////////////////////////////////////////////////////////// + * File: stlsoft/api/internal/bitfns.h + * + * Purpose: Internal adaptations for bit functions. + * + * Created: 24th September 2026 + * Updated: 25th September 2026 + * + * Home: http://stlsoft.org/ + * + * Copyright (c) 2026, Matthew Wilson and Synesis Information Systems + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name(s) of Matthew Wilson and Synesis Information Systems + * nor the names of any contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ////////////////////////////////////////////////////////////////////// */ + + +/* WARNING: this file contains undocumented internal features that are + * subject to change at any time, so if you use them it is at your own risk. + */ + +#ifndef STLSOFT_INCL_STLSOFT_API_internal_h_bitfns +#define STLSOFT_INCL_STLSOFT_API_internal_h_bitfns + + +/* ///////////////////////////////////////////////////////////////////////// + * includes + */ + +#ifndef STLSOFT_INCL_STLSOFT_H_STLSOFT +# include +#endif /* !STLSOFT_INCL_STLSOFT_H_STLSOFT */ +#ifdef STLSOFT_TRACE_INCLUDE +# pragma message(__FILE__) +#endif /* STLSOFT_TRACE_INCLUDE */ + +#ifndef STLSOFT_INCL_STLSOFT_API_external_h_bitfns +# include +#endif /* !STLSOFT_INCL_STLSOFT_API_external_h_bitfns */ + + +/* ///////////////////////////////////////////////////////////////////////// + * bit functions + */ + +#ifndef STLSOFT_API_INTERNAL_bitfns_popcount_uint16 + +# if 0 ||\ + defined (STLSOFT_API_EXTERNAL_bitfns_popcount_uint) ||\ + defined (STLSOFT_API_EXTERNAL_bitfns_popcnt_uint16) ||\ + 0 + +STLSOFT_INLINE +int +STLSOFT_API_INTERNAL_bitfns_popcount_uint16( + STLSOFT_NS_QUAL(ss_uint16_t) v +) +{ +# if 0 +# elif defined(STLSOFT_API_EXTERNAL_bitfns_popcount_uint) + + return STLSOFT_API_EXTERNAL_bitfns_popcount_uint(STLSOFT_C_CAST(unsigned int, v)); +# elif defined(STLSOFT_API_EXTERNAL_bitfns_popcnt_uint16) + + return STLSOFT_API_EXTERNAL_bitfns_popcnt_uint16(STLSOFT_C_CAST(unsigned short, v)); +# else + +# error Unexpected +# endif +} +# define STLSOFT_API_INTERNAL_bitfns_popcount_uint16 STLSOFT_API_INTERNAL_bitfns_popcount_uint16 +# endif +#endif + +#ifndef STLSOFT_API_INTERNAL_bitfns_popcount_uint32 + +# if 0 ||\ + defined (STLSOFT_API_EXTERNAL_bitfns_popcount_uint) ||\ + defined (STLSOFT_API_EXTERNAL_bitfns_popcnt_uint32) ||\ + 0 + +STLSOFT_INLINE +int +STLSOFT_API_INTERNAL_bitfns_popcount_uint32( + STLSOFT_NS_QUAL(ss_uint32_t) v +) +{ +# if 0 +# elif defined(STLSOFT_API_EXTERNAL_bitfns_popcount_uint) + + return STLSOFT_API_EXTERNAL_bitfns_popcount_uint(STLSOFT_C_CAST(unsigned int, v)); +# elif defined(STLSOFT_API_EXTERNAL_bitfns_popcnt_uint32) + + return STLSOFT_API_EXTERNAL_bitfns_popcnt_uint32(STLSOFT_C_CAST(unsigned int, v)); +# else + +# error Unexpected +# endif +} +# define STLSOFT_API_INTERNAL_bitfns_popcount_uint32 STLSOFT_API_INTERNAL_bitfns_popcount_uint32 +# endif +#endif + +#ifndef STLSOFT_API_INTERNAL_bitfns_popcount_uint64 + +# if 0 ||\ + defined (STLSOFT_API_EXTERNAL_bitfns_popcount_ullong) ||\ + defined (STLSOFT_API_EXTERNAL_bitfns_popcnt_uint64) ||\ + 0 + +STLSOFT_INLINE +int +STLSOFT_API_INTERNAL_bitfns_popcount_uint64( + STLSOFT_NS_QUAL(ss_uint64_t) v +) +{ +# if 0 +# elif defined(STLSOFT_API_EXTERNAL_bitfns_popcount_ullong) + + return STLSOFT_API_EXTERNAL_bitfns_popcount_ullong(STLSOFT_C_CAST(unsigned long long, v)); +# elif defined(STLSOFT_API_EXTERNAL_bitfns_popcnt_uint64) + + return STLSOFT_C_CAST(int, STLSOFT_API_EXTERNAL_bitfns_popcnt_uint64(STLSOFT_C_CAST(unsigned __int64, v))); +# else + +# error Unexpected +# endif +} +# define STLSOFT_API_INTERNAL_bitfns_popcount_uint64 STLSOFT_API_INTERNAL_bitfns_popcount_uint64 +# endif +#endif + + +/* ///////////////////////////////////////////////////////////////////////// + * inclusion control + */ + +#ifdef STLSOFT_CF_PRAGMA_ONCE_SUPPORT +# pragma once +#endif /* STLSOFT_CF_PRAGMA_ONCE_SUPPORT */ + +#endif /* !STLSOFT_INCL_STLSOFT_API_internal_h_bitfns */ + +/* ///////////////////////////// end of file //////////////////////////// */ + diff --git a/include/stlsoft/internal/cccap/clang.h b/include/stlsoft/internal/cccap/clang.h index 0e049b4a..bbf78d32 100644 --- a/include/stlsoft/internal/cccap/clang.h +++ b/include/stlsoft/internal/cccap/clang.h @@ -4,7 +4,7 @@ * Purpose: Compiler feature discrimination for Clang C/C++. * * Created: 14th March 2015 - * Updated: 20th September 2026 + * Updated: 25th September 2026 * * Home: http://stlsoft.org/ * @@ -59,9 +59,9 @@ #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION # define STLSOFT_VER_H_STLSOFT_CCCAP_CLANG_MAJOR 1 -# define STLSOFT_VER_H_STLSOFT_CCCAP_CLANG_MINOR 11 -# define STLSOFT_VER_H_STLSOFT_CCCAP_CLANG_REVISION 2 -# define STLSOFT_VER_H_STLSOFT_CCCAP_CLANG_EDIT 33 +# define STLSOFT_VER_H_STLSOFT_CCCAP_CLANG_MINOR 12 +# define STLSOFT_VER_H_STLSOFT_CCCAP_CLANG_REVISION 1 +# define STLSOFT_VER_H_STLSOFT_CCCAP_CLANG_EDIT 34 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ @@ -101,6 +101,46 @@ * custom macros */ +#define STLSOFT_CLANG_VER \ + \ + ( \ + (__clang_major__ * 10000) \ + + \ + (__clang_minor__ * 100) \ + + \ + (__clang_patchlevel__ * 1) \ + ) + +#ifdef __GNUC__ + +# ifdef __GNUC_PATCHLEVEL__ + +# define STLSOFT_INTERNAL_GCC_PATCHLEVEL_ __GNUC_PATCHLEVEL__ +# else /* ? __GNUC_PATCHLEVEL__ */ + +# define STLSOFT_INTERNAL_GCC_PATCHLEVEL_ (0) +# endif /* __GNUC_PATCHLEVEL__ */ + +/** \def STLSOFT_GCC_VER A composite version object-like macro comprising + * the major*10000 + minor*100 + patch, e.g. 30401 (3.4.1). + * + * \note Because several compilers (e.g. Clang) may offer GCC compatibility, + * the presence of this symbol does NOT, in and of itself, mean that the + * compiler is actually GCC. Rather, code must first check for definition + * of STLSOFT_COMPILER_IS_GCC. + * + */ +# define STLSOFT_GCC_VER \ + \ + ( \ + (__GNUC__ * 10000) \ + + \ + (__GNUC_MINOR__ * 100) \ + + \ + (STLSOFT_INTERNAL_GCC_PATCHLEVEL_ * 1) \ + ) +#endif /* __GNUC__ */ + /* ///////////////////////////////////////////////////////////////////////// * preprocessor features diff --git a/include/stlsoft/internal/cccap/gcc.h b/include/stlsoft/internal/cccap/gcc.h index 06b90aee..3e6e759f 100644 --- a/include/stlsoft/internal/cccap/gcc.h +++ b/include/stlsoft/internal/cccap/gcc.h @@ -110,6 +110,15 @@ # define STLSOFT_INTERNAL_GCC_PATCHLEVEL_ (0) #endif /* __GNUC_PATCHLEVEL__ */ +/** \def STLSOFT_GCC_VER A composite version object-like macro comprising + * the major*10000 + minor*100 + patch, e.g. 30401 (3.4.1). + * + * \note Because several compilers (e.g. Clang) may offer GCC compatibility, + * the presence of this symbol does NOT, in and of itself, mean that the + * compiler is actually GCC. Rather, code must first check for definition + * of STLSOFT_COMPILER_IS_GCC. + * + */ #define STLSOFT_GCC_VER \ \ ( \ diff --git a/include/stlsoft/stlsoft.h b/include/stlsoft/stlsoft.h index 1d7130cb..80b0b806 100644 --- a/include/stlsoft/stlsoft.h +++ b/include/stlsoft/stlsoft.h @@ -5,7 +5,7 @@ * and platform discriminations, and definitions of types. * * Created: 15th January 2002 - * Updated: 21st September 2026 + * Updated: 25th September 2026 * * Home: http://stlsoft.org/ * @@ -55,8 +55,8 @@ #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION # define STLSOFT_VER_STLSOFT_H_STLSOFT_MAJOR 3 # define STLSOFT_VER_STLSOFT_H_STLSOFT_MINOR 57 -# define STLSOFT_VER_STLSOFT_H_STLSOFT_REVISION 18 -# define STLSOFT_VER_STLSOFT_H_STLSOFT_EDIT 606 +# define STLSOFT_VER_STLSOFT_H_STLSOFT_REVISION 19 +# define STLSOFT_VER_STLSOFT_H_STLSOFT_EDIT 607 #else /* ? STLSOFT_DOCUMENTATION_SKIP_SECTION */ /* # include "./internal/doxygen_defs.h" */ #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ @@ -421,12 +421,13 @@ # define _STLSOFT_VER_1_11_1_RC4 0x010b01c4 /*!< Version 1.11.1 rc 4 (1st July 2026) */ # define _STLSOFT_VER_1_11_1_RC5 0x010b01c5 /*!< Version 1.11.1 rc 5 (4th August 2026) */ # define _STLSOFT_VER_1_11_1_RC6 0x010b01c6 /*!< Version 1.11.1 rc 6 (21st September 2026) */ +# define _STLSOFT_VER_1_11_1_RC7 0x010b01c7 /*!< Version 1.11.1 rc 7 (25th September 2026) */ #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ #define _STLSOFT_VER_MAJOR 1 #define _STLSOFT_VER_MINOR 11 #define _STLSOFT_VER_PATCH 1 -#define _STLSOFT_VER_ALPHABETA 0xc6 +#define _STLSOFT_VER_ALPHABETA 0xc7 #define _STLSOFT_VER \ (0\ diff --git a/include/stlsoft/util/bits/count_functions.h b/include/stlsoft/util/bits/count_functions.h index 8e0ada2c..90e022a9 100644 --- a/include/stlsoft/util/bits/count_functions.h +++ b/include/stlsoft/util/bits/count_functions.h @@ -1,14 +1,14 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: stlsoft/util/bits/count_functions.h + * File: stlsoft/util/bits/count_functions.h * - * Purpose: Bit count functions. + * Purpose: Bit count functions. * - * Created: 2nd June 2010 - * Updated: 11th March 2024 + * Created: 2nd June 2010 + * Updated: 25th September 2026 * - * Home: http://stlsoft.org/ + * Home: http://stlsoft.org/ * - * Copyright (c) 2019-2024, Matthew Wilson and Synesis Information Systems + * Copyright (c) 2019-2026, Matthew Wilson and Synesis Information Systems * Copyright (c) 2010-2019, Matthew Wilson and Synesis Software * All rights reserved. * @@ -51,10 +51,10 @@ #define STLSOFT_INCL_STLSOFT_UTIL_BITS_H_COUNT_FUNCTIONS #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION -# define STLSOFT_VER_STLSOFT_UTIL_BITS_H_COUNT_FUNCTIONS_MAJOR 1 -# define STLSOFT_VER_STLSOFT_UTIL_BITS_H_COUNT_FUNCTIONS_MINOR 3 -# define STLSOFT_VER_STLSOFT_UTIL_BITS_H_COUNT_FUNCTIONS_REVISION 1 -# define STLSOFT_VER_STLSOFT_UTIL_BITS_H_COUNT_FUNCTIONS_EDIT 19 +# define STLSOFT_VER_STLSOFT_UTIL_BITS_H_COUNT_FUNCTIONS_MAJOR 1 +# define STLSOFT_VER_STLSOFT_UTIL_BITS_H_COUNT_FUNCTIONS_MINOR 3 +# define STLSOFT_VER_STLSOFT_UTIL_BITS_H_COUNT_FUNCTIONS_REVISION 3 +# define STLSOFT_VER_STLSOFT_UTIL_BITS_H_COUNT_FUNCTIONS_EDIT 23 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ @@ -76,6 +76,13 @@ # include #endif /* !STLSOFT_INCL_STLSOFT_QUALITY_H_COVER */ +#ifndef STLSOFT_INCL_STLSOFT_API_external_h_bitfns +# include +#endif /* !STLSOFT_INCL_STLSOFT_API_external_h_bitfns */ +#ifndef STLSOFT_INCL_STLSOFT_API_internal_h_bitfns +# include +#endif /* !STLSOFT_INCL_STLSOFT_API_internal_h_bitfns */ + /* ///////////////////////////////////////////////////////////////////////// * namespace @@ -364,7 +371,6 @@ namespace ximpl_bit_functions return &s_table; } - # ifdef __cplusplus } /* namespace ximpl_bit_functions */ # endif /* __cplusplus */ @@ -404,6 +410,38 @@ stlsoft_C_count_bits_in_32bit_unsigned_integer_by_Kernighan_method( return n; } +/** Counts the number of bits in an 8-bit unsigned integer, using Brian + * Kernighan's method (see TCPL). + * + * \param v The number whose bits are to be counted + * + * \return The number of bits in \c v + */ +STLSOFT_INLINE +unsigned +stlsoft_C_count_bits_in_8bit_unsigned_integer_by_Kernighan_method( + ss_uint8_t v +) STLSOFT_NOEXCEPT +{ + return stlsoft_C_count_bits_in_32bit_unsigned_integer_by_Kernighan_method(STLSOFT_STATIC_CAST(ss_uint32_t, v)); +} + +/** Counts the number of bits in a 16-bit unsigned integer, using Brian + * Kernighan's method (see TCPL). + * + * \param v The number whose bits are to be counted + * + * \return The number of bits in \c v + */ +STLSOFT_INLINE +unsigned +stlsoft_C_count_bits_in_16bit_unsigned_integer_by_Kernighan_method( + ss_uint16_t v +) STLSOFT_NOEXCEPT +{ + return stlsoft_C_count_bits_in_32bit_unsigned_integer_by_Kernighan_method(STLSOFT_STATIC_CAST(ss_uint32_t, v)); +} + /** Counts the number of bits in a 64-bit unsigned integer, using Brian * Kernighan's method (see TCPL). * @@ -449,6 +487,38 @@ stlsoft_C_count_bits_in_32bit_unsigned_integer_by_8bit_table( return (*ptr)[0[py]] + (*ptr)[1[py]] + (*ptr)[2[py]] + (*ptr)[3[py]]; } +/** Counts the number of bits in an 8-bit unsigned integer, using an 8-bit + * lookup table. + * + * \param v The number whose bits are to be counted + * + * \return The number of bits in \c v + */ +STLSOFT_INLINE +unsigned +stlsoft_C_count_bits_in_8bit_unsigned_integer_by_8bit_table( + ss_uint8_t v +) STLSOFT_NOEXCEPT +{ + return stlsoft_C_count_bits_in_32bit_unsigned_integer_by_8bit_table(STLSOFT_STATIC_CAST(ss_uint32_t, v)); +} + +/** Counts the number of bits in a 16-bit unsigned integer, using an 8-bit + * lookup table. + * + * \param v The number whose bits are to be counted + * + * \return The number of bits in \c v + */ +STLSOFT_INLINE +unsigned +stlsoft_C_count_bits_in_16bit_unsigned_integer_by_8bit_table( + ss_uint16_t v +) STLSOFT_NOEXCEPT +{ + return stlsoft_C_count_bits_in_32bit_unsigned_integer_by_8bit_table(STLSOFT_STATIC_CAST(ss_uint32_t, v)); +} + /** Counts the number of bits in a 64-bit unsigned integer, using an 8-bit. * lookup table. * @@ -467,6 +537,64 @@ stlsoft_C_count_bits_in_64bit_unsigned_integer_by_8bit_table( return n_high + n_low; } +#if defined(STLSOFT_API_INTERNAL_bitfns_popcount_uint16) || \ + defined(STLSOFT_DOCUMENTATION_SKIP_SECTION) + +/** Counts the number of bits in a 16-bit unsigned integer, using a + * compiler intrinsic. Not selected by count_bits(). + * + * \param v The number whose bits are to be counted + * + * \return The number of bits in \c v + */ +STLSOFT_INLINE +unsigned +stlsoft_C_count_bits_in_16bit_unsigned_integer_by_intrinsic( + ss_uint16_t v +) STLSOFT_NOEXCEPT +{ + return STLSOFT_C_CAST(unsigned, STLSOFT_API_INTERNAL_bitfns_popcount_uint16(v)); +} +#endif /* STLSOFT_API_INTERNAL_bitfns_popcount_uint16 */ +#if defined(STLSOFT_API_INTERNAL_bitfns_popcount_uint32) || \ + defined(STLSOFT_DOCUMENTATION_SKIP_SECTION) + +/** Counts the number of bits in a 32-bit unsigned integer, using a + * compiler intrinsic. Not selected by count_bits(). + * + * \param v The number whose bits are to be counted + * + * \return The number of bits in \c v + */ +STLSOFT_INLINE +unsigned +stlsoft_C_count_bits_in_32bit_unsigned_integer_by_intrinsic( + ss_uint32_t v +) STLSOFT_NOEXCEPT +{ + return STLSOFT_C_CAST(unsigned, STLSOFT_API_INTERNAL_bitfns_popcount_uint32(v)); +} +#endif /* STLSOFT_API_INTERNAL_bitfns_popcount_uint32 */ +#if defined(STLSOFT_API_INTERNAL_bitfns_popcount_uint64) || \ + defined(STLSOFT_DOCUMENTATION_SKIP_SECTION) + +/** Counts the number of bits in a 64-bit unsigned integer, using a + * compiler intrinsic. One instruction for the full width, not two + * 32-bit calls. Not selected by count_bits(). + * + * \param v The number whose bits are to be counted + * + * \return The number of bits in \c v + */ +STLSOFT_INLINE +unsigned +stlsoft_C_count_bits_in_64bit_unsigned_integer_by_intrinsic( + ss_uint64_t v +) STLSOFT_NOEXCEPT +{ + return STLSOFT_C_CAST(unsigned, STLSOFT_API_INTERNAL_bitfns_popcount_uint64(v)); +} +#endif /* STLSOFT_API_INTERNAL_bitfns_popcount_uint64 */ /* ///////////////////////////////////////////////////////////////////////// @@ -475,6 +603,32 @@ stlsoft_C_count_bits_in_64bit_unsigned_integer_by_8bit_table( #ifdef __cplusplus +/** + * + * \see stlsoft_C_count_bits_in_8bit_unsigned_integer_by_Kernighan_method + */ +inline +unsigned +count_bits_by_Kernighan_method( + ss_uint8_t v +) STLSOFT_NOEXCEPT +{ + return stlsoft_C_count_bits_in_8bit_unsigned_integer_by_Kernighan_method(v); +} + +/** + * + * \see stlsoft_C_count_bits_in_16bit_unsigned_integer_by_Kernighan_method + */ +inline +unsigned +count_bits_by_Kernighan_method( + ss_uint16_t v +) STLSOFT_NOEXCEPT +{ + return stlsoft_C_count_bits_in_16bit_unsigned_integer_by_Kernighan_method(v); +} + /** * * \see stlsoft_C_count_bits_in_32bit_unsigned_integer_by_Kernighan_method @@ -501,6 +655,32 @@ count_bits_by_Kernighan_method( return stlsoft_C_count_bits_in_64bit_unsigned_integer_by_Kernighan_method(v); } +/** + * + * \see stlsoft_C_count_bits_in_8bit_unsigned_integer_by_8bit_table + */ +inline +unsigned +count_bits_by_8bit_table( + ss_uint8_t v +) STLSOFT_NOEXCEPT +{ + return stlsoft_C_count_bits_in_8bit_unsigned_integer_by_8bit_table(v); +} + +/** + * + * \see stlsoft_C_count_bits_in_16bit_unsigned_integer_by_8bit_table + */ +inline +unsigned +count_bits_by_8bit_table( + ss_uint16_t v +) STLSOFT_NOEXCEPT +{ + return stlsoft_C_count_bits_in_16bit_unsigned_integer_by_8bit_table(v); +} + /** * * \see stlsoft_C_count_bits_in_32bit_unsigned_integer_by_8bit_table @@ -526,7 +706,108 @@ count_bits_by_8bit_table( { return stlsoft_C_count_bits_in_64bit_unsigned_integer_by_8bit_table(v); } +#if defined(STLSOFT_API_INTERNAL_bitfns_popcount_uint16) || \ + defined(STLSOFT_DOCUMENTATION_SKIP_SECTION) +/** + * + * \see stlsoft_C_count_bits_in_16bit_unsigned_integer_by_intrinsic + */ +inline +unsigned +count_bits_by_intrinsic( + ss_uint16_t v +) STLSOFT_NOEXCEPT +{ + return stlsoft_C_count_bits_in_16bit_unsigned_integer_by_intrinsic(v); +} + +/** + * + * \see stlsoft_C_count_bits_in_16bit_unsigned_integer_by_intrinsic + */ +inline +unsigned +count_bits_by_intrinsic( + ss_uint8_t v +) STLSOFT_NOEXCEPT +{ + return stlsoft_C_count_bits_in_16bit_unsigned_integer_by_intrinsic(STLSOFT_STATIC_CAST(ss_uint16_t, v)); +} +#endif +#if defined(STLSOFT_API_INTERNAL_bitfns_popcount_uint32) || \ + defined(STLSOFT_DOCUMENTATION_SKIP_SECTION) + +/** + * + * \see stlsoft_C_count_bits_in_32bit_unsigned_integer_by_intrinsic + */ +inline +unsigned +count_bits_by_intrinsic( + ss_uint32_t v +) STLSOFT_NOEXCEPT +{ + return stlsoft_C_count_bits_in_32bit_unsigned_integer_by_intrinsic(v); +} +#endif +#if defined(STLSOFT_API_INTERNAL_bitfns_popcount_uint64) || \ + defined(STLSOFT_DOCUMENTATION_SKIP_SECTION) + +/** + * + * \see stlsoft_C_count_bits_in_64bit_unsigned_integer_by_intrinsic + */ +inline +unsigned +count_bits_by_intrinsic( + ss_uint64_t v +) STLSOFT_NOEXCEPT +{ + return stlsoft_C_count_bits_in_64bit_unsigned_integer_by_intrinsic(v); +} +#endif + + +/** Counts the number of bits in an 8-bit unsigned integer + * + * \param v The number whose bits are to be counted + * + * \return The number of bits in \c v + */ +inline +unsigned +count_bits( + ss_uint8_t v +) STLSOFT_NOEXCEPT +{ +# if 0 +# elif defined(STLSOFT_BIT_COUNT_BY_Kernighan) + return count_bits_by_Kernighan_method(v); +# else + return count_bits_by_8bit_table(v); +# endif +} + +/** Counts the number of bits in a 16-bit unsigned integer + * + * \param v The number whose bits are to be counted + * + * \return The number of bits in \c v + */ +inline +unsigned +count_bits( + ss_uint16_t v +) STLSOFT_NOEXCEPT +{ +# if 0 +# elif defined(STLSOFT_BIT_COUNT_BY_Kernighan) + return count_bits_by_Kernighan_method(v); +# else + return count_bits_by_8bit_table(v); +# endif +} /** Counts the number of bits in a 32-bit unsigned integer * @@ -540,8 +821,9 @@ count_bits( ss_uint32_t v ) STLSOFT_NOEXCEPT { -# if defined(STLSOFT_BIT_COUNT_BY_Kernighan) - return count_bits_by_Kernighan(v); +# if 0 +# elif defined(STLSOFT_BIT_COUNT_BY_Kernighan) + return count_bits_by_Kernighan_method(v); # else return count_bits_by_8bit_table(v); # endif @@ -559,8 +841,9 @@ count_bits( ss_uint64_t v ) STLSOFT_NOEXCEPT { -# if defined(STLSOFT_BIT_COUNT_BY_Kernighan) - return count_bits_by_Kernighan(v); +# if 0 +# elif defined(STLSOFT_BIT_COUNT_BY_Kernighan) + return count_bits_by_Kernighan_method(v); # else return count_bits_by_8bit_table(v); # endif @@ -612,7 +895,10 @@ count_bits( } #endif /* __cplusplus */ -/* ////////////////////////////////////////////////////////////////////// */ + +/* ///////////////////////////////////////////////////////////////////////// + * namespace + */ #ifndef STLSOFT_NO_NAMESPACE } /* namespace stlsoft */ @@ -627,8 +913,6 @@ count_bits( # pragma once #endif /* STLSOFT_CF_PRAGMA_ONCE_SUPPORT */ -/* ////////////////////////////////////////////////////////////////////// */ - #endif /* !STLSOFT_INCL_STLSOFT_UTIL_BITS_H_COUNT_FUNCTIONS */ /* ///////////////////////////// end of file //////////////////////////// */ diff --git a/include/stlsoft/util/bits/test_functions.h b/include/stlsoft/util/bits/test_functions.h index 8823df45..ac681bdc 100644 --- a/include/stlsoft/util/bits/test_functions.h +++ b/include/stlsoft/util/bits/test_functions.h @@ -1,14 +1,14 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: stlsoft/util/bits/test_functions.h + * File: stlsoft/util/bits/test_functions.h * - * Purpose: Bit test functions + * Purpose: Bit test functions * - * Created: 2nd June 2010 - * Updated: 11th March 2024 + * Created: 2nd June 2010 + * Updated: 25th September 2026 * - * Home: http://stlsoft.org/ + * Home: http://stlsoft.org/ * - * Copyright (c) 2019-2024, Matthew Wilson and Synesis Information Systems + * Copyright (c) 2019-2026, Matthew Wilson and Synesis Information Systems * Copyright (c) 2010-2019, Matthew Wilson and Synesis Software * All rights reserved. * @@ -53,8 +53,8 @@ #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION # define STLSOFT_VER_STLSOFT_UTIL_BITS_H_TEST_FUNCTIONS_MAJOR 1 # define STLSOFT_VER_STLSOFT_UTIL_BITS_H_TEST_FUNCTIONS_MINOR 0 -# define STLSOFT_VER_STLSOFT_UTIL_BITS_H_TEST_FUNCTIONS_REVISION 3 -# define STLSOFT_VER_STLSOFT_UTIL_BITS_H_TEST_FUNCTIONS_EDIT 12 +# define STLSOFT_VER_STLSOFT_UTIL_BITS_H_TEST_FUNCTIONS_REVISION 5 +# define STLSOFT_VER_STLSOFT_UTIL_BITS_H_TEST_FUNCTIONS_EDIT 15 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ @@ -76,6 +76,10 @@ # include #endif /* !STLSOFT_INCL_STLSOFT_QUALITY_H_COVER */ +#ifndef STLSOFT_INCL_STLSOFT_API_external_h_bitfns +# include +#endif /* !STLSOFT_INCL_STLSOFT_API_external_h_bitfns */ + /* ///////////////////////////////////////////////////////////////////////// * namespace @@ -173,6 +177,152 @@ stlsoft_C_find_highest_bit_in_64bit_unsigned_integer( return stlsoft_C_find_highest_bit_in_32bit_unsigned_integer(STLSOFT_STATIC_CAST(ss_uint32_t, v)); } +#if 0 +#elif defined(STLSOFT_CF__builtin_clz_SUPPORT) || \ + defined(STLSOFT_CF__BitScanReverse_SUPPORT) + +/** Find the 1-based index of the highest set bit, using a compiler + * intrinsic. Returns 0 when \c v is 0. Not selected by find_highest_bit(). + */ +STLSOFT_INLINE +unsigned +stlsoft_C_find_highest_bit_in_8bit_unsigned_integer_by_intrinsic( + ss_uint8_t v +) STLSOFT_NOEXCEPT +{ +# if 0 +# elif defined(STLSOFT_CF__builtin_clz_SUPPORT) + + if (0u == v) + { + return 0u; + } + + return 32u - STLSOFT_STATIC_CAST(unsigned, __builtin_clz(STLSOFT_STATIC_CAST(unsigned, v))); +# elif defined(STLSOFT_CF__BitScanReverse_SUPPORT) + + unsigned long index; + + if (0 == _BitScanReverse(&index, STLSOFT_STATIC_CAST(unsigned long, v))) + { + return 0u; + } + + return STLSOFT_STATIC_CAST(unsigned, index) + 1u; +# else + +# error Unexpected +# endif +} + +/** Find the 1-based index of the highest set bit, using a compiler + * intrinsic. Returns 0 when \c v is 0. Not selected by find_highest_bit(). + */ +STLSOFT_INLINE +unsigned +stlsoft_C_find_highest_bit_in_16bit_unsigned_integer_by_intrinsic( + ss_uint16_t v +) STLSOFT_NOEXCEPT +{ +# if 0 +# elif defined(STLSOFT_CF__builtin_clz_SUPPORT) + + if (0u == v) + { + return 0u; + } + + return 32u - STLSOFT_STATIC_CAST(unsigned, __builtin_clz(STLSOFT_STATIC_CAST(unsigned, v))); +# elif defined(STLSOFT_CF__BitScanReverse_SUPPORT) + + unsigned long index; + + if (0 == _BitScanReverse(&index, STLSOFT_STATIC_CAST(unsigned long, v))) + { + return 0u; + } + + return STLSOFT_STATIC_CAST(unsigned, index) + 1u; +# else + +# error Unexpected +# endif +} + +/** Find the 1-based index of the highest set bit, using a compiler + * intrinsic. Returns 0 when \c v is 0. Not selected by find_highest_bit(). + */ +STLSOFT_INLINE +unsigned +stlsoft_C_find_highest_bit_in_32bit_unsigned_integer_by_intrinsic( + ss_uint32_t v +) STLSOFT_NOEXCEPT +{ +# if 0 +# elif defined(STLSOFT_CF__builtin_clz_SUPPORT) + + if (0u == v) + { + return 0u; + } + + return 32u - STLSOFT_STATIC_CAST(unsigned, __builtin_clz(v)); +# elif defined(STLSOFT_CF__BitScanReverse_SUPPORT) + + unsigned long index; + + if (0 == _BitScanReverse(&index, STLSOFT_STATIC_CAST(unsigned long, v))) + { + return 0u; + } + + return STLSOFT_STATIC_CAST(unsigned, index) + 1u; +# else + +# error Unexpected +# endif +} +#endif + +#if 0 +#elif defined(STLSOFT_CF__builtin_clzll_SUPPORT) || \ + defined(STLSOFT_CF__BitScanReverse64_SUPPORT) + +/** Find the 1-based index of the highest set bit, using a compiler + * intrinsic. Returns 0 when \c v is 0. Not selected by find_highest_bit(). + */ +STLSOFT_INLINE +unsigned +stlsoft_C_find_highest_bit_in_64bit_unsigned_integer_by_intrinsic( + ss_uint64_t v +) STLSOFT_NOEXCEPT +{ +# if 0 +# elif defined(STLSOFT_CF__builtin_clzll_SUPPORT) + + if (0u == v) + { + return 0u; + } + + return 64u - STLSOFT_STATIC_CAST(unsigned, __builtin_clzll(v)); +# elif defined(STLSOFT_CF__BitScanReverse64_SUPPORT) + + unsigned long index; + + if (0 == _BitScanReverse64(&index, v)) + { + return 0u; + } + + return STLSOFT_STATIC_CAST(unsigned, index) + 1u; +# else + +# error Unexpected +# endif +} +#endif + /* ///////////////////////////////////////////////////////////////////////// * C++ @@ -232,10 +382,73 @@ find_highest_bit( return stlsoft_C_find_highest_bit_in_8bit_unsigned_integer(v); } +#if 0 +#elif defined(STLSOFT_CF__builtin_clz_SUPPORT) || \ + defined(STLSOFT_CF__BitScanReverse64_SUPPORT) + +/** + * + * \see stlsoft_C_find_highest_bit_in_64bit_unsigned_integer_by_intrinsic + */ +inline +unsigned +find_highest_bit_by_intrinsic( + ss_uint64_t v +) STLSOFT_NOEXCEPT +{ + return stlsoft_C_find_highest_bit_in_64bit_unsigned_integer_by_intrinsic(v); +} +#endif + +#if 0 +#elif defined(STLSOFT_CF__builtin_clz_SUPPORT) || \ + defined(STLSOFT_CF__BitScanReverse_SUPPORT) + +/** + * + * \see stlsoft_C_find_highest_bit_in_32bit_unsigned_integer_by_intrinsic + */ +inline +unsigned +find_highest_bit_by_intrinsic( + ss_uint32_t v +) STLSOFT_NOEXCEPT +{ + return stlsoft_C_find_highest_bit_in_32bit_unsigned_integer_by_intrinsic(v); +} + +/** + * + * \see stlsoft_C_find_highest_bit_in_16bit_unsigned_integer_by_intrinsic + */ +inline +unsigned +find_highest_bit_by_intrinsic( + ss_uint16_t v +) STLSOFT_NOEXCEPT +{ + return stlsoft_C_find_highest_bit_in_16bit_unsigned_integer_by_intrinsic(v); +} +/** + * + * \see stlsoft_C_find_highest_bit_in_8bit_unsigned_integer_by_intrinsic + */ +inline +unsigned +find_highest_bit_by_intrinsic( + ss_uint8_t v +) STLSOFT_NOEXCEPT +{ + return stlsoft_C_find_highest_bit_in_8bit_unsigned_integer_by_intrinsic(v); +} +#endif #endif /* __cplusplus */ -/* ////////////////////////////////////////////////////////////////////// */ + +/* ///////////////////////////////////////////////////////////////////////// + * namespace + */ #ifndef STLSOFT_NO_NAMESPACE } /* namespace stlsoft */ @@ -250,8 +463,6 @@ find_highest_bit( # pragma once #endif /* STLSOFT_CF_PRAGMA_ONCE_SUPPORT */ -/* ////////////////////////////////////////////////////////////////////// */ - #endif /* !STLSOFT_INCL_STLSOFT_UTIL_BITS_H_TEST_FUNCTIONS */ /* ///////////////////////////// end of file //////////////////////////// */ diff --git a/include/stlsoft/util/bits/xor_functions.h b/include/stlsoft/util/bits/xor_functions.h index 289447d3..27d6040c 100644 --- a/include/stlsoft/util/bits/xor_functions.h +++ b/include/stlsoft/util/bits/xor_functions.h @@ -1,14 +1,14 @@ /* ///////////////////////////////////////////////////////////////////////// - * File: stlsoft/util/bits/xor_functions.h + * File: stlsoft/util/bits/xor_functions.h * - * Purpose: Bit XOR functions + * Purpose: Bit XOR functions * - * Created: 2nd June 2010 - * Updated: 11th March 2024 + * Created: 2nd June 2010 + * Updated: 24th September 2026 * - * Home: http://stlsoft.org/ + * Home: http://stlsoft.org/ * - * Copyright (c) 2019-2024, Matthew Wilson and Synesis Information Systems + * Copyright (c) 2019-2026, Matthew Wilson and Synesis Information Systems * Copyright (c) 2010-2019, Matthew Wilson and Synesis Software * All rights reserved. * @@ -54,7 +54,7 @@ # define STLSOFT_VER_STLSOFT_UTIL_BITS_H_XOR_FUNCTIONS_MAJOR 1 # define STLSOFT_VER_STLSOFT_UTIL_BITS_H_XOR_FUNCTIONS_MINOR 2 # define STLSOFT_VER_STLSOFT_UTIL_BITS_H_XOR_FUNCTIONS_REVISION 1 -# define STLSOFT_VER_STLSOFT_UTIL_BITS_H_XOR_FUNCTIONS_EDIT 14 +# define STLSOFT_VER_STLSOFT_UTIL_BITS_H_XOR_FUNCTIONS_EDIT 15 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ @@ -253,11 +253,12 @@ calculate_xor_over_range( { return stlsoft_C_calculate_xor_over_8bit_unsigned_range(p, n); } - - #endif /* __cplusplus */ -/* ////////////////////////////////////////////////////////////////////// */ + +/* ///////////////////////////////////////////////////////////////////////// + * namespace + */ #ifndef STLSOFT_NO_NAMESPACE } /* namespace stlsoft */ @@ -272,8 +273,6 @@ calculate_xor_over_range( # pragma once #endif /* STLSOFT_CF_PRAGMA_ONCE_SUPPORT */ -/* ////////////////////////////////////////////////////////////////////// */ - #endif /* !STLSOFT_INCL_STLSOFT_UTIL_BITS_H_XOR_FUNCTIONS */ /* ///////////////////////////// end of file //////////////////////////// */ diff --git a/strategy/BIT_FUNCTIONS.md b/strategy/BIT_FUNCTIONS.md new file mode 100644 index 00000000..3d6065d9 --- /dev/null +++ b/strategy/BIT_FUNCTIONS.md @@ -0,0 +1,92 @@ +# STLSoft.b - Bit Functions + +Strategy note for **STLSoft.b** bit utilities. Measurements are of the performance program **test/performance/stlsoft/bit_functions/main.cpp**. Library sources are **include/stlsoft/util/bits/count_functions.h**, **include/stlsoft/util/bits/test_functions.h**, and **include/stlsoft/util/bits/xor_functions.h**. Intrinsic detection and naming live in **include/stlsoft/api/external/bitfns.h** and **include/stlsoft/api/internal/bitfns.h**. + + +## Question + +If intrinsics are never adopted, should `count_bits()` use Kernighan on Apple and the 8-bit table everywhere else? + +No. The fast Kernighan numbers are Apple Clang rewriting the loop into a hardware popcount. They are not a property of Apple hardware. On every other toolchain measured here, that rewrite did not happen, and the table is several times faster. A default keyed on Apple, or on ARM, would be right only while the compiler keeps doing that rewrite, and badly wrong when it does not. + +The cost of leaving the table in place on Apple Clang is a fraction of a nanosecond per call. The cost of leaving Kernighan in place on a compiler that executes the source loop is about 12 ns (`uint32_t`, all ones) and about 24 ns (`uint64_t`, all ones), against about 1 ns and 2 ns for the table. + + +## What was measured + +Optimised release builds (`optimisation: speed`, `NDEBUG`), five-sample medians, 20,000,000 iterations. Anchors match across machines for the same input pattern, so the loops did the same work. + +* **Cross-platform, commit `74b74407875100e0f1b6f5f7658a714c9a8d57b3`.** Sequential `i`, dense `~i`, volatile all-ones, and `ones^1`, plus `find_highest_bit` and `calculate_xor_over_range`. Linux Clang 18.1.3, Linux GCC 13.3, two macOS runs, Windows MSVC 18, Windows MinGW GCC 15.2. No intrinsic rows. +* **Later local Apple Clang 21**, then **CI** (GitHub Actions): full matrix of widths including `uint8_t` / `uint16_t`, plus unselected intrinsic rows, zero, one-hot, and both-halves-live patterns. Use CI for cross-compiler intrinsic evidence; use the early matrix for pre-intrinsic baselines. + + +### Popcount, cross-platform (pre-intrinsic) + +Nanoseconds per call, `uint32_t` / `uint64_t`. Divide the printed loop time by 20,000,000. + +| Row | Linux Clang 18 | Linux GCC 13.3 | macOS Clang 21 | macOS Clang 21 (2nd) | Windows MSVC 18 | MinGW GCC 15.2 | +| --- | --- | --- | --- | --- | --- | --- | +| Kernighan, sequential `i` | 4.9 / 4.9 | 4.8 / 4.8 | 0.21 / 0.20 | 0.18 / 0.18 | 4.9 / 5.3 | 5.3 / 5.5 | +| Kernighan, all-ones | 11.9 / 26.1 | 11.5 / 22.6 | 0.35 / 0.68 | 0.34 / 0.64 | 11.7 / 24.4 | 11.3 / 24.6 | +| 8-bit table, sequential `i` | 0.98 / 0.98 | 0.94 / 0.94 | 1.7 / 1.2 | 1.3 / 0.95 | 1.4 / 1.3 | 0.96 / 0.95 | +| 8-bit table, all-ones | 0.94 / 1.9 | 0.93 / 1.9 | 1.1 / 1.3 | 1.0 / 1.3 | 1.3 / 2.1 | 0.94 / 1.8 | + +`count_bits()` tracks the table on every toolchain, including Apple Clang. + + +### CI: Linux GCC 13.3 (ubuntu, intrinsic rows) + +Nanoseconds per call. Popcount cells shown as `uint8_t` / `uint16_t` / `uint32_t` / `uint64_t` where useful; otherwise `uint32_t` / `uint64_t`. + +| Row | Kernighan | 8-bit table | intrinsic | +| --- | --- | --- | --- | +| sequential `i` | 1.83 / 3.22 / 4.77 / 4.78 | 0.63 / 0.64 / 0.94 / 0.95 | 3.11 / 3.11 / 3.12 / 3.12 | +| `~i` | 1.62 / 3.60 / 8.84 / 14.09 | 0.63 / 0.83 / 0.94 / 0.94 | 3.11 / 3.11 / 3.11 / 3.11 | +| all-ones | 2.80 / 9.98 / 11.26 / 31.48 | 0.62 / 0.64 / 0.97 / 1.84 | 3.11 / 3.12 / 3.11 / 3.12 | +| rotating bit | 0.62 / 0.62 / 0.62 / 0.94 | 1.18 / 1.19 / 1.06 / 1.87 | 3.43 / 3.11 / 3.11 / 3.11 | + +`count_bits()` tracks the table. The intrinsic is flat at about **3.11 ns** on every density and width — a libgcc-style helper, not hardware `POPCNT`. The table wins by about 3× on sequential and dense inputs. Dense Kernighan still scales with set-bit count (all-ones `uint64_t` ~31 ns). + + +### CI: Apple Clang 21 (macos) + +| Row | Kernighan | 8-bit table | intrinsic | +| --- | --- | --- | --- | +| sequential `i` (32/64) | 0.21 / 0.25 | 1.69 / 1.20 | 0.36 / 0.40 | +| all-ones (32/64) | 0.44 / 0.81 | 1.47 / 2.03 | 0.49 / 0.44 | +| rotating bit (32/64) | 0 / 0.47 | 1.77 / 1.98 | 0 / 0 | + +Kernighan and the intrinsic stay in the same hardware-popcount band; `/bit` again deletes several loops (0 ns, anchor still `80,000,000` with 8/16 columns). The table remains ~1–2 ns. `find_highest_bit_by_intrinsic` is clearly faster than the scan from 16 bits up (sequential 0.32 / 0.19 / 0.22 vs 1.53 / 1.25 / 1.23 for 16/32/64). + + +## Learnings + +* **Kernighan scales with the number of set bits when the compiler leaves the loop alone.** All-ones is about 32 iterations for `uint32_t`, and about twice that for `uint64_t` (two 32-bit calls). That is Linux Clang 18, Linux GCC 13.3, MSVC, and MinGW GCC 15.2. +* **Apple Clang rewrites the Kernighan source into the same class of instruction as the intrinsic.** CI macOS Clang 21 reproduces that. Local runs with a live high half showed the intrinsic beating two-call Kernighan on dense 64-bit words. +* **Generic x86-64 does not emit `POPCNT` for this loop or for `__builtin_popcount`.** CI Linux GCC 13.3 is the decisive measurement: the explicit intrinsic is a flat ~3.11 ns call (library helper), while the table is ~0.6–1.0 ns. Recognition of the idiom is not enough if the target forbids the instruction. +* **A one-hot input can delete Kernighan and the popcount intrinsic on Apple Clang.** `/bit` reports 0 ns while the anchor stays non-zero. The table stays near 1–2 ns. Do not read a zero time as "sparse popcount is free". Linux GCC does not delete those loops (~0.6 ns Kernighan, ~3.1 ns intrinsic). +* **Sequential `uint64_t` is not a 64-bit input.** `uint64_t v = i` with `i` below 2^25 has a zero high half. All-ones and `~i` are the rows that exercise the high half. +* **The table is density-insensitive relative to Kernighan**, with byte-wise shortcuts on all-zero / all-ones and on copied halves. +* **`find_highest_bit` is a software scan by default.** On Apple Clang the `clz` / `BitScanReverse` intrinsic is faster from 16 bits up. On Linux GCC 13.3 the intrinsic is only sometimes better (sequential 32-bit 1.24 vs 1.67; elsewhere similar or worse), so it does not justify a default switch on that toolchain alone. +* **XOR is a range scan** and does not justify SIMD on this harness (`n` at most 64, data in L1). + + +## Strategy + +* **Keep the 8-bit table as the default** for `count_bits()`, on every architecture. +* **Do not select Kernighan by Apple, by ARM, or by Clang.** The measured switch is "this compiler, on this target, rewrote this loop". Apple Clang 21 did. Linux GCC 13.3 did not. +* **Leave `STLSOFT_BIT_COUNT_BY_Kernighan` as an opt-in** for a build that has been measured. +* **Keep `count_bits_by_intrinsic()` unselected.** On Apple Clang it matches rewritten Kernighan and beats the table when the loop is not deleted. On Linux GCC 13.3 without a `POPCNT`-legal arch it is ~3× slower than the table. `count_bits()` still uses the table. +* **Keep `find_highest_bit_by_intrinsic()` unselected.** Favourable on Apple Clang from 16 bits up; mixed on Linux GCC 13.3. `find_highest_bit()` still uses the shift-and-split scan. +* **MSVC popcount is gated by architecture and toolset, in `external/bitfns.h`.** `__popcnt16` / `__popcnt`: x86 and x64 from MSVC 15.00, ARM64 from VS 2022 17.11 (`_MSC_VER` 1941); not 32-bit ARM or ARM64EC. `__popcnt64`: x64 from 15.00, ARM64 and ARM64EC from 17.11. `_BitScanReverse64`: ARM64, ARM64EC, and x64 from 14.00. When a GCC/Clang builtin and an MSVC intrinsic are both visible, the builtin wins. +* **Do not change `calculate_xor_over_range` for performance** on the strength of this harness. + + +## Not yet done + +* Selecting either intrinsic into the dispatchers. Apple Clang favours both; Linux GCC 13.3 favours the table for popcount and is mixed for highest-bit. Still wanted: MSVC and MinGW intrinsic rows, and a build with `-march=native` / `-mpopcnt` / `/arch` that allows `POPCNT`. +* GCC, or non-Apple Clang, on Apple Silicon. +* Correct INTERNAL `clz(0)` to full width (`32` / `64`), then optionally drive `find_highest_bit_by_intrinsic` through those adapters. + + + diff --git a/test/performance/CMakeLists.txt b/test/performance/CMakeLists.txt index 1e025c0e..e65c7bf9 100644 --- a/test/performance/CMakeLists.txt +++ b/test/performance/CMakeLists.txt @@ -1,4 +1,6 @@ +add_subdirectory(stlsoft) + if(X_CMAKE_CXX_FULLSTANDARD GREATER_EQUAL 2011) add_subdirectory(test.performance.platformstl.stopwatch) diff --git a/test/performance/stlsoft/CMakeLists.txt b/test/performance/stlsoft/CMakeLists.txt new file mode 100644 index 00000000..c14ae17f --- /dev/null +++ b/test/performance/stlsoft/CMakeLists.txt @@ -0,0 +1,2 @@ +# SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten +add_subdirectory(bit_functions) diff --git a/test/performance/stlsoft/bit_functions/CMakeLists.txt b/test/performance/stlsoft/bit_functions/CMakeLists.txt new file mode 100644 index 00000000..96b868bb --- /dev/null +++ b/test/performance/stlsoft/bit_functions/CMakeLists.txt @@ -0,0 +1,2 @@ +# SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten +define_example_program(test.performance.stlsoft.bit_functions main.cpp) diff --git a/test/performance/stlsoft/bit_functions/main.cpp b/test/performance/stlsoft/bit_functions/main.cpp new file mode 100644 index 00000000..b19331e8 --- /dev/null +++ b/test/performance/stlsoft/bit_functions/main.cpp @@ -0,0 +1,3830 @@ +/* ///////////////////////////////////////////////////////////////////////// + * File: test.performance.stlsoft.bit_functions/main.cpp + * + * Purpose: Perf-test for bit functions. + * + * Created: 24th September 2026 + * Updated: 25th September 2026 + * + * ////////////////////////////////////////////////////////////////////// */ + + +/* ///////////////////////////////////////////////////////////////////////// + * compatibility + */ + +#if !defined(__cplusplus) || \ + __cplusplus < 201103L +# error Requires C++11 or later +#endif + + +/* ///////////////////////////////////////////////////////////////////////// + * feature control + */ + + +/* ///////////////////////////////////////////////////////////////////////// + * includes + */ + +#include + +#if __cplusplus >= 201103L +# include +#else +# include +#endif /* C++11+ */ +#include + +#include +#include +#include + +#include +#include +#include + + +/* ///////////////////////////////////////////////////////////////////////// + * types + */ + +#if __cplusplus >= 201103L + +typedef stlsoft::std_chrono_hrc_stopwatch stopwatch_t; +#else + +typedef platformstl::stopwatch stopwatch_t; +#endif /* C++11+ */ +typedef stopwatch_t::interval_type interval_t; + +using stlsoft::ss_size_t; +using stlsoft::ss_uint8_t; +using stlsoft::ss_uint16_t; +using stlsoft::ss_uint32_t; +using stlsoft::ss_uint64_t; + + +/* ///////////////////////////////////////////////////////////////////////// + * forward declarations + */ + +void +emit_result_row( + char const* function_name +, interval_t const* uint8_ns +, interval_t const* uint16_ns +, interval_t const* uint32_ns +, interval_t const* uint64_ns +, interval_t const* int_ns +, ss_uint64_t anchor_value +, bool report_per_element +); + + +/* ///////////////////////////////////////////////////////////////////////// + * constants + */ + +namespace { + + ss_size_t const NUM_ITERATIONS = 20000000; + ss_size_t const NUM_SAMPLES = 5; + ss_size_t const XOR_RANGE_LEN = 64; + int const FN_COL_WIDTH = 42; + int const METRIC_COL_WIDTH = 16; + + + interval_t + median_sample( + interval_t const* samples + , ss_size_t n + ) + { + interval_t sorted[NUM_SAMPLES] = {}; + + if (0 == n) + { + return 0; + } + + if (n > NUM_SAMPLES) + { + n = NUM_SAMPLES; + } + + for (ss_size_t i = 0; n != i; ++i) + { + sorted[i] = samples[i]; + } + + for (ss_size_t i = 1; n != i; ++i) + { + interval_t const v = sorted[i]; + ss_size_t j = i; + + for (; 0 != j && sorted[j - 1] > v; --j) + { + sorted[j] = sorted[j - 1]; + } + + sorted[j] = v; + } + + return sorted[n / 2]; + } + + struct row_samples + { + interval_t u8[NUM_SAMPLES]; + interval_t u16[NUM_SAMPLES]; + interval_t u32[NUM_SAMPLES]; + interval_t u64[NUM_SAMPLES]; + interval_t si[NUM_SAMPLES]; + ss_size_t n; + ss_uint64_t anchor; + bool has_u8; + bool has_u16; + bool has_u32; + bool has_u64; + bool has_si; + + void clear() + { + n = 0; + anchor = 0; + has_u8 = false; + has_u16 = false; + has_u32 = false; + has_u64 = false; + has_si = false; + } + + void push( + interval_t const* uint8_ns + , interval_t const* uint16_ns + , interval_t const* uint32_ns + , interval_t const* uint64_ns + , interval_t const* int_ns + , ss_uint64_t anchor_value + ) + { + has_u8 = NULL != uint8_ns; + has_u16 = NULL != uint16_ns; + has_u32 = NULL != uint32_ns; + has_u64 = NULL != uint64_ns; + has_si = NULL != int_ns; + + if (has_u8) + { + u8[n] = *uint8_ns; + } + if (has_u16) + { + u16[n] = *uint16_ns; + } + if (has_u32) + { + u32[n] = *uint32_ns; + } + if (has_u64) + { + u64[n] = *uint64_ns; + } + if (has_si) + { + si[n] = *int_ns; + } + + anchor = anchor_value; + ++n; + } + + void emit( + char const* function_name + , bool report_per_element = false + ) const + { + interval_t const med_u8 = has_u8 ? median_sample(u8, n) : 0; + interval_t const med_u16 = has_u16 ? median_sample(u16, n) : 0; + interval_t const med_u32 = has_u32 ? median_sample(u32, n) : 0; + interval_t const med_u64 = has_u64 ? median_sample(u64, n) : 0; + interval_t const med_si = has_si ? median_sample(si, n) : 0; + + emit_result_row( + function_name + , has_u8 ? &med_u8 : NULL + , has_u16 ? &med_u16 : NULL + , has_u32 ? &med_u32 : NULL + , has_u64 ? &med_u64 : NULL + , has_si ? &med_si : NULL + , anchor + , report_per_element + ); + } + }; +} // anonymous namespace + + +/* ///////////////////////////////////////////////////////////////////////// + * functions + */ + +template +std::string +thousands( + T_integer const& v +) +{ + char dest[41]; + size_t const n = stlsoft::format_thousands(dest, STLSOFT_NUM_ELEMENTS(dest), "3;0", v); + + return std::string(dest, n); +} + +void +emit_metric_cell( + char const* s +) +{ + std::cout + << '\t' + << std::setw(METRIC_COL_WIDTH) << std::right << s; +} + +void +emit_metric_cell( + interval_t const& v +) +{ + emit_metric_cell(thousands(v).c_str()); +} + +void +emit_absent_metric_cell() +{ + emit_metric_cell("-"); +} + +void +emit_rate_cell( + interval_t const* total_ns +, double divisor +); + +void +emit_header_row() +{ + std::cout + << std::setw(FN_COL_WIDTH) << std::left << "" + ; + emit_metric_cell("uint8_t"); + emit_metric_cell("uint16_t"); + emit_metric_cell("uint32_t"); + emit_metric_cell("uint64_t"); + emit_metric_cell("int"); + emit_metric_cell("uint8_t ns"); + emit_metric_cell("uint16_t ns"); + emit_metric_cell("uint32_t ns"); + emit_metric_cell("uint64_t ns"); + emit_metric_cell("int ns"); + emit_metric_cell("uint8_t el"); + emit_metric_cell("uint16_t el"); + emit_metric_cell("uint32_t el"); + emit_metric_cell("uint64_t el"); + emit_metric_cell("anchor"); + std::cout << std::endl; +} + +bool +env_is_truey( + char const* name +) +{ +#if defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable : 4996) +#endif + char const* const env = ::getenv(name); +#if defined(_MSC_VER) +# pragma warning(pop) +#endif + + if (NULL == env || '\0' == *env) + { + return false; + } + + if (0 == ::strcmp(env, "1") || + 0 == ::strcmp(env, "ok") || + 0 == ::strcmp(env, "on") || + 0 == ::strcmp(env, "true") || + 0 == ::strcmp(env, "yes") || + 0 == ::strcmp(env, "y") || + 0 == ::strcmp(env, "OK") || + 0 == ::strcmp(env, "ON") || + 0 == ::strcmp(env, "TRUE") || + 0 == ::strcmp(env, "YES") || + 0 == ::strcmp(env, "Y")) + { + return true; + } + + return false; +} + +void +maybe_emit_group_gap( + char const* function_name +) +{ + static bool have_prev = false; + static char prev_key[64] = ""; + + if (!env_is_truey("SIS_PERFTESTS_GROUPGAPS")) + { + return; + } + + char const* const slash = ::strrchr(function_name, '/'); + char const* const pattern = (NULL == slash) ? "" : slash; + char const* family = "other"; + + if (0 == ::strncmp(function_name, "count_bits", 10)) + { + family = "count"; + } + else if (0 == ::strncmp(function_name, "find_highest_bit", 16)) + { + family = "find"; + } + else if (0 == ::strncmp(function_name, "calculate_xor", 13)) + { + family = "xor"; + } + + char key[64]; + + snprintf(key, sizeof(key), "%s%s", family, pattern); + + if (have_prev && 0 != ::strcmp(prev_key, key)) + { + std::cout << std::endl; + } + + snprintf(prev_key, sizeof(prev_key), "%s", key); + have_prev = true; +} + +void +emit_result_row( + char const* function_name +, interval_t const* uint8_ns +, interval_t const* uint16_ns +, interval_t const* uint32_ns +, interval_t const* uint64_ns +, interval_t const* int_ns +, ss_uint64_t anchor_value +, bool report_per_element +) +{ + maybe_emit_group_gap(function_name); + + std::cout + << std::setw(FN_COL_WIDTH) << std::left << function_name + ; + + if (NULL != uint8_ns) + { + emit_metric_cell(*uint8_ns); + } + else + { + emit_absent_metric_cell(); + } + + if (NULL != uint16_ns) + { + emit_metric_cell(*uint16_ns); + } + else + { + emit_absent_metric_cell(); + } + + if (NULL != uint32_ns) + { + emit_metric_cell(*uint32_ns); + } + else + { + emit_absent_metric_cell(); + } + + if (NULL != uint64_ns) + { + emit_metric_cell(*uint64_ns); + } + else + { + emit_absent_metric_cell(); + } + + if (NULL != int_ns) + { + emit_metric_cell(*int_ns); + } + else + { + emit_absent_metric_cell(); + } + + double const per_call = double(NUM_ITERATIONS); + double const per_element = double(NUM_ITERATIONS) * double(XOR_RANGE_LEN + 1) / 2.0; + + emit_rate_cell(uint8_ns, per_call); + emit_rate_cell(uint16_ns, per_call); + emit_rate_cell(uint32_ns, per_call); + emit_rate_cell(uint64_ns, per_call); + emit_rate_cell(int_ns, per_call); + + if (report_per_element) + { + emit_rate_cell(uint8_ns, per_element); + emit_rate_cell(uint16_ns, per_element); + emit_rate_cell(uint32_ns, per_element); + emit_rate_cell(uint64_ns, per_element); + } + else + { + emit_absent_metric_cell(); + emit_absent_metric_cell(); + emit_absent_metric_cell(); + emit_absent_metric_cell(); + } + + emit_metric_cell(thousands(anchor_value).c_str()); + std::cout << std::endl; +} + +void +emit_rate_cell( + interval_t const* total_ns +, double divisor +) +{ + if (NULL == total_ns) + { + emit_absent_metric_cell(); + + return; + } + + char buf[32]; + double const rate = (0.0 == divisor) ? 0.0 : (double(*total_ns) / divisor); + + snprintf(buf, sizeof(buf), "%.3f", rate); + + emit_metric_cell(buf); +} + +void +emit_build_banner() +{ + std::cout << "compiler: " << STLSOFT_COMPILER_VERSION_STRING << std::endl; + std::cout << "optimisation: "; +#if 0 +#elif defined(__OPTIMIZE_SIZE__) + + std::cout << "size"; +#elif defined(__OPTIMIZE__) + + std::cout << "speed"; +#elif defined(STLSOFT_COMPILER_IS_MSVC) && \ + !defined(STLSOFT_DEBUG) + + std::cout << "speed"; +#else + + std::cout << "off"; +#endif +#ifdef NDEBUG + + std::cout << ", release"; +#else + + std::cout << ", debug-asserts"; +#endif + std::cout << std::endl; + std::cout + << "samples: " + << NUM_SAMPLES + << " (median; 1 warmup discarded)" + << std::endl; + std::cout + << "width columns are loop ns; ns columns are ns/call; el columns are ns/element" + << std::endl; + if (env_is_truey("SIS_PERFTESTS_GROUPGAPS")) + { + std::cout + << "Env: SIS_PERFTESTS_GROUPGAPS=1" + << std::endl; + } +} + + +/* ///////////////////////////////////////////////////////////////////////// + * main() + */ + +int main(int /*argc*/, char* /*argv*/[]) +{ + ss_uint8_t xor8[XOR_RANGE_LEN]; + ss_uint16_t xor16[XOR_RANGE_LEN]; + ss_uint32_t xor32[XOR_RANGE_LEN]; + ss_uint64_t xor64[XOR_RANGE_LEN]; + + for (ss_size_t i = 0; XOR_RANGE_LEN != i; ++i) + { + xor8[i] = static_cast(i * 3u + 1u); + xor16[i] = static_cast(i * 7u + 1u); + xor32[i] = static_cast(i * 11u + 1u); + xor64[i] = static_cast(i * 13u + 1u); + } + + row_samples rows; + + emit_build_banner(); + emit_header_row(); + + + // count_bits_by_Kernighan_method + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = ss_uint8_t(i); + + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = ss_uint16_t(i); + + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = i; + + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = i; + + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits_by_Kernighan_method()"); + } + } + + + // count_bits_by_8bit_table + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = ss_uint8_t(i); + + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = ss_uint16_t(i); + + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = i; + + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = i; + + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits_by_8bit_table()"); + } + } + + + // count_bits + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = ss_uint8_t(i); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = ss_uint16_t(i); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = i; + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = i; + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + int const v = static_cast(i); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_int = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , &int_int + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits()"); + } + + } + +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt_SUPPORT) + // count_bits_by_intrinsic (sequential) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = ss_uint8_t(i); + + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = ss_uint16_t(i); + + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = i; + + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt64_SUPPORT) + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = i; + + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); +#endif + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt64_SUPPORT) + , &int_uint64 +#else + , NULL +#endif + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits_by_intrinsic()"); + } + } +#endif + + + // ------------------------------------------------------------------ + // Dense inputs (~i): high popcount — favourable to the table path + // ------------------------------------------------------------------ + + // count_bits_by_Kernighan_method (dense) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = ~ss_uint8_t(i); + + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = ~ss_uint16_t(i); + + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = ~ss_uint32_t(i); + + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = ~ss_uint64_t(i); + + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits_by_Kernighan_method()/~i"); + } + } + + + // count_bits_by_8bit_table (dense) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = ~ss_uint8_t(i); + + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = ~ss_uint16_t(i); + + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = ~ss_uint32_t(i); + + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = ~ss_uint64_t(i); + + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits_by_8bit_table()/~i"); + } + } + + + // count_bits (dense) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = ~ss_uint8_t(i); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = ~ss_uint16_t(i); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = ~ss_uint32_t(i); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = ~ss_uint64_t(i); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + int const v = static_cast(~ss_uint32_t(i)); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_int = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , &int_int + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits()/~i"); + } + + } + +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt_SUPPORT) + // count_bits_by_intrinsic (/~i) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = ~ss_uint8_t(i); + + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = ~ss_uint16_t(i); + + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = ~ss_uint32_t(i); + + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt64_SUPPORT) + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = ~ss_uint64_t(i); + + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); +#endif + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt64_SUPPORT) + , &int_uint64 +#else + , NULL +#endif + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits_by_intrinsic()/~i"); + } + } +#endif + + + // ------------------------------------------------------------------ + // Max density (all-ones). Source via volatile so inlining cannot + // constant-fold popcount(~0) to a literal. + // ------------------------------------------------------------------ + + { + ss_uint8_t volatile ones8 = ss_uint8_t(~ss_uint8_t(0)); + ss_uint16_t volatile ones16 = ss_uint16_t(~ss_uint16_t(0)); + ss_uint32_t volatile ones32 = ~ss_uint32_t(0); + ss_uint64_t volatile ones64 = ~ss_uint64_t(0); + + + // count_bits_by_Kernighan_method (max) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = ones8; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = ones16; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = ones32; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = ones64; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits_by_Kernighan_method()/ones"); + } + } + + + // count_bits_by_8bit_table (max) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = ones8; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = ones16; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = ones32; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = ones64; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits_by_8bit_table()/ones"); + } + } + + + // count_bits (max) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = ones8; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = ones16; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = ones32; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = ones64; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + int const v = static_cast(ones32); + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_int = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , &int_int + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits()/ones"); + } + + } + +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt_SUPPORT) + // count_bits_by_intrinsic (/ones) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = ones8; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = ones16; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = ones32; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt64_SUPPORT) + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = ones64; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); +#endif + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt64_SUPPORT) + , &int_uint64 +#else + , NULL +#endif + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits_by_intrinsic()/ones"); + } + } +#endif + + } + + + // ------------------------------------------------------------------ + // Close-to-max: all-ones with one rotating bit cleared (31 / 63 ones) + // ------------------------------------------------------------------ + + // count_bits_by_Kernighan_method (close-to-max) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = ss_uint8_t(~ss_uint8_t(0)) ^ (ss_uint8_t(1) << (i % 8u)); + + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = ss_uint16_t(~ss_uint16_t(0)) ^ (ss_uint16_t(1) << (i % 16u)); + + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = ~ss_uint32_t(0) ^ (ss_uint32_t(1) << (i % 32u)); + + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = ~ss_uint64_t(0) ^ (ss_uint64_t(1) << (i % 64u)); + + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits_by_Kernighan_method()/ones^1"); + } + } + + + // count_bits_by_8bit_table (close-to-max) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = ss_uint8_t(~ss_uint8_t(0)) ^ (ss_uint8_t(1) << (i % 8u)); + + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = ss_uint16_t(~ss_uint16_t(0)) ^ (ss_uint16_t(1) << (i % 16u)); + + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = ~ss_uint32_t(0) ^ (ss_uint32_t(1) << (i % 32u)); + + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = ~ss_uint64_t(0) ^ (ss_uint64_t(1) << (i % 64u)); + + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits_by_8bit_table()/ones^1"); + } + } + + + // count_bits (close-to-max) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = ss_uint8_t(~ss_uint8_t(0)) ^ (ss_uint8_t(1) << (i % 8u)); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = ss_uint16_t(~ss_uint16_t(0)) ^ (ss_uint16_t(1) << (i % 16u)); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = ~ss_uint32_t(0) ^ (ss_uint32_t(1) << (i % 32u)); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = ~ss_uint64_t(0) ^ (ss_uint64_t(1) << (i % 64u)); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + int const v = static_cast(~ss_uint32_t(0) ^ (ss_uint32_t(1) << (i % 32u))); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_int = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , &int_int + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits()/ones^1"); + } + + } + +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt_SUPPORT) + // count_bits_by_intrinsic (/ones^1) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = ss_uint8_t(~ss_uint8_t(0)) ^ (ss_uint8_t(1) << (i % 8u)); + + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = ss_uint16_t(~ss_uint16_t(0)) ^ (ss_uint16_t(1) << (i % 16u)); + + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = ~ss_uint32_t(0) ^ (ss_uint32_t(1) << (i % 32u)); + + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt64_SUPPORT) + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = ~ss_uint64_t(0) ^ (ss_uint64_t(1) << (i % 64u)); + + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); +#endif + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt64_SUPPORT) + , &int_uint64 +#else + , NULL +#endif + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits_by_intrinsic()/ones^1"); + } + } +#endif + + + // ------------------------------------------------------------------ + // All-zero. Volatile so the call is not constant-folded to 0. + // ------------------------------------------------------------------ + + { + ss_uint8_t volatile zero8 = 0; + ss_uint16_t volatile zero16 = 0; + ss_uint32_t volatile zero32 = 0; + ss_uint64_t volatile zero64 = 0; + + + // count_bits_by_Kernighan_method (zero) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = zero8; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = zero16; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = zero32; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = zero64; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits_by_Kernighan_method()/0"); + } + } + + + // count_bits_by_8bit_table (zero) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = zero8; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = zero16; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = zero32; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = zero64; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits_by_8bit_table()/0"); + } + } + + + // count_bits (zero) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = zero8; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = zero16; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = zero32; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = zero64; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + int const v = static_cast(zero32); + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_int = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , &int_int + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits()/0"); + } + + } + +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt_SUPPORT) + // count_bits_by_intrinsic (/0) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = zero8; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = zero16; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = zero32; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt64_SUPPORT) + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = zero64; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); +#endif + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt64_SUPPORT) + , &int_uint64 +#else + , NULL +#endif + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits_by_intrinsic()/0"); + } + } +#endif + + } + + + // ------------------------------------------------------------------ + // Single rotating bit. The 64-bit shift reaches bits 32..63. + // ------------------------------------------------------------------ + + // count_bits_by_Kernighan_method (bit) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = ss_uint8_t(1) << (i % 8u); + + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = ss_uint16_t(1) << (i % 16u); + + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = ss_uint32_t(1) << (i % 32u); + + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = ss_uint64_t(1) << (i % 64u); + + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits_by_Kernighan_method()/bit"); + } + } + + + // count_bits_by_8bit_table (bit) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = ss_uint8_t(1) << (i % 8u); + + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = ss_uint16_t(1) << (i % 16u); + + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = ss_uint32_t(1) << (i % 32u); + + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = ss_uint64_t(1) << (i % 64u); + + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits_by_8bit_table()/bit"); + } + } + + + // count_bits (bit) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = ss_uint8_t(1) << (i % 8u); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = ss_uint16_t(1) << (i % 16u); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = ss_uint32_t(1) << (i % 32u); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = ss_uint64_t(1) << (i % 64u); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + int const v = static_cast(ss_uint32_t(1) << (i % 32u)); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_int = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , &int_int + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits()/bit"); + } + + } + +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt_SUPPORT) + // count_bits_by_intrinsic (/bit) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = ss_uint8_t(1) << (i % 8u); + + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = ss_uint16_t(1) << (i % 16u); + + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = ss_uint32_t(1) << (i % 32u); + + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt64_SUPPORT) + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = ss_uint64_t(1) << (i % 64u); + + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); +#endif + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt64_SUPPORT) + , &int_uint64 +#else + , NULL +#endif + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits_by_intrinsic()/bit"); + } + } +#endif + + + // ------------------------------------------------------------------ + // Both halves live. uint32 high 16 bits vary; uint64 high half is i. + // ------------------------------------------------------------------ + + // count_bits_by_Kernighan_method (wide) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = (ss_uint8_t(i) << 4) | ss_uint8_t(i & 0x0fu); + + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = (ss_uint16_t(i) << 8) | ss_uint16_t(i & 0xffu); + + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = (ss_uint32_t(i) << 16) | ss_uint32_t(i & 0xffffu); + + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = (ss_uint64_t(i) << 32) | ss_uint64_t(i); + + anchor_value += stlsoft::count_bits_by_Kernighan_method(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits_by_Kernighan_method()/wide"); + } + } + + + // count_bits_by_8bit_table (wide) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = (ss_uint8_t(i) << 4) | ss_uint8_t(i & 0x0fu); + + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = (ss_uint16_t(i) << 8) | ss_uint16_t(i & 0xffu); + + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = (ss_uint32_t(i) << 16) | ss_uint32_t(i & 0xffffu); + + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = (ss_uint64_t(i) << 32) | ss_uint64_t(i); + + anchor_value += stlsoft::count_bits_by_8bit_table(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits_by_8bit_table()/wide"); + } + } + + + // count_bits (wide) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = (ss_uint8_t(i) << 4) | ss_uint8_t(i & 0x0fu); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = (ss_uint16_t(i) << 8) | ss_uint16_t(i & 0xffu); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = (ss_uint32_t(i) << 16) | ss_uint32_t(i & 0xffffu); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = (ss_uint64_t(i) << 32) | ss_uint64_t(i); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + int const v = static_cast((ss_uint32_t(i) << 16) | ss_uint32_t(i & 0xffffu)); + + anchor_value += stlsoft::count_bits(v); + } + sw.stop(); + + interval_t const int_int = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , &int_int + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits()/wide"); + } + + } + +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt_SUPPORT) + // count_bits_by_intrinsic (/wide) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = (ss_uint8_t(i) << 4) | ss_uint8_t(i & 0x0fu); + + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = (ss_uint16_t(i) << 8) | ss_uint16_t(i & 0xffu); + + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = (ss_uint32_t(i) << 16) | ss_uint32_t(i & 0xffffu); + + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt64_SUPPORT) + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = (ss_uint64_t(i) << 32) | ss_uint64_t(i); + + anchor_value += stlsoft::count_bits_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); +#endif + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt64_SUPPORT) + , &int_uint64 +#else + , NULL +#endif + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("count_bits_by_intrinsic()/wide"); + } + } +#endif + + + // find_highest_bit + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = static_cast(i & 0xff); + + anchor_value += stlsoft::find_highest_bit(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = static_cast(i & 0xffff); + + anchor_value += stlsoft::find_highest_bit(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = i; + + anchor_value += stlsoft::find_highest_bit(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = i; + + anchor_value += stlsoft::find_highest_bit(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("find_highest_bit()"); + } + + } + +#if defined(STLSOFT_CF__builtin_clz_SUPPORT) || \ + defined(STLSOFT_CF__BitScanReverse_SUPPORT) + // find_highest_bit_by_intrinsic (sequential) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = ss_uint8_t(i); + + anchor_value += stlsoft::find_highest_bit_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = ss_uint16_t(i); + + anchor_value += stlsoft::find_highest_bit_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = i; + + anchor_value += stlsoft::find_highest_bit_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + +#if defined(STLSOFT_CF__builtin_clz_SUPPORT) || \ + defined(STLSOFT_CF__BitScanReverse64_SUPPORT) + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = i; + + anchor_value += stlsoft::find_highest_bit_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); +#endif + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 +#if defined(STLSOFT_CF__builtin_clz_SUPPORT) || \ + defined(STLSOFT_CF__BitScanReverse64_SUPPORT) + , &int_uint64 +#else + , NULL +#endif + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("find_highest_bit_by_intrinsic()"); + } + } +#endif + + + // ------------------------------------------------------------------ + // find_highest_bit: zero, one rotating bit, both halves live. + // ------------------------------------------------------------------ + + { + ss_uint8_t volatile zero8 = 0; + ss_uint16_t volatile zero16 = 0; + ss_uint32_t volatile zero32 = 0; + ss_uint64_t volatile zero64 = 0; + + + // find_highest_bit (zero) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = zero8; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::find_highest_bit(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = zero16; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::find_highest_bit(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = zero32; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::find_highest_bit(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = zero64; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::find_highest_bit(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("find_highest_bit()/0"); + } + + } + +#if defined(STLSOFT_CF__builtin_clz_SUPPORT) || \ + defined(STLSOFT_CF__BitScanReverse_SUPPORT) + // find_highest_bit_by_intrinsic (/0) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = zero8; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::find_highest_bit_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = zero16; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::find_highest_bit_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = zero32; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::find_highest_bit_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + +#if defined(STLSOFT_CF__builtin_clz_SUPPORT) || \ + defined(STLSOFT_CF__BitScanReverse64_SUPPORT) + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = zero64; + + STLSOFT_SUPPRESS_UNUSED(i); + anchor_value += stlsoft::find_highest_bit_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); +#endif + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 +#if defined(STLSOFT_CF__builtin_clz_SUPPORT) || \ + defined(STLSOFT_CF__BitScanReverse64_SUPPORT) + , &int_uint64 +#else + , NULL +#endif + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("find_highest_bit_by_intrinsic()/0"); + } + } +#endif + + } + + + // find_highest_bit (bit) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = static_cast(1u << (i % 8u)); + + anchor_value += stlsoft::find_highest_bit(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = static_cast(1u << (i % 16u)); + + anchor_value += stlsoft::find_highest_bit(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = ss_uint32_t(1) << (i % 32u); + + anchor_value += stlsoft::find_highest_bit(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = ss_uint64_t(1) << (i % 64u); + + anchor_value += stlsoft::find_highest_bit(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("find_highest_bit()/bit"); + } + + } + +#if defined(STLSOFT_CF__builtin_clz_SUPPORT) || \ + defined(STLSOFT_CF__BitScanReverse_SUPPORT) + // find_highest_bit_by_intrinsic (/bit) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = static_cast(1u << (i % 8u)); + + anchor_value += stlsoft::find_highest_bit_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = static_cast(1u << (i % 16u)); + + anchor_value += stlsoft::find_highest_bit_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = ss_uint32_t(1) << (i % 32u); + + anchor_value += stlsoft::find_highest_bit_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + +#if defined(STLSOFT_CF__builtin_clz_SUPPORT) || \ + defined(STLSOFT_CF__BitScanReverse64_SUPPORT) + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = ss_uint64_t(1) << (i % 64u); + + anchor_value += stlsoft::find_highest_bit_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); +#endif + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 +#if defined(STLSOFT_CF__builtin_clz_SUPPORT) || \ + defined(STLSOFT_CF__BitScanReverse64_SUPPORT) + , &int_uint64 +#else + , NULL +#endif + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("find_highest_bit_by_intrinsic()/bit"); + } + } +#endif + + + // find_highest_bit (wide) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = static_cast(i & 0xff); + + anchor_value += stlsoft::find_highest_bit(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = static_cast(i & 0xffff); + + anchor_value += stlsoft::find_highest_bit(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = (ss_uint32_t(i) << 16) | ss_uint32_t(i & 0xffffu); + + anchor_value += stlsoft::find_highest_bit(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = (ss_uint64_t(i) << 32) | ss_uint64_t(i); + + anchor_value += stlsoft::find_highest_bit(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("find_highest_bit()/wide"); + } + + } + +#if defined(STLSOFT_CF__builtin_clz_SUPPORT) || \ + defined(STLSOFT_CF__BitScanReverse_SUPPORT) + // find_highest_bit_by_intrinsic (/wide) + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint8_t const v = static_cast(i & 0xff); + + anchor_value += stlsoft::find_highest_bit_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint16_t const v = static_cast(i & 0xffff); + + anchor_value += stlsoft::find_highest_bit_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint32_t const v = (ss_uint32_t(i) << 16) | ss_uint32_t(i & 0xffffu); + + anchor_value += stlsoft::find_highest_bit_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + +#if defined(STLSOFT_CF__builtin_clz_SUPPORT) || \ + defined(STLSOFT_CF__BitScanReverse64_SUPPORT) + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_uint64_t const v = (ss_uint64_t(i) << 32) | ss_uint64_t(i); + + anchor_value += stlsoft::find_highest_bit_by_intrinsic(v); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); +#endif + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 +#if defined(STLSOFT_CF__builtin_clz_SUPPORT) || \ + defined(STLSOFT_CF__BitScanReverse64_SUPPORT) + , &int_uint64 +#else + , NULL +#endif + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("find_highest_bit_by_intrinsic()/wide"); + } + } +#endif + + + // calculate_xor_over_range + for (int W = int(NUM_SAMPLES) + 1; 0 != W; --W) + { + if (int(NUM_SAMPLES) + 1 == W) + { + rows.clear(); + } + + stopwatch_t sw; + + ss_uint64_t anchor_value = 0; + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_size_t const n = (i % XOR_RANGE_LEN) + 1u; + + anchor_value += stlsoft::calculate_xor_over_range(xor8, n); + } + sw.stop(); + + interval_t const int_uint8 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_size_t const n = (i % XOR_RANGE_LEN) + 1u; + + anchor_value += stlsoft::calculate_xor_over_range(xor16, n); + } + sw.stop(); + + interval_t const int_uint16 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_size_t const n = (i % XOR_RANGE_LEN) + 1u; + + anchor_value += stlsoft::calculate_xor_over_range(xor32, n); + } + sw.stop(); + + interval_t const int_uint32 = sw.get_nanoseconds(); + + + sw.start(); + for (unsigned i = 0; NUM_ITERATIONS != i; ++i) + { + ss_size_t const n = (i % XOR_RANGE_LEN) + 1u; + + anchor_value += stlsoft::calculate_xor_over_range(xor64, n); + } + sw.stop(); + + interval_t const int_uint64 = sw.get_nanoseconds(); + + + if (W <= int(NUM_SAMPLES)) + { + rows.push( + &int_uint8 + , &int_uint16 + , &int_uint32 + , &int_uint64 + , NULL + , anchor_value + ); + } + + if (1 == W) + { + rows.emit("calculate_xor_over_range()", true); + } + } + + + return EXIT_SUCCESS; +} + + +/* ///////////////////////////// end of file //////////////////////////// */ + diff --git a/test/unit/stlsoft/util/test.unit.stlsoft.util.bit_functions/entry.cpp b/test/unit/stlsoft/util/test.unit.stlsoft.util.bit_functions/entry.cpp index 97e2584f..610ba160 100644 --- a/test/unit/stlsoft/util/test.unit.stlsoft.util.bit_functions/entry.cpp +++ b/test/unit/stlsoft/util/test.unit.stlsoft.util.bit_functions/entry.cpp @@ -4,7 +4,7 @@ * Purpose: Unit-tests for `stlsoft::bit_functions`. * * Created: 19th March 2010 - * Updated: 9th August 2026 + * Updated: 25th September 2026 * * ////////////////////////////////////////////////////////////////////// */ @@ -29,12 +29,10 @@ #include /* STLSoft header files */ -#include /* Standard C++ header files */ /* Standard C header files */ -#include #include @@ -44,11 +42,49 @@ namespace { - static void test_count_bits_Kernighan(); - static void test_count_bits_8bit_table(); - static void test_find_high_bit_32(); - static void test_find_high_bit_64(); - static void test_calculate_xor_over_range_8_bit(); + static void TEST_count_bits_Kernighan_method_FOR_8_BIT(); + static void TEST_count_bits_Kernighan_method_FOR_16_BIT(); + static void TEST_count_bits_Kernighan_method_FOR_32_BIT(); + static void TEST_count_bits_Kernighan_method_FOR_64_BIT(); + static void TEST_count_bits_8bit_table_FOR_8_BIT(); + static void TEST_count_bits_8bit_table_FOR_16_BIT(); + static void TEST_count_bits_8bit_table_FOR_32_BIT(); + static void TEST_count_bits_8bit_table_FOR_64_BIT(); + static void TEST_count_bits_FOR_8_BIT(); + static void TEST_count_bits_FOR_16_BIT(); + static void TEST_count_bits_FOR_32_BIT(); + static void TEST_count_bits_FOR_64_BIT(); + static void TEST_count_bits_FOR_int(); +#if defined(STLSOFT_API_INTERNAL_bitfns_popcount_uint16) + static void TEST_count_bits_by_intrinsic_FOR_8_BIT(); + static void TEST_count_bits_by_intrinsic_FOR_16_BIT(); +#endif +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt_SUPPORT) + static void TEST_count_bits_by_intrinsic_FOR_32_BIT(); +#endif +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt64_SUPPORT) + static void TEST_count_bits_by_intrinsic_FOR_64_BIT(); +#endif +#if defined(STLSOFT_CF__builtin_clz_SUPPORT) || \ + defined(STLSOFT_CF__BitScanReverse_SUPPORT) + static void TEST_find_highest_bit_by_intrinsic_FOR_8_BIT(); + static void TEST_find_highest_bit_by_intrinsic_FOR_16_BIT(); + static void TEST_find_highest_bit_by_intrinsic_FOR_32_BIT(); +#endif +#if defined(STLSOFT_CF__builtin_clz_SUPPORT) || \ + defined(STLSOFT_CF__BitScanReverse64_SUPPORT) + static void TEST_find_highest_bit_by_intrinsic_FOR_64_BIT(); +#endif + static void TEST_find_high_bit_FOR_8_BIT(); + static void TEST_find_high_bit_FOR_16_BIT(); + static void TEST_find_high_bit_FOR_32_BIT(); + static void TEST_find_high_bit_FOR_64_BIT(); + static void TEST_calculate_xor_over_range_FOR_8_BIT(); + static void TEST_calculate_xor_over_range_FOR_16_BIT(); + static void TEST_calculate_xor_over_range_FOR_32_BIT(); + static void TEST_calculate_xor_over_range_FOR_64_BIT(); } // anonymous namespace @@ -56,7 +92,7 @@ namespace { * main */ -int main(int argc, char **argv) +int main(int argc, char* argv[]) { int retCode = EXIT_SUCCESS; int verbosity = 2; @@ -65,11 +101,49 @@ int main(int argc, char **argv) if (XTESTS_START_RUNNER("test.unit.stlsoft.util.bit_functions", verbosity)) { - XTESTS_RUN_CASE(test_count_bits_Kernighan); - XTESTS_RUN_CASE(test_count_bits_8bit_table); - XTESTS_RUN_CASE(test_find_high_bit_32); - XTESTS_RUN_CASE(test_find_high_bit_64); - XTESTS_RUN_CASE(test_calculate_xor_over_range_8_bit); + XTESTS_RUN_CASE(TEST_count_bits_Kernighan_method_FOR_8_BIT); + XTESTS_RUN_CASE(TEST_count_bits_Kernighan_method_FOR_16_BIT); + XTESTS_RUN_CASE(TEST_count_bits_Kernighan_method_FOR_32_BIT); + XTESTS_RUN_CASE(TEST_count_bits_Kernighan_method_FOR_64_BIT); + XTESTS_RUN_CASE(TEST_count_bits_8bit_table_FOR_8_BIT); + XTESTS_RUN_CASE(TEST_count_bits_8bit_table_FOR_16_BIT); + XTESTS_RUN_CASE(TEST_count_bits_8bit_table_FOR_32_BIT); + XTESTS_RUN_CASE(TEST_count_bits_8bit_table_FOR_64_BIT); + XTESTS_RUN_CASE(TEST_count_bits_FOR_8_BIT); + XTESTS_RUN_CASE(TEST_count_bits_FOR_16_BIT); + XTESTS_RUN_CASE(TEST_count_bits_FOR_32_BIT); + XTESTS_RUN_CASE(TEST_count_bits_FOR_64_BIT); + XTESTS_RUN_CASE(TEST_count_bits_FOR_int); +#if defined(STLSOFT_API_INTERNAL_bitfns_popcount_uint16) + XTESTS_RUN_CASE(TEST_count_bits_by_intrinsic_FOR_8_BIT); + XTESTS_RUN_CASE(TEST_count_bits_by_intrinsic_FOR_16_BIT); +#endif +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt_SUPPORT) + XTESTS_RUN_CASE(TEST_count_bits_by_intrinsic_FOR_32_BIT); +#endif +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt64_SUPPORT) + XTESTS_RUN_CASE(TEST_count_bits_by_intrinsic_FOR_64_BIT); +#endif +#if defined(STLSOFT_CF__builtin_clz_SUPPORT) || \ + defined(STLSOFT_CF__BitScanReverse_SUPPORT) + XTESTS_RUN_CASE(TEST_find_highest_bit_by_intrinsic_FOR_8_BIT); + XTESTS_RUN_CASE(TEST_find_highest_bit_by_intrinsic_FOR_16_BIT); + XTESTS_RUN_CASE(TEST_find_highest_bit_by_intrinsic_FOR_32_BIT); +#endif +#if defined(STLSOFT_CF__builtin_clz_SUPPORT) || \ + defined(STLSOFT_CF__BitScanReverse64_SUPPORT) + XTESTS_RUN_CASE(TEST_find_highest_bit_by_intrinsic_FOR_64_BIT); +#endif + XTESTS_RUN_CASE(TEST_find_high_bit_FOR_8_BIT); + XTESTS_RUN_CASE(TEST_find_high_bit_FOR_16_BIT); + XTESTS_RUN_CASE(TEST_find_high_bit_FOR_32_BIT); + XTESTS_RUN_CASE(TEST_find_high_bit_FOR_64_BIT); + XTESTS_RUN_CASE(TEST_calculate_xor_over_range_FOR_8_BIT); + XTESTS_RUN_CASE(TEST_calculate_xor_over_range_FOR_16_BIT); + XTESTS_RUN_CASE(TEST_calculate_xor_over_range_FOR_32_BIT); + XTESTS_RUN_CASE(TEST_calculate_xor_over_range_FOR_64_BIT); XTESTS_PRINT_RESULTS(); @@ -86,23 +160,34 @@ int main(int argc, char **argv) namespace { - using stlsoft::sint8_t; using stlsoft::uint8_t; - using stlsoft::sint16_t; using stlsoft::uint16_t; - using stlsoft::sint32_t; using stlsoft::uint32_t; - using stlsoft::sint64_t; using stlsoft::uint64_t; - using platformstl::stopwatch; -static void test_count_bits_Kernighan() +static void TEST_count_bits_Kernighan_method_FOR_8_BIT() { - stopwatch sw; + TEST_INT_EQ(0u, stlsoft::count_bits_by_Kernighan_method(uint8_t(0x00u))); + TEST_INT_EQ(8u, stlsoft::count_bits_by_Kernighan_method(uint8_t(0xffu))); + TEST_INT_EQ(4u, stlsoft::count_bits_by_Kernighan_method(uint8_t(0x55u))); + TEST_INT_EQ(4u, stlsoft::count_bits_by_Kernighan_method(uint8_t(0xaau))); + TEST_INT_EQ(1u, stlsoft::count_bits_by_Kernighan_method(uint8_t(0x80u))); + TEST_INT_EQ(2u, stlsoft::count_bits_by_Kernighan_method(uint8_t(0x81u))); +} - sw.start(); +static void TEST_count_bits_Kernighan_method_FOR_16_BIT() +{ + TEST_INT_EQ(0u, stlsoft::count_bits_by_Kernighan_method(uint16_t(0x0000u))); + TEST_INT_EQ(16u, stlsoft::count_bits_by_Kernighan_method(uint16_t(0xffffu))); + TEST_INT_EQ(8u, stlsoft::count_bits_by_Kernighan_method(uint16_t(0x5555u))); + TEST_INT_EQ(8u, stlsoft::count_bits_by_Kernighan_method(uint16_t(0xaaaau))); + TEST_INT_EQ(1u, stlsoft::count_bits_by_Kernighan_method(uint16_t(0x8000u))); + TEST_INT_EQ(2u, stlsoft::count_bits_by_Kernighan_method(uint16_t(0x8001u))); +} +static void TEST_count_bits_Kernighan_method_FOR_32_BIT() +{ TEST_INT_EQ(0u, stlsoft::count_bits_by_Kernighan_method(uint32_t(0))); TEST_INT_EQ(0u, stlsoft::count_bits_by_Kernighan_method(uint32_t(0x00000000))); @@ -136,14 +221,6 @@ static void test_count_bits_Kernighan() TEST_INT_EQ(1u, stlsoft::count_bits_by_Kernighan_method(uint32_t(0x00200000))); TEST_INT_EQ(1u, stlsoft::count_bits_by_Kernighan_method(uint32_t(0x02000000))); TEST_INT_EQ(1u, stlsoft::count_bits_by_Kernighan_method(uint32_t(0x20000000))); - TEST_INT_EQ(1u, stlsoft::count_bits_by_Kernighan_method(uint32_t(0x00000002))); - TEST_INT_EQ(1u, stlsoft::count_bits_by_Kernighan_method(uint32_t(0x00000020))); - TEST_INT_EQ(1u, stlsoft::count_bits_by_Kernighan_method(uint32_t(0x00000200))); - TEST_INT_EQ(1u, stlsoft::count_bits_by_Kernighan_method(uint32_t(0x00002000))); - TEST_INT_EQ(1u, stlsoft::count_bits_by_Kernighan_method(uint32_t(0x00020000))); - TEST_INT_EQ(1u, stlsoft::count_bits_by_Kernighan_method(uint32_t(0x00200000))); - TEST_INT_EQ(1u, stlsoft::count_bits_by_Kernighan_method(uint32_t(0x02000000))); - TEST_INT_EQ(1u, stlsoft::count_bits_by_Kernighan_method(uint32_t(0x20000000))); TEST_INT_EQ(2u, stlsoft::count_bits_by_Kernighan_method(uint32_t(0x00001001))); TEST_INT_EQ(2u, stlsoft::count_bits_by_Kernighan_method(uint32_t(0x00001010))); @@ -151,20 +228,55 @@ static void test_count_bits_Kernighan() TEST_INT_EQ(2u, stlsoft::count_bits_by_Kernighan_method(uint32_t(0x01001000))); TEST_INT_EQ(2u, stlsoft::count_bits_by_Kernighan_method(uint32_t(0x00011000))); TEST_INT_EQ(2u, stlsoft::count_bits_by_Kernighan_method(uint32_t(0x00101000))); - TEST_INT_EQ(2u, stlsoft::count_bits_by_Kernighan_method(uint32_t(0x01001000))); TEST_INT_EQ(2u, stlsoft::count_bits_by_Kernighan_method(uint32_t(0x10001000))); +} + +static void TEST_count_bits_Kernighan_method_FOR_64_BIT() +{ + TEST_INT_EQ(0u, stlsoft::count_bits_by_Kernighan_method(uint64_t(0))); + TEST_INT_EQ(0u, stlsoft::count_bits_by_Kernighan_method(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000000)))); - sw.stop(); + TEST_INT_EQ(64u, stlsoft::count_bits_by_Kernighan_method(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0xffffffffffffffff)))); - fprintf(stdout, "t: %luns\n", static_cast(sw.get_nanoseconds())); + TEST_INT_EQ(32u, stlsoft::count_bits_by_Kernighan_method(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x3333333333333333)))); + TEST_INT_EQ(32u, stlsoft::count_bits_by_Kernighan_method(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x5555555555555555)))); + TEST_INT_EQ(32u, stlsoft::count_bits_by_Kernighan_method(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0xaaaaaaaaaaaaaaaa)))); + + TEST_INT_EQ(8u, stlsoft::count_bits_by_Kernighan_method(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x00000000000000ff)))); + TEST_INT_EQ(8u, stlsoft::count_bits_by_Kernighan_method(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x00000000ff000000)))); + TEST_INT_EQ(8u, stlsoft::count_bits_by_Kernighan_method(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x000000ff00000000)))); + TEST_INT_EQ(8u, stlsoft::count_bits_by_Kernighan_method(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0xff00000000000000)))); + + TEST_INT_EQ(1u, stlsoft::count_bits_by_Kernighan_method(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000001)))); + TEST_INT_EQ(1u, stlsoft::count_bits_by_Kernighan_method(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x0000000100000000)))); + TEST_INT_EQ(1u, stlsoft::count_bits_by_Kernighan_method(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x8000000000000000)))); + + TEST_INT_EQ(2u, stlsoft::count_bits_by_Kernighan_method(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x0000000100000001)))); + TEST_INT_EQ(2u, stlsoft::count_bits_by_Kernighan_method(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x8000000000000001)))); } -static void test_count_bits_8bit_table() +static void TEST_count_bits_8bit_table_FOR_8_BIT() { - stopwatch sw; + TEST_INT_EQ(0u, stlsoft::count_bits_by_8bit_table(uint8_t(0x00u))); + TEST_INT_EQ(8u, stlsoft::count_bits_by_8bit_table(uint8_t(0xffu))); + TEST_INT_EQ(4u, stlsoft::count_bits_by_8bit_table(uint8_t(0x55u))); + TEST_INT_EQ(4u, stlsoft::count_bits_by_8bit_table(uint8_t(0xaau))); + TEST_INT_EQ(1u, stlsoft::count_bits_by_8bit_table(uint8_t(0x80u))); + TEST_INT_EQ(2u, stlsoft::count_bits_by_8bit_table(uint8_t(0x81u))); +} - sw.start(); +static void TEST_count_bits_8bit_table_FOR_16_BIT() +{ + TEST_INT_EQ(0u, stlsoft::count_bits_by_8bit_table(uint16_t(0x0000u))); + TEST_INT_EQ(16u, stlsoft::count_bits_by_8bit_table(uint16_t(0xffffu))); + TEST_INT_EQ(8u, stlsoft::count_bits_by_8bit_table(uint16_t(0x5555u))); + TEST_INT_EQ(8u, stlsoft::count_bits_by_8bit_table(uint16_t(0xaaaau))); + TEST_INT_EQ(1u, stlsoft::count_bits_by_8bit_table(uint16_t(0x8000u))); + TEST_INT_EQ(2u, stlsoft::count_bits_by_8bit_table(uint16_t(0x8001u))); +} +static void TEST_count_bits_8bit_table_FOR_32_BIT() +{ TEST_INT_EQ(0u, stlsoft::count_bits_by_8bit_table(uint32_t(0))); TEST_INT_EQ(0u, stlsoft::count_bits_by_8bit_table(uint32_t(0x00000000))); @@ -198,14 +310,6 @@ static void test_count_bits_8bit_table() TEST_INT_EQ(1u, stlsoft::count_bits_by_8bit_table(uint32_t(0x00200000))); TEST_INT_EQ(1u, stlsoft::count_bits_by_8bit_table(uint32_t(0x02000000))); TEST_INT_EQ(1u, stlsoft::count_bits_by_8bit_table(uint32_t(0x20000000))); - TEST_INT_EQ(1u, stlsoft::count_bits_by_8bit_table(uint32_t(0x00000002))); - TEST_INT_EQ(1u, stlsoft::count_bits_by_8bit_table(uint32_t(0x00000020))); - TEST_INT_EQ(1u, stlsoft::count_bits_by_8bit_table(uint32_t(0x00000200))); - TEST_INT_EQ(1u, stlsoft::count_bits_by_8bit_table(uint32_t(0x00002000))); - TEST_INT_EQ(1u, stlsoft::count_bits_by_8bit_table(uint32_t(0x00020000))); - TEST_INT_EQ(1u, stlsoft::count_bits_by_8bit_table(uint32_t(0x00200000))); - TEST_INT_EQ(1u, stlsoft::count_bits_by_8bit_table(uint32_t(0x02000000))); - TEST_INT_EQ(1u, stlsoft::count_bits_by_8bit_table(uint32_t(0x20000000))); TEST_INT_EQ(2u, stlsoft::count_bits_by_8bit_table(uint32_t(0x00001001))); TEST_INT_EQ(2u, stlsoft::count_bits_by_8bit_table(uint32_t(0x00001010))); @@ -213,15 +317,124 @@ static void test_count_bits_8bit_table() TEST_INT_EQ(2u, stlsoft::count_bits_by_8bit_table(uint32_t(0x01001000))); TEST_INT_EQ(2u, stlsoft::count_bits_by_8bit_table(uint32_t(0x00011000))); TEST_INT_EQ(2u, stlsoft::count_bits_by_8bit_table(uint32_t(0x00101000))); - TEST_INT_EQ(2u, stlsoft::count_bits_by_8bit_table(uint32_t(0x01001000))); TEST_INT_EQ(2u, stlsoft::count_bits_by_8bit_table(uint32_t(0x10001000))); +} + +static void TEST_count_bits_8bit_table_FOR_64_BIT() +{ + TEST_INT_EQ(0u, stlsoft::count_bits_by_8bit_table(uint64_t(0))); + TEST_INT_EQ(0u, stlsoft::count_bits_by_8bit_table(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000000)))); + + TEST_INT_EQ(64u, stlsoft::count_bits_by_8bit_table(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0xffffffffffffffff)))); + + TEST_INT_EQ(32u, stlsoft::count_bits_by_8bit_table(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x3333333333333333)))); + TEST_INT_EQ(32u, stlsoft::count_bits_by_8bit_table(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x5555555555555555)))); + TEST_INT_EQ(32u, stlsoft::count_bits_by_8bit_table(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0xaaaaaaaaaaaaaaaa)))); + + TEST_INT_EQ(8u, stlsoft::count_bits_by_8bit_table(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x00000000000000ff)))); + TEST_INT_EQ(8u, stlsoft::count_bits_by_8bit_table(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x00000000ff000000)))); + TEST_INT_EQ(8u, stlsoft::count_bits_by_8bit_table(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x000000ff00000000)))); + TEST_INT_EQ(8u, stlsoft::count_bits_by_8bit_table(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0xff00000000000000)))); + + TEST_INT_EQ(1u, stlsoft::count_bits_by_8bit_table(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000001)))); + TEST_INT_EQ(1u, stlsoft::count_bits_by_8bit_table(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x0000000100000000)))); + TEST_INT_EQ(1u, stlsoft::count_bits_by_8bit_table(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x8000000000000000)))); + + TEST_INT_EQ(2u, stlsoft::count_bits_by_8bit_table(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x0000000100000001)))); + TEST_INT_EQ(2u, stlsoft::count_bits_by_8bit_table(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x8000000000000001)))); +} + +static void TEST_count_bits_FOR_8_BIT() +{ + TEST_INT_EQ(0u, stlsoft::count_bits(uint8_t(0))); + TEST_INT_EQ(8u, stlsoft::count_bits(uint8_t(0xff))); + TEST_INT_EQ(4u, stlsoft::count_bits(uint8_t(0x55))); + TEST_INT_EQ(1u, stlsoft::count_bits(uint8_t(0x80))); + TEST_INT_EQ(2u, stlsoft::count_bits(uint8_t(0x81))); +} + +static void TEST_count_bits_FOR_16_BIT() +{ + TEST_INT_EQ(0u, stlsoft::count_bits(uint16_t(0))); + TEST_INT_EQ(16u, stlsoft::count_bits(uint16_t(0xffff))); + TEST_INT_EQ(8u, stlsoft::count_bits(uint16_t(0x5555))); + TEST_INT_EQ(1u, stlsoft::count_bits(uint16_t(0x8000))); + TEST_INT_EQ(2u, stlsoft::count_bits(uint16_t(0x8001))); +} + +static void TEST_count_bits_FOR_32_BIT() +{ + TEST_INT_EQ(0u, stlsoft::count_bits(uint32_t(0))); + TEST_INT_EQ(32u, stlsoft::count_bits(uint32_t(0xffffffff))); + TEST_INT_EQ(16u, stlsoft::count_bits(uint32_t(0x55555555))); + TEST_INT_EQ(1u, stlsoft::count_bits(uint32_t(0x80000000))); + TEST_INT_EQ(2u, stlsoft::count_bits(uint32_t(0x80000001))); +} + +static void TEST_count_bits_FOR_64_BIT() +{ + TEST_INT_EQ(0u, stlsoft::count_bits(uint64_t(0))); + TEST_INT_EQ(64u, stlsoft::count_bits(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0xffffffffffffffff)))); + TEST_INT_EQ(32u, stlsoft::count_bits(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x5555555555555555)))); + TEST_INT_EQ(1u, stlsoft::count_bits(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x8000000000000000)))); + TEST_INT_EQ(2u, stlsoft::count_bits(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x8000000000000001)))); +} + +static void TEST_count_bits_FOR_int() +{ + TEST_INT_EQ(0u, stlsoft::count_bits(0)); + TEST_INT_EQ(1u, stlsoft::count_bits(1)); + TEST_INT_EQ(1u, stlsoft::count_bits(2)); + TEST_INT_EQ(2u, stlsoft::count_bits(3)); + + /* Negative values are counted via their two's-complement bit pattern. */ + TEST_INT_EQ(sizeof(int) * 8u, stlsoft::count_bits(-1)); + TEST_INT_EQ(1u, stlsoft::count_bits(static_cast(1u << (sizeof(int) * 8u - 1u)))); +} + +static void TEST_find_high_bit_FOR_8_BIT() +{ + TEST_INT_EQ(0u, stlsoft::find_highest_bit(uint8_t(0))); + + TEST_INT_EQ(1u, stlsoft::find_highest_bit(uint8_t(1))); + + TEST_INT_EQ(2u, stlsoft::find_highest_bit(uint8_t(2))); + TEST_INT_EQ(2u, stlsoft::find_highest_bit(uint8_t(3))); + + TEST_INT_EQ(3u, stlsoft::find_highest_bit(uint8_t(4))); + TEST_INT_EQ(3u, stlsoft::find_highest_bit(uint8_t(5))); + TEST_INT_EQ(3u, stlsoft::find_highest_bit(uint8_t(6))); + TEST_INT_EQ(3u, stlsoft::find_highest_bit(uint8_t(7))); + + TEST_INT_EQ(5u, stlsoft::find_highest_bit(uint8_t(0x10))); + TEST_INT_EQ(5u, stlsoft::find_highest_bit(uint8_t(0x1f))); - sw.stop(); + TEST_INT_EQ(8u, stlsoft::find_highest_bit(uint8_t(0x80))); + TEST_INT_EQ(8u, stlsoft::find_highest_bit(uint8_t(0xff))); +} + +static void TEST_find_high_bit_FOR_16_BIT() +{ + TEST_INT_EQ(0u, stlsoft::find_highest_bit(uint16_t(0))); + + TEST_INT_EQ(1u, stlsoft::find_highest_bit(uint16_t(1))); - fprintf(stdout, "t: %luns\n", static_cast(sw.get_nanoseconds())); + TEST_INT_EQ(2u, stlsoft::find_highest_bit(uint16_t(2))); + TEST_INT_EQ(2u, stlsoft::find_highest_bit(uint16_t(3))); + + TEST_INT_EQ(3u, stlsoft::find_highest_bit(uint16_t(4))); + TEST_INT_EQ(3u, stlsoft::find_highest_bit(uint16_t(5))); + TEST_INT_EQ(3u, stlsoft::find_highest_bit(uint16_t(6))); + TEST_INT_EQ(3u, stlsoft::find_highest_bit(uint16_t(7))); + + TEST_INT_EQ(9u, stlsoft::find_highest_bit(uint16_t(0x0100))); + TEST_INT_EQ(9u, stlsoft::find_highest_bit(uint16_t(0x01ff))); + + TEST_INT_EQ(16u, stlsoft::find_highest_bit(uint16_t(0x8000))); + TEST_INT_EQ(16u, stlsoft::find_highest_bit(uint16_t(0xffff))); } -static void test_find_high_bit_32() +static void TEST_find_high_bit_FOR_32_BIT() { TEST_INT_EQ(0u, stlsoft::find_highest_bit(uint32_t(0))); @@ -243,7 +456,7 @@ static void test_find_high_bit_32() TEST_INT_EQ(32u, stlsoft::find_highest_bit(uint32_t(0x80000000))); } -static void test_find_high_bit_64() +static void TEST_find_high_bit_FOR_64_BIT() { TEST_INT_EQ(0u, stlsoft::find_highest_bit(uint64_t(0))); @@ -274,7 +487,7 @@ static void test_find_high_bit_64() TEST_INT_EQ(45u, stlsoft::find_highest_bit(uint64_t(STLSOFT_GEN_UINT64_SUFFIX(0x1c3c3c3c3c3c)))); } -static void test_calculate_xor_over_range_8_bit() +static void TEST_calculate_xor_over_range_FOR_8_BIT() { uint8_t const elements[] = { @@ -315,7 +528,225 @@ static void test_calculate_xor_over_range_8_bit() TEST_INT_EQ(0xd0, stlsoft::calculate_xor_over_range(elements, 12u)); TEST_INT_EQ(0xf0, stlsoft::calculate_xor_over_range(elements, 13u)); } + +static void TEST_calculate_xor_over_range_FOR_16_BIT() +{ + uint16_t const elements[] = + { + 0x0000 + + , 0x0001 + , 0x0002 + , 0x0004 + , 0x0008 + + , 0x0001 + , 0x0002 + , 0x0004 + , 0x0008 + + , 0x0040 + , 0x0080 + , 0x0010 + , 0x0020 + + , 0x0100 + , 0x8000 + }; + + TEST_INT_EQ(0x0000, stlsoft::calculate_xor_over_range(elements, 0u)); + TEST_INT_EQ(0x0000, stlsoft::calculate_xor_over_range(elements, 1u)); + TEST_INT_EQ(0x0001, stlsoft::calculate_xor_over_range(elements, 2u)); + TEST_INT_EQ(0x0003, stlsoft::calculate_xor_over_range(elements, 3u)); + TEST_INT_EQ(0x0007, stlsoft::calculate_xor_over_range(elements, 4u)); + TEST_INT_EQ(0x000f, stlsoft::calculate_xor_over_range(elements, 5u)); + TEST_INT_EQ(0x000e, stlsoft::calculate_xor_over_range(elements, 6u)); + TEST_INT_EQ(0x000c, stlsoft::calculate_xor_over_range(elements, 7u)); + TEST_INT_EQ(0x0008, stlsoft::calculate_xor_over_range(elements, 8u)); + TEST_INT_EQ(0x0000, stlsoft::calculate_xor_over_range(elements, 9u)); + TEST_INT_EQ(0x0040, stlsoft::calculate_xor_over_range(elements, 10u)); + TEST_INT_EQ(0x00c0, stlsoft::calculate_xor_over_range(elements, 11u)); + TEST_INT_EQ(0x00d0, stlsoft::calculate_xor_over_range(elements, 12u)); + TEST_INT_EQ(0x00f0, stlsoft::calculate_xor_over_range(elements, 13u)); + TEST_INT_EQ(0x01f0, stlsoft::calculate_xor_over_range(elements, 14u)); + TEST_INT_EQ(0x81f0, stlsoft::calculate_xor_over_range(elements, 15u)); +} + +static void TEST_calculate_xor_over_range_FOR_32_BIT() +{ + uint32_t const elements[] = + { + 0x00000000u + + , 0x00000001u + , 0x00000002u + , 0x00000004u + , 0x00000008u + + , 0x00000001u + , 0x00000002u + , 0x00000004u + , 0x00000008u + + , 0x00000040u + , 0x00000080u + , 0x00000010u + , 0x00000020u + + , 0x00000100u + , 0x80000000u + }; + + TEST_INT_EQ(0x00000000u, stlsoft::calculate_xor_over_range(elements, 0u)); + TEST_INT_EQ(0x00000000u, stlsoft::calculate_xor_over_range(elements, 1u)); + TEST_INT_EQ(0x00000001u, stlsoft::calculate_xor_over_range(elements, 2u)); + TEST_INT_EQ(0x00000003u, stlsoft::calculate_xor_over_range(elements, 3u)); + TEST_INT_EQ(0x00000007u, stlsoft::calculate_xor_over_range(elements, 4u)); + TEST_INT_EQ(0x0000000fu, stlsoft::calculate_xor_over_range(elements, 5u)); + TEST_INT_EQ(0x0000000eu, stlsoft::calculate_xor_over_range(elements, 6u)); + TEST_INT_EQ(0x0000000cu, stlsoft::calculate_xor_over_range(elements, 7u)); + TEST_INT_EQ(0x00000008u, stlsoft::calculate_xor_over_range(elements, 8u)); + TEST_INT_EQ(0x00000000u, stlsoft::calculate_xor_over_range(elements, 9u)); + TEST_INT_EQ(0x00000040u, stlsoft::calculate_xor_over_range(elements, 10u)); + TEST_INT_EQ(0x000000c0u, stlsoft::calculate_xor_over_range(elements, 11u)); + TEST_INT_EQ(0x000000d0u, stlsoft::calculate_xor_over_range(elements, 12u)); + TEST_INT_EQ(0x000000f0u, stlsoft::calculate_xor_over_range(elements, 13u)); + TEST_INT_EQ(0x000001f0u, stlsoft::calculate_xor_over_range(elements, 14u)); + TEST_INT_EQ(0x800001f0u, stlsoft::calculate_xor_over_range(elements, 15u)); +} + +static void TEST_calculate_xor_over_range_FOR_64_BIT() +{ + uint64_t const elements[] = + { + STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000000) + + , STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000001) + , STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000002) + , STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000004) + , STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000008) + + , STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000001) + , STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000002) + , STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000004) + , STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000008) + + , STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000040) + , STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000080) + , STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000010) + , STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000020) + + , STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000100) + , STLSOFT_GEN_UINT64_SUFFIX(0x8000000000000000) + }; + + TEST_INT_EQ(STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000000), stlsoft::calculate_xor_over_range(elements, 0u)); + TEST_INT_EQ(STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000000), stlsoft::calculate_xor_over_range(elements, 1u)); + TEST_INT_EQ(STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000001), stlsoft::calculate_xor_over_range(elements, 2u)); + TEST_INT_EQ(STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000003), stlsoft::calculate_xor_over_range(elements, 3u)); + TEST_INT_EQ(STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000007), stlsoft::calculate_xor_over_range(elements, 4u)); + TEST_INT_EQ(STLSOFT_GEN_UINT64_SUFFIX(0x000000000000000f), stlsoft::calculate_xor_over_range(elements, 5u)); + TEST_INT_EQ(STLSOFT_GEN_UINT64_SUFFIX(0x000000000000000e), stlsoft::calculate_xor_over_range(elements, 6u)); + TEST_INT_EQ(STLSOFT_GEN_UINT64_SUFFIX(0x000000000000000c), stlsoft::calculate_xor_over_range(elements, 7u)); + TEST_INT_EQ(STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000008), stlsoft::calculate_xor_over_range(elements, 8u)); + TEST_INT_EQ(STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000000), stlsoft::calculate_xor_over_range(elements, 9u)); + TEST_INT_EQ(STLSOFT_GEN_UINT64_SUFFIX(0x0000000000000040), stlsoft::calculate_xor_over_range(elements, 10u)); + TEST_INT_EQ(STLSOFT_GEN_UINT64_SUFFIX(0x00000000000000c0), stlsoft::calculate_xor_over_range(elements, 11u)); + TEST_INT_EQ(STLSOFT_GEN_UINT64_SUFFIX(0x00000000000000d0), stlsoft::calculate_xor_over_range(elements, 12u)); + TEST_INT_EQ(STLSOFT_GEN_UINT64_SUFFIX(0x00000000000000f0), stlsoft::calculate_xor_over_range(elements, 13u)); + TEST_INT_EQ(STLSOFT_GEN_UINT64_SUFFIX(0x00000000000001f0), stlsoft::calculate_xor_over_range(elements, 14u)); + TEST_INT_EQ(STLSOFT_GEN_UINT64_SUFFIX(0x80000000000001f0), stlsoft::calculate_xor_over_range(elements, 15u)); +} +#if defined(STLSOFT_API_INTERNAL_bitfns_popcount_uint16) + +static void TEST_count_bits_by_intrinsic_FOR_8_BIT() +{ + TEST_INT_EQ(0u, stlsoft::count_bits_by_intrinsic(uint8_t(0u))); + TEST_INT_EQ(1u, stlsoft::count_bits_by_intrinsic(uint8_t(1u))); + TEST_INT_EQ(1u, stlsoft::count_bits_by_intrinsic(uint8_t(0x80u))); + TEST_INT_EQ(8u, stlsoft::count_bits_by_intrinsic(uint8_t(0xffu))); + TEST_INT_EQ(stlsoft::count_bits_by_8bit_table(uint8_t(0x3cu)), stlsoft::count_bits_by_intrinsic(uint8_t(0x3cu))); +} + +static void TEST_count_bits_by_intrinsic_FOR_16_BIT() +{ + TEST_INT_EQ(0u, stlsoft::count_bits_by_intrinsic(uint16_t(0u))); + TEST_INT_EQ(1u, stlsoft::count_bits_by_intrinsic(uint16_t(1u))); + TEST_INT_EQ(1u, stlsoft::count_bits_by_intrinsic(uint16_t(0x8000u))); + TEST_INT_EQ(16u, stlsoft::count_bits_by_intrinsic(uint16_t(0xffffu))); + TEST_INT_EQ(stlsoft::count_bits_by_8bit_table(uint16_t(0x1234u)), stlsoft::count_bits_by_intrinsic(uint16_t(0x1234u))); +} +#endif +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt_SUPPORT) + +static void TEST_count_bits_by_intrinsic_FOR_32_BIT() +{ + TEST_INT_EQ(0u, stlsoft::count_bits_by_intrinsic(uint32_t(0u))); + TEST_INT_EQ(1u, stlsoft::count_bits_by_intrinsic(uint32_t(1u))); + TEST_INT_EQ(1u, stlsoft::count_bits_by_intrinsic(uint32_t(0x80000000u))); + TEST_INT_EQ(32u, stlsoft::count_bits_by_intrinsic(uint32_t(0xffffffffu))); + TEST_INT_EQ(stlsoft::count_bits_by_8bit_table(uint32_t(0x12345678u)), stlsoft::count_bits_by_intrinsic(uint32_t(0x12345678u))); +} +#endif +#if defined(STLSOFT_CF__builtin_popcount_SUPPORT) || \ + defined(STLSOFT_CF__popcnt64_SUPPORT) + +static void TEST_count_bits_by_intrinsic_FOR_64_BIT() +{ + TEST_INT_EQ(0u, stlsoft::count_bits_by_intrinsic(uint64_t(0u))); + TEST_INT_EQ(1u, stlsoft::count_bits_by_intrinsic(uint64_t(1u))); + TEST_INT_EQ(1u, stlsoft::count_bits_by_intrinsic(STLSOFT_GEN_UINT64_SUFFIX(0x8000000000000000))); + TEST_INT_EQ(64u, stlsoft::count_bits_by_intrinsic(STLSOFT_GEN_UINT64_SUFFIX(0xffffffffffffffff))); + TEST_INT_EQ( + stlsoft::count_bits_by_8bit_table(STLSOFT_GEN_UINT64_SUFFIX(0x0123456789abcdef)) + , stlsoft::count_bits_by_intrinsic(STLSOFT_GEN_UINT64_SUFFIX(0x0123456789abcdef)) + ); +} +#endif +#if defined(STLSOFT_CF__builtin_clz_SUPPORT) || \ + defined(STLSOFT_CF__BitScanReverse_SUPPORT) + +static void TEST_find_highest_bit_by_intrinsic_FOR_8_BIT() +{ + TEST_INT_EQ(0u, stlsoft::find_highest_bit_by_intrinsic(uint8_t(0u))); + TEST_INT_EQ(1u, stlsoft::find_highest_bit_by_intrinsic(uint8_t(1u))); + TEST_INT_EQ(8u, stlsoft::find_highest_bit_by_intrinsic(uint8_t(0x80u))); + TEST_INT_EQ(stlsoft::find_highest_bit(uint8_t(0x3cu)), stlsoft::find_highest_bit_by_intrinsic(uint8_t(0x3cu))); +} + +static void TEST_find_highest_bit_by_intrinsic_FOR_16_BIT() +{ + TEST_INT_EQ(0u, stlsoft::find_highest_bit_by_intrinsic(uint16_t(0u))); + TEST_INT_EQ(1u, stlsoft::find_highest_bit_by_intrinsic(uint16_t(1u))); + TEST_INT_EQ(16u, stlsoft::find_highest_bit_by_intrinsic(uint16_t(0x8000u))); + TEST_INT_EQ(stlsoft::find_highest_bit(uint16_t(0x03c0u)), stlsoft::find_highest_bit_by_intrinsic(uint16_t(0x03c0u))); +} + +static void TEST_find_highest_bit_by_intrinsic_FOR_32_BIT() +{ + TEST_INT_EQ(0u, stlsoft::find_highest_bit_by_intrinsic(uint32_t(0u))); + TEST_INT_EQ(1u, stlsoft::find_highest_bit_by_intrinsic(uint32_t(1u))); + TEST_INT_EQ(32u, stlsoft::find_highest_bit_by_intrinsic(uint32_t(0x80000000u))); + TEST_INT_EQ(stlsoft::find_highest_bit(uint32_t(0x0003c000u)), stlsoft::find_highest_bit_by_intrinsic(uint32_t(0x0003c000u))); +} +#endif +#if defined(STLSOFT_CF__builtin_clz_SUPPORT) || \ + defined(STLSOFT_CF__BitScanReverse64_SUPPORT) + +static void TEST_find_highest_bit_by_intrinsic_FOR_64_BIT() +{ + TEST_INT_EQ(0u, stlsoft::find_highest_bit_by_intrinsic(uint64_t(0u))); + TEST_INT_EQ(1u, stlsoft::find_highest_bit_by_intrinsic(uint64_t(1u))); + TEST_INT_EQ(64u, stlsoft::find_highest_bit_by_intrinsic(STLSOFT_GEN_UINT64_SUFFIX(0x8000000000000000))); + TEST_INT_EQ( + stlsoft::find_highest_bit(STLSOFT_GEN_UINT64_SUFFIX(0x000000030000c000)) + , stlsoft::find_highest_bit_by_intrinsic(STLSOFT_GEN_UINT64_SUFFIX(0x000000030000c000)) + ); +} +#endif } // anonymous namespace /* ///////////////////////////// end of file //////////////////////////// */ + diff --git a/test/unit/test.unit.versions/entry.cpp b/test/unit/test.unit.versions/entry.cpp index 83be0623..7a5883d7 100644 --- a/test/unit/test.unit.versions/entry.cpp +++ b/test/unit/test.unit.versions/entry.cpp @@ -4,7 +4,7 @@ * Purpose: Unit-tests for versions * * Created: 23rd August 2025 - * Updated: 21st September 2026 + * Updated: 25th September 2026 * * ////////////////////////////////////////////////////////////////////// */ @@ -133,7 +133,7 @@ namespace { static void TEST__STLSOFT_VER() { - TEST_INT_EQ(_STLSOFT_VER_1_11_1_RC6, _STLSOFT_VER); + TEST_INT_EQ(_STLSOFT_VER_1_11_1_RC7, _STLSOFT_VER); } #ifdef STLSOFT_HAS_ACE