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 > >