[libcxx-commits] [libcxx] [libc++] Optimize bitset::to_string (PR #128832)

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Wed May 21 09:15:26 PDT 2025


https://github.com/ldionne updated https://github.com/llvm/llvm-project/pull/128832

>From b194e1acd1d09ad888e0ee997025ec27b15be653 Mon Sep 17 00:00:00 2001
From: Peng Liu <winner245 at hotmail.com>
Date: Mon, 24 Feb 2025 22:37:04 -0500
Subject: [PATCH 1/3] Optimize bitset::to_string

---
 libcxx/include/bitset                   |  58 ++++++++++--
 libcxx/test/benchmarks/bitset.bench.cpp | 115 ++++++++++++++++++++++++
 2 files changed, 167 insertions(+), 6 deletions(-)
 create mode 100644 libcxx/test/benchmarks/bitset.bench.cpp

diff --git a/libcxx/include/bitset b/libcxx/include/bitset
index 9273ccabbb4e3..45a20033806a2 100644
--- a/libcxx/include/bitset
+++ b/libcxx/include/bitset
@@ -137,6 +137,8 @@ template <size_t N> struct hash<std::bitset<N>>;
 #  include <__algorithm/fill_n.h>
 #  include <__algorithm/find.h>
 #  include <__assert>
+#  include <__bit/countr.h>
+#  include <__bit/invert_if.h>
 #  include <__bit_reference>
 #  include <__config>
 #  include <__cstddef/ptrdiff_t.h>
@@ -224,6 +226,10 @@ protected:
     return to_ullong(integral_constant < bool, _Size< sizeof(unsigned long long) * CHAR_BIT>());
   }
 
+  template <bool _Spare, class _CharT, class _Traits, class _Allocator>
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 basic_string<_CharT, _Traits, _Allocator>
+  __to_string(_CharT __zero, _CharT __one) const;
+
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool all() const _NOEXCEPT;
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool any() const _NOEXCEPT;
   _LIBCPP_HIDE_FROM_ABI size_t __hash_code() const _NOEXCEPT;
@@ -388,6 +394,22 @@ __bitset<_N_words, _Size>::to_ullong(true_type, true_type) const {
   return __r;
 }
 
+template <size_t _N_words, size_t _Size>
+template <bool _Spare, class _CharT, class _Traits, class _Allocator>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 basic_string<_CharT, _Traits, _Allocator>
+__bitset<_N_words, _Size>::__to_string(_CharT __zero, _CharT __one) const {
+  basic_string<_CharT, _Traits, _Allocator> __r(_Size, __zero);
+  for (size_t __i = 0, __bits = 0; __i < _N_words; ++__i, __bits += __bits_per_word) {
+    __storage_type __word = std::__invert_if<!_Spare>(__first_[__i]);
+    if (__i == _N_words - 1 && _Size - __bits < __bits_per_word)
+      __word &= (__storage_type(1) << (_Size - __bits)) - 1;
+    for (; __word; __word &= (__word - 1))
+      __r[_Size - 1 - (__bits + std::__countr_zero(__word))] = __one;
+  }
+
+  return __r;
+}
+
 template <size_t _N_words, size_t _Size>
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool __bitset<_N_words, _Size>::all() const _NOEXCEPT {
   // do middle whole words
@@ -483,6 +505,10 @@ protected:
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long to_ulong() const;
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long to_ullong() const;
 
+  template <bool _Sparse, class _CharT, class _Traits, class _Allocator>
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 basic_string<_CharT, _Traits, _Allocator>
+  __to_string(_CharT __zero, _CharT __one) const;
+
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool all() const _NOEXCEPT;
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool any() const _NOEXCEPT;
 
@@ -530,6 +556,21 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long __
   return __first_;
 }
 
