From 3ff6fc6ff948dd3d1743fc23ea0f502c07272baa Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Wed, 28 Jun 2023 13:25:35 +0800 Subject: [PATCH 1/8] p0 --- stl/inc/bitset | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/stl/inc/bitset b/stl/inc/bitset index 488c57eb2a..f493a2367c 100644 --- a/stl/inc/bitset +++ b/stl/inc/bitset @@ -76,17 +76,13 @@ public: #endif // _ITERATOR_DEBUG_LEVEL == 0 } - constexpr bool _Subscript(size_t _Pos) const { + constexpr bool _Subscript(size_t _Pos) const noexcept { return (_Array[_Pos / _Bitsperword] & (_Ty{1} << _Pos % _Bitsperword)) != 0; } - _NODISCARD constexpr bool operator[](size_t _Pos) const { -#if _ITERATOR_DEBUG_LEVEL == 0 + _NODISCARD constexpr bool operator[](size_t _Pos) const noexcept /* strengthened */ { + _Validate(_Pos); return _Subscript(_Pos); - -#else // _ITERATOR_DEBUG_LEVEL == 0 - return _Bits <= _Pos ? (_Validate(_Pos), false) : _Subscript(_Pos); -#endif // _ITERATOR_DEBUG_LEVEL == 0 } _NODISCARD _CONSTEXPR23 reference operator[](const size_t _Pos) noexcept /* strengthened */ { From 0fecd8d344ab6b894b45902b80c09661857eb114 Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Thu, 29 Jun 2023 16:28:15 +0800 Subject: [PATCH 2/8] optimize to_string --- stl/inc/bitset | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/stl/inc/bitset b/stl/inc/bitset index f493a2367c..cd857fabd2 100644 --- a/stl/inc/bitset +++ b/stl/inc/bitset @@ -343,11 +343,11 @@ public: _NODISCARD _CONSTEXPR23 basic_string<_Elem, _Tr, _Alloc> to_string( const _Elem _Elem0 = static_cast<_Elem>('0'), const _Elem _Elem1 = static_cast<_Elem>('1')) const { // convert bitset to string - basic_string<_Elem, _Tr, _Alloc> _Str; - _Str.reserve(_Bits); - - for (auto _Pos = _Bits; 0 < _Pos;) { - _Str.push_back(_Subscript(--_Pos) ? _Elem1 : _Elem0); + basic_string<_Elem, _Tr, _Alloc> _Str(_Bits, _Elem0); + for (size_t _Pos = 0; _Pos < _Bits; ++_Pos) { + if (_Subscript(_Bits - 1 - _Pos)) { + _Str[_Pos] = _Elem1; + } } return _Str; From e05842e1bf796d5b2b816d0a61b617210474a820 Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Thu, 29 Jun 2023 16:38:49 +0800 Subject: [PATCH 3/8] p1 --- stl/inc/bitset | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/stl/inc/bitset b/stl/inc/bitset index cd857fabd2..7049dec336 100644 --- a/stl/inc/bitset +++ b/stl/inc/bitset @@ -68,6 +68,7 @@ public: size_t _Mypos; // position of element in bitset }; +private: static _CONSTEXPR23 void _Validate(const size_t _Pos) noexcept { // verify that _Pos is within bounds #if _ITERATOR_DEBUG_LEVEL == 0 (void) _Pos; @@ -80,6 +81,10 @@ public: return (_Array[_Pos / _Bitsperword] & (_Ty{1} << _Pos % _Bitsperword)) != 0; } + static constexpr bool _Need_mask = _Bits < CHAR_BIT * sizeof(unsigned long long); + static constexpr unsigned long long _Mask = (1ULL << (_Need_mask ? _Bits : 0)) - 1ULL; + +public: _NODISCARD constexpr bool operator[](size_t _Pos) const noexcept /* strengthened */ { _Validate(_Pos); return _Subscript(_Pos); @@ -92,12 +97,9 @@ public: constexpr bitset() noexcept : _Array() {} // construct with all false values - static constexpr bool _Need_mask = _Bits < CHAR_BIT * sizeof(unsigned long long); - - static constexpr unsigned long long _Mask = (1ULL << (_Need_mask ? _Bits : 0)) - 1ULL; - constexpr bitset(unsigned long long _Val) noexcept : _Array{static_cast<_Ty>(_Need_mask ? _Val & _Mask : _Val)} {} +private: template _CONSTEXPR23 void _Construct(const _Elem* const _Ptr, size_t _Count, const _Elem _Elem0, const _Elem _Elem1) { if (_Count > _Bits) { @@ -143,6 +145,7 @@ public: } } +public: template _CONSTEXPR23 explicit bitset(const basic_string<_Elem, _Traits, _Alloc>& _Str, typename basic_string<_Elem, _Traits, _Alloc>::size_type _Pos = 0, From 7f4107c5d912dafcaeb7a617412b7eaed3e29de4 Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Thu, 29 Jun 2023 18:17:37 +0800 Subject: [PATCH 4/8] make _Validate constexpr Co-authored-by: A. Jiang --- stl/inc/bitset | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/bitset b/stl/inc/bitset index 7049dec336..594f6c566c 100644 --- a/stl/inc/bitset +++ b/stl/inc/bitset @@ -69,7 +69,7 @@ public: }; private: - static _CONSTEXPR23 void _Validate(const size_t _Pos) noexcept { // verify that _Pos is within bounds + static constexpr void _Validate(const size_t _Pos) noexcept { // verify that _Pos is within bounds #if _ITERATOR_DEBUG_LEVEL == 0 (void) _Pos; #else // ^^^ _ITERATOR_DEBUG_LEVEL == 0 / _ITERATOR_DEBUG_LEVEL != 0 vvv From c5c13d9b71acb6e1454f4e851d5d86c0edf4013c Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Thu, 6 Jul 2023 07:35:57 +0800 Subject: [PATCH 5/8] add benchmark --- benchmarks/src/bitset_to_string.cpp | 82 +++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 benchmarks/src/bitset_to_string.cpp diff --git a/benchmarks/src/bitset_to_string.cpp b/benchmarks/src/bitset_to_string.cpp new file mode 100644 index 0000000000..60697ff413 --- /dev/null +++ b/benchmarks/src/bitset_to_string.cpp @@ -0,0 +1,82 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include + +using namespace std; + +namespace { + auto random_bits = [] { + mt19937_64 rnd(12345); + array data; + for (auto& d : data) { + d = rnd(); + } + return data; + }(); + + auto large_bitset = [] { + constexpr size_t len = 2000; + bitset bs; + mt19937_64 rnd(12345); + for (int i = 0; i < len; i++) { + bs[i] = rnd() & 1; + } + return bs; + }(); + + void BM_to_string_small(benchmark::State& state) { + for (auto _ : state) { + for (auto bits : random_bits) { + std::bitset<15> bs{bits}; + benchmark::DoNotOptimize(bs.to_string()); + } + } + } + void BM_to_string_medium(benchmark::State& state) { + for (auto _ : state) { + for (auto bits : random_bits) { + std::bitset<64> bs{bits}; + benchmark::DoNotOptimize(bs.to_string()); + } + } + } + void BM_to_string_large(benchmark::State& state) { + for (auto _ : state) { + benchmark::DoNotOptimize(large_bitset.to_string()); + } + } + void BM_to_wstring_small(benchmark::State& state) { + for (auto _ : state) { + for (auto bits : random_bits) { + std::bitset<7> bs{bits}; + benchmark::DoNotOptimize(bs.to_string()); + } + } + } + void BM_to_wstring_medium(benchmark::State& state) { + for (auto _ : state) { + for (auto bits : random_bits) { + std::bitset<64> bs{bits}; + benchmark::DoNotOptimize(bs.to_string()); + } + } + } + void BM_to_wstring_large(benchmark::State& state) { + for (auto _ : state) { + benchmark::DoNotOptimize(large_bitset.to_string()); + } + } +} // namespace + +BENCHMARK(BM_to_string_small); +BENCHMARK(BM_to_string_medium); +BENCHMARK(BM_to_string_large); +BENCHMARK(BM_to_wstring_small); +BENCHMARK(BM_to_wstring_medium); +BENCHMARK(BM_to_wstring_large); + +BENCHMARK_MAIN(); From 364735244e8d23bf6567c708b935482a32b41804 Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Thu, 6 Jul 2023 21:17:24 +0800 Subject: [PATCH 6/8] refactor benchmark --- benchmarks/src/bitset_to_string.cpp | 72 ++++++++--------------------- 1 file changed, 19 insertions(+), 53 deletions(-) diff --git a/benchmarks/src/bitset_to_string.cpp b/benchmarks/src/bitset_to_string.cpp index 60697ff413..73cb7cba08 100644 --- a/benchmarks/src/bitset_to_string.cpp +++ b/benchmarks/src/bitset_to_string.cpp @@ -3,80 +3,46 @@ #include #include +#include #include #include using namespace std; namespace { - auto random_bits = [] { - mt19937_64 rnd(12345); - array data; + const auto random_bits = [] { + mt19937_64 rnd{}; + array data; for (auto& d : data) { d = rnd(); } return data; }(); - auto large_bitset = [] { - constexpr size_t len = 2000; - bitset bs; - mt19937_64 rnd(12345); - for (int i = 0; i < len; i++) { - bs[i] = rnd() & 1; - } - return bs; - }(); - - void BM_to_string_small(benchmark::State& state) { - for (auto _ : state) { - for (auto bits : random_bits) { - std::bitset<15> bs{bits}; - benchmark::DoNotOptimize(bs.to_string()); - } - } - } - void BM_to_string_medium(benchmark::State& state) { - for (auto _ : state) { - for (auto bits : random_bits) { - std::bitset<64> bs{bits}; - benchmark::DoNotOptimize(bs.to_string()); - } - } - } - void BM_to_string_large(benchmark::State& state) { - for (auto _ : state) { - benchmark::DoNotOptimize(large_bitset.to_string()); - } - } - void BM_to_wstring_small(benchmark::State& state) { + template + void BM_bitset_to_string(benchmark::State& state) { for (auto _ : state) { for (auto bits : random_bits) { - std::bitset<7> bs{bits}; - benchmark::DoNotOptimize(bs.to_string()); + bitset bs{bits}; + benchmark::DoNotOptimize(bs.to_string()); } } } - void BM_to_wstring_medium(benchmark::State& state) { - for (auto _ : state) { - for (auto bits : random_bits) { - std::bitset<64> bs{bits}; - benchmark::DoNotOptimize(bs.to_string()); - } - } - } - void BM_to_wstring_large(benchmark::State& state) { + + template + void BM_bitset_to_string_large_single(benchmark::State& state) { + const auto large_bitset = bit_cast>(random_bits); for (auto _ : state) { - benchmark::DoNotOptimize(large_bitset.to_string()); + benchmark::DoNotOptimize(large_bitset.to_string()); } } } // namespace -BENCHMARK(BM_to_string_small); -BENCHMARK(BM_to_string_medium); -BENCHMARK(BM_to_string_large); -BENCHMARK(BM_to_wstring_small); -BENCHMARK(BM_to_wstring_medium); -BENCHMARK(BM_to_wstring_large); +BENCHMARK(BM_bitset_to_string<15, char>); +BENCHMARK(BM_bitset_to_string<64, char>); +BENCHMARK(BM_bitset_to_string_large_single); +BENCHMARK(BM_bitset_to_string<7, wchar_t>); +BENCHMARK(BM_bitset_to_string<64, wchar_t>); +BENCHMARK(BM_bitset_to_string_large_single); BENCHMARK_MAIN(); From 01dd800b136344fa1fdd125026bfcd1b947583a8 Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Sat, 8 Jul 2023 14:51:20 +0800 Subject: [PATCH 7/8] update CMakeLists.txt --- benchmarks/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index cc188710c1..b3162c5f99 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -105,6 +105,7 @@ function(add_benchmark name) target_compile_definitions(benchmark-${name} PRIVATE BENCHMARK_STATIC_DEFINE) endfunction() +add_benchmark(bitset_to_string src/bitset_to_string.cpp) add_benchmark(locale_classic src/locale_classic.cpp) add_benchmark(random_integer_generation src/random_integer_generation.cpp) add_benchmark(std_copy src/std_copy.cpp) From b75f4c307472524197aa4847f90b20c0a4059499 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 10 Jul 2023 20:49:35 -0700 Subject: [PATCH 8/8] Code review feedback. --- benchmarks/src/bitset_to_string.cpp | 13 ++++++++----- stl/inc/bitset | 3 ++- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/benchmarks/src/bitset_to_string.cpp b/benchmarks/src/bitset_to_string.cpp index 73cb7cba08..8e219a269d 100644 --- a/benchmarks/src/bitset_to_string.cpp +++ b/benchmarks/src/bitset_to_string.cpp @@ -5,6 +5,9 @@ #include #include #include +#include +#include +#include #include using namespace std; @@ -12,17 +15,17 @@ using namespace std; namespace { const auto random_bits = [] { mt19937_64 rnd{}; - array data; - for (auto& d : data) { + array arr; + for (auto& d : arr) { d = rnd(); } - return data; + return arr; }(); template void BM_bitset_to_string(benchmark::State& state) { for (auto _ : state) { - for (auto bits : random_bits) { + for (const auto& bits : random_bits) { bitset bs{bits}; benchmark::DoNotOptimize(bs.to_string()); } @@ -31,7 +34,7 @@ namespace { template void BM_bitset_to_string_large_single(benchmark::State& state) { - const auto large_bitset = bit_cast>(random_bits); + const auto large_bitset = bit_cast>(random_bits); for (auto _ : state) { benchmark::DoNotOptimize(large_bitset.to_string()); } diff --git a/stl/inc/bitset b/stl/inc/bitset index 594f6c566c..b91f8a6eb3 100644 --- a/stl/inc/bitset +++ b/stl/inc/bitset @@ -22,12 +22,13 @@ _STL_DISABLE_CLANG_WARNINGS _STD_BEGIN _EXPORT_STD template class bitset { // store fixed-length sequence of Boolean elements -public: +private: #pragma warning(push) #pragma warning(disable : 4296) // expression is always true (/Wall) using _Ty = conditional_t<_Bits <= sizeof(unsigned long) * CHAR_BIT, unsigned long, unsigned long long>; #pragma warning(pop) +public: class reference { // proxy for an element friend bitset;