On Thu, 3 Jul 2025, 00:56 Nathan Myers, <n...@cantrip.org> wrote:

> Changes in V2:
> * Generalize private member _M_check_initial_position for use with
>   both string and string_view arguments.
> * Remove unnecessary #if guards for version and hostedness.
> * Remove redundant "std::" qualifications in new code.
> * Improve Doxygen source readability.
> * Clarify commit message text.
> * Fix ChangeLog style.
>

OK for trunk, thanks



> Add a bitset constructor from string_view, per P2697. Fix existing
> tests that would fail to detect incorrect exception behavior.
>
> Argument checks that result in exceptions guarded by "#if HOSTED"
> are made unguarded because the functions called to throw just call
> terminate() in free-standing builds. Improve readability in Doxygen
> comments. Generalize a private member argument-checking function
> to work with string and string_view without mentioning either,
> obviating need for guards.
>
> The version.h symbol is not "hosted" because string_view, though
> not specified to be available in free-standing builds, is defined
> there and the feature is useful there.
>
> libstdc++-v3/ChangeLog:
>         PR libstdc++/119742
>         * include/bits/version.def: Add preprocessor symbol.
>         * include/bits/version.h: Add preprocessor symbol.
>         * include/std/bitset: Add constructor.
>         * testsuite/20_util/bitset/cons/1.cc: Fix.
>         * testsuite/20_util/bitset/cons/6282.cc: Fix.
>         * testsuite/20_util/bitset/cons/string_view.cc: Test new ctor.
>         * testsuite/20_util/bitset/cons/string_view_wide.cc: Test new ctor.
> ---
>  libstdc++-v3/include/bits/version.def         |   8 ++
>  libstdc++-v3/include/bits/version.h           |  10 ++
>  libstdc++-v3/include/std/bitset               |  82 +++++++----
>  .../testsuite/20_util/bitset/cons/1.cc        |   1 +
>  .../testsuite/20_util/bitset/cons/6282.cc     |   5 +-
>  .../20_util/bitset/cons/string_view.cc        | 132 ++++++++++++++++++
>  .../20_util/bitset/cons/string_view_wide.cc   |   8 ++
>  7 files changed, 215 insertions(+), 31 deletions(-)
>  create mode 100644
> libstdc++-v3/testsuite/20_util/bitset/cons/string_view.cc
>  create mode 100644
> libstdc++-v3/testsuite/20_util/bitset/cons/string_view_wide.cc
>
> diff --git a/libstdc++-v3/include/bits/version.def
> b/libstdc++-v3/include/bits/version.def
> index f4ba501c403..b89b287e8e8 100644
> --- a/libstdc++-v3/include/bits/version.def
> +++ b/libstdc++-v3/include/bits/version.def
> @@ -2030,6 +2030,14 @@ ftms = {
>    };
>  };
>
> +ftms = {
> +  name = bitset  // ...construct from string_view
> +  values = {
> +    v = 202306;
> +    cxxmin = 26;
> +  };
> +};
> +
>  // Standard test specifications.
>  stds[97] = ">= 199711L";
>  stds[03] = ">= 199711L";
> diff --git a/libstdc++-v3/include/bits/version.h
> b/libstdc++-v3/include/bits/version.h
> index dc8ac07be16..a70a7ede68c 100644
> --- a/libstdc++-v3/include/bits/version.h
> +++ b/libstdc++-v3/include/bits/version.h
> @@ -2273,4 +2273,14 @@
>  #endif /* !defined(__cpp_lib_exception_ptr_cast) &&
> defined(__glibcxx_want_exception_ptr_cast) */
>  #undef __glibcxx_want_exception_ptr_cast
>
> +#if !defined(__cpp_lib_bitset)
> +# if (__cplusplus >  202302L)
> +#  define __glibcxx_bitset 202306L
> +#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_bitset)
> +#   define __cpp_lib_bitset 202306L
> +#  endif
> +# endif
> +#endif /* !defined(__cpp_lib_bitset) && defined(__glibcxx_want_bitset) */
> +#undef __glibcxx_bitset
> +
>  #undef __glibcxx_want_all
> diff --git a/libstdc++-v3/include/std/bitset
> b/libstdc++-v3/include/std/bitset
> index 8b5d270c2a9..1c1e1670c33 100644
> --- a/libstdc++-v3/include/std/bitset
> +++ b/libstdc++-v3/include/std/bitset
> @@ -61,8 +61,13 @@
>  #endif
>
>  #define __glibcxx_want_constexpr_bitset
> +#define __glibcxx_want_bitset  // ...construct from string_view
>  #include <bits/version.h>
>
> +#ifdef __cpp_lib_bitset // ...construct from string_view
> +# include <string_view>
> +#endif
> +
>  #define _GLIBCXX_BITSET_BITS_PER_WORD  (__CHAR_BIT__ * __SIZEOF_LONG__)
>  #define _GLIBCXX_BITSET_WORDS(__n) \
>    ((__n) / _GLIBCXX_BITSET_BITS_PER_WORD + \
> @@ -752,7 +757,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
>     *  (Note that %bitset does @e not meet the formal requirements of a
>     *  <a href="tables.html#65">container</a>.  Mainly, it lacks
> iterators.)
>     *
> -   *  The template argument, @a Nb, may be any non-negative number,
> +   *  The template argument, `Nb`, may be any non-negative number,
>     *  specifying the number of bits (e.g., "0", "12", "1024*1024").
>     *
>     *  In the general unoptimized case, storage is allocated in word-sized
> @@ -816,28 +821,25 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
>        typedef _Base_bitset<_GLIBCXX_BITSET_WORDS(_Nb)> _Base;
>        typedef unsigned long _WordT;
>
> -#if _GLIBCXX_HOSTED
> -      template<class _CharT, class _Traits, class _Alloc>
> -      _GLIBCXX23_CONSTEXPR
> -      void
> -      _M_check_initial_position(const std::basic_string<_CharT, _Traits,
> _Alloc>& __s,
> -                               size_t __position) const
> +      template<class _Str>
> +      _GLIBCXX23_CONSTEXPR void
> +      _M_check_initial_position(
> +       const _Str& __s, typename _Str::size_type __position) const
>        {
>         if (__position > __s.size())
> -         __throw_out_of_range_fmt(__N("bitset::bitset: __position "
> -                                      "(which is %zu) > __s.size() "
> -                                      "(which is %zu)"),
> -                                  __position, __s.size());
> +         __throw_out_of_range_fmt(
> +           __N("bitset::bitset:"
> +               " __position (which is %zu) > __s.size() (which is %zu)"),
> +           size_t(__position), size_t(__s.size()));
>        }
> -#endif // HOSTED
>
>        _GLIBCXX23_CONSTEXPR
>        void _M_check(size_t __position, const char *__s) const
>        {
>         if (__position >= _Nb)
> -         __throw_out_of_range_fmt(__N("%s: __position (which is %zu) "
> -                                      ">= _Nb (which is %zu)"),
> -                                  __s, __position, _Nb);
> +         __throw_out_of_range_fmt(
> +           __N("%s: __position (which is %zu) >= _Nb (which is %zu)"),
> +           __s, size_t(__position), size_t(_Nb));
>        }
>
>        _GLIBCXX23_CONSTEXPR
> @@ -954,12 +956,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
>  #if _GLIBCXX_HOSTED
>        /**
>         *  Use a subset of a string.
> -       *  @param  __s  A string of @a 0 and @a 1 characters.
> -       *  @param  __position  Index of the first character in @a __s to
> use;
> +       *  @param  __s  A string of `0` and `1` characters.
> +       *  @param  __position  Index of the first character in `__s` to
> use;
>         *                    defaults to zero.
> -       *  @throw  std::out_of_range  If @a pos is bigger the size of @a
> __s.
> +       *  @throw  std::out_of_range  If `__position > __s.size()`.
>         *  @throw  std::invalid_argument  If a character appears in the
> string
> -       *                                 which is neither @a 0 nor @a 1.
> +       *                                 which is neither `0` nor `1`.
>         */
>        template<class _CharT, class _Traits, class _Alloc>
>         _GLIBCXX23_CONSTEXPR
> @@ -976,13 +978,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
>
>        /**
>         *  Use a subset of a string.
> -       *  @param  __s  A string of @a 0 and @a 1 characters.
> -       *  @param  __position  Index of the first character in @a __s to
> use.
> +       *  @param  __s  A string of `0` and `1` characters.
> +       *  @param  __position  Index of the first character in `__s` to
> use.
>         *  @param  __n    The number of characters to copy.
> -       *  @throw std::out_of_range If @a __position is bigger the size
> -       *  of @a __s.
> +       *  @throw  std::out_of_range  If `__position > __s.size()`.
>         *  @throw  std::invalid_argument  If a character appears in the
> string
> -       *                                 which is neither @a 0 nor @a 1.
> +       *                                 which is neither `0` nor `1`.
>         */
>        template<class _CharT, class _Traits, class _Alloc>
>         _GLIBCXX23_CONSTEXPR
> @@ -1008,15 +1009,42 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
>         }
>  #endif // HOSTED
>
> +#ifdef __cpp_lib_bitset
> +      /**
> +       *  Use a subset of a string view.
> +       *  @param  __s  A `string_view` of a sequence of `0` and `1`
> characters.
> +       *  @param  __position  Index of the first character in `__s` to
> use.
> +       *  @param  __n    The maximum number of characters from `__s` to
> use.
> +       *  @param  __zero The character corresponding to the value 0.
> +       *  @param  __one  The character corresponding to the value 1.
> +       *  @throw  std::out_of_range  If `__position > __s.size()`.
> +       *  @throw  std::invalid_argument  If a character appears in `__s`
> +       *                                 which is neither `0` nor `1`.
> +       */
> +      template<class _CharT, class _Traits>
> +       constexpr explicit
> +       bitset(basic_string_view<_CharT, _Traits> __s,
> +         basic_string_view<_CharT, _Traits>::size_type __position = 0,
> +         basic_string_view<_CharT, _Traits>::size_type __n =
> +           basic_string_view<_CharT, _Traits>::npos,
> +         _CharT __zero = _CharT('0'), _CharT __one = _CharT('1'))
> +       : _Base()
> +       {
> +         _M_check_initial_position(__s, __position);
> +         _M_copy_from_ptr<_CharT, _Traits>(
> +           __s.data(), __s.size(), __position, __n, __zero, __one);
> +       }
> +#endif
> +
>  #if __cplusplus >= 201103L
>        /**
>         *  Construct from a character %array.
> -       *  @param  __str  An %array of characters @a zero and @a one.
> +       *  @param  __str  An %array of characters `__zero` and `__one`.
>         *  @param  __n    The number of characters to use.
>         *  @param  __zero The character corresponding to the value 0.
>         *  @param  __one  The character corresponding to the value 1.
>         *  @throw  std::invalid_argument If a character appears in the
> string
> -       *                                which is neither @a __zero nor @a
> __one.
> +       *                                which is neither `__zero` nor
> `__one`.
>         */
>        template<typename _CharT>
>         [[__gnu__::__nonnull__]]
> @@ -1028,10 +1056,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
>                _CharT __zero = _CharT('0'), _CharT __one = _CharT('1'))
>          : _Base()
>          {
> -#if _GLIBCXX_HOSTED
>           if (!__str)
>             __throw_logic_error(__N("bitset::bitset(const _CharT*, ...)"));
> -#endif
>           using _Traits = typename __bitset::__string<_CharT>::traits_type;
>
>           if (__n == __bitset::__string<_CharT>::npos)
> diff --git a/libstdc++-v3/testsuite/20_util/bitset/cons/1.cc
> b/libstdc++-v3/testsuite/20_util/bitset/cons/1.cc
> index 0a40b6cd965..6441332c8d6 100644
> --- a/libstdc++-v3/testsuite/20_util/bitset/cons/1.cc
> +++ b/libstdc++-v3/testsuite/20_util/bitset/cons/1.cc
> @@ -47,6 +47,7 @@ void test01(void)
>    const size_t n3 = 128;
>    try {
>      std::bitset<n3> bit03(str01, 5);
> +    VERIFY(false);
>    }
>    catch(std::invalid_argument& fail) {
>      VERIFY( true );
> diff --git a/libstdc++-v3/testsuite/20_util/bitset/cons/6282.cc
> b/libstdc++-v3/testsuite/20_util/bitset/cons/6282.cc
> index fafa9fc808b..ee348c35b2a 100644
> --- a/libstdc++-v3/testsuite/20_util/bitset/cons/6282.cc
> +++ b/libstdc++-v3/testsuite/20_util/bitset/cons/6282.cc
> @@ -39,6 +39,8 @@ void test02(void)
>    std::bitset<0>  z3(std::string("10101010101"));
>    VERIFY( z3.any() == false );
>
> +  VERIFY( z1.to_ulong() == 0 );
> +  VERIFY( (z1.to_string<char,char_traits<char>,allocator<char>
> >().empty() ));
>    try {
>      z1.set(0);
>      VERIFY( false );
> @@ -49,9 +51,6 @@ void test02(void)
>    catch(...) {
>      VERIFY( false );
>    }
> -
> -  VERIFY( z1.to_ulong() == 0 );
> -  VERIFY( (z1.to_string<char,char_traits<char>,allocator<char>
> >().empty() ));
>  }
>
>  int main()
> diff --git a/libstdc++-v3/testsuite/20_util/bitset/cons/string_view.cc
> b/libstdc++-v3/testsuite/20_util/bitset/cons/string_view.cc
> new file mode 100644
> index 00000000000..ec3a6c86b68
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/20_util/bitset/cons/string_view.cc
> @@ -0,0 +1,132 @@
> +// C++26 [bitset.cons]
> +
> +// { dg-do run { target c++26 } }
> +
> +#ifndef C
> +# define C char
> +# define L(s) s
> +#endif
> +
> +#include <bitset>
> +#include <string>
> +#include <string_view>
> +#include <algorithm> // std::reverse, std::transform
> +#include <stdexcept>
> +#include <testsuite_hooks.h>
> +
> +void test01()
> +{
> +  // template<_C,_T>
> +  // constexpr explicit
> +  // bitset(const basic_string_view<_C,_T>,
> +  //   size_type pos, size_type n, _C zero, _C one)
> +  try {
> +    std::basic_string_view<C> str(L("stuff smith sessions"));
> +    const std::size_t n = 128;
> +    std::bitset<n> bit(str, 5);
> +    VERIFY(false);
> +  }
> +  catch(std::invalid_argument& fail) {
> +    VERIFY( true );
> +  }
> +  catch(...) {
> +    VERIFY( false );
> +  }
> +
> +  try {
> +    std::basic_string_view<C> str(L("010101000011"));
> +    const std::size_t n = 128;
> +    const auto sz = str.size();
> +    std::bitset<n> bit(str, 0);
> +    std::basic_string<C> str02;
> +    for (std::size_t i = 0; i < sz; ++i)
> +      str02 += (bit.test(i) ? C('1') : C('0'));
> +    std::reverse(str02.begin(), str02.end());
> +    VERIFY( str02 == str );
> +  }
> +  catch(std::invalid_argument& fail) {
> +    VERIFY( false );
> +  }
> +  catch(...) {
> +    VERIFY( false );
> +  }
> +
> +  // substring<C> "010101000011"
> +  //              "10100001"
> +  try {
> +    std::basic_string_view<C> str(L("010101000011"));
> +    const std::size_t n = 128;
> +    const auto sz = 8;
> +    std::bitset<n> bit(str, 3, sz);
> +    std::basic_string<C> str02;
> +    for (std::size_t i = 0; i < sz; ++i)
> +      str02 += (bit.test(i) ? C('1') : C('0'));
> +    std::reverse(str02.begin(), str02.end());
> +    VERIFY( str02 == str.substr(3, sz) );
> +  }
> +  catch(std::invalid_argument& fail) {
> +    VERIFY( false );
> +  }
> +  catch(...) {
> +    VERIFY( false );
> +  }
> +
> +  // "abababaaaabb", zero = 'a', one = 'b'
> +  try {
> +    std::basic_string_view<C> str(L("010101000011"));
> +    const std::size_t n = 128;
> +    const auto sz = str.size();
> +    std::basic_string<C> str02(str);
> +    std::transform(str02.cbegin(), str02.cend(), str02.begin(), [](auto
> c) {
> +      return (c - C('0')) + C('a');
> +    });
> +    std::basic_string_view<C> str03(str02);
> +    std::bitset<n> bit(str03, 0, 100, C('a'), C('b'));
> +    std::basic_string<C> str04;
> +    for (std::size_t i = 0; i < sz; ++i)
> +      str04 += (bit.test(i) ? C('1') : C('0'));
> +    std::reverse(str04.begin(), str04.end());
> +    VERIFY( str04 == str );
> +  }
> +  catch(std::invalid_argument& fail) {
> +    VERIFY( false );
> +  }
> +  catch(...) {
> +    VERIFY( false );
> +  }
> +
> +  // "aba0aba", zero = 'a', one = 'b', '0' appears
> +  try {
> +    const std::size_t n = 128;
> +    std::basic_string_view<C> str05(L("aba0aba"));
> +    std::bitset<n> bit(str05, 0, 100, C('a'), C('b'));
> +    VERIFY( false );
> +  }
> +  catch(std::invalid_argument& fail) {
> +    VERIFY( true );
> +  }
> +  catch(...) {
> +    VERIFY( false );
> +  }
> +
> +  // pos > str.size()
> +  try {
> +    std::basic_string_view<C> str(L("010101000011"));
> +    const std::size_t n = 128;
> +    const auto sz = str.size();
> +    std::bitset<n> bit(str, sz + 1, 100);
> +    VERIFY( false );
> +  }
> +  catch(std::out_of_range& fail) {
> +    VERIFY( true );
> +  }
> +  catch(...) {
> +    VERIFY( false );
> +  }
> +}
> +
> +int main()
> +{
> +  test01();
> +  return 0;
> +}
> diff --git
> a/libstdc++-v3/testsuite/20_util/bitset/cons/string_view_wide.cc
> b/libstdc++-v3/testsuite/20_util/bitset/cons/string_view_wide.cc
> new file mode 100644
> index 00000000000..b53fe74a7ce
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/20_util/bitset/cons/string_view_wide.cc
> @@ -0,0 +1,8 @@
> +// C++26 [bitset.cons]
> +
> +// { dg-do run { target c++26 } }
> +
> +#define C wchar_t
> +#define L(s) L ## s
> +
> +#include "./string_view.cc"
> --
> 2.50.0
>
>

Reply via email to