libstdc++: Implement <stdbit.h> for C++26 (P3370R1)

This is the first part of the P3370R1 proposal just approved by the
committee in Wrocław. This adds C++ equivalents of the functions added
to C23 by WG14 N3022.

These functions are in the global namespace, but to avoid collisions
with the same functions defined by other standard library
implementations, this change defines them in namespace __gnu_cxx and
then adds them to the global namespace.

libstdc++-v3/ChangeLog:

	* include/Makefile.am: Add stdbit.h.
	* include/Makefile.in: Regenerate.
	* src/c++23/std.compat.cc.in: Export <stdbit.h> functions.
	* include/c_compatibility/stdbit.h: New file.
	* testsuite/20_util/stdbit/1.cc: New test.
	* testsuite/20_util/stdbit/2_neg.cc: New test.

Reviewed-by: Patrick Palka <ppalka@redhat.com>
This commit is contained in:
Jonathan Wakely 2025-03-13 13:34:55 +00:00 committed by Jonathan Wakely
parent c5e7cfc1d3
commit 7ee31bc927
No known key found for this signature in database
6 changed files with 978 additions and 0 deletions

View file

@ -911,6 +911,7 @@ c_compatibility_headers = \
${c_compatibility_srcdir}/tgmath.h \
${c_compatibility_srcdir}/math.h \
${c_compatibility_srcdir}/stdatomic.h \
${c_compatibility_srcdir}/stdbit.h \
${c_compatibility_srcdir}/stdlib.h
endif

View file

@ -1248,6 +1248,7 @@ c_compatibility_builddir = .
@GLIBCXX_C_HEADERS_C_GLOBAL_TRUE@ ${c_compatibility_srcdir}/tgmath.h \
@GLIBCXX_C_HEADERS_C_GLOBAL_TRUE@ ${c_compatibility_srcdir}/math.h \
@GLIBCXX_C_HEADERS_C_GLOBAL_TRUE@ ${c_compatibility_srcdir}/stdatomic.h \
@GLIBCXX_C_HEADERS_C_GLOBAL_TRUE@ ${c_compatibility_srcdir}/stdbit.h \
@GLIBCXX_C_HEADERS_C_GLOBAL_TRUE@ ${c_compatibility_srcdir}/stdlib.h
@GLIBCXX_C_HEADERS_C_STD_TRUE@c_compatibility_headers =

View file

