Skip to content

Commit 212b5cd

Browse files
committed
🎨 Add ct_string deduction guide for {atomic_}bitset
1 parent e00f89a commit 212b5cd

File tree

6 files changed

+115
-82
lines changed

6 files changed

+115
-82
lines changed

include/stdx/atomic_bitset.hpp

Lines changed: 41 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <stdx/bitset.hpp>
55
#include <stdx/compiler.hpp>
66
#include <stdx/concepts.hpp>
7+
#include <stdx/ct_string.hpp>
78
#include <stdx/detail/bitset_common.hpp>
89
#include <stdx/type_traits.hpp>
910
#include <stdx/udls.hpp>
@@ -17,49 +18,54 @@
1718

1819
namespace stdx {
1920
inline namespace v1 {
20-
namespace detail {
21-
template <std::size_t N, typename StorageElem> class atomic_bitset {
22-
constexpr static auto bit = StorageElem{1U};
21+
template <auto Size,
22+
typename StorageElem = decltype(smallest_uint<to_underlying(Size)>())>
23+
class atomic_bitset {
24+
constexpr static std::size_t N = to_underlying(Size);
25+
using elem_t = StorageElem;
26+
static_assert(std::is_unsigned_v<elem_t>,
27+
"Storage element for atomic_bitset must be an unsigned type");
2328

24-
static_assert(N <= std::numeric_limits<StorageElem>::digits,
29+
constexpr static auto bit = elem_t{1U};
30+
31+
static_assert(N <= std::numeric_limits<elem_t>::digits,
2532
"atomic_bitset is limited to a single storage element");
26-
static_assert(std::atomic<StorageElem>::is_always_lock_free,
27-
"atomic_bitset must always be lock free");
28-
std::atomic<StorageElem> storage{};
33+
std::atomic<elem_t> storage{};
2934

30-
constexpr static auto mask = bit_mask<StorageElem, N - 1>();
31-
StorageElem salient_value(std::memory_order order) const {
35+
constexpr static auto mask = bit_mask<elem_t, N - 1>();
36+
elem_t salient_value(std::memory_order order) const {
3237
return storage.load(order) & mask;
3338
}
3439

35-
[[nodiscard]] static constexpr auto
36-
value_from_string(std::string_view str, std::size_t pos, std::size_t n,
37-
char one) -> StorageElem {
38-
StorageElem ret{};
40+
[[nodiscard]] static constexpr auto value_from_string(std::string_view str,
41+
std::size_t pos,
42+
std::size_t n,
43+
char one) -> elem_t {
44+
elem_t ret{};
3945
auto const len = std::min(n, str.size() - pos);
4046
auto const s = str.substr(pos, std::min(len, N));
4147
auto i = bit;
4248
for (auto it = std::rbegin(s); it != std::rend(s); ++it) {
4349
if (*it == one) {
4450
ret |= i;
4551
}
46-
i = static_cast<StorageElem>(i << 1u);
52+
i = static_cast<elem_t>(i << 1u);
4753
}
4854
return ret;
4955
}
5056

51-
using bitset_t = bitset<N, StorageElem>;
57+
using bitset_t = bitset<Size, elem_t>;
5258

5359
public:
5460
constexpr atomic_bitset() = default;
5561
constexpr explicit atomic_bitset(std::uint64_t value)
56-
: storage{static_cast<StorageElem>(value & mask)} {}
62+
: storage{static_cast<elem_t>(value & mask)} {}
5763

5864
template <typename... Bs>
5965
constexpr explicit atomic_bitset(place_bits_t, Bs... bs)
60-
: storage{static_cast<StorageElem>(
61-
(StorageElem{} | ... |
62-
static_cast<StorageElem>(bit << to_underlying(bs))))} {}
66+
: storage{static_cast<elem_t>(
67+
(elem_t{} | ... |
68+
static_cast<elem_t>(bit << to_underlying(bs))))} {}
6369

6470
constexpr explicit atomic_bitset(all_bits_t) : storage{mask} {}
6571

@@ -68,6 +74,11 @@ template <std::size_t N, typename StorageElem> class atomic_bitset {
6874
char one = '1')
6975
: storage{value_from_string(str, pos, n, one)} {}
7076

77+
#if __cplusplus >= 202002L
78+
constexpr explicit atomic_bitset(ct_string<N + 1> s)
79+
: atomic_bitset{static_cast<std::string_view>(s)} {}
80+
#endif
81+
7182
template <typename T>
7283
[[nodiscard]] auto
7384
to(std::memory_order order = std::memory_order_seq_cst) const -> T {
@@ -93,13 +104,13 @@ template <std::size_t N, typename StorageElem> class atomic_bitset {
93104
}
94105
auto store(bitset_t b,
95106
std::memory_order order = std::memory_order_seq_cst) {
96-
storage.store(b.template to<StorageElem>(), order);
107+
storage.store(b.template to<elem_t>(), order);
97108
}
98109

99110
constexpr static std::integral_constant<std::size_t, N> size{};
100111

101112
constexpr static std::bool_constant<
102-
std::atomic<StorageElem>::is_always_lock_free>
113+
std::atomic<elem_t>::is_always_lock_free>
103114
is_always_lock_free{};
104115

105116
template <typename T> [[nodiscard]] auto operator[](T idx) const -> bool {
@@ -113,17 +124,17 @@ template <std::size_t N, typename StorageElem> class atomic_bitset {
113124
auto const pos = static_cast<std::size_t>(to_underlying(idx));
114125
if (value) {
115126
return bitset_t{
116-
storage.fetch_or(static_cast<StorageElem>(bit << pos), order)};
127+
storage.fetch_or(static_cast<elem_t>(bit << pos), order)};
117128
}
118129
return bitset_t{
119-
storage.fetch_and(static_cast<StorageElem>(~(bit << pos)), order)};
130+
storage.fetch_and(static_cast<elem_t>(~(bit << pos)), order)};
120131
}
121132

122133
auto set(lsb_t lsb, msb_t msb, bool value = true,
123134
std::memory_order order = std::memory_order_seq_cst) -> bitset_t {
124135
auto const l = to_underlying(lsb);
125136
auto const m = to_underlying(msb);
126-
auto const shifted_value = bit_mask<StorageElem>(m, l);
137+
auto const shifted_value = bit_mask<elem_t>(m, l);
127138
if (value) {
128139
return bitset_t{storage.fetch_or(shifted_value, order)};
129140
}
@@ -145,13 +156,12 @@ template <std::size_t N, typename StorageElem> class atomic_bitset {
145156

146157
template <typename T> auto reset(T idx) -> bitset_t {
147158
auto const pos = static_cast<std::size_t>(to_underlying(idx));
148-
return bitset_t{
149-
storage.fetch_and(static_cast<StorageElem>(~(bit << pos)))};
159+
return bitset_t{storage.fetch_and(static_cast<elem_t>(~(bit << pos)))};
150160
}
151161

152162
auto reset(std::memory_order order = std::memory_order_seq_cst)
153163
LIFETIMEBOUND -> atomic_bitset & {
154-
storage.store(StorageElem{}, order);
164+
storage.store(elem_t{}, order);
155165
return *this;
156166
}
157167

@@ -172,7 +182,7 @@ template <std::size_t N, typename StorageElem> class atomic_bitset {
172182
std::memory_order order = std::memory_order_seq_cst) -> bitset_t {
173183
auto const pos = static_cast<std::size_t>(to_underlying(idx));
174184
return bitset_t{
175-
storage.fetch_xor(static_cast<StorageElem>(bit << pos), order)};
185+
storage.fetch_xor(static_cast<elem_t>(bit << pos), order)};
176186
}
177187

178188
auto flip(std::memory_order order = std::memory_order_seq_cst) -> bitset_t {
@@ -198,10 +208,9 @@ template <std::size_t N, typename StorageElem> class atomic_bitset {
198208
return static_cast<std::size_t>(popcount(salient_value(order)));
199209
}
200210
};
201-
} // namespace detail
202211

203-
template <auto N, typename StorageElem = void>
204-
using atomic_bitset = detail::atomic_bitset<
205-
to_underlying(N), decltype(smallest_uint<to_underlying(N), StorageElem>())>;
212+
#if __cplusplus >= 202002L
213+
template <std::size_t N> atomic_bitset(ct_string<N>) -> atomic_bitset<N - 1>;
214+
#endif
206215
} // namespace v1
207216
} // namespace stdx

include/stdx/bit.hpp

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -341,12 +341,8 @@ template <typename T> constexpr auto bit_size() -> std::size_t {
341341
return sizeof(T) * CHAR_BIT;
342342
}
343343

344-
template <std::size_t N, typename S = void> CONSTEVAL auto smallest_uint() {
345-
if constexpr (not std::is_same_v<S, void>) {
346-
static_assert(std::is_unsigned_v<S>,
347-
"smallest_uint override must be an unsigned type");
348-
return S{};
349-
} else if constexpr (N <= std::numeric_limits<std::uint8_t>::digits) {
344+
template <std::size_t N> CONSTEVAL auto smallest_uint() {
345+
if constexpr (N <= std::numeric_limits<std::uint8_t>::digits) {
350346
return std::uint8_t{};
351347
} else if constexpr (N <= std::numeric_limits<std::uint16_t>::digits) {
352348
return std::uint16_t{};
@@ -357,7 +353,6 @@ template <std::size_t N, typename S = void> CONSTEVAL auto smallest_uint() {
357353
}
358354
}
359355

360-
template <std::size_t N, typename S = void>
361-
using smallest_uint_t = decltype(smallest_uint<N, S>());
356+
template <std::size_t N> using smallest_uint_t = decltype(smallest_uint<N>());
362357
} // namespace v1
363358
} // namespace stdx

0 commit comments

Comments
 (0)