• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
2 
3 #pragma once
4 
5 #if !defined(RXCPP_RX_UTIL_HPP)
6 #define RXCPP_RX_UTIL_HPP
7 
8 #include "rx-includes.hpp"
9 
10 #if !defined(RXCPP_ON_IOS) && !defined(RXCPP_ON_ANDROID) && !defined(RXCPP_THREAD_LOCAL)
11 #if defined(_MSC_VER)
12 #define RXCPP_THREAD_LOCAL __declspec(thread)
13 #else
14 #define RXCPP_THREAD_LOCAL __thread
15 #endif
16 #endif
17 
18 #if !defined(RXCPP_DELETE)
19 #if defined(_MSC_VER)
20 #define RXCPP_DELETE __pragma(warning(disable: 4822)) =delete
21 #else
22 #define RXCPP_DELETE =delete
23 #endif
24 #endif
25 
26 #define RXCPP_CONCAT(Prefix, Suffix) Prefix ## Suffix
27 #define RXCPP_CONCAT_EVALUATE(Prefix, Suffix) RXCPP_CONCAT(Prefix, Suffix)
28 
29 #define RXCPP_MAKE_IDENTIFIER(Prefix) RXCPP_CONCAT_EVALUATE(Prefix, __LINE__)
30 
31 // Provide replacements for try/catch keywords, using which is a compilation error
32 // when exceptions are disabled with -fno-exceptions.
33 #if RXCPP_USE_EXCEPTIONS
34 #define RXCPP_TRY try
35 #define RXCPP_CATCH(...) catch(__VA_ARGS__)
36 // See also rxu::throw_exception for 'throw' keyword replacement.
37 #else
38 #define RXCPP_TRY if ((true))
39 #define RXCPP_CATCH(...) if ((false))
40 // See also rxu::throw_exception, which will std::terminate without exceptions.
41 #endif
42 
43 namespace rxcpp {
44 
45 namespace util {
46 
47 template<class T> using value_type_t = typename std::decay<T>::type::value_type;
48 template<class T> using decay_t = typename std::decay<T>::type;
49 template<class... TN> using result_of_t = typename std::result_of<TN...>::type;
50 
51 template<class T, std::size_t size>
to_vector(const T (& arr)[size])52 std::vector<T> to_vector(const T (&arr) [size]) {
53     return std::vector<T>(std::begin(arr), std::end(arr));
54 }
55 
56 template<class T>
to_vector(std::initializer_list<T> il)57 std::vector<T> to_vector(std::initializer_list<T> il) {
58     return std::vector<T>(il);
59 }
60 
61 template<class T0, class... TN>
to_vector(T0 t0,TN...tn)62 typename std::enable_if<!std::is_array<T0>::value && std::is_pod<T0>::value, std::vector<T0>>::type to_vector(T0 t0, TN... tn) {
63     return to_vector({t0, tn...});
64 }
65 
66 // lifted from https://github.com/ericniebler/range-v3/blob/630fc70baa07cbfd222f329e44a3122ab64ce364/include/range/v3/range_fwd.hpp
67 // removed constexpr & noexcept to support older VC compilers
68 template<typename T>
as_const(T & t)69 /*constexpr*/ T const &as_const(T & t) /*noexcept*/
70 {
71     return t;
72 }
73 template<typename T>
74 void as_const(T const &&) = delete;
75 
76 template<class T, T... ValueN>
77 struct values {};
78 
79 template<class T, int Remaining, T Step = 1, T Cursor = 0, T... ValueN>
80 struct values_from;
81 
82 template<class T, T Step, T Cursor, T... ValueN>
83 struct values_from<T, 0, Step, Cursor, ValueN...>
84 {
85     typedef values<T, ValueN...> type;
86 };
87 
88 template<class T, int Remaining, T Step, T Cursor, T... ValueN>
89 struct values_from
90 {
91     typedef typename values_from<T, Remaining - 1, Step, Cursor + Step, ValueN..., Cursor>::type type;
92 };
93 
94 template<bool... BN>
95 struct all_true;
96 
97 template<bool B>
98 struct all_true<B>
99 {
100     static const bool value = B;
101 };
102 template<bool B, bool... BN>
103 struct all_true<B, BN...>
104 {
105     static const bool value = B && all_true<BN...>::value;
106 };
107 
108 template<bool... BN>
109 using enable_if_all_true_t = typename std::enable_if<all_true<BN...>::value>::type;
110 
111 template<class... BN>
112 struct all_true_type;
113 
114 template<class B>
115 struct all_true_type<B>
116 {
117     static const bool value = B::value;
118 };
119 template<class B, class... BN>
120 struct all_true_type<B, BN...>
121 {
122     static const bool value = B::value && all_true_type<BN...>::value;
123 };
124 
125 template<class... BN>
126 using enable_if_all_true_type_t = typename std::enable_if<all_true_type<BN...>::value>::type;
127 
128 struct all_values_true {
129     template<class... ValueN>
130     bool operator()(ValueN... vn) const;
131 
132     template<class Value0>
operator ()rxcpp::util::all_values_true133     bool operator()(Value0 v0) const {
134         return v0;
135     }
136 
137     template<class Value0, class... ValueN>
operator ()rxcpp::util::all_values_true138     bool operator()(Value0 v0, ValueN... vn) const {
139         return v0 && all_values_true()(vn...);
140     }
141 };
142 
143 struct any_value_true {
144     template<class... ValueN>
145     bool operator()(ValueN... vn) const;
146 
147     template<class Value0>
operator ()rxcpp::util::any_value_true148     bool operator()(Value0 v0) const {
149         return v0;
150     }
151 
152     template<class Value0, class... ValueN>
operator ()rxcpp::util::any_value_true153     bool operator()(Value0 v0, ValueN... vn) const {
154         return v0 || any_value_true()(vn...);
155     }
156 };
157 
158 template<class... TN>
159 struct types {};
160 
161 //
162 // based on Walter Brown's void_t proposal
163 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3911.pdf
164 //
165 
166 struct types_checked {};
167 
168 namespace detail {
169 template<class... TN> struct types_checked_from {typedef types_checked type;};
170 }
171 
172 template<class... TN>
173 struct types_checked_from {typedef typename detail::types_checked_from<TN...>::type type;};
174 
175 template<class... TN>
176 using types_checked_t = typename types_checked_from<TN...>::type;
177 
178 
179 template<class Types, class =types_checked>
180 struct expand_value_types { struct type; };
181 template<class... TN>
182 struct expand_value_types<types<TN...>, types_checked_t<typename std::decay<TN>::type::value_type...>>
183 {
184     using type = types<typename std::decay<TN>::type::value_type...>;
185 };
186 template<class... TN>
187 using value_types_t = typename expand_value_types<types<TN...>>::type;
188 
189 
190 template<class T, class C = types_checked>
191 struct value_type_from : public std::false_type {typedef types_checked type;};
192 
193 template<class T>
194 struct value_type_from<T, typename types_checked_from<value_type_t<T>>::type>
195     : public std::true_type {typedef value_type_t<T> type;};
196 
197 namespace detail {
198 template<class F, class... ParamN, int... IndexN>
apply(std::tuple<ParamN...> p,values<int,IndexN...>,F && f)199 auto apply(std::tuple<ParamN...> p, values<int, IndexN...>, F&& f)
200     -> decltype(f(std::forward<ParamN>(std::get<IndexN>(p))...)) {
201     return      f(std::forward<ParamN>(std::get<IndexN>(p))...);
202 }
203 
204 template<class F_inner, class F_outer, class... ParamN, int... IndexN>
apply_to_each(std::tuple<ParamN...> & p,values<int,IndexN...>,F_inner & f_inner,F_outer & f_outer)205 auto apply_to_each(std::tuple<ParamN...>& p, values<int, IndexN...>, F_inner& f_inner, F_outer& f_outer)
206     -> decltype(f_outer(std::move(f_inner(std::get<IndexN>(p)))...)) {
207     return      f_outer(std::move(f_inner(std::get<IndexN>(p)))...);
208 }
209 
210 template<class F_inner, class F_outer, class... ParamN, int... IndexN>
apply_to_each(std::tuple<ParamN...> & p,values<int,IndexN...>,const F_inner & f_inner,const F_outer & f_outer)211 auto apply_to_each(std::tuple<ParamN...>& p, values<int, IndexN...>, const F_inner& f_inner, const F_outer& f_outer)
212     -> decltype(f_outer(std::move(f_inner(std::get<IndexN>(p)))...)) {
213     return      f_outer(std::move(f_inner(std::get<IndexN>(p)))...);
214 }
215 
216 }
217 template<class F, class... ParamN>
apply(std::tuple<ParamN...> p,F && f)218 auto apply(std::tuple<ParamN...> p, F&& f)
219     -> decltype(detail::apply(std::move(p), typename values_from<int, sizeof...(ParamN)>::type(), std::forward<F>(f))) {
220     return      detail::apply(std::move(p), typename values_from<int, sizeof...(ParamN)>::type(), std::forward<F>(f));
221 }
222 
223 template<class F_inner, class F_outer, class... ParamN>
apply_to_each(std::tuple<ParamN...> & p,F_inner & f_inner,F_outer & f_outer)224 auto apply_to_each(std::tuple<ParamN...>& p, F_inner& f_inner, F_outer& f_outer)
225     -> decltype(detail::apply_to_each(p, typename values_from<int, sizeof...(ParamN)>::type(), f_inner, f_outer)) {
226     return      detail::apply_to_each(p, typename values_from<int, sizeof...(ParamN)>::type(), f_inner, f_outer);
227 }
228 
229 template<class F_inner, class F_outer, class... ParamN>
apply_to_each(std::tuple<ParamN...> & p,const F_inner & f_inner,const F_outer & f_outer)230 auto apply_to_each(std::tuple<ParamN...>& p, const F_inner& f_inner, const F_outer& f_outer)
231     -> decltype(detail::apply_to_each(p, typename values_from<int, sizeof...(ParamN)>::type(), f_inner, f_outer)) {
232     return      detail::apply_to_each(p, typename values_from<int, sizeof...(ParamN)>::type(), f_inner, f_outer);
233 }
234 
235 namespace detail {
236 
237 template<class F>
238 struct apply_to
239 {
240     F to;
241 
apply_torxcpp::util::detail::apply_to242     explicit apply_to(F f)
243         : to(std::move(f))
244     {
245     }
246 
247     template<class... ParamN>
operator ()rxcpp::util::detail::apply_to248     auto operator()(std::tuple<ParamN...> p)
249         -> decltype(rxcpp::util::apply(std::move(p), to)) {
250         return      rxcpp::util::apply(std::move(p), to);
251     }
252     template<class... ParamN>
operator ()rxcpp::util::detail::apply_to253     auto operator()(std::tuple<ParamN...> p) const
254         -> decltype(rxcpp::util::apply(std::move(p), to)) {
255         return      rxcpp::util::apply(std::move(p), to);
256     }
257 };
258 
259 }
260 
261 template<class F>
apply_to(F f)262 auto apply_to(F f)
263     ->      detail::apply_to<F> {
264     return  detail::apply_to<F>(std::move(f));
265 }
266 
267 namespace detail {
268 
269 struct pack
270 {
271     template<class... ParamN>
operator ()rxcpp::util::detail::pack272     auto operator()(ParamN... pn)
273         -> decltype(std::make_tuple(std::move(pn)...)) {
274         return      std::make_tuple(std::move(pn)...);
275     }
276     template<class... ParamN>
operator ()rxcpp::util::detail::pack277     auto operator()(ParamN... pn) const
278         -> decltype(std::make_tuple(std::move(pn)...)) {
279         return      std::make_tuple(std::move(pn)...);
280     }
281 };
282 
283 }
284 
pack()285 inline auto pack()
286     ->      detail::pack {
287     return  detail::pack();
288 }
289 
290 namespace detail {
291 
292 template<int Index>
293 struct take_at
294 {
295     template<class... ParamN>
operator ()rxcpp::util::detail::take_at296     auto operator()(ParamN... pn)
297         -> typename std::tuple_element<Index, std::tuple<decay_t<ParamN>...>>::type {
298         return                std::get<Index>(std::make_tuple(std::move(pn)...));
299     }
300     template<class... ParamN>
operator ()rxcpp::util::detail::take_at301     auto operator()(ParamN... pn) const
302         -> typename std::tuple_element<Index, std::tuple<decay_t<ParamN>...>>::type {
303         return                std::get<Index>(std::make_tuple(std::move(pn)...));
304     }
305 };
306 
307 }
308 
309 template<int Index>
take_at()310 inline auto take_at()
311     ->      detail::take_at<Index> {
312     return  detail::take_at<Index>();
313 }
314 
315 template <class D>
316 struct resolve_type;
317 
318 template <template<class... TN> class Deferred, class... AN>
319 struct defer_trait
320 {
321     template<bool R>
322     struct tag_valid {static const bool valid = true; static const bool value = R;};
323     struct tag_not_valid {static const bool valid = false; static const bool value = false;};
324     typedef Deferred<typename resolve_type<AN>::type...> resolved_type;
325     template<class... CN>
326     static auto check(int) -> tag_valid<resolved_type::value>;
327     template<class... CN>
328     static tag_not_valid check(...);
329 
330     typedef decltype(check<AN...>(0)) tag_type;
331     static const bool valid = tag_type::valid;
332     static const bool value = tag_type::value;
333     static const bool not_value = valid && !value;
334 };
335 
336 template <template<class... TN> class Deferred, class... AN>
337 struct defer_type
338 {
339     template<class R>
340     struct tag_valid {typedef R type; static const bool value = true;};
341     struct tag_not_valid {typedef void type; static const bool value = false;};
342     typedef Deferred<typename resolve_type<AN>::type...> resolved_type;
343     template<class... CN>
344     static auto check(int) -> tag_valid<resolved_type>;
345     template<class... CN>
346     static tag_not_valid check(...);
347 
348     typedef decltype(check<AN...>(0)) tag_type;
349     typedef typename tag_type::type type;
350     static const bool value = tag_type::value;
351 };
352 
353 template <template<class... TN> class Deferred, class... AN>
354 struct defer_value_type
355 {
356     template<class R>
357     struct tag_valid {typedef R type; static const bool value = true;};
358     struct tag_not_valid {typedef void type; static const bool value = false;};
359     typedef Deferred<typename resolve_type<AN>::type...> resolved_type;
360     template<class... CN>
361     static auto check(int) -> tag_valid<value_type_t<resolved_type>>;
362     template<class... CN>
363     static tag_not_valid check(...);
364 
365     typedef decltype(check<AN...>(0)) tag_type;
366     typedef typename tag_type::type type;
367     static const bool value = tag_type::value;
368 };
369 
370 template <template<class... TN> class Deferred, class... AN>
371 struct defer_seed_type
372 {
373     template<class R>
374     struct tag_valid {typedef R type; static const bool value = true;};
375     struct tag_not_valid {typedef void type; static const bool value = false;};
376     typedef Deferred<typename resolve_type<AN>::type...> resolved_type;
377     template<class... CN>
378     static auto check(int) -> tag_valid<typename resolved_type::seed_type>;
379     template<class... CN>
380     static tag_not_valid check(...);
381 
382     typedef decltype(check<AN...>(0)) tag_type;
383     typedef typename tag_type::type type;
384     static const bool value = tag_type::value;
385 };
386 
387 template <class D>
388 struct resolve_type
389 {
390     typedef D type;
391 };
392 template <template<class... TN> class Deferred, class... AN>
393 struct resolve_type<defer_type<Deferred, AN...>>
394 {
395     typedef typename defer_type<Deferred, AN...>::type type;
396 };
397 template <template<class... TN> class Deferred, class... AN>
398 struct resolve_type<defer_value_type<Deferred, AN...>>
399 {
400     typedef typename defer_value_type<Deferred, AN...>::type type;
401 };
402 template <template<class... TN> class Deferred, class... AN>
403 struct resolve_type<defer_seed_type<Deferred, AN...>>
404 {
405     typedef typename defer_seed_type<Deferred, AN...>::type type;
406 };
407 
408 struct plus
409 {
410     template <class LHS, class RHS>
operator ()rxcpp::util::plus411     auto operator()(LHS&& lhs, RHS&& rhs) const
412         -> decltype(std::forward<LHS>(lhs) + std::forward<RHS>(rhs))
413         { return std::forward<LHS>(lhs) + std::forward<RHS>(rhs); }
414 };
415 
416 struct count
417 {
418     template <class T>
operator ()rxcpp::util::count419     int operator()(int cnt, T&&) const
420     { return cnt + 1; }
421 };
422 
423 struct less
424 {
425     template <class LHS, class RHS>
operator ()rxcpp::util::less426     auto operator()(LHS&& lhs, RHS&& rhs) const
427         -> decltype(std::forward<LHS>(lhs) < std::forward<RHS>(rhs))
428         { return std::forward<LHS>(lhs) < std::forward<RHS>(rhs); }
429 };
430 
431 template <class T>
432 struct ret
433 {
434     template <class LHS>
operator ()rxcpp::util::ret435     auto operator()(LHS&& ) const
436         -> decltype(T())
437         { return T(); }
438 };
439 
440 template<class T = void>
441 struct equal_to
442 {
operator ()rxcpp::util::equal_to443     bool operator()(const T& lhs, const T& rhs) const { return lhs == rhs; }
444 };
445 
446 template<>
447 struct equal_to<void>
448 {
449     template<class LHS, class RHS>
operator ()rxcpp::util::equal_to450     auto operator()(LHS&& lhs, RHS&& rhs) const
451     -> decltype(std::forward<LHS>(lhs) == std::forward<RHS>(rhs))
452     { return std::forward<LHS>(lhs) == std::forward<RHS>(rhs); }
453 };
454 
455 namespace detail {
456 template<class OStream, class Delimit>
457 struct print_function
458 {
459     OStream& os;
460     Delimit delimit;
print_functionrxcpp::util::detail::print_function461     print_function(OStream& os, Delimit d) : os(os), delimit(std::move(d)) {}
462 
463     template<class... TN>
operator ()rxcpp::util::detail::print_function464     void operator()(const TN&... tn) const {
465         bool inserts[] = {(os << tn, true)...};
466         inserts[0] = *reinterpret_cast<bool*>(inserts); // silence warning
467         delimit();
468     }
469 
470     template<class... TN>
operator ()rxcpp::util::detail::print_function471     void operator()(const std::tuple<TN...>& tpl) const {
472         rxcpp::util::apply(tpl, *this);
473     }
474 };
475 
476 template<class OStream>
477 struct endline
478 {
479     OStream& os;
endlinerxcpp::util::detail::endline480     endline(OStream& os) : os(os) {}
operator ()rxcpp::util::detail::endline481     void operator()() const {
482         os << std::endl;
483     }
484 private:
485     endline& operator=(const endline&) RXCPP_DELETE;
486 };
487 
488 template<class OStream, class ValueType>
489 struct insert_value
490 {
491     OStream& os;
492     ValueType value;
insert_valuerxcpp::util::detail::insert_value493     insert_value(OStream& os, ValueType v) : os(os), value(std::move(v)) {}
operator ()rxcpp::util::detail::insert_value494     void operator()() const {
495         os << value;
496     }
497 private:
498     insert_value& operator=(const insert_value&) RXCPP_DELETE;
499 };
500 
501 template<class OStream, class Function>
502 struct insert_function
503 {
504     OStream& os;
505     Function call;
insert_functionrxcpp::util::detail::insert_function506     insert_function(OStream& os, Function f) : os(os), call(std::move(f)) {}
operator ()rxcpp::util::detail::insert_function507     void operator()() const {
508         call(os);
509     }
510 private:
511     insert_function& operator=(const insert_function&) RXCPP_DELETE;
512 };
513 
514 template<class OStream, class Delimit>
print_followed_with(OStream & os,Delimit d)515 auto print_followed_with(OStream& os, Delimit d)
516     ->      detail::print_function<OStream, Delimit> {
517     return  detail::print_function<OStream, Delimit>(os, std::move(d));
518 }
519 
520 }
521 
522 template<class OStream>
endline(OStream & os)523 auto endline(OStream& os)
524     -> detail::endline<OStream> {
525     return detail::endline<OStream>(os);
526 }
527 
528 template<class OStream>
println(OStream & os)529 auto println(OStream& os)
530     -> decltype(detail::print_followed_with(os, endline(os))) {
531     return      detail::print_followed_with(os, endline(os));
532 }
533 template<class OStream, class Delimit>
print_followed_with(OStream & os,Delimit d)534 auto print_followed_with(OStream& os, Delimit d)
535     -> decltype(detail::print_followed_with(os, detail::insert_function<OStream, Delimit>(os, std::move(d)))) {
536     return      detail::print_followed_with(os, detail::insert_function<OStream, Delimit>(os, std::move(d)));
537 }
538 template<class OStream, class DelimitValue>
print_followed_by(OStream & os,DelimitValue dv)539 auto print_followed_by(OStream& os, DelimitValue dv)
540     -> decltype(detail::print_followed_with(os, detail::insert_value<OStream, DelimitValue>(os, std::move(dv)))) {
541     return      detail::print_followed_with(os, detail::insert_value<OStream, DelimitValue>(os, std::move(dv)));
542 }
543 
what(std::exception_ptr ep)544 inline std::string what(std::exception_ptr ep) {
545 #if RXCPP_USE_EXCEPTIONS
546     try {std::rethrow_exception(ep);}
547     catch (const std::exception& ex) {
548         return ex.what();
549     } catch (...) {
550         return std::string("<not derived from std::exception>");
551     }
552 #endif
553     (void)ep;
554     return std::string("<exceptions are disabled>");
555 }
556 
557 namespace detail {
558 
559 template <class T>
560 class maybe
561 {
562     bool is_set;
563     typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type
564         storage;
565 public:
maybe()566     maybe()
567     : is_set(false)
568     {
569     }
570 
maybe(T value)571     maybe(T value)
572     : is_set(false)
573     {
574         new (reinterpret_cast<T*>(&storage)) T(value);
575         is_set = true;
576     }
577 
maybe(const maybe & other)578     maybe(const maybe& other)
579     : is_set(false)
580     {
581         if (other.is_set) {
582             new (reinterpret_cast<T*>(&storage)) T(other.get());
583             is_set = true;
584         }
585     }
maybe(maybe && other)586     maybe(maybe&& other)
587     : is_set(false)
588     {
589         if (other.is_set) {
590             new (reinterpret_cast<T*>(&storage)) T(std::move(other.get()));
591             is_set = true;
592             other.reset();
593         }
594     }
595 
~maybe()596     ~maybe()
597     {
598         reset();
599     }
600 
601     typedef T value_type;
602     typedef T* iterator;
603     typedef const T* const_iterator;
604 
empty() const605     bool empty() const {
606         return !is_set;
607     }
608 
size() const609     std::size_t size() const {
610         return is_set ? 1 : 0;
611     }
612 
begin()613     iterator begin() {
614         return reinterpret_cast<T*>(&storage);
615     }
begin() const616     const_iterator begin() const {
617         return reinterpret_cast<T*>(&storage);
618     }
619 
end()620     iterator end() {
621         return reinterpret_cast<T*>(&storage) + size();
622     }
end() const623     const_iterator end() const {
624         return reinterpret_cast<T*>(&storage) + size();
625     }
626 
operator ->()627     T* operator->() {
628         if (!is_set) std::terminate();
629         return reinterpret_cast<T*>(&storage);
630     }
operator ->() const631     const T* operator->() const {
632         if (!is_set) std::terminate();
633         return reinterpret_cast<T*>(&storage);
634     }
635 
operator *()636     T& operator*() {
637         if (!is_set) std::terminate();
638         return *reinterpret_cast<T*>(&storage);
639     }
operator *() const640     const T& operator*() const {
641         if (!is_set) std::terminate();
642         return *reinterpret_cast<T*>(&storage);
643     }
644 
get()645     T& get() {
646         if (!is_set) std::terminate();
647         return *reinterpret_cast<T*>(&storage);
648     }
get() const649     const T& get() const {
650         if (!is_set) std::terminate();
651         return *reinterpret_cast<const T*>(&storage);
652     }
653 
reset()654     void reset()
655     {
656         if (is_set) {
657             is_set = false;
658             reinterpret_cast<T*>(&storage)->~T();
659             //std::fill_n(reinterpret_cast<char*>(&storage), sizeof(T), 0);
660         }
661     }
662 
663     template<class U>
reset(U && value)664     void reset(U&& value) {
665         reset();
666         new (reinterpret_cast<T*>(&storage)) T(std::forward<U>(value));
667         is_set = true;
668     }
669 
operator =(const T & other)670     maybe& operator=(const T& other) {
671         reset(other);
672         return *this;
673     }
operator =(const maybe & other)674     maybe& operator=(const maybe& other) {
675         if (!other.empty()) {
676             reset(other.get());
677         } else {
678             reset();
679         }
680         return *this;
681     }
682 };
683 
684 }
685 using detail::maybe;
686 
687 namespace detail {
688     struct surely
689     {
690         template<class... T>
operator ()rxcpp::util::detail::surely691         auto operator()(T... t)
692             -> decltype(std::make_tuple(t.get()...)) {
693             return      std::make_tuple(t.get()...);
694         }
695         template<class... T>
operator ()rxcpp::util::detail::surely696         auto operator()(T... t) const
697             -> decltype(std::make_tuple(t.get()...)) {
698             return      std::make_tuple(t.get()...);
699         }
700     };
701 }
702 
703 template<class... T>
surely(const std::tuple<T...> & tpl)704 inline auto surely(const std::tuple<T...>& tpl)
705     -> decltype(apply(tpl, detail::surely())) {
706     return      apply(tpl, detail::surely());
707 }
708 
709 namespace detail {
710 
711 template<typename Function>
712 class unwinder
713 {
714 public:
~unwinder()715     ~unwinder()
716     {
717         if (!!function)
718         {
719             RXCPP_TRY {
720                 (*function)();
721             } RXCPP_CATCH(...) {
722                 std::terminate();
723             }
724         }
725     }
726 
unwinder(Function * functionArg)727     explicit unwinder(Function* functionArg)
728         : function(functionArg)
729     {
730     }
731 
dismiss()732     void dismiss()
733     {
734         function = nullptr;
735     }
736 
737 private:
738     unwinder();
739     unwinder(const unwinder&);
740     unwinder& operator=(const unwinder&);
741 
742     Function* function;
743 };
744 
745 }
746 
747 #if !defined(RXCPP_THREAD_LOCAL)
748 template<typename T>
749 class thread_local_storage
750 {
751 private:
752     pthread_key_t key;
753 
754 public:
thread_local_storage()755     thread_local_storage()
756     {
757         pthread_key_create(&key, NULL);
758     }
759 
~thread_local_storage()760     ~thread_local_storage()
761     {
762         pthread_key_delete(key);
763     }
764 
operator =(T * p)765     thread_local_storage& operator =(T* p)
766     {
767         pthread_setspecific(key, p);
768         return *this;
769     }
770 
operator !()771     bool operator !()
772     {
773         return pthread_getspecific(key) == NULL;
774     }
775 
operator ->()776     T* operator ->()
777     {
778         return static_cast<T*>(pthread_getspecific(key));
779     }
780 
get()781     T* get()
782     {
783         return static_cast<T*>(pthread_getspecific(key));
784     }
785 };
786 #endif
787 
788 template<typename, typename C = types_checked>
789 struct is_string : std::false_type {
790 };
791 
792 template <typename T>
793 struct is_string<T,
794     typename types_checked_from<
795         typename T::value_type,
796         typename T::traits_type,
797         typename T::allocator_type>::type>
798     : std::is_base_of<
799             std::basic_string<
800                 typename T::value_type,
801                 typename T::traits_type,
802                 typename T::allocator_type>, T> {
803 };
804 
805 namespace detail {
806 
807     template <class T, class = types_checked>
808     struct is_duration : std::false_type {};
809 
810     template <class T>
811     struct is_duration<T, types_checked_t<T, typename T::rep, typename T::period>>
812             : std::is_convertible<T*, std::chrono::duration<typename T::rep, typename T::period>*> {};
813 
814 }
815 
816 template <class T, class Decayed = decay_t<T>>
817 struct is_duration : detail::is_duration<Decayed> {};
818 
819 
820 // C++17 negation
821 namespace detail {
822     template<class T>
823     struct not_value : std::conditional<T::value, std::false_type, std::true_type>::type {
824     };
825 }
826 
827 template <class T>
828 struct negation : detail::not_value<T> {};
829 
830 }
831 
832 #if !RXCPP_USE_EXCEPTIONS
833 namespace util {
834 
835 namespace detail {
836 
837 struct error_base {
838   virtual const char* what() = 0;
~error_baserxcpp::util::detail::error_base839   virtual ~error_base() {}
840 };
841 
842 // Use the "Type Erasure" idiom to wrap an std::exception-like
843 // value into an error pointer.
844 //
845 // Supported types:
846 //   exception, bad_exception, bad_alloc.
847 template <class E>
848 struct error_specific : public error_base {
error_specificrxcpp::util::detail::error_specific849   error_specific(const E& e) : data(e) {}
error_specificrxcpp::util::detail::error_specific850   error_specific(E&& e) : data(std::move(e)) {}
851 
~error_specificrxcpp::util::detail::error_specific852   virtual ~error_specific() {}
853 
whatrxcpp::util::detail::error_specific854   virtual const char* what() {
855     return data.what();
856   }
857 
858   E data;
859 };
860 
861 }
862 
863 }
864 #endif
865 
866 namespace util {
867 
868 #if RXCPP_USE_EXCEPTIONS
869 using error_ptr = std::exception_ptr;
870 #else
871 // Note: std::exception_ptr cannot be used directly when exceptions are disabled.
872 // Any attempt to 'throw' or to call into any of the std functions accepting
873 // an std::exception_ptr will either fail to compile or result in an abort at runtime.
874 using error_ptr = std::shared_ptr<util::detail::error_base>;
875 
876 inline std::string what(error_ptr ep) {
877     return std::string(ep->what());
878 }
879 #endif
880 
881 // TODO: Do we really need an identity make?
882 // (It was causing some compilation errors deep inside templates).
make_error_ptr(error_ptr e)883 inline error_ptr make_error_ptr(error_ptr e) {
884   return e;
885 }
886 
887 // Replace std::make_exception_ptr (which would immediately terminate
888 // when exceptions are disabled).
889 template <class E>
make_error_ptr(E && e)890 error_ptr make_error_ptr(E&& e) {
891 #if RXCPP_USE_EXCEPTIONS
892     return std::make_exception_ptr(std::forward<E>(e));
893 #else
894     using e_type = rxcpp::util::decay_t<E>;
895     using pointed_to_type = rxcpp::util::detail::error_specific<e_type>;
896     auto sp = std::make_shared<pointed_to_type>(std::forward<E>(e));
897     return std::static_pointer_cast<rxcpp::util::detail::error_base>(sp);
898 #endif
899 }
900 
901 // Replace std::rethrow_exception to be compatible with our error_ptr typedef.
rethrow_exception(error_ptr e)902 RXCPP_NORETURN inline void rethrow_exception(error_ptr e) {
903 #if RXCPP_USE_EXCEPTIONS
904   std::rethrow_exception(e);
905 #else
906   // error_ptr != std::exception_ptr so we can't use std::rethrow_exception
907   //
908   // However even if we could, calling std::rethrow_exception just terminates if exceptions are disabled.
909   //
910   // Therefore this function should only be called when we are completely giving up and have no idea
911   // how to handle the error.
912   (void)e;
913   std::terminate();
914 #endif
915 }
916 
917 // A replacement for the "throw" keyword which is illegal when
918 // exceptions are disabled with -fno-exceptions.
919 template <typename E>
throw_exception(E && e)920 RXCPP_NORETURN inline void throw_exception(E&& e) {
921 #if RXCPP_USE_EXCEPTIONS
922   throw std::forward<E>(e);
923 #else
924   // "throw" keyword is unsupported when exceptions are disabled.
925   // Immediately terminate instead.
926   (void)e;
927   std::terminate();
928 #endif
929 }
930 
931 // TODO: Do we really need this? rxu::rethrow_exception(rxu::current_exception())
932 // would have the same semantics in either case.
rethrow_current_exception()933 RXCPP_NORETURN inline void rethrow_current_exception() {
934 #if RXCPP_USE_EXCEPTIONS
935   std::rethrow_exception(std::current_exception());
936 #else
937   std::terminate();
938 #endif
939 }
940 
941 // If called during exception handling, return the currently caught exception.
942 // Otherwise return null.
current_exception()943 inline error_ptr current_exception() {
944 #if RXCPP_USE_EXCEPTIONS
945   return std::current_exception();
946 #else
947   // When exceptions are disabled, we can never be inside of a catch block.
948   // Return null similar to std::current_exception returning null outside of catch.
949   return nullptr;
950 #endif
951 }
952 
953 }
954 namespace rxu=util;
955 
956 
957 //
958 // due to an noisy static_assert issue in more than one std lib impl,
959 // rxcpp maintains a whitelist filter for the types that are allowed
960 // to be hashed. this allows is_hashable<T> to work.
961 //
962 // NOTE: this should eventually be removed!
963 //
964 template <class T, typename = void>
965 struct filtered_hash;
966 
967 #if RXCPP_HASH_ENUM
968 template <class T>
969 struct filtered_hash<T, typename std::enable_if<std::is_enum<T>::value>::type> : std::hash<T> {
970 };
971 #elif RXCPP_HASH_ENUM_UNDERLYING
972 template <class T>
973 struct filtered_hash<T, typename std::enable_if<std::is_enum<T>::value>::type> : std::hash<typename std::underlying_type<T>::type> {
974 };
975 #endif
976 
977 template <class T>
978 struct filtered_hash<T, typename std::enable_if<std::is_integral<T>::value>::type> : std::hash<T> {
979 };
980 template <class T>
981 struct filtered_hash<T, typename std::enable_if<std::is_pointer<T>::value>::type> : std::hash<T> {
982 };
983 template <class T>
984 struct filtered_hash<T, typename std::enable_if<rxu::is_string<T>::value>::type> : std::hash<T> {
985 };
986 template <class T>
987 struct filtered_hash<T, typename std::enable_if<std::is_convertible<T, std::chrono::duration<typename T::rep, typename T::period>>::value>::type> {
988     using argument_type = T;
989     using result_type = std::size_t;
990 
operator ()rxcpp::filtered_hash991     result_type operator()(argument_type const & dur) const
992     {
993         return std::hash<typename argument_type::rep>{}(dur.count());
994     }
995 };
996 template <class T>
997 struct filtered_hash<T, typename std::enable_if<std::is_convertible<T, std::chrono::time_point<typename T::clock, typename T::duration>>::value>::type> {
998     using argument_type = T;
999     using result_type = std::size_t;
1000 
operator ()rxcpp::filtered_hash1001     result_type operator()(argument_type const & tp) const
1002     {
1003         return std::hash<typename argument_type::rep>{}(tp.time_since_epoch().count());
1004     }
1005 };
1006 
1007 template<typename, typename C = rxu::types_checked>
1008 struct is_hashable
1009     : std::false_type {};
1010 
1011 template<typename T>
1012 struct is_hashable<T,
1013     typename rxu::types_checked_from<
1014         typename filtered_hash<T>::result_type,
1015         typename filtered_hash<T>::argument_type,
1016         typename std::result_of<filtered_hash<T>(T)>::type>::type>
1017     : std::true_type {};
1018 
1019 }
1020 
1021 #define RXCPP_UNWIND(Name, Function) \
1022     RXCPP_UNWIND_EXPLICIT(uwfunc_ ## Name, Name, Function)
1023 
1024 #define RXCPP_UNWIND_AUTO(Function) \
1025     RXCPP_UNWIND_EXPLICIT(RXCPP_MAKE_IDENTIFIER(uwfunc_), RXCPP_MAKE_IDENTIFIER(unwind_), Function)
1026 
1027 #define RXCPP_UNWIND_EXPLICIT(FunctionName, UnwinderName, Function) \
1028     auto FunctionName = (Function); \
1029     rxcpp::util::detail::unwinder<decltype(FunctionName)> UnwinderName(std::addressof(FunctionName))
1030 
1031 #endif
1032