@ -0,0 +1,582 @@
// C compatibility header <stdbit.h> -*- C++ -*-
// Copyright The GNU Toolchain Authors.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.
// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
// <http://www.gnu.org/licenses/>.
/** @file include/stdbit.h
* This is a Standard C++ Library header.
*/
#ifndef _GLIBCXX_STDBIT_H
#define _GLIBCXX_STDBIT_H
#if __cplusplus > 202302L
#include <bit>
#define __STDC_VERSION_STDBIT_H__ 202311L
#define __STDC_ENDIAN_BIG__ __ORDER_BIG_ENDIAN__
#define __STDC_ENDIAN_LITTLE__ __ORDER_LITTLE_ENDIAN__
#define __STDC_ENDIAN_NATIVE__ __BYTE_ORDER__
#ifndef _GLIBCXX_DOXYGEN
// We define these in our own namespace, but let Doxygen think otherwise.
namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)
{
#endif
/** Count the number of leading zero bits
*
* @param __value An unsigned integer.
* @since C++26
* @{
*/
template<typename _Tp>
inline unsigned int
stdc_leading_zeros(_Tp __value)
{
static_assert(std::__unsigned_integer<_Tp>);
return std::countl_zero(__value);
}
inline unsigned int
stdc_leading_zeros_uc(unsigned char __value)
{ return stdc_leading_zeros(__value); }
inline unsigned int
stdc_leading_zeros_us(unsigned short __value)
{ return stdc_leading_zeros(__value); }
inline unsigned int
stdc_leading_zeros_ui(unsigned int __value)
{ return stdc_leading_zeros(__value); }
inline unsigned int
stdc_leading_zeros_ul(unsigned long int __value)
{ return stdc_leading_zeros(__value); }
inline unsigned int
stdc_leading_zeros_ull(unsigned long long int __value)
{ return stdc_leading_zeros(__value); }
/// @}
/** Count the number of leading one bits
*
* @param __value An unsigned integer.
* @since C++26
* @{
*/
template<typename _Tp>
inline unsigned int
stdc_leading_ones(_Tp __value)
{
static_assert(std::__unsigned_integer<_Tp>);
return std::countl_one(__value);
}
inline unsigned int
stdc_leading_ones_uc(unsigned char __value)
{ return stdc_leading_ones(__value); }
inline unsigned int
stdc_leading_ones_us(unsigned short __value)
{ return stdc_leading_ones(__value); }
inline unsigned int
stdc_leading_ones_ui(unsigned int __value)
{ return stdc_leading_ones(__value); }
inline unsigned int
stdc_leading_ones_ul(unsigned long int __value)
{ return stdc_leading_ones(__value); }
inline unsigned int
stdc_leading_ones_ull(unsigned long long int __value)
{ return stdc_leading_ones(__value); }
/// @}
/** Count the number of trailing zero bits
*
* @param __value An unsigned integer.
* @since C++26
* @{
*/
template<typename _Tp>
inline unsigned int
stdc_trailing_zeros(_Tp __value)
{
static_assert(std::__unsigned_integer<_Tp>);
return std::countr_zero(__value);
}
inline unsigned int
stdc_trailing_zeros_uc(unsigned char __value)
{ return stdc_trailing_zeros(__value); }
inline unsigned int
stdc_trailing_zeros_us(unsigned short __value)
{ return stdc_trailing_zeros(__value); }
inline unsigned int
stdc_trailing_zeros_ui(unsigned int __value)
{ return stdc_trailing_zeros(__value); }
inline unsigned int
stdc_trailing_zeros_ul(unsigned long int __value)
{ return stdc_trailing_zeros(__value); }
inline unsigned int
stdc_trailing_zeros_ull(unsigned long long int __value)
{ return stdc_trailing_zeros(__value); }
/// @}
/** Count the number of trailing one bits
*
* @param __value An unsigned integer.
* @since C++26
* @{
*/
template<typename _Tp>
inline unsigned int
stdc_trailing_ones(_Tp __value)
{
static_assert(std::__unsigned_integer<_Tp>);
return std::countr_one(__value);
}
inline unsigned int
stdc_trailing_ones_uc(unsigned char __value)
{ return stdc_trailing_ones(__value); }
inline unsigned int
stdc_trailing_ones_us(unsigned short __value)
{ return stdc_trailing_ones(__value); }
inline unsigned int
stdc_trailing_ones_ui(unsigned int __value)
{ return stdc_trailing_ones(__value); }
inline unsigned int
stdc_trailing_ones_ul(unsigned long int __value)
{ return stdc_trailing_ones(__value); }
inline unsigned int
stdc_trailing_ones_ull(unsigned long long int __value)
{ return stdc_trailing_ones(__value); }
/// @}
/** Find the leftmost (i.e. most significant) zero bit
*
* @param __value An unsigned integer.
* @return The one-based index of the first zero bit counting from the left,
* or zero if there are no zero bits.
* @since C++26
* @{
*/
template<typename _Tp>
inline unsigned int
stdc_first_leading_zero(_Tp __value)
{
static_assert(std::__unsigned_integer<_Tp>);
return __value == _Tp(-1) ? 0 : 1 + std::countl_one(__value);
}
inline unsigned int
stdc_first_leading_zero_uc(unsigned char __value)
{ return stdc_first_leading_zero(__value); }
inline unsigned int
stdc_first_leading_zero_us(unsigned short __value)
{ return stdc_first_leading_zero(__value); }
inline unsigned int
stdc_first_leading_zero_ui(unsigned int __value)
{ return stdc_first_leading_zero(__value); }
inline unsigned int
stdc_first_leading_zero_ul(unsigned long int __value)
{ return stdc_first_leading_zero(__value); }
inline unsigned int
stdc_first_leading_zero_ull(unsigned long long int __value)
{ return stdc_first_leading_zero(__value); }
/// @}
/** Find the leftmost (i.e. most significant) one bit
*
* @param __value An unsigned integer.
* @return The one-based index of the first one bit counting from the left,
* or zero if there are no one bits.
* @since C++26
* @{
*/
template<typename _Tp>
inline unsigned int
stdc_first_leading_one(_Tp __value)
{
static_assert(std::__unsigned_integer<_Tp>);
return __value == 0 ? 0 : 1 + std::countl_zero(__value);
}
inline unsigned int
stdc_first_leading_one_uc(unsigned char __value)
{ return stdc_first_leading_one(__value); }
inline unsigned int
stdc_first_leading_one_us(unsigned short __value)
{ return stdc_first_leading_one(__value); }
inline unsigned int
stdc_first_leading_one_ui(unsigned int __value)
{ return stdc_first_leading_one(__value); }
inline unsigned int
stdc_first_leading_one_ul(unsigned long int __value)
{ return stdc_first_leading_one(__value); }
inline unsigned int
stdc_first_leading_one_ull(unsigned long long int __value)
{ return stdc_first_leading_one(__value); }
/// @}
/** Find the rightmost (i.e. least significant) zero bit
*
* @param __value An unsigned integer.
* @return The one-based index of the first zero bit counting from the right,
* or zero if there are no zero bits.
* @since C++26
* @{
*/
template<typename _Tp>
inline unsigned int
stdc_first_trailing_zero(_Tp __value)
{
static_assert(std::__unsigned_integer<_Tp>);
return __value == _Tp(-1) ? 0 : 1 + std::countr_one(__value);
}
inline unsigned int
stdc_first_trailing_zero_uc(unsigned char __value)
{ return stdc_first_trailing_zero(__value); }
inline unsigned int
stdc_first_trailing_zero_us(unsigned short __value)
{ return stdc_first_trailing_zero(__value); }
inline unsigned int
stdc_first_trailing_zero_ui(unsigned int __value)
{ return stdc_first_trailing_zero(__value); }
inline unsigned int
stdc_first_trailing_zero_ul(unsigned long int __value)
{ return stdc_first_trailing_zero(__value); }
inline unsigned int
stdc_first_trailing_zero_ull(unsigned long long int __value)
{ return stdc_first_trailing_zero(__value); }
/// @}
/** Find the rightmost (i.e. least significant) one bit
*
* @param __value An unsigned integer.
* @return The one-based index of the first one bit counting from the right,
* or zero if there are no one bits.
* @since C++26
* @{
*/
template<typename _Tp>
inline unsigned int
stdc_first_trailing_one(_Tp __value)
{
static_assert(std::__unsigned_integer<_Tp>);
return __value == 0 ? 0 : 1 + std::countr_zero(__value);
}
inline unsigned int
stdc_first_trailing_one_uc(unsigned char __value)
{ return stdc_first_trailing_one(__value); }
inline unsigned int
stdc_first_trailing_one_us(unsigned short __value)
{ return stdc_first_trailing_one(__value); }
inline unsigned int
stdc_first_trailing_one_ui(unsigned int __value)
{ return stdc_first_trailing_one(__value); }
inline unsigned int
stdc_first_trailing_one_ul(unsigned long int __value)
{ return stdc_first_trailing_one(__value); }
inline unsigned int
stdc_first_trailing_one_ull(unsigned long long int __value)
{ return stdc_first_trailing_one(__value); }
/// @}
/** Count zeros
*
* @param __value An unsigned integer.
* @return The total number of zero bits in `__value`.
* @since C++26
* @{
*/
template<typename _Tp>
inline unsigned int
stdc_count_zeros(_Tp __value)
{
static_assert(std::__unsigned_integer<_Tp>);
return std::popcount(_Tp(~__value));
}
inline unsigned int
stdc_count_zeros_uc(unsigned char __value)
{ return stdc_count_zeros(__value); }
inline unsigned int
stdc_count_zeros_us(unsigned short __value)
{ return stdc_count_zeros(__value); }
inline unsigned int
stdc_count_zeros_ui(unsigned int __value)
{ return stdc_count_zeros(__value); }
inline unsigned int
stdc_count_zeros_ul(unsigned long int __value)
{ return stdc_count_zeros(__value); }
inline unsigned int
stdc_count_zeros_ull(unsigned long long int __value)
{ return stdc_count_zeros(__value); }
/// @}
/** Count ones
*
* @param __value An unsigned integer.
* @return The total number of one bits in `__value`.
* @since C++26
* @{
*/
template<typename _Tp>
inline unsigned int
stdc_count_ones(_Tp __value)
{
static_assert(std::__unsigned_integer<_Tp>);
return std::popcount(__value);
}
inline unsigned int
stdc_count_ones_uc(unsigned char __value)
{ return stdc_count_ones(__value); }
inline unsigned int
stdc_count_ones_us(unsigned short __value)
{ return stdc_count_ones(__value); }
inline unsigned int
stdc_count_ones_ui(unsigned int __value)
{ return stdc_count_ones(__value); }
inline unsigned int
stdc_count_ones_ul(unsigned long int __value)
{ return stdc_count_ones(__value); }
inline unsigned int
stdc_count_ones_ull(unsigned long long int __value)
{ return stdc_count_ones(__value); }
/// @}
/** Power of two check
*
* @param __value An unsigned integer.
* @return True if the value has a single bit set, false otherwise.
* @since C++26
* @{
*/
template<typename _Tp>
inline bool
stdc_has_single_bit(_Tp __value)
{
static_assert(std::__unsigned_integer<_Tp>);
return std::has_single_bit(__value);
}
inline bool
stdc_has_single_bit_uc(unsigned char __value)
{ return stdc_has_single_bit(__value); }
inline bool
stdc_has_single_bit_us(unsigned short __value)
{ return stdc_has_single_bit(__value); }
inline bool
stdc_has_single_bit_ui(unsigned int __value)
{ return stdc_has_single_bit(__value); }
inline bool
stdc_has_single_bit_ul(unsigned long int __value)
{ return stdc_has_single_bit(__value); }
inline bool
stdc_has_single_bit_ull(unsigned long long int __value)
{ return stdc_has_single_bit(__value); }
/// @}
/** Bit width
*
* @param __value An unsigned integer.
* @return The minimum number of bits needed to represent `__value`.
* @since C++26
* @{
*/
template<typename _Tp>
inline unsigned int
stdc_bit_width(_Tp __value)
{
static_assert(std::__unsigned_integer<_Tp>);
return std::bit_width(__value);
}
inline unsigned int
stdc_bit_width_uc(unsigned char __value)
{ return stdc_bit_width(__value); }
inline unsigned int
stdc_bit_width_us(unsigned short __value)
{ return stdc_bit_width(__value); }
inline unsigned int
stdc_bit_width_ui(unsigned int __value)
{ return stdc_bit_width(__value); }
inline unsigned int
stdc_bit_width_ul(unsigned long int __value)
{ return stdc_bit_width(__value); }
inline unsigned int
stdc_bit_width_ull(unsigned long long int __value)
{ return stdc_bit_width(__value); }
/// @}
/** Bit floor
*
* @param __value An unsigned integer.
* @return The largest power of two that is not greater than `__value`.
* @since C++26
* @{
*/
template<typename _Tp>
inline _Tp
stdc_bit_floor(_Tp __value)
{
static_assert(std::__unsigned_integer<_Tp>);
return std::bit_floor(__value);
}
inline unsigned char
stdc_bit_floor_uc(unsigned char __value)
{ return stdc_bit_floor(__value); }
inline unsigned short
stdc_bit_floor_us(unsigned short __value)
{ return stdc_bit_floor(__value); }
inline unsigned int
stdc_bit_floor_ui(unsigned int __value)
{ return stdc_bit_floor(__value); }
inline unsigned long int
stdc_bit_floor_ul(unsigned long int __value)
{ return stdc_bit_floor(__value); }
inline unsigned long long int
stdc_bit_floor_ull(unsigned long long int __value)
{ return stdc_bit_floor(__value); }
/// @}
/** Bit ceiling
*
* Unlike `std::bit_ceil`, this is defined to return zero for values which
* are not representable in the return type.
*
* @param __value An unsigned integer.
* @return The smallest power of two that is not less than `__value`.
* @since C++26
* @{
*/
template<typename _Tp>
inline _Tp
stdc_bit_ceil(_Tp __value)
{
static_assert(std::__unsigned_integer<_Tp>);
constexpr _Tp __msb = _Tp(1) << (__gnu_cxx::__int_traits<_Tp>::__digits - 1);
return (__value & __msb) ? 0 : std::bit_ceil(__value);
}
inline unsigned char
stdc_bit_ceil_uc(unsigned char __value)
{ return stdc_bit_ceil(__value); }
inline unsigned short
stdc_bit_ceil_us(unsigned short __value)
{ return stdc_bit_ceil(__value); }
inline unsigned int
stdc_bit_ceil_ui(unsigned int __value)
{ return stdc_bit_ceil(__value); }
inline unsigned long int
stdc_bit_ceil_ul(unsigned long int __value)
{ return stdc_bit_ceil(__value); }
inline unsigned long long int
stdc_bit_ceil_ull(unsigned long long int __value)
{ return stdc_bit_ceil(__value); }
/// @}
#ifndef _GLIBCXX_DOXYGEN
} // namespace __gnu_cxx
#define _GLIBCXX_STDBIT_FUNC(F) \
using __gnu_cxx::F ## _uc; \
using __gnu_cxx::F ## _us; \
using __gnu_cxx::F ## _ui; \
using __gnu_cxx::F ## _ul; \
using __gnu_cxx::F ## _ull; \
using __gnu_cxx::F
_GLIBCXX_STDBIT_FUNC(stdc_leading_zeros);
_GLIBCXX_STDBIT_FUNC(stdc_leading_ones);
_GLIBCXX_STDBIT_FUNC(stdc_trailing_zeros);
_GLIBCXX_STDBIT_FUNC(stdc_trailing_ones);
_GLIBCXX_STDBIT_FUNC(stdc_first_leading_zero);
_GLIBCXX_STDBIT_FUNC(stdc_first_leading_one);
_GLIBCXX_STDBIT_FUNC(stdc_first_trailing_zero);
_GLIBCXX_STDBIT_FUNC(stdc_first_trailing_one);
_GLIBCXX_STDBIT_FUNC(stdc_count_zeros);
_GLIBCXX_STDBIT_FUNC(stdc_count_ones);
_GLIBCXX_STDBIT_FUNC(stdc_has_single_bit);
_GLIBCXX_STDBIT_FUNC(stdc_bit_width);
_GLIBCXX_STDBIT_FUNC(stdc_bit_floor);
_GLIBCXX_STDBIT_FUNC(stdc_bit_ceil);
#undef _GLIBCXX_STDBIT_FUNC
#endif // !DOXYGEN
#endif // C++26
#endif // _GLIBCXX_STDBIT_H