+template <size_t _Size>
+template <bool _Spare, class _CharT, class _Traits, class _Allocator>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 basic_string<_CharT, _Traits, _Allocator>
+__bitset<1, _Size>::__to_string(_CharT __zero, _CharT __one) const {
+  basic_string<_CharT, _Traits, _Allocator> __r(_Size, __zero);
+  __storage_type __word = std::__invert_if<!_Spare>(__first_);
+  if (_Size < __bits_per_word)
+    __word &= (__storage_type(1) << _Size) - 1;
+  for (; __word; __word &= (__word - 1)) {
+    size_t __pos           = std::__countr_zero(__word);
+    __r[_Size - 1 - __pos] = __one;
+  }
+  return __r;
+}
+
 template <size_t _Size>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool __bitset<1, _Size>::all() const _NOEXCEPT {
   __storage_type __m = ~__storage_type(0) >> (__bits_per_word - _Size);
@@ -594,6 +635,12 @@ protected:
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long to_ulong() const { return 0; }
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long to_ullong() const { return 0; }
 
+  template <bool _Spare, class _CharT, class _Traits, class _Allocator>
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 basic_string<_CharT, _Traits, _Allocator>
+  __to_string(_CharT, _CharT) const {
+    return basic_string<_CharT, _Traits, _Allocator>();
+  }
+
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool all() const _NOEXCEPT { return true; }
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool any() const _NOEXCEPT { return false; }
 
@@ -847,12 +894,11 @@ template <size_t _Size>
 template <class _CharT, class _Traits, class _Allocator>
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 basic_string<_CharT, _Traits, _Allocator>
 bitset<_Size>::to_string(_CharT __zero, _CharT __one) const {
-  basic_string<_CharT, _Traits, _Allocator> __r(_Size, __zero);
-  for (size_t __i = 0; __i != _Size; ++__i) {
-    if ((*this)[__i])
-      __r[_Size - 1 - __i] = __one;
-  }
-  return __r;
+  bool __sparse = size_t(std::count(__base::__make_iter(0), __base::__make_iter(_Size), true)) < _Size / 2;
+  if (__sparse)
+    return __base::template __to_string<true, _CharT, _Traits, _Allocator>(__zero, __one);
+  else
+    return __base::template __to_string<false, _CharT, _Traits, _Allocator>(__one, __zero);
 }
 
 template <size_t _Size>
diff --git a/libcxx/test/benchmarks/bitset.bench.cpp b/libcxx/test/benchmarks/bitset.bench.cpp
new file mode 100644
index 0000000000000..f89ed6036b7cc
--- /dev/null
+++ b/libcxx/test/benchmarks/bitset.bench.cpp
@@ -0,0 +1,115 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03
+
+#include "benchmark/benchmark.h"
+#include <bitset>
+#include <cmath>
+#include <cstddef>
+
+template <std::size_t N>
+struct GenerateBitset {
+  // Construct a bitset with p*N true bits
+  static std::bitset<N> generate(double p) {
+    std::bitset<N> b;
+    if (p <= 0.0)
+      return b;
+    if (p >= 1.0)
+      return ~b;
+
+    std::size_t num_ones = std::round(N * p);
+    if (num_ones == 0)
+      return b;
+
+    double step  = static_cast<double>(N) / num_ones;
+    double error = 0.0;
+
+    std::size_t pos = 0;
+    for (std::size_t i = 0; i < num_ones; ++i) {
+      if (pos >= N)
+        break;
+      b.set(pos);
+      error += step;
+      pos += std::floor(error);
+      error -= std::floor(error);
+    }
+    return b;
+  }
+
+  static std::bitset<N> sparse() { return generate(0.1); }
+  static std::bitset<N> dense() { return generate(0.9); }
+  static std::bitset<N> uniform() { return generate(0.5); }
+};
+
+template <std::size_t N>
+static void BM_BitsetToString(benchmark::State& state) {
+  double p         = state.range(0) / 100.0;
+  std::bitset<N> b = GenerateBitset<N>::generate(p);
+  benchmark::DoNotOptimize(b);
+
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(b.to_string());
+  }
+}
+
+// Sparse bitset
+BENCHMARK(BM_BitsetToString<32>)->Arg(10)->Name("BM_BitsetToString<32>/Sparse (10%)");
+BENCHMARK(BM_BitsetToString<64>)->Arg(10)->Name("BM_BitsetToString<64>/Sparse (10%)");
+BENCHMARK(BM_BitsetToString<128>)->Arg(10)->Name("BM_BitsetToString<128>/Sparse (10%)");
+BENCHMARK(BM_BitsetToString<256>)->Arg(10)->Name("BM_BitsetToString<256>/Sparse (10%)");
+BENCHMARK(BM_BitsetToString<512>)->Arg(10)->Name("BM_BitsetToString<512>/Sparse (10%)");
+BENCHMARK(BM_BitsetToString<1024>)->Arg(10)->Name("BM_BitsetToString<1024>/Sparse (10%)");
+BENCHMARK(BM_BitsetToString<2048>)->Arg(10)->Name("BM_BitsetToString<2048>/Sparse (10%)");
+BENCHMARK(BM_BitsetToString<4096>)->Arg(10)->Name("BM_BitsetToString<4096>/Sparse (10%)");
+BENCHMARK(BM_BitsetToString<8192>)->Arg(10)->Name("BM_BitsetToString<8192>/Sparse (10%)");
+BENCHMARK(BM_BitsetToString<16384>)->Arg(10)->Name("BM_BitsetToString<16384>/Sparse (10%)");
+BENCHMARK(BM_BitsetToString<32768>)->Arg(10)->Name("BM_BitsetToString<32768>/Sparse (10%)");
+BENCHMARK(BM_BitsetToString<65536>)->Arg(10)->Name("BM_BitsetToString<65536>/Sparse (10%)");
+BENCHMARK(BM_BitsetToString<131072>)->Arg(10)->Name("BM_BitsetToString<131072>/Sparse (10%)");
+BENCHMARK(BM_BitsetToString<262144>)->Arg(10)->Name("BM_BitsetToString<262144>/Sparse (10%)");
+BENCHMARK(BM_BitsetToString<524288>)->Arg(10)->Name("BM_BitsetToString<524288>/Sparse (10%)");
+BENCHMARK(BM_BitsetToString<1048576>)->Arg(10)->Name("BM_BitsetToString<1048576>/Sparse (10%)"); // 1 << 20
+
+// Dense bitset
+BENCHMARK(BM_BitsetToString<32>)->Arg(90)->Name("BM_BitsetToString<32>/Dense (90%)");
+BENCHMARK(BM_BitsetToString<64>)->Arg(90)->Name("BM_BitsetToString<64>/Dense (90%)");
+BENCHMARK(BM_BitsetToString<128>)->Arg(90)->Name("BM_BitsetToString<128>/Dense (90%)");
+BENCHMARK(BM_BitsetToString<256>)->Arg(90)->Name("BM_BitsetToString<256>/Dense (90%)");
+BENCHMARK(BM_BitsetToString<512>)->Arg(90)->Name("BM_BitsetToString<512>/Dense (90%)");
+BENCHMARK(BM_BitsetToString<1024>)->Arg(90)->Name("BM_BitsetToString<1024>/Dense (90%)");
+BENCHMARK(BM_BitsetToString<2048>)->Arg(90)->Name("BM_BitsetToString<2048>/Dense (90%)");
+BENCHMARK(BM_BitsetToString<4096>)->Arg(90)->Name("BM_BitsetToString<4096>/Dense (90%)");
+BENCHMARK(BM_BitsetToString<8192>)->Arg(90)->Name("BM_BitsetToString<8192>/Dense (90%)");
+BENCHMARK(BM_BitsetToString<16384>)->Arg(90)->Name("BM_BitsetToString<16384>/Dense (90%)");
+BENCHMARK(BM_BitsetToString<32768>)->Arg(90)->Name("BM_BitsetToString<32768>/Dense (90%)");
+BENCHMARK(BM_BitsetToString<65536>)->Arg(90)->Name("BM_BitsetToString<65536>/Dense (90%)");
+BENCHMARK(BM_BitsetToString<131072>)->Arg(90)->Name("BM_BitsetToString<131072>/Dense (90%)");
+BENCHMARK(BM_BitsetToString<262144>)->Arg(90)->Name("BM_BitsetToString<262144>/Dense (90%)");
+BENCHMARK(BM_BitsetToString<524288>)->Arg(90)->Name("BM_BitsetToString<524288>/Dense (90%)");
+BENCHMARK(BM_BitsetToString<1048576>)->Arg(90)->Name("BM_BitsetToString<1048576>/Dense (90%)"); // 1 << 20
+
+// Uniform bitset
+BENCHMARK(BM_BitsetToString<32>)->Arg(50)->Name("BM_BitsetToString<32>/Uniform (50%)");
+BENCHMARK(BM_BitsetToString<64>)->Arg(50)->Name("BM_BitsetToString<64>/Uniform (50%)");
+BENCHMARK(BM_BitsetToString<128>)->Arg(50)->Name("BM_BitsetToString<128>/Uniform (50%)");
+BENCHMARK(BM_BitsetToString<256>)->Arg(50)->Name("BM_BitsetToString<256>/Uniform (50%)");
+BENCHMARK(BM_BitsetToString<512>)->Arg(50)->Name("BM_BitsetToString<512>/Uniform (50%)");
+BENCHMARK(BM_BitsetToString<1024>)->Arg(50)->Name("BM_BitsetToString<1024>/Uniform (50%)");
+BENCHMARK(BM_BitsetToString<2048>)->Arg(50)->Name("BM_BitsetToString<2048>/Uniform (50%)");
+BENCHMARK(BM_BitsetToString<4096>)->Arg(50)->Name("BM_BitsetToString<4096>/Uniform (50%)");
+BENCHMARK(BM_BitsetToString<8192>)->Arg(50)->Name("BM_BitsetToString<8192>/Uniform (50%)");
+BENCHMARK(BM_BitsetToString<16384>)->Arg(50)->Name("BM_BitsetToString<16384>/Uniform (50%)");
+BENCHMARK(BM_BitsetToString<32768>)->Arg(50)->Name("BM_BitsetToString<32768>/Uniform (50%)");
+BENCHMARK(BM_BitsetToString<65536>)->Arg(50)->Name("BM_BitsetToString<65536>/Uniform (50%)");
+BENCHMARK(BM_BitsetToString<131072>)->Arg(50)->Name("BM_BitsetToString<131072>/Uniform (50%)");
+BENCHMARK(BM_BitsetToString<262144>)->Arg(50)->Name("BM_BitsetToString<262144>/Uniform (50%)");
+BENCHMARK(BM_BitsetToString<524288>)->Arg(50)->Name("BM_BitsetToString<524288>/Uniform (50%)");
+BENCHMARK(BM_BitsetToString<1048576>)->Arg(50)->Name("BM_BitsetToString<1048576>/Uniform (50%)"); // 1 << 20
+
+BENCHMARK_MAIN();

