RxCpp
The Reactive Extensions for Native (RxCpp) is a library for composing asynchronous and event-based programs using observable sequences and LINQ-style query operators in both C and C++.
rx-util.hpp
Go to the documentation of this file.
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>
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>
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>
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>
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>
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 
129  template<class... ValueN>
130  bool operator()(ValueN... vn) const;
131 
132  template<class Value0>
133  bool operator()(Value0 v0) const {
134  return v0;
135  }
136 
137  template<class Value0, class... ValueN>
138  bool operator()(Value0 v0, ValueN... vn) const {
139  return v0 && all_values_true()(vn...);
140  }
141 };
142 
144  template<class... ValueN>
145  bool operator()(ValueN... vn) const;
146 
147  template<class Value0>
148  bool operator()(Value0 v0) const {
149  return v0;
150  }
151 
152  template<class Value0, class... ValueN>
153  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 {
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>
195  : public std::true_type {typedef value_type_t<T> type;};
196 
197 namespace detail {
198 template<class F, class... ParamN, int... IndexN>
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>
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>
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>
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>
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>
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 
242  explicit apply_to(F f)
243  : to(std::move(f))
244  {
245  }
246 
247  template<class... ParamN>
248  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>
253  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>
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>
272  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>
277  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 
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>
296  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>
301  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>
310 inline auto take_at()
311  -> detail::take_at<Index> {
312  return detail::take_at<Index>();
313 }
314 
315 template <class D>
317 
318 template <template<class... TN> class Deferred, class... AN>
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>
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>
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>
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>
411  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>
419  int operator()(int cnt, T&&) const
420  { return cnt + 1; }
421 };
422 
423 struct less
424 {
425  template <class LHS, class RHS>
426  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>
435  auto operator()(LHS&& ) const
436  -> decltype(T())
437  { return T(); }
438 };
439 
440 template<class T = void>
441 struct equal_to
442 {
443  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>
450  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;
461  print_function(OStream& os, Delimit d) : os(os), delimit(std::move(d)) {}
462 
463  template<class... TN>
464  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>
471  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;
480  endline(OStream& os) : os(os) {}
481  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;
493  insert_value(OStream& os, ValueType v) : os(os), value(std::move(v)) {}
494  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;
506  insert_function(OStream& os, Function f) : os(os), call(std::move(f)) {}
507  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>
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>
523 auto endline(OStream& os)
524  -> detail::endline<OStream> {
525  return detail::endline<OStream>(os);
526 }
527 
528 template<class OStream>
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>
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>
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 
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:
566  maybe()
567  : is_set(false)
568  {
569  }
570 
571  maybe(T value)
572  : is_set(false)
573  {
574  new (reinterpret_cast<T*>(&storage)) T(value);
575  is_set = true;
576  }
577 
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  }
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 
596  ~maybe()
597  {
598  reset();
599  }
600 
601  typedef T value_type;
602  typedef T* iterator;
603  typedef const T* const_iterator;
604 
605  bool empty() const {
606  return !is_set;
607  }
608 
609  std::size_t size() const {
610  return is_set ? 1 : 0;
611  }
612 
613  iterator begin() {
614  return reinterpret_cast<T*>(&storage);
615  }
616  const_iterator begin() const {
617  return reinterpret_cast<T*>(&storage);
618  }
619 
620  iterator end() {
621  return reinterpret_cast<T*>(&storage) + size();
622  }
623  const_iterator end() const {
624  return reinterpret_cast<T*>(&storage) + size();
625  }
626 
627  T* operator->() {
628  if (!is_set) std::terminate();
629  return reinterpret_cast<T*>(&storage);
630  }
631  const T* operator->() const {
632  if (!is_set) std::terminate();
633  return reinterpret_cast<T*>(&storage);
634  }
635 
636  T& operator*() {
637  if (!is_set) std::terminate();
638  return *reinterpret_cast<T*>(&storage);
639  }
640  const T& operator*() const {
641  if (!is_set) std::terminate();
642  return *reinterpret_cast<T*>(&storage);
643  }
644 
645  T& get() {
646  if (!is_set) std::terminate();
647  return *reinterpret_cast<T*>(&storage);
648  }
649  const T& get() const {
650  if (!is_set) std::terminate();
651  return *reinterpret_cast<const T*>(&storage);
652  }
653 
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>
664  void reset(U&& value) {
665  reset();
666  new (reinterpret_cast<T*>(&storage)) T(std::forward<U>(value));
667  is_set = true;
668  }
669 
670  maybe& operator=(const T& other) {
671  reset(other);
672  return *this;
673  }
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>
691  auto operator()(T... t)
692  -> decltype(std::make_tuple(t.get()...)) {
693  return std::make_tuple(t.get()...);
694  }
695  template<class... T>
696  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>
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:
715  ~unwinder()
716  {
717  if (!!function)
718  {
719  RXCPP_TRY {
720  (*function)();
721  } RXCPP_CATCH(...) {
722  std::terminate();
723  }
724  }
725  }
726 
727  explicit unwinder(Function* functionArg)
728  : function(functionArg)
729  {
730  }
731 
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:
755  thread_local_storage()
756  {
757  pthread_key_create(&key, NULL);
758  }
759 
760  ~thread_local_storage()
761  {
762  pthread_key_delete(key);
763  }
764 
765  thread_local_storage& operator =(T* p)
766  {
767  pthread_setspecific(key, p);
768  return *this;
769  }
770 
771  bool operator !()
772  {
773  return pthread_getspecific(key) == NULL;
774  }
775 
776  T* operator ->()
777  {
778  return static_cast<T*>(pthread_getspecific(key));
779  }
780 
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;
839  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 {
849  error_specific(const E& e) : data(e) {}
850  error_specific(E&& e) : data(std::move(e)) {}
851 
852  virtual ~error_specific() {}
853 
854  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).
884  return e;
885 }
886 
887 // Replace std::make_exception_ptr (which would immediately terminate
888 // when exceptions are disabled).
889 template <class 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.
902 RXCPP_NORETURN inline void rethrow_exception(error_ptr e) {
903 #if RXCPP_USE_EXCEPTIONS
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>
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.
933 RXCPP_NORETURN inline void rethrow_current_exception() {
934 #if RXCPP_USE_EXCEPTIONS
936 #else
937  std::terminate();
938 #endif
939 }
940 
941 // If called during exception handling, return the currently caught exception.
942 // Otherwise return null.
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>
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 
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 
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>
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
typename std::enable_if< all_true< BN... >::value >::type enable_if_all_true_t
Definition: rx-util.hpp:109
#define RXCPP_TRY
Definition: rx-util.hpp:38
void type
Definition: rx-util.hpp:358
Definition: rx-util.hpp:817
Definition: rx-util.hpp:173
Definition: rx-util.hpp:112
bool operator()(Value0 v0) const
Definition: rx-util.hpp:133
auto print_followed_with(OStream &os, Delimit d) -> decltype(detail::print_followed_with(os, detail::insert_function< OStream, Delimit >(os, std::move(d))))
Definition: rx-util.hpp:534
Definition: rx-util.hpp:191
tag_type::type type
Definition: rx-util.hpp:383
Definition: rx-util.hpp:340
Definition: rx-util.hpp:371
std::shared_ptr< util::detail::error_base > error_ptr
Definition: rx-util.hpp:874
Definition: rx-all.hpp:26
Definition: rx-util.hpp:319
Definition: rx-util.hpp:180
typename std::decay< T >::type::value_type value_type_t
Definition: rx-util.hpp:47
error_ptr make_error_ptr(error_ptr e)
Definition: rx-util.hpp:883
RXCPP_NORETURN void rethrow_current_exception()
Definition: rx-util.hpp:933
std::vector< T > to_vector(const T(&arr) [size])
Definition: rx-util.hpp:52
Definition: rx-util.hpp:357
auto empty() -> decltype(from< T >())
Returns an observable that sends no items to observer and immediately completes, on the specified sch...
Definition: rx-empty.hpp:37
auto AN
Definition: rx-finally.hpp:105
Deferred< typename resolve_type< AN >::type... > resolved_type
Definition: rx-util.hpp:324
R type
Definition: rx-util.hpp:340
R type
Definition: rx-util.hpp:357
#define RXCPP_CATCH(...)
Definition: rx-util.hpp:39
auto println(OStream &os) -> decltype(detail::print_followed_with(os, endline(os)))
Definition: rx-util.hpp:529
Definition: rx-util.hpp:1008
typename std::decay< T >::type decay_t
Definition: rx-util.hpp:48
bool operator()(Value0 v0) const
Definition: rx-util.hpp:148
auto pack() -> detail::pack
Definition: rx-util.hpp:285
RXCPP_NORETURN void throw_exception(E &&e)
Definition: rx-util.hpp:920
auto operator()(LHS &&) const -> decltype(T())
Definition: rx-util.hpp:435
Definition: rx-util.hpp:354
tag_type::type type
Definition: rx-util.hpp:349
Definition: rx-util.hpp:965
Definition: rx-util.hpp:416
auto operator()(LHS &&lhs, RHS &&rhs) const -> decltype(std::forward< LHS >(lhs)==std::forward< RHS >(rhs))
Definition: rx-util.hpp:450
Definition: rx-util.hpp:374
Definition: rx-util.hpp:166
defer_seed_type< Deferred, AN... >::type type
Definition: rx-util.hpp:405
auto apply_to(F f) -> detail::apply_to< F >
Definition: rx-util.hpp:262
Definition: rx-util.hpp:408
typename std::enable_if< all_true_type< BN... >::value >::type enable_if_all_true_type_t
Definition: rx-util.hpp:126
T const & as_const(T &t)
Definition: rx-util.hpp:69
Definition: rx-util.hpp:159
D type
Definition: rx-util.hpp:390
Definition: rx-util.hpp:337
defer_type< Deferred, AN... >::type type
Definition: rx-util.hpp:395
auto endline(OStream &os) -> detail::endline< OStream >
Definition: rx-util.hpp:523
Deferred< typename resolve_type< AN >::type... > resolved_type
Definition: rx-util.hpp:359
Definition: rx-util.hpp:432
Deferred< typename resolve_type< AN >::type... > resolved_type
Definition: rx-util.hpp:376
auto surely(const std::tuple< T... > &tpl) -> decltype(apply(tpl, detail::surely()))
Definition: rx-util.hpp:704
void type
Definition: rx-util.hpp:341
bool operator()(Value0 v0, ValueN... vn) const
Definition: rx-util.hpp:153
int operator()(int cnt, T &&) const
Definition: rx-util.hpp:419
error_ptr current_exception()
Definition: rx-util.hpp:943
auto take_at() -> detail::take_at< Index >
Definition: rx-util.hpp:310
auto apply(std::tuple< ParamN... > p, F &&f) -> decltype(detail::apply(std::move(p), typename values_from< int, sizeof...(ParamN)>::type(), std::forward< F >(f)))
Definition: rx-util.hpp:218
Definition: rx-util.hpp:95
bool operator()(ValueN... vn) const
bool operator()(ValueN... vn) const
bool operator()(Value0 v0, ValueN... vn) const
Definition: rx-util.hpp:138
Definition: rx-util.hpp:341
Definition: rx-util.hpp:423
auto print_followed_by(OStream &os, DelimitValue dv) -> decltype(detail::print_followed_with(os, detail::insert_value< OStream, DelimitValue >(os, std::move(dv))))
Definition: rx-util.hpp:539
Definition: rx-util.hpp:316
typename types_checked_from< TN... >::type types_checked_t
Definition: rx-util.hpp:176
typename expand_value_types< types< TN... > >::type value_types_t
Definition: rx-util.hpp:187
bool operator()(const T &lhs, const T &rhs) const
Definition: rx-util.hpp:443
detail::types_checked_from< TN... >::type type
Definition: rx-util.hpp:173
values_from< T, Remaining - 1, Step, Cursor+Step, ValueN..., Cursor >::type type
Definition: rx-util.hpp:91
RXCPP_NORETURN void rethrow_exception(error_ptr e)
Definition: rx-util.hpp:902
auto operator()(LHS &&lhs, RHS &&rhs) const -> decltype(std::forward< LHS >(lhs)+std::forward< RHS >(rhs))
Definition: rx-util.hpp:411
values< T, ValueN... > type
Definition: rx-util.hpp:85
tag_type::type type
Definition: rx-util.hpp:366
Definition: rx-util.hpp:322
Deferred< typename resolve_type< AN >::type... > resolved_type
Definition: rx-util.hpp:342
Definition: rx-util.hpp:77
Definition: rx-util.hpp:323
Definition: rx-util.hpp:441
Definition: rx-util.hpp:143
R type
Definition: rx-util.hpp:374
void type
Definition: rx-util.hpp:375
std::string what(std::exception_ptr ep)
Definition: rx-util.hpp:544
auto apply_to_each(std::tuple< ParamN... > &p, const F_inner &f_inner, const F_outer &f_outer) -> decltype(detail::apply_to_each(p, typename values_from< int, sizeof...(ParamN)>::type(), f_inner, f_outer))
Definition: rx-util.hpp:230
typename std::result_of< TN... >::type result_of_t
Definition: rx-util.hpp:49
defer_value_type< Deferred, AN... >::type type
Definition: rx-util.hpp:400
Definition: rx-util.hpp:828
Definition: rx-util.hpp:128
auto operator()(LHS &&lhs, RHS &&rhs) const -> decltype(std::forward< LHS >(lhs)< std::forward< RHS >(rhs))
Definition: rx-util.hpp:426
types_checked type
Definition: rx-util.hpp:191
Definition: rx-util.hpp:789
Definition: rx-util.hpp:80
auto apply_to_each(std::tuple< ParamN... > &p, F_inner &f_inner, F_outer &f_outer) -> decltype(detail::apply_to_each(p, typename values_from< int, sizeof...(ParamN)>::type(), f_inner, f_outer))
Definition: rx-util.hpp:224