View file

@ -24,6 +24,35 @@
export module std.compat;
export import std;
#include <stdbit.h>
// <stdbit.h>
export
{
#define _GLIBCXX_STDBIT_FUNC(F) \
using __gnu_cxx::F ## _uc; \
using __gnu_cxx::F ## _us; \
using __gnu_cxx::F ## _ui; \
using __gnu_cxx::F ## _ul; \
using __gnu_cxx::F ## _ull; \
using __gnu_cxx::F
_GLIBCXX_STDBIT_FUNC(stdc_leading_zeros);
_GLIBCXX_STDBIT_FUNC(stdc_leading_ones);
_GLIBCXX_STDBIT_FUNC(stdc_trailing_zeros);
_GLIBCXX_STDBIT_FUNC(stdc_trailing_ones);
_GLIBCXX_STDBIT_FUNC(stdc_first_leading_zero);
_GLIBCXX_STDBIT_FUNC(stdc_first_leading_one);
_GLIBCXX_STDBIT_FUNC(stdc_first_trailing_zero);
_GLIBCXX_STDBIT_FUNC(stdc_first_trailing_one);
_GLIBCXX_STDBIT_FUNC(stdc_count_zeros);
_GLIBCXX_STDBIT_FUNC(stdc_count_ones);
_GLIBCXX_STDBIT_FUNC(stdc_has_single_bit);
_GLIBCXX_STDBIT_FUNC(stdc_bit_width);
_GLIBCXX_STDBIT_FUNC(stdc_bit_floor);
_GLIBCXX_STDBIT_FUNC(stdc_bit_ceil);
#undef _GLIBCXX_STDBIT_FUNC
}
#define STD_COMPAT 1
// C library exports are appended from std-clib.cc.in.

