Skip to content

Commit

Permalink
Enhancements for <bitset> (#3838)
Browse files Browse the repository at this point in the history
Co-authored-by: A. Jiang <de34@live.cn>
Co-authored-by: Stephan T. Lavavej <stl@nuwen.net>
  • Loading branch information
3 people authored Jul 14, 2023
1 parent 5c91cbb commit 750ec42
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 18 deletions.
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(path_lexically_normal src/path_lexically_normal.cpp)
add_benchmark(random_integer_generation src/random_integer_generation.cpp)
Expand Down
51 changes: 51 additions & 0 deletions benchmarks/src/bitset_to_string.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

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

using namespace std;

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

template <size_t N, class charT>
void BM_bitset_to_string(benchmark::State& state) {
for (auto _ : state) {
for (const 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);
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();
36 changes: 18 additions & 18 deletions stl/inc/bitset
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@ _STL_DISABLE_CLANG_WARNINGS
_STD_BEGIN
_EXPORT_STD template <size_t _Bits>
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;

Expand Down Expand Up @@ -68,25 +69,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 +98,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 +146,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 +347,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

0 comments on commit 750ec42

Please sign in to comment.