ReactivePlusPlus
ReactiveX implementation for C++20
Toggle main menu visibility
Loading...
Searching...
No Matches
utils.hpp
1
// ReactivePlusPlus library
2
//
3
// Copyright Aleksey Loginov 2023 - present.
4
// Distributed under the Boost Software License, Version 1.0.
5
// (See accompanying file LICENSE_1_0.txt or copy at
6
// https://www.boost.org/LICENSE_1_0.txt)
7
//
8
// Project home: https://github.com/AlexInLog/ReactivePlusPlus
9
//
10
11
#pragma once
12
13
#include <rpp/defs.hpp>
14
#include <rpp/utils/constraints.hpp>
15
#include <rpp/utils/tuple.hpp>
16
17
#include <algorithm>
18
#include <mutex>
19
#include <variant>
20
21
namespace
rpp::utils
22
{
23
24
struct
none
25
{
26
};
27
28
template
<
typename
... Args>
29
struct
types
30
{
31
};
32
33
template
<constra
int
::iterable T>
34
using
iterable_value_t = std::iter_value_t<decltype(std::begin(std::declval<T>()))>;
35
36
namespace
details
37
{
38
template
<
template
<
typename
...>
typename
Base>
39
struct
traits
40
{
41
template
<
typename
... Types>
42
constexpr
static
rpp::utils::tuple
<Types...> extract_params(
const
Base<Types...>*);
43
constexpr
static
std::false_type extract_params(...);
44
};
45
}
// namespace details
46
47
template
<
typename
T,
template
<
typename
...>
typename
Base>
48
concept
is_base_of_v
= !std::is_same_v<
decltype
(details::traits<Base>::extract_params(std::declval<std::decay_t<T>*>())), std::false_type>;
49
50
template
<
typename
T,
template
<
typename
...>
typename
Base>
51
requires
is_base_of_v<T, Base>
52
using
extract_base_type_params_t =
decltype
(details::traits<Base>::extract_params(std::declval<std::decay_t<T>*>()));
53
54
template
<
class
T>
55
constexpr
std::add_const_t<T>& as_const(
const
T& v)
noexcept
56
{
57
return
v;
58
}
59
60
template
<
class
T>
61
constexpr
T&& as_const(T&& v)
noexcept
62
requires
std::is_rvalue_reference_v<T&&>
63
{
64
return
std::forward<T>(v);
65
}
66
67
struct
convertible_to_any
68
{
69
convertible_to_any() =
default
;
70
71
template
<
typename
T>
72
operator
T&()
const
;
73
74
template
<
typename
T>
75
operator
const
T&()
const
;
76
77
template
<
typename
T>
78
operator
T&&()
const
;
79
};
80
81
template
<
typename
Cont, std::invocable<iterable_value_t<Cont>> Fn>
82
void
for_each(Cont&& container, Fn&& fn)
83
{
84
std::for_each(std::begin(container), std::end(container), std::forward<Fn>(fn));
85
}
86
87
template
<
typename
Cont, std::predicate<iterable_value_t<Cont>> Fn>
88
bool
all_of(
const
Cont& container,
const
Fn& fn)
89
{
90
return
std::all_of(std::cbegin(container), std::cend(container), fn);
91
}
92
93
template
<auto Fn,
bool
Inverse = false>
94
requires
std::is_member_function_pointer_v<
decltype
(Fn)>
95
struct
static_mem_fn
96
{
97
template
<
typename
TT>
98
requires
(Inverse ==
false
&& std::invocable<
decltype
(Fn), TT &&>)
99
auto
operator
()(TT&& d)
const
100
{
101
return
(std::forward<TT>(d).*Fn)();
102
}
103
104
template
<
typename
TT>
105
requires
(Inverse ==
true
&& std::invocable<
decltype
(Fn), TT &&>)
106
auto
operator
()(TT&& d)
const
107
{
108
return
!(std::forward<TT>(d).*Fn)();
109
}
110
};
111
112
template
<auto Fn>
113
using
static_not_mem_fn =
static_mem_fn<Fn, true>
;
114
118
template
<std::invocable Fn>
119
class
finally_action
120
{
121
public
:
122
explicit
finally_action(Fn&& fn)
123
: m_fn{std::move(fn)}
124
{
125
}
126
127
explicit
finally_action(
const
Fn& fn)
128
: m_fn{fn}
129
{
130
}
131
132
finally_action(
const
finally_action&) =
delete
;
133
finally_action(finally_action&&)
noexcept
=
delete
;
134
135
~finally_action()
noexcept
{ m_fn(); }
136
137
private
:
138
RPP_NO_UNIQUE_ADDRESS Fn m_fn;
139
};
140
141
template
<rpp::constra
int
::decayed_type T>
142
class
repeated_container
143
{
144
public
:
145
repeated_container(T&& value,
size_t
count)
146
: m_value{std::move(value)}
147
, m_count{count}
148
{
149
}
150
151
repeated_container(
const
T& value,
size_t
count)
152
: m_value{value}
153
, m_count{count}
154
{
155
}
156
157
class
iterator
158
{
159
public
:
160
iterator(
const
repeated_container* container,
size_t
index)
161
: m_container{container}
162
, m_index{index}
163
{
164
}
165
166
using
iterator_category = std::input_iterator_tag;
167
using
difference_type = std::ptrdiff_t;
168
using
value_type = T;
169
using
pointer = T*;
170
171
const
value_type& operator*()
const
{
return
m_container->m_value; }
172
173
iterator& operator++()
174
{
175
++m_index;
176
return
*
this
;
177
}
178
179
iterator operator++(
int
)
180
{
181
auto
old = *
this
;
182
++(*this);
183
return
old;
184
}
185
186
bool
operator==(
const
iterator&)
const
=
default
;
187
bool
operator!=(
const
iterator&)
const
=
default
;
188
189
private
:
190
const
repeated_container* m_container;
191
size_t
m_index;
192
};
193
194
iterator
begin()
const
{
return
{
this
, 0}; }
195
196
iterator end()
const
{
return
{
this
, m_count}; }
197
198
private
:
199
RPP_NO_UNIQUE_ADDRESS T m_value;
200
size_t
m_count;
201
};
202
203
template
<rpp::constra
int
::decayed_type T>
204
class
infinite_repeated_container
205
{
206
public
:
207
infinite_repeated_container(T&& value)
208
: m_value{std::move(value)}
209
{
210
}
211
212
infinite_repeated_container(
const
T& value)
213
: m_value{value}
214
{
215
}
216
217
class
iterator
218
{
219
public
:
220
iterator(
const
infinite_repeated_container* container)
221
: m_container{container}
222
{
223
}
224
225
using
iterator_category = std::input_iterator_tag;
226
using
difference_type = std::ptrdiff_t;
227
using
value_type = T;
228
using
pointer = T*;
229
230
const
value_type& operator*()
const
{
return
m_container->m_value; }
231
232
iterator& operator++() {
return
*
this
; }
233
234
iterator operator++(
int
) {
return
*
this
; }
235
236
bool
operator==(
const
iterator&)
const
=
default
;
237
bool
operator!=(
const
iterator&)
const
=
default
;
238
239
private
:
240
const
infinite_repeated_container* m_container;
241
};
242
243
iterator
begin()
const
{
return
{
this
}; }
244
245
iterator end()
const
{
return
{
nullptr
}; }
246
247
private
:
248
RPP_NO_UNIQUE_ADDRESS T m_value;
249
};
250
251
struct
none_mutex
252
{
253
static
constexpr
void
lock() { }
254
static
constexpr
void
unlock() { }
255
static
constexpr
void
try_lock() { }
256
};
257
258
template
<
typename
T>
259
class
value_with_mutex
260
{
261
public
:
262
value_with_mutex() =
default
;
263
264
explicit
value_with_mutex(
const
T& v)
265
: m_value{v}
266
{
267
}
268
269
explicit
value_with_mutex(T&& v)
270
: m_value{std::move(v)}
271
{
272
}
273
274
class
pointer_under_lock
275
{
276
public
:
277
pointer_under_lock(value_with_mutex<T>&& value) =
delete
;
278
279
pointer_under_lock(value_with_mutex<T>& value)
280
: pointer_under_lock{value.m_value, value.m_mutex}
281
{
282
}
283
284
private
:
285
pointer_under_lock(T& val, std::mutex& mutex)
286
: m_ptr{&val}
287
, m_lock{mutex}
288
{
289
}
290
291
public
:
292
T* operator->() {
return
m_ptr; }
293
const
T* operator->()
const
{
return
m_ptr; }
294
295
T& operator*() {
return
*m_ptr; }
296
const
T& operator*()
const
{
return
*m_ptr; }
297
298
private
:
299
T* m_ptr;
300
std::scoped_lock<std::mutex> m_lock;
301
};
302
303
pointer_under_lock
lock() {
return
*
this
; }
304
305
std::mutex& get_mutex() {
return
m_mutex; }
306
T& get_value_unsafe() {
return
m_value; }
307
308
private
:
309
RPP_NO_UNIQUE_ADDRESS T m_value{};
310
std::mutex m_mutex{};
311
};
312
313
template
<
typename
T>
314
using
pointer_under_lock =
typename
value_with_mutex<T>::pointer_under_lock
;
315
316
namespace
details
317
{
318
template
<
typename
T,
typename
... Ts>
319
struct
unique_variant_t
: std::type_identity<T>
320
{
321
};
322
323
template
<
typename
... Ts,
typename
U,
typename
... Us>
324
requires
(std::is_same_v<U, Ts> || ...)
325
struct
unique_variant_t
<std::variant<Ts...>, U, Us...> :
unique_variant_t
<std::variant<Ts...>, Us...>
326
{
327
};
328
329
template
<
typename
... Ts,
typename
U,
typename
... Us>
330
struct
unique_variant_t
<std::variant<Ts...>, U, Us...> :
public
unique_variant_t
<std::variant<Ts..., U>, Us...>
331
{
332
};
333
}
// namespace details
334
335
template
<
typename
... Ts>
336
using
unique_variant =
typename
details::unique_variant_t<std::variant<>, Ts...>::type;
// inspired by https://stackoverflow.com/a/57528226/17771792
337
338
339
#define RPP_CALL_DURING_CONSTRUCTION(...) RPP_NO_UNIQUE_ADDRESS rpp::utils::none _ = [&]() { \
340
__VA_ARGS__; \
341
return rpp::utils::none{}; \
342
}()
343
}
// namespace rpp::utils
rpp::utils::infinite_repeated_container::iterator
Definition
utils.hpp:218
rpp::utils::repeated_container::iterator
Definition
utils.hpp:158
rpp::utils::tuple
Definition
tuple.hpp:105
rpp::utils::value_with_mutex::pointer_under_lock
Definition
utils.hpp:275
rpp::utils::is_base_of_v
Definition
utils.hpp:48
rpp::utils::details::traits
Definition
utils.hpp:40
rpp::utils::details::unique_variant_t
Definition
utils.hpp:320
rpp::utils::none_mutex
Definition
utils.hpp:252
rpp::utils::none
Definition
utils.hpp:25
rpp::utils::static_mem_fn
Definition
utils.hpp:96
rpp::utils::types
Definition
utils.hpp:30
src
rpp
rpp
utils
utils.hpp
Generated by
1.17.0