View file

@ -0,0 +1,320 @@
// { dg-do run { target c++26 } }
#include <stdbit.h>
#if __STDC_VERSION_STDBIT_H__ != 202311L
# error "__STDC_VERSION_STDBIT_H__ not defined correctly in <stdbit.h>"
#endif
#ifndef __STDC_ENDIAN_BIG__
# error "__STDC_ENDIAN_BIG__ is not defined in <stdbit.h>"
#endif
#ifndef __STDC_ENDIAN_LITTLE__
# error "__STDC_ENDIAN_LITTLE__ is not defined in <stdbit.h>"
#endif
#ifndef __STDC_ENDIAN_NATIVE__
# error "__STDC_ENDIAN_NATIVE__ is not defined in <stdbit.h>"
#endif
#include <testsuite_hooks.h>
#include <limits.h>
void
test_leading_zeros()
{
VERIFY( stdc_leading_zeros_uc(0) == CHAR_BIT );
VERIFY( stdc_leading_zeros_uc(UCHAR_MAX) == 0 );
VERIFY( stdc_leading_zeros_uc(CHAR_MAX) == (CHAR_MIN ? 1 : 0) );
VERIFY( stdc_leading_zeros_uc(UCHAR_MAX >> 3) == 3 );
VERIFY( stdc_leading_zeros_uc((unsigned char)(UCHAR_MAX << 3)) == 0 );
// TODO: replace __X_WIDTH__ with the standard macros once they're in C++26
VERIFY( stdc_leading_zeros_us(0) == __SHRT_WIDTH__ );
VERIFY( stdc_leading_zeros_us(USHRT_MAX) == 0 );
VERIFY( stdc_leading_zeros_us(USHRT_MAX >> 11) == 11 );
VERIFY( stdc_leading_zeros_ui(0) == __INT_WIDTH__ );
VERIFY( stdc_leading_zeros_ui(UINT_MAX) == 0 );
VERIFY( stdc_leading_zeros_ui(UINT_MAX >> 11) == 11 );
VERIFY( stdc_leading_zeros_ul(0) == __LONG_WIDTH__ );
VERIFY( stdc_leading_zeros_ul(ULONG_MAX) == 0 );
VERIFY( stdc_leading_zeros_ul(ULONG_MAX >> 19) == 19 );
VERIFY( stdc_leading_zeros_ull(0) == __LONG_LONG_WIDTH__ );
VERIFY( stdc_leading_zeros_ull(ULLONG_MAX) == 0 );
VERIFY( stdc_leading_zeros_ull(ULLONG_MAX >> 33) == 33 );
VERIFY( stdc_leading_zeros_ull(7) == (__LONG_LONG_WIDTH__ - 3) );
VERIFY( stdc_leading_zeros(7U) == (__INT_WIDTH__ - 3) );
VERIFY( stdc_leading_zeros(7UL) == (__LONG_WIDTH__ - 3) );
VERIFY( stdc_leading_zeros(7ULL) == (__LONG_LONG_WIDTH__ - 3) );
static_assert( std::is_same_v<decltype(stdc_leading_zeros(0UL)), unsigned> );
}
void
test_leading_ones()
{
VERIFY( stdc_leading_ones_uc(0) == 0 );
VERIFY( stdc_leading_ones_uc(UCHAR_MAX) == CHAR_BIT );
VERIFY( stdc_leading_ones_uc(CHAR_MAX) == (CHAR_MIN ? 0 : CHAR_BIT) );
VERIFY( stdc_leading_ones_uc(UCHAR_MAX >> 3) == 0 );
VERIFY( stdc_leading_ones_uc((unsigned char)(UCHAR_MAX << 3)) == (CHAR_BIT - 3) );
VERIFY( stdc_leading_ones_us(0) == 0 );
VERIFY( stdc_leading_ones_us(USHRT_MAX) == __SHRT_WIDTH__ );
VERIFY( stdc_leading_ones_us((unsigned short)(USHRT_MAX << 11)) == (__SHRT_WIDTH__ - 11) );
VERIFY( stdc_leading_ones_us(USHRT_MAX >> 11) == 0 );
VERIFY( stdc_leading_ones_ui(0) == 0 );
VERIFY( stdc_leading_ones_ui(UINT_MAX) == __INT_WIDTH__ );
VERIFY( stdc_leading_ones_ui(UINT_MAX << 11) == (__INT_WIDTH__ - 11) );
VERIFY( stdc_leading_ones_ul(0) == 0 );
VERIFY( stdc_leading_ones_ul(ULONG_MAX) == __LONG_WIDTH__ );
VERIFY( stdc_leading_ones_ul(ULONG_MAX << 19) == (__LONG_WIDTH__ - 19) );
VERIFY( stdc_leading_ones_ull(0) == 0 );
VERIFY( stdc_leading_ones_ull(ULLONG_MAX) == __LONG_LONG_WIDTH__ );
VERIFY( stdc_leading_ones_ull(ULLONG_MAX << 33) == (__LONG_LONG_WIDTH__ - 33) );
VERIFY( stdc_leading_ones(-1U << 2) == (__INT_WIDTH__ - 2) );
VERIFY( stdc_leading_ones(-1UL << 3) == (__LONG_WIDTH__ - 3) );
VERIFY( stdc_leading_ones(-1ULL << 4) == (__LONG_LONG_WIDTH__ - 4) );
static_assert( std::is_same_v<decltype(stdc_leading_ones(0UL)), unsigned> );
}
void
test_trailing_zeros()
{
VERIFY( stdc_trailing_zeros_uc((unsigned char)(UCHAR_MAX << 5)) == 5 );
VERIFY( stdc_trailing_zeros_us((unsigned short)(USHRT_MAX << 5)) == 5 );
VERIFY( stdc_trailing_zeros_ui(UINT_MAX << 9) == 9 );
VERIFY( stdc_trailing_zeros_ul(ULONG_MAX << 19) == 19 );
VERIFY( stdc_trailing_zeros_ull(ULLONG_MAX << 39) == 39 );
VERIFY( stdc_trailing_zeros(8U) == 3 );
static_assert( std::is_same_v<decltype(stdc_trailing_zeros(0UL)), unsigned> );
}
void
test_trailing_ones()
{
VERIFY( stdc_trailing_ones_uc((unsigned char)3) == 2 );
VERIFY( stdc_trailing_ones_uc((unsigned char)135) == 3 );
VERIFY( stdc_trailing_ones_us((unsigned short)7) == 3 );
VERIFY( stdc_trailing_ones_us((unsigned short)23) == 3 );
VERIFY( stdc_trailing_ones_us((unsigned short)235) == 2 );
VERIFY( stdc_trailing_ones_ui(11U) == 2 );
VERIFY( stdc_trailing_ones_ui(15U) == 4 );
VERIFY( stdc_trailing_ones_ul(ULONG_MAX) == __LONG_WIDTH__ );
VERIFY( stdc_trailing_ones_ull(ULLONG_MAX) == __LONG_LONG_WIDTH__ );
VERIFY( stdc_trailing_ones(7U) == 3 );
static_assert( std::is_same_v<decltype(stdc_trailing_ones(0UL)), unsigned> );
}
void
test_first_leading_zero()
{
VERIFY( stdc_first_leading_zero_uc(0) == 1 );
VERIFY( stdc_first_leading_zero_uc(UCHAR_MAX) == 0 );
VERIFY( stdc_first_leading_zero_uc(UCHAR_MAX ^ 0b111) == (CHAR_BIT - 2) );
VERIFY( stdc_first_leading_zero_us(USHRT_MAX) == 0 );
VERIFY( stdc_first_leading_zero_us(USHRT_MAX ^ 0b111) == (__SHRT_WIDTH__ - 2) );
VERIFY( stdc_first_leading_zero_ui(UINT_MAX ^ 0b10111) == (__INT_WIDTH__ - 4) );
VERIFY( stdc_first_leading_zero_ul(ULONG_MAX ^ 0b10111) == (__LONG_WIDTH__ - 4) );
VERIFY( stdc_first_leading_zero_ull(ULLONG_MAX ^ 0b10111) == (__LONG_LONG_WIDTH__ - 4) );
VERIFY( stdc_first_leading_zero(0U) == 1 );
VERIFY( stdc_first_leading_zero(-1U ^ 0b1111) == (__INT_WIDTH__ - 3) );
static_assert( std::is_same_v<decltype(stdc_first_leading_zero(0UL)), unsigned> );
}
void
test_first_leading_one()
{
VERIFY( stdc_first_leading_one_uc(0) == 0 );
VERIFY( stdc_first_leading_one_uc(0b00100) == (CHAR_BIT - 2) );
VERIFY( stdc_first_leading_one_ui(0b001100) == (__INT_WIDTH__ - 3) );
VERIFY( stdc_first_leading_one_ul(0b101100) == (__LONG_WIDTH__ - 5) );
VERIFY( stdc_first_leading_one_ull(0b1110000) == (__LONG_LONG_WIDTH__ - 6) );
VERIFY( stdc_first_leading_one(0U) == 0 );
VERIFY( stdc_first_leading_one(-1U >> 4) == 5 );
VERIFY( stdc_first_leading_one(-1ULL >> 43) == 44 );
static_assert( std::is_same_v<decltype(stdc_first_leading_one(0UL)), unsigned> );
}
void
test_first_trailing_zero()
{
VERIFY( stdc_first_trailing_zero_uc(0) == 1 );
VERIFY( stdc_first_trailing_zero_uc(1) == 2 );
VERIFY( stdc_first_trailing_zero_uc(7) == 4 );
VERIFY( stdc_first_trailing_zero_us(15) == 5 );
VERIFY( stdc_first_trailing_zero_ui(15) == 5 );
VERIFY( stdc_first_trailing_zero_ul(15) == 5 );
VERIFY( stdc_first_trailing_zero_ull(15) == 5 );
VERIFY( stdc_first_trailing_zero(15U) == 5 );
static_assert( std::is_same_v<decltype(stdc_first_trailing_zero(0UL)), unsigned> );
}
void
test_first_trailing_one()
{
VERIFY( stdc_first_trailing_one_uc(0) == 0 );
VERIFY( stdc_first_trailing_one_uc(1) == 1 );
VERIFY( stdc_first_trailing_one_uc(7) == 1 );
VERIFY( stdc_first_trailing_one_us(16) == 5 );
VERIFY( stdc_first_trailing_one_ui(16) == 5 );
VERIFY( stdc_first_trailing_one_ul(16) == 5 );
VERIFY( stdc_first_trailing_one_ull(16) == 5 );
VERIFY( stdc_first_trailing_one(16U) == 5 );
VERIFY( stdc_first_trailing_one(-1ULL << 17) == 18 );
static_assert( std::is_same_v<decltype(stdc_first_trailing_one(0UL)), unsigned> );
}
void
test_count_zeros()
{
VERIFY( stdc_count_zeros_uc(0b101010) == (CHAR_BIT - 3) );
VERIFY( stdc_count_zeros_us(0b1010101) == (__SHRT_WIDTH__ - 4) );
VERIFY( stdc_count_zeros_ui(0b1010101111) == (__INT_WIDTH__ - 7) );
VERIFY( stdc_count_zeros_ul(0b10101011110101) == (__LONG_WIDTH__ - 9) );
VERIFY( stdc_count_zeros_ull(0b10101011110101) == (__LONG_LONG_WIDTH__ - 9) );
VERIFY( stdc_count_zeros(0b111UL) == (__LONG_WIDTH__ - 3) );
VERIFY( stdc_count_zeros(0U) == __INT_WIDTH__ );
// std::popcount returns signed int, stdc_count_zeros_uc returns unsigned int.
static_assert( std::is_same_v<decltype(stdc_count_zeros_uc(0)), unsigned> );
static_assert( std::is_same_v<decltype(stdc_count_zeros_uc(0)), unsigned> );
static_assert( std::is_same_v<decltype(stdc_count_zeros_uc(0)), unsigned> );
static_assert( std::is_same_v<decltype(stdc_count_zeros_uc(0)), unsigned> );
static_assert( std::is_same_v<decltype(stdc_count_zeros_uc(0)), unsigned> );
static_assert( std::is_same_v<decltype(stdc_count_zeros_uc(0u)), unsigned> );
}
void
test_count_ones()
{
VERIFY( stdc_count_ones_uc(0b101010) == 3 );
VERIFY( stdc_count_ones_us(0b1010101) == 4 );
VERIFY( stdc_count_ones_ui(0b1010101111) == 7 );
VERIFY( stdc_count_ones_ul(0b10101011110101) == 9 );
VERIFY( stdc_count_ones_ull(0b10101011110101) == 9 );
VERIFY( stdc_count_ones(0b10101011110101U) == 9 );
VERIFY( stdc_count_ones(0U) == 0 );
// std::popcount returns signed int, stdc_count_ones_uc returns unsigned int.
static_assert( std::is_same_v<decltype(stdc_count_ones_uc(0)), unsigned> );
static_assert( std::is_same_v<decltype(stdc_count_ones_uc(0)), unsigned> );
static_assert( std::is_same_v<decltype(stdc_count_ones_uc(0)), unsigned> );
static_assert( std::is_same_v<decltype(stdc_count_ones_uc(0)), unsigned> );
static_assert( std::is_same_v<decltype(stdc_count_ones_uc(0)), unsigned> );
static_assert( std::is_same_v<decltype(stdc_count_ones_uc(0u)), unsigned> );
}
void
test_has_single_bit()
{
VERIFY ( ! stdc_has_single_bit_uc(0) );
VERIFY ( ! stdc_has_single_bit_uc(41) );
VERIFY ( stdc_has_single_bit_uc(1) );
VERIFY ( stdc_has_single_bit_uc(64) );
VERIFY ( stdc_has_single_bit_us(1 << 7) );
VERIFY ( stdc_has_single_bit_ui(1 << 11) );
VERIFY ( stdc_has_single_bit_ul(1 << 14) );
VERIFY ( stdc_has_single_bit_ull(1 << 24) );
VERIFY ( stdc_has_single_bit(64U) );
VERIFY ( stdc_has_single_bit(128UL) );
VERIFY ( ! stdc_has_single_bit(129UL) );
}
void
test_bit_width()
{
VERIFY( stdc_bit_width_uc(0) == 0 );
VERIFY( stdc_bit_width_uc(7) == 3 );
VERIFY( stdc_bit_width_uc(0b10101) == 5 );
VERIFY( stdc_bit_width_us(0b101010) == 6 );
VERIFY( stdc_bit_width_ui(0b1010101) == 7 );
VERIFY( stdc_bit_width_ul(ULONG_MAX) == __LONG_WIDTH__ );
VERIFY( stdc_bit_width_ull(ULLONG_MAX >> 2) == (__LONG_LONG_WIDTH__ - 2) );
VERIFY( stdc_bit_width(0b1010101U) == 7U );
// std::bit_width returns signed int, stdc_bit_width returns unsigned int.
static_assert( std::is_same_v<decltype(stdc_bit_width_uc(0)), unsigned> );
static_assert( std::is_same_v<decltype(stdc_bit_width_us(0)), unsigned> );
static_assert( std::is_same_v<decltype(stdc_bit_width_ui(0)), unsigned> );
static_assert( std::is_same_v<decltype(stdc_bit_width_ul(0)), unsigned> );
static_assert( std::is_same_v<decltype(stdc_bit_width_ul(0)), unsigned> );
static_assert( std::is_same_v<decltype(stdc_bit_width(0u)), unsigned> );
}
void
test_bit_floor()
{
VERIFY( stdc_bit_floor_uc(0) == 0 );
VERIFY( stdc_bit_floor_uc(7) == 4 );
VERIFY( stdc_bit_floor_uc(0b10101) == 0b10000 );
VERIFY( stdc_bit_floor_us(0b101010) == 0b100000 );
VERIFY( stdc_bit_floor_ui(0b1010101) == 0b1000000 );
VERIFY( stdc_bit_floor_ul(ULONG_MAX) == (1ul << (__LONG_WIDTH__ - 1)) );
VERIFY( stdc_bit_floor_ull(1000000) == (1ULL << 19) );
VERIFY( stdc_bit_floor(0b1010101U) == 0b1000000 );
}
void
test_bit_ceil()
{
VERIFY( stdc_bit_ceil_uc(0) == 1 );
VERIFY( stdc_bit_ceil_uc(1) == 1 );
VERIFY( stdc_bit_ceil_uc(2) == 2 );
VERIFY( stdc_bit_ceil_uc(3) == 4 );
VERIFY( stdc_bit_ceil_us(11) == 16 );
VERIFY( stdc_bit_ceil_ui(257) == 512 );
VERIFY( stdc_bit_ceil_ul(1048) == 2048 );
VERIFY( stdc_bit_ceil_ull(1000000) == (1ULL << 20) );
VERIFY( stdc_bit_ceil(0b1010101U) == 0b10000000 );
}
int main()
{
test_leading_zeros();
test_leading_ones();
test_trailing_zeros();
test_trailing_ones();
test_first_leading_zero();
test_first_leading_one();
test_first_trailing_zero();
test_first_trailing_one();
test_count_zeros();
test_count_ones();
test_has_single_bit();
test_bit_width();
test_bit_floor();
test_bit_ceil();
}
#include <bit>
// The standard doesn't require these values to match,
// so this is specific to libstdc++.
#ifdef _GLIBCXX_RELEASE
static_assert(__STDC_ENDIAN_BIG__ == (int)std::endian::big);
static_assert(__STDC_ENDIAN_LITTLE__ == (int)std::endian::little);
static_assert(__STDC_ENDIAN_NATIVE__ == (int)std::endian::native);
#endif

