Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhancements for <bitset> #3838

Merged
merged 9 commits into from
Jul 14, 2023
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions benchmarks/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
48 changes: 48 additions & 0 deletions benchmarks/src/bitset_to_string.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include <array>
#include <benchmark/benchmark.h>
#include <bit>
#include <bitset>
#include <random>

using namespace std;

namespace {
const auto random_bits = [] {
mt19937_64 rnd{};
array<uint64_t, 32> data;
for (auto& d : data) {
d = rnd();
}
return data;
}();

template <size_t N, class charT>
void BM_bitset_to_string(benchmark::State& state) {
for (auto _ : state) {
for (auto bits : random_bits) {
bitset<N> bs{bits};
benchmark::DoNotOptimize(bs.to_string<charT>());
}
}
}

template <class charT>
void BM_bitset_to_string_large_single(benchmark::State& state) {
const auto large_bitset = bit_cast<bitset<CHAR_BIT * sizeof random_bits>>(random_bits);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No change requested: Technically, I don't believe that this is Standard. [bit.cast] is constrained for trivially copyable types, but [template.bitset] doesn't guarantee that for bitset. That said, bit_cast would refuse to compile otherwise, so I think we can get away with it.

for (auto _ : state) {
benchmark::DoNotOptimize(large_bitset.to_string<charT>());
}
}
} // namespace

BENCHMARK(BM_bitset_to_string<15, char>);
BENCHMARK(BM_bitset_to_string<64, char>);
BENCHMARK(BM_bitset_to_string_large_single<char>);
BENCHMARK(BM_bitset_to_string<7, wchar_t>);
BENCHMARK(BM_bitset_to_string<64, wchar_t>);
BENCHMARK(BM_bitset_to_string_large_single<wchar_t>);

BENCHMARK_MAIN();
33 changes: 16 additions & 17 deletions stl/inc/bitset
Original file line number Diff line number Diff line change
Expand Up @@ -68,25 +68,26 @@ public:
size_t _Mypos; // position of element in bitset
};

static _CONSTEXPR23 void _Validate(const size_t _Pos) noexcept { // verify that _Pos is within bounds
private:
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
_STL_VERIFY(_Pos < _Bits, "bitset index outside range");
#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
return _Subscript(_Pos);
static constexpr bool _Need_mask = _Bits < CHAR_BIT * sizeof(unsigned long long);
static constexpr unsigned long long _Mask = (1ULL << (_Need_mask ? _Bits : 0)) - 1ULL;

#else // _ITERATOR_DEBUG_LEVEL == 0
return _Bits <= _Pos ? (_Validate(_Pos), false) : _Subscript(_Pos);
#endif // _ITERATOR_DEBUG_LEVEL == 0
public:
_NODISCARD constexpr bool operator[](size_t _Pos) const noexcept /* strengthened */ {
_Validate(_Pos);
return _Subscript(_Pos);
}

_NODISCARD _CONSTEXPR23 reference operator[](const size_t _Pos) noexcept /* strengthened */ {
Expand All @@ -96,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 <class _Traits, class _Elem>
_CONSTEXPR23 void _Construct(const _Elem* const _Ptr, size_t _Count, const _Elem _Elem0, const _Elem _Elem1) {
if (_Count > _Bits) {
Expand Down Expand Up @@ -147,6 +145,7 @@ public:
}
}

public:
template <class _Elem, class _Traits, class _Alloc>
_CONSTEXPR23 explicit bitset(const basic_string<_Elem, _Traits, _Alloc>& _Str,
typename basic_string<_Elem, _Traits, _Alloc>::size_type _Pos = 0,
Expand Down Expand Up @@ -347,11 +346,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;
Expand Down