>From 78a21d3e96b3a4f15cccbbb92b966fe5561e7ee5 Mon Sep 17 00:00:00 2001
From: Peng Liu <winner245 at hotmail.com>
Date: Wed, 26 Feb 2025 11:28:09 -0500
Subject: [PATCH 2/3] Make benchmark tests truly random

---
 libcxx/test/benchmarks/bitset.bench.cpp | 23 +++++++----------------
 1 file changed, 7 insertions(+), 16 deletions(-)

diff --git a/libcxx/test/benchmarks/bitset.bench.cpp b/libcxx/test/benchmarks/bitset.bench.cpp
index f89ed6036b7cc..5e95d3aad1cb2 100644
--- a/libcxx/test/benchmarks/bitset.bench.cpp
+++ b/libcxx/test/benchmarks/bitset.bench.cpp
@@ -12,10 +12,11 @@
 #include <bitset>
 #include <cmath>
 #include <cstddef>
+#include <random>
 
 template <std::size_t N>
 struct GenerateBitset {
-  // Construct a bitset with p*N true bits
+  // Construct a bitset with N bits, where each bit is set with probability p.
   static std::bitset<N> generate(double p) {
     std::bitset<N> b;
     if (p <= 0.0)
@@ -23,22 +24,12 @@ struct GenerateBitset {
     if (p >= 1.0)
       return ~b;
 
-    std::size_t num_ones = std::round(N * p);
-    if (num_ones == 0)
-      return b;
-
-    double step  = static_cast<double>(N) / num_ones;
-    double error = 0.0;
+    std::random_device rd;
+    std::mt19937 gen(rd());
+    std::bernoulli_distribution d(p);
+    for (std::size_t i = 0; i < N; ++i)
+      b[i] = d(gen);
 
-    std::size_t pos = 0;
-    for (std::size_t i = 0; i < num_ones; ++i) {
-      if (pos >= N)
-        break;
-      b.set(pos);
-      error += step;
-      pos += std::floor(error);
-      error -= std::floor(error);
-    }
     return b;
   }
 

>From f17d31f4593c2916ea80d591d129e1fc88de7462 Mon Sep 17 00:00:00 2001
From: Peng Liu <winner245 at hotmail.com>
Date: Thu, 15 May 2025 10:10:59 -0400
Subject: [PATCH 3/3] Inline selection of __zero and __one inside __to_string

---
 libcxx/docs/ReleaseNotes/21.rst |  3 ++
 libcxx/include/bitset           | 66 ++++++++++++++-------------------
 2 files changed, 31 insertions(+), 38 deletions(-)

diff --git a/libcxx/docs/ReleaseNotes/21.rst b/libcxx/docs/ReleaseNotes/21.rst
index 4c4227dfef6a2..e7ff106b8a2d9 100644
--- a/libcxx/docs/ReleaseNotes/21.rst
+++ b/libcxx/docs/ReleaseNotes/21.rst
@@ -70,6 +70,9 @@ Improvements and New Features
 - The segmented iterator optimization for ``std::for_each`` has been backported to C++11. Previously it was only available
   in C++23 and later.
 
+- The ``bitset::to_string`` function has been optimized, resulting in a performance improvement of up to 8.3x for bitsets
+  with uniformly distributed zeros and ones, and up to 13.5x and 16.1x for sparse and dense bitsets, respectively.
+
 Deprecations and Removals
 -------------------------
 
diff --git a/libcxx/include/bitset b/libcxx/include/bitset
index 45a20033806a2..eee5a51a39e24 100644
--- a/libcxx/include/bitset
+++ b/libcxx/include/bitset
@@ -226,14 +226,25 @@ protected:
     return to_ullong(integral_constant < bool, _Size< sizeof(unsigned long long) * CHAR_BIT>());
   }
 
-  template <bool _Spare, class _CharT, class _Traits, class _Allocator>
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 basic_string<_CharT, _Traits, _Allocator>
-  __to_string(_CharT __zero, _CharT __one) const;
-
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool all() const _NOEXCEPT;
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool any() const _NOEXCEPT;
   _LIBCPP_HIDE_FROM_ABI size_t __hash_code() const _NOEXCEPT;
 
+  template <bool _Sparse, class _CharT, class _Traits, class _Allocator>
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 basic_string<_CharT, _Traits, _Allocator>
+  __to_string(_CharT __zero, _CharT __one) const {
+    basic_string<_CharT, _Traits, _Allocator> __r(_Size, _Sparse ? __zero : __one);
+    for (size_t __i = 0, __bits = 0; __i < _N_words; ++__i, __bits += __bits_per_word) {
+      __storage_type __word = std::__invert_if<!_Sparse>(__first_[__i]);
+      if (__i == _N_words - 1 && _Size - __bits < __bits_per_word)
+        __word &= (__storage_type(1) << (_Size - __bits)) - 1;
+      for (; __word; __word &= (__word - 1))
+        __r[_Size - 1 - (__bits + std::__countr_zero(__word))] = _Sparse ? __one : __zero;
+    }
+
+    return __r;
+  }
+
 private:
 #  ifdef _LIBCPP_CXX03_LANG
   void __init(unsigned long long __v, false_type) _NOEXCEPT;
@@ -394,22 +405,6 @@ __bitset<_N_words, _Size>::to_ullong(true_type, true_type) const {
   return __r;
 }
 
-template <size_t _N_words, size_t _Size>
-template <bool _Spare, class _CharT, class _Traits, class _Allocator>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 basic_string<_CharT, _Traits, _Allocator>
-__bitset<_N_words, _Size>::__to_string(_CharT __zero, _CharT __one) const {
-  basic_string<_CharT, _Traits, _Allocator> __r(_Size, __zero);
-  for (size_t __i = 0, __bits = 0; __i < _N_words; ++__i, __bits += __bits_per_word) {
-    __storage_type __word = std::__invert_if<!_Spare>(__first_[__i]);
-    if (__i == _N_words - 1 && _Size - __bits < __bits_per_word)
-      __word &= (__storage_type(1) << (_Size - __bits)) - 1;
-    for (; __word; __word &= (__word - 1))
-      __r[_Size - 1 - (__bits + std::__countr_zero(__word))] = __one;
-  }
-
-  return __r;
-}
-
 template <size_t _N_words, size_t _Size>
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool __bitset<_N_words, _Size>::all() const _NOEXCEPT {
   // do middle whole words
@@ -507,7 +502,17 @@ protected:
 
   template <bool _Sparse, class _CharT, class _Traits, class _Allocator>
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 basic_string<_CharT, _Traits, _Allocator>
-  __to_string(_CharT __zero, _CharT __one) const;
+  __to_string(_CharT __zero, _CharT __one) const {
+    basic_string<_CharT, _Traits, _Allocator> __r(_Size, _Sparse ? __zero : __one);
+    __storage_type __word = std::__invert_if<!_Sparse>(__first_);
+    if (_Size < __bits_per_word)
+      __word &= (__storage_type(1) << _Size) - 1;
+    for (; __word; __word &= (__word - 1)) {
+      size_t __pos           = std::__countr_zero(__word);
+      __r[_Size - 1 - __pos] = _Sparse ? __one : __zero;
+    }
+    return __r;
+  }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool all() const _NOEXCEPT;
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool any() const _NOEXCEPT;
@@ -556,21 +561,6 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long __
   return __first_;
 }
 
-template <size_t _Size>
-template <bool _Spare, class _CharT, class _Traits, class _Allocator>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 basic_string<_CharT, _Traits, _Allocator>
-__bitset<1, _Size>::__to_string(_CharT __zero, _CharT __one) const {
-  basic_string<_CharT, _Traits, _Allocator> __r(_Size, __zero);
-  __storage_type __word = std::__invert_if<!_Spare>(__first_);
-  if (_Size < __bits_per_word)
-    __word &= (__storage_type(1) << _Size) - 1;
-  for (; __word; __word &= (__word - 1)) {
-    size_t __pos           = std::__countr_zero(__word);
-    __r[_Size - 1 - __pos] = __one;
-  }
-  return __r;
-}
-
 template <size_t _Size>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool __bitset<1, _Size>::all() const _NOEXCEPT {
   __storage_type __m = ~__storage_type(0) >> (__bits_per_word - _Size);
@@ -635,7 +625,7 @@ protected:
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long to_ulong() const { return 0; }
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long to_ullong() const { return 0; }
 
-  template <bool _Spare, class _CharT, class _Traits, class _Allocator>
+  template <bool _Sparse, class _CharT, class _Traits, class _Allocator>
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 basic_string<_CharT, _Traits, _Allocator>
   __to_string(_CharT, _CharT) const {
     return basic_string<_CharT, _Traits, _Allocator>();
@@ -898,7 +888,7 @@ bitset<_Size>::to_string(_CharT __zero, _CharT __one) const {
   if (__sparse)
     return __base::template __to_string<true, _CharT, _Traits, _Allocator>(__zero, __one);
   else
-    return __base::template __to_string<false, _CharT, _Traits, _Allocator>(__one, __zero);
+    return __base::template __to_string<false, _CharT, _Traits, _Allocator>(__zero, __one);
 }
 
 template <size_t _Size>



More information about the libcxx-commits mailing list