View file

@ -0,0 +1,45 @@
// { dg-do compile { target c++26 } }
#include <stdbit.h>
void
test_mandates()
{
// Mandates: T is an unsigned integer type.
::stdc_leading_zeros(1); // { dg-error "here" }
::stdc_leading_ones(1); // { dg-error "here" }
::stdc_trailing_zeros(1); // { dg-error "here" }
::stdc_trailing_ones(1); // { dg-error "here" }
::stdc_first_leading_zero(1); // { dg-error "here" }
::stdc_first_leading_one(1); // { dg-error "here" }
::stdc_first_trailing_zero(1); // { dg-error "here" }
::stdc_first_trailing_one(1); // { dg-error "here" }
::stdc_count_zeros(1); // { dg-error "here" }
::stdc_count_ones(1); // { dg-error "here" }
::stdc_has_single_bit(1); // { dg-error "here" }
::stdc_bit_width(1); // { dg-error "here" }
::stdc_bit_floor(1); // { dg-error "here" }
::stdc_bit_ceil(1); // { dg-error "here" }
::stdc_leading_zeros(1.0); // { dg-error "here" }
::stdc_leading_ones(1.0); // { dg-error "here" }
::stdc_trailing_zeros(1.0); // { dg-error "here" }
::stdc_trailing_ones(1.0); // { dg-error "here" }
::stdc_first_leading_zero(1.0); // { dg-error "here" }
::stdc_first_leading_one(1.0); // { dg-error "here" }
::stdc_first_trailing_zero(1.0); // { dg-error "here" }
::stdc_first_trailing_one(1.0); // { dg-error "here" }
::stdc_count_zeros(1.0); // { dg-error "here" }
::stdc_count_ones(1.0); // { dg-error "here" }
::stdc_has_single_bit(1.0); // { dg-error "here" }
::stdc_bit_width(1.0); // { dg-error "here" }
::stdc_bit_floor(1.0); // { dg-error "here" }
::stdc_bit_ceil(1.0); // { dg-error "here" }
}
// { dg-prune-output "static assertion failed" }
// { dg-prune-output "no matching function" }
// { dg-prune-output "wrong type" }
// { dg-prune-output "invalid operands" }
// { dg-prune-output "non-integral type" }