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 namespace rxcpp {
32 
33 namespace util {
34 
35 template<class T> using value_type_t = typename std::decay<T>::type::value_type;
36 template<class T> using decay_t = typename std::decay<T>::type;
37 template<class... TN> using result_of_t = typename std::result_of<TN...>::type;
38 
39 template<class T, std::size_t size>
40 std::vector<T> to_vector(const T (&arr) [size]) {
41  return std::vector<T>(std::begin(arr), std::end(arr));
42 }
43 
44 template<class T>
45 std::vector<T> to_vector(std::initializer_list<T> il) {
46  return std::vector<T>(il);
47 }
48 
49 template<class T0, class... TN>
50 typename std::enable_if<!std::is_array<T0>::value && std::is_pod<T0>::value, std::vector<T0>>::type to_vector(T0 t0, TN... tn) {
51  return to_vector({t0, tn...});
52 }
53 
54 // lifted from https://github.com/ericniebler/range-v3/blob/630fc70baa07cbfd222f329e44a3122ab64ce364/include/range/v3/range_fwd.hpp
55 // removed constexpr & noexcept to support older VC compilers
56 template<typename T>
57 /*constexpr*/ T const &as_const(T & t) /*noexcept*/
58 {
59  return t;
60 }
61 template<typename T>
62 void as_const(T const &&) = delete;
63 
64 template<class T, T... ValueN>
65 struct values {};
66 
67 template<class T, int Remaining, T Step = 1, T Cursor = 0, T... ValueN>
68 struct values_from;
69 
70 template<class T, T Step, T Cursor, T... ValueN>
71 struct values_from<T, 0, Step, Cursor, ValueN...>
72 {
73  typedef values<T, ValueN...> type;
74 };
75 
76 template<class T, int Remaining, T Step, T Cursor, T... ValueN>
77 struct values_from
78 {
79  typedef typename values_from<T, Remaining - 1, Step, Cursor + Step, ValueN..., Cursor>::type type;
80 };
81 
82 template<bool... BN>
83 struct all_true;
84 
85 template<bool B>
86 struct all_true<B>
87 {
88  static const bool value = B;
89 };
90 template<bool B, bool... BN>
91 struct all_true<B, BN...>
92 {
93  static const bool value = B && all_true<BN...>::value;
94 };
95 
96 template<bool... BN>
97 using enable_if_all_true_t = typename std::enable_if<all_true<BN...>::value>::type;
98 
99 template<class... BN>
101 
102 template<class B>
103 struct all_true_type<B>
104 {
105  static const bool value = B::value;
106 };
107 template<class B, class... BN>
108 struct all_true_type<B, BN...>
109 {
110  static const bool value = B::value && all_true_type<BN...>::value;
111 };
112 
113 template<class... BN>
114 using enable_if_all_true_type_t = typename std::enable_if<all_true_type<BN...>::value>::type;
115 
117  template<class... ValueN>
118  bool operator()(ValueN... vn) const;
119 
120  template<class Value0>
121  bool operator()(Value0 v0) const {
122  return v0;
123  }
124 
125  template<class Value0, class... ValueN>
126  bool operator()(Value0 v0, ValueN... vn) const {
127  return v0 && all_values_true()(vn...);
128  }
129 };
130 
132  template<class... ValueN>
133  bool operator()(ValueN... vn) const;
134 
135  template<class Value0>
136  bool operator()(Value0 v0) const {
137  return v0;
138  }
139 
140  template<class Value0, class... ValueN>
141  bool operator()(Value0 v0, ValueN... vn) const {
142  return v0 || any_value_true()(vn...);
143  }
144 };
145 
146 template<class... TN>
147 struct types {};
148 
149 //
150 // based on Walter Brown's void_t proposal
151 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3911.pdf
152 //
153 
154 struct types_checked {};
155 
156 namespace detail {
157 template<class... TN> struct types_checked_from {typedef types_checked type;};
158 }
159 
160 template<class... TN>
161 struct types_checked_from {typedef typename detail::types_checked_from<TN...>::type type;};
162 
163 template<class... TN>
164 using types_checked_t = typename types_checked_from<TN...>::type;
165 
166 
167 template<class Types, class =types_checked>
168 struct expand_value_types { struct type; };
169 template<class... TN>
170 struct expand_value_types<types<TN...>, types_checked_t<typename std::decay<TN>::type::value_type...>>
171 {
173 };
174 template<class... TN>
175 using value_types_t = typename expand_value_types<types<TN...>>::type;
176 
177 
178 template<class T, class C = types_checked>
179 struct value_type_from : public std::false_type {typedef types_checked type;};
180 
181 template<class T>
183  : public std::true_type {typedef value_type_t<T> type;};
184 
185 namespace detail {
186 template<class F, class... ParamN, int... IndexN>
187 auto apply(std::tuple<ParamN...> p, values<int, IndexN...>, F&& f)
188  -> decltype(f(std::forward<ParamN>(std::get<IndexN>(p))...)) {
189  return f(std::forward<ParamN>(std::get<IndexN>(p))...);
190 }
191 
192 template<class F_inner, class F_outer, class... ParamN, int... IndexN>
193 auto apply_to_each(std::tuple<ParamN...>& p, values<int, IndexN...>, F_inner& f_inner, F_outer& f_outer)
194  -> decltype(f_outer(std::move(f_inner(std::get<IndexN>(p)))...)) {
195  return f_outer(std::move(f_inner(std::get<IndexN>(p)))...);
196 }
197 
198 template<class F_inner, class F_outer, class... ParamN, int... IndexN>
199 auto apply_to_each(std::tuple<ParamN...>& p, values<int, IndexN...>, const F_inner& f_inner, const F_outer& f_outer)
200  -> decltype(f_outer(std::move(f_inner(std::get<IndexN>(p)))...)) {
201  return f_outer(std::move(f_inner(std::get<IndexN>(p)))...);
202 }
203 
204 }
205 template<class F, class... ParamN>
206 auto apply(std::tuple<ParamN...> p, F&& f)
207  -> decltype(detail::apply(std::move(p), typename values_from<int, sizeof...(ParamN)>::type(), std::forward<F>(f))) {
208  return detail::apply(std::move(p), typename values_from<int, sizeof...(ParamN)>::type(), std::forward<F>(f));
209 }
210 
211 template<class F_inner, class F_outer, class... ParamN>
212 auto apply_to_each(std::tuple<ParamN...>& p, F_inner& f_inner, F_outer& f_outer)
213  -> decltype(detail::apply_to_each(p, typename values_from<int, sizeof...(ParamN)>::type(), f_inner, f_outer)) {
214  return detail::apply_to_each(p, typename values_from<int, sizeof...(ParamN)>::type(), f_inner, f_outer);
215 }
216 
217 template<class F_inner, class F_outer, class... ParamN>
218 auto apply_to_each(std::tuple<ParamN...>& p, const F_inner& f_inner, const F_outer& f_outer)
219  -> decltype(detail::apply_to_each(p, typename values_from<int, sizeof...(ParamN)>::type(), f_inner, f_outer)) {
220  return detail::apply_to_each(p, typename values_from<int, sizeof...(ParamN)>::type(), f_inner, f_outer);
221 }
222 
223 namespace detail {
224 
225 template<class F>
226 struct apply_to
227 {
228  F to;
229 
230  explicit apply_to(F f)
231  : to(std::move(f))
232  {
233  }
234 
235  template<class... ParamN>
236  auto operator()(std::tuple<ParamN...> p)
237  -> decltype(rxcpp::util::apply(std::move(p), to)) {
238  return rxcpp::util::apply(std::move(p), to);
239  }
240  template<class... ParamN>
241  auto operator()(std::tuple<ParamN...> p) const
242  -> decltype(rxcpp::util::apply(std::move(p), to)) {
243  return rxcpp::util::apply(std::move(p), to);
244  }
245 };
246 
247 }
248 
249 template<class F>
250 auto apply_to(F f)
251  -> detail::apply_to<F> {
252  return detail::apply_to<F>(std::move(f));
253 }
254 
255 namespace detail {
256 
257 struct pack
258 {
259  template<class... ParamN>
260  auto operator()(ParamN... pn)
261  -> decltype(std::make_tuple(std::move(pn)...)) {
262  return std::make_tuple(std::move(pn)...);
263  }
264  template<class... ParamN>
265  auto operator()(ParamN... pn) const
266  -> decltype(std::make_tuple(std::move(pn)...)) {
267  return std::make_tuple(std::move(pn)...);
268  }
269 };
270 
271 }
272 
273 inline auto pack()
274  -> detail::pack {
275  return detail::pack();
276 }
277 
278 namespace detail {
279 
280 template<int Index>
281 struct take_at
282 {
283  template<class... ParamN>
284  auto operator()(ParamN... pn)
285  -> typename std::tuple_element<Index, std::tuple<decay_t<ParamN>...>>::type {
286  return std::get<Index>(std::make_tuple(std::move(pn)...));
287  }
288  template<class... ParamN>
289  auto operator()(ParamN... pn) const
290  -> typename std::tuple_element<Index, std::tuple<decay_t<ParamN>...>>::type {
291  return std::get<Index>(std::make_tuple(std::move(pn)...));
292  }
293 };
294 
295 }
296 
297 template<int Index>
298 inline auto take_at()
299  -> detail::take_at<Index> {
300  return detail::take_at<Index>();
301 }
302 
303 template <class D>
305 
306 template <template<class... TN> class Deferred, class... AN>
308 {
309  template<bool R>
310  struct tag_valid {static const bool valid = true; static const bool value = R;};
311  struct tag_not_valid {static const bool valid = false; static const bool value = false;};
312  typedef Deferred<typename resolve_type<AN>::type...> resolved_type;
313  template<class... CN>
314  static auto check(int) -> tag_valid<resolved_type::value>;
315  template<class... CN>
316  static tag_not_valid check(...);
317 
318  typedef decltype(check<AN...>(0)) tag_type;
319  static const bool valid = tag_type::valid;
320  static const bool value = tag_type::value;
321  static const bool not_value = valid && !value;
322 };
323 
324 template <template<class... TN> class Deferred, class... AN>
326 {
327  template<class R>
328  struct tag_valid {typedef R type; static const bool value = true;};
329  struct tag_not_valid {typedef void type; static const bool value = false;};
330  typedef Deferred<typename resolve_type<AN>::type...> resolved_type;
331  template<class... CN>
332  static auto check(int) -> tag_valid<resolved_type>;
333  template<class... CN>
334  static tag_not_valid check(...);
335 
336  typedef decltype(check<AN...>(0)) tag_type;
337  typedef typename tag_type::type type;
338  static const bool value = tag_type::value;
339 };
340 
341 template <template<class... TN> class Deferred, class... AN>
343 {
344  template<class R>
345  struct tag_valid {typedef R type; static const bool value = true;};
346  struct tag_not_valid {typedef void type; static const bool value = false;};
347  typedef Deferred<typename resolve_type<AN>::type...> resolved_type;
348  template<class... CN>
349  static auto check(int) -> tag_valid<value_type_t<resolved_type>>;
350  template<class... CN>
351  static tag_not_valid check(...);
352 
353  typedef decltype(check<AN...>(0)) tag_type;
354  typedef typename tag_type::type type;
355  static const bool value = tag_type::value;
356 };
357 
358 template <template<class... TN> class Deferred, class... AN>
360 {
361  template<class R>
362  struct tag_valid {typedef R type; static const bool value = true;};
363  struct tag_not_valid {typedef void type; static const bool value = false;};
364  typedef Deferred<typename resolve_type<AN>::type...> resolved_type;
365  template<class... CN>
366  static auto check(int) -> tag_valid<typename resolved_type::seed_type>;
367  template<class... CN>
368  static tag_not_valid check(...);
369 
370  typedef decltype(check<AN...>(0)) tag_type;
371  typedef typename tag_type::type type;
372  static const bool value = tag_type::value;
373 };
374 
375 template <class D>
376 struct resolve_type
377 {
378  typedef D type;
379 };
380 template <template<class... TN> class Deferred, class... AN>
381 struct resolve_type<defer_type<Deferred, AN...>>
382 {
383  typedef typename defer_type<Deferred, AN...>::type type;
384 };
385 template <template<class... TN> class Deferred, class... AN>
386 struct resolve_type<defer_value_type<Deferred, AN...>>
387 {
388  typedef typename defer_value_type<Deferred, AN...>::type type;
389 };
390 template <template<class... TN> class Deferred, class... AN>
391 struct resolve_type<defer_seed_type<Deferred, AN...>>
392 {
393  typedef typename defer_seed_type<Deferred, AN...>::type type;
394 };
395 
396 struct plus
397 {
398  template <class LHS, class RHS>
399  auto operator()(LHS&& lhs, RHS&& rhs) const
400  -> decltype(std::forward<LHS>(lhs) + std::forward<RHS>(rhs))
401  { return std::forward<LHS>(lhs) + std::forward<RHS>(rhs); }
402 };
403 
404 struct count
405 {
406  template <class T>
407  int operator()(int cnt, T&&) const
408  { return cnt + 1; }
409 };
410 
411 struct less
412 {
413  template <class LHS, class RHS>
414  auto operator()(LHS&& lhs, RHS&& rhs) const
415  -> decltype(std::forward<LHS>(lhs) < std::forward<RHS>(rhs))
416  { return std::forward<LHS>(lhs) < std::forward<RHS>(rhs); }
417 };
418 
419 template<class T = void>
420 struct equal_to
421 {
422  bool operator()(const T& lhs, const T& rhs) const { return lhs == rhs; }
423 };
424 
425 template<>
426 struct equal_to<void>
427 {
428  template<class LHS, class RHS>
429  auto operator()(LHS&& lhs, RHS&& rhs) const
430  -> decltype(std::forward<LHS>(lhs) == std::forward<RHS>(rhs))
431  { return std::forward<LHS>(lhs) == std::forward<RHS>(rhs); }
432 };
433 
434 namespace detail {
435 template<class OStream, class Delimit>
436 struct print_function
437 {
438  OStream& os;
439  Delimit delimit;
440  print_function(OStream& os, Delimit d) : os(os), delimit(std::move(d)) {}
441 
442  template<class... TN>
443  void operator()(const TN&... tn) const {
444  bool inserts[] = {(os << tn, true)...};
445  inserts[0] = *reinterpret_cast<bool*>(inserts); // silence warning
446  delimit();
447  }
448 
449  template<class... TN>
450  void operator()(const std::tuple<TN...>& tpl) const {
451  rxcpp::util::apply(tpl, *this);
452  }
453 };
454 
455 template<class OStream>
456 struct endline
457 {
458  OStream& os;
459  endline(OStream& os) : os(os) {}
460  void operator()() const {
461  os << std::endl;
462  }
463 private:
464  endline& operator=(const endline&) RXCPP_DELETE;
465 };
466 
467 template<class OStream, class ValueType>
468 struct insert_value
469 {
470  OStream& os;
471  ValueType value;
472  insert_value(OStream& os, ValueType v) : os(os), value(std::move(v)) {}
473  void operator()() const {
474  os << value;
475  }
476 private:
477  insert_value& operator=(const insert_value&) RXCPP_DELETE;
478 };
479 
480 template<class OStream, class Function>
481 struct insert_function
482 {
483  OStream& os;
484  Function call;
485  insert_function(OStream& os, Function f) : os(os), call(std::move(f)) {}
486  void operator()() const {
487  call(os);
488  }
489 private:
490  insert_function& operator=(const insert_function&) RXCPP_DELETE;
491 };
492 
493 template<class OStream, class Delimit>
494 auto print_followed_with(OStream& os, Delimit d)
495  -> detail::print_function<OStream, Delimit> {
496  return detail::print_function<OStream, Delimit>(os, std::move(d));
497 }
498 
499 }
500 
501 template<class OStream>
502 auto endline(OStream& os)
503  -> detail::endline<OStream> {
504  return detail::endline<OStream>(os);
505 }
506 
507 template<class OStream>
508 auto println(OStream& os)
509  -> decltype(detail::print_followed_with(os, endline(os))) {
510  return detail::print_followed_with(os, endline(os));
511 }
512 template<class OStream, class Delimit>
513 auto print_followed_with(OStream& os, Delimit d)
514  -> decltype(detail::print_followed_with(os, detail::insert_function<OStream, Delimit>(os, std::move(d)))) {
515  return detail::print_followed_with(os, detail::insert_function<OStream, Delimit>(os, std::move(d)));
516 }
517 template<class OStream, class DelimitValue>
518 auto print_followed_by(OStream& os, DelimitValue dv)
519  -> decltype(detail::print_followed_with(os, detail::insert_value<OStream, DelimitValue>(os, std::move(dv)))) {
520  return detail::print_followed_with(os, detail::insert_value<OStream, DelimitValue>(os, std::move(dv)));
521 }
522 
523 inline std::string what(std::exception_ptr ep) {
524  try {std::rethrow_exception(ep);}
525  catch (const std::exception& ex) {
526  return ex.what();
527  }
528  return std::string();
529 }
530 
531 namespace detail {
532 
533 template <class T>
534 class maybe
535 {
536  bool is_set;
537  typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type
538  storage;
539 public:
540  maybe()
541  : is_set(false)
542  {
543  }
544 
545  maybe(T value)
546  : is_set(false)
547  {
548  new (reinterpret_cast<T*>(&storage)) T(value);
549  is_set = true;
550  }
551 
552  maybe(const maybe& other)
553  : is_set(false)
554  {
555  if (other.is_set) {
556  new (reinterpret_cast<T*>(&storage)) T(other.get());
557  is_set = true;
558  }
559  }
560  maybe(maybe&& other)
561  : is_set(false)
562  {
563  if (other.is_set) {
564  new (reinterpret_cast<T*>(&storage)) T(std::move(other.get()));
565  is_set = true;
566  other.reset();
567  }
568  }
569 
570  ~maybe()
571  {
572  reset();
573  }
574 
575  typedef T value_type;
576  typedef T* iterator;
577  typedef const T* const_iterator;
578 
579  bool empty() const {
580  return !is_set;
581  }
582 
583  std::size_t size() const {
584  return is_set ? 1 : 0;
585  }
586 
587  iterator begin() {
588  return reinterpret_cast<T*>(&storage);
589  }
590  const_iterator begin() const {
591  return reinterpret_cast<T*>(&storage);
592  }
593 
594  iterator end() {
595  return reinterpret_cast<T*>(&storage) + size();
596  }
597  const_iterator end() const {
598  return reinterpret_cast<T*>(&storage) + size();
599  }
600 
601  T* operator->() {
602  if (!is_set) std::terminate();
603  return reinterpret_cast<T*>(&storage);
604  }
605  const T* operator->() const {
606  if (!is_set) std::terminate();
607  return reinterpret_cast<T*>(&storage);
608  }
609 
610  T& operator*() {
611  if (!is_set) std::terminate();
612  return *reinterpret_cast<T*>(&storage);
613  }
614  const T& operator*() const {
615  if (!is_set) std::terminate();
616  return *reinterpret_cast<T*>(&storage);
617  }
618 
619  T& get() {
620  if (!is_set) std::terminate();
621  return *reinterpret_cast<T*>(&storage);
622  }
623  const T& get() const {
624  if (!is_set) std::terminate();
625  return *reinterpret_cast<const T*>(&storage);
626  }
627 
628  void reset()
629  {
630  if (is_set) {
631  is_set = false;
632  reinterpret_cast<T*>(&storage)->~T();
633  //std::fill_n(reinterpret_cast<char*>(&storage), sizeof(T), 0);
634  }
635  }
636 
637  template<class U>
638  void reset(U&& value) {
639  reset();
640  new (reinterpret_cast<T*>(&storage)) T(std::forward<U>(value));
641  is_set = true;
642  }
643 
644  maybe& operator=(const T& other) {
645  reset(other);
646  return *this;
647  }
648  maybe& operator=(const maybe& other) {
649  if (!other.empty()) {
650  reset(other.get());
651  } else {
652  reset();
653  }
654  return *this;
655  }
656 };
657 
658 }
659 using detail::maybe;
660 
661 namespace detail {
662  struct surely
663  {
664  template<class... T>
665  auto operator()(T... t)
666  -> decltype(std::make_tuple(t.get()...)) {
667  return std::make_tuple(t.get()...);
668  }
669  template<class... T>
670  auto operator()(T... t) const
671  -> decltype(std::make_tuple(t.get()...)) {
672  return std::make_tuple(t.get()...);
673  }
674  };
675 }
676 
677 template<class... T>
678 inline auto surely(const std::tuple<T...>& tpl)
679  -> decltype(apply(tpl, detail::surely())) {
680  return apply(tpl, detail::surely());
681 }
682 
683 namespace detail {
684 
685 template<typename Function>
686 class unwinder
687 {
688 public:
689  ~unwinder()
690  {
691  if (!!function)
692  {
693  try {
694  (*function)();
695  } catch (...) {
696  std::unexpected();
697  }
698  }
699  }
700 
701  explicit unwinder(Function* functionArg)
702  : function(functionArg)
703  {
704  }
705 
706  void dismiss()
707  {
708  function = nullptr;
709  }
710 
711 private:
712  unwinder();
713  unwinder(const unwinder&);
714  unwinder& operator=(const unwinder&);
715 
716  Function* function;
717 };
718 
719 }
720 
721 #if !defined(RXCPP_THREAD_LOCAL)
722 template<typename T>
723 class thread_local_storage
724 {
725 private:
726  pthread_key_t key;
727 
728 public:
729  thread_local_storage()
730  {
731  pthread_key_create(&key, NULL);
732  }
733 
734  ~thread_local_storage()
735  {
736  pthread_key_delete(key);
737  }
738 
739  thread_local_storage& operator =(T* p)
740  {
741  pthread_setspecific(key, p);
742  return *this;
743  }
744 
745  bool operator !()
746  {
747  return pthread_getspecific(key) == NULL;
748  }
749 
750  T* operator ->()
751  {
752  return static_cast<T*>(pthread_getspecific(key));
753  }
754 
755  T* get()
756  {
757  return static_cast<T*>(pthread_getspecific(key));
758  }
759 };
760 #endif
761 
762 template<typename, typename C = types_checked>
763 struct is_string : std::false_type {
764 };
765 
766 template <typename T>
767 struct is_string<T,
768  typename types_checked_from<
769  typename T::value_type,
770  typename T::traits_type,
771  typename T::allocator_type>::type>
772  : std::is_base_of<
773  std::basic_string<
774  typename T::value_type,
775  typename T::traits_type,
776  typename T::allocator_type>, T> {
777 };
778 
779 namespace detail {
780 
781  template <class T, class = types_checked>
782  struct is_duration : std::false_type {};
783 
784  template <class T>
785  struct is_duration<T, types_checked_t<T, typename T::rep, typename T::period>>
786  : std::is_convertible<T*, std::chrono::duration<typename T::rep, typename T::period>*> {};
787 
788 }
789 
790 template <class T, class Decayed = decay_t<T>>
791 struct is_duration : detail::is_duration<Decayed> {};
792 
793 
794 // C++17 negation
795 namespace detail {
796  template<class T>
797  struct not_value : std::conditional<T::value, std::false_type, std::true_type>::type {
798  };
799 }
800 
801 template <class T>
802 struct negation : detail::not_value<T> {};
803 
804 }
805 namespace rxu=util;
806 
807 
808 //
809 // due to an noisy static_assert issue in more than one std lib impl,
810 // rxcpp maintains a whitelist filter for the types that are allowed
811 // to be hashed. this allows is_hashable<T> to work.
812 //
813 // NOTE: this should eventually be removed!
814 //
815 template <class T, typename = void>
817 
818 #if RXCPP_HASH_ENUM
819 template <class T>
820 struct filtered_hash<T, typename std::enable_if<std::is_enum<T>::value>::type> : std::hash<T> {
821 };
822 #elif RXCPP_HASH_ENUM_UNDERLYING
823 template <class T>
824 struct filtered_hash<T, typename std::enable_if<std::is_enum<T>::value>::type> : std::hash<typename std::underlying_type<T>::type> {
825 };
826 #endif
827 
828 template <class T>
829 struct filtered_hash<T, typename std::enable_if<std::is_integral<T>::value>::type> : std::hash<T> {
830 };
831 template <class T>
832 struct filtered_hash<T, typename std::enable_if<std::is_pointer<T>::value>::type> : std::hash<T> {
833 };
834 template <class T>
835 struct filtered_hash<T, typename std::enable_if<rxu::is_string<T>::value>::type> : std::hash<T> {
836 };
837 template <class T>
838 struct filtered_hash<T, typename std::enable_if<std::is_convertible<T, std::chrono::duration<typename T::rep, typename T::period>>::value>::type> {
839  using argument_type = T;
840  using result_type = std::size_t;
841 
843  {
844  return std::hash<typename argument_type::rep>{}(dur.count());
845  }
846 };
847 template <class T>
848 struct filtered_hash<T, typename std::enable_if<std::is_convertible<T, std::chrono::time_point<typename T::clock, typename T::duration>>::value>::type> {
849  using argument_type = T;
850  using result_type = std::size_t;
851 
853  {
854  return std::hash<typename argument_type::rep>{}(tp.time_since_epoch().count());
855  }
856 };
857 
858 template<typename, typename C = rxu::types_checked>
860  : std::false_type {};
861 
862 template<typename T>
863 struct is_hashable<T,
864  typename rxu::types_checked_from<
865  typename filtered_hash<T>::result_type,
866  typename filtered_hash<T>::argument_type,
867  typename std::result_of<filtered_hash<T>(T)>::type>::type>
868  : std::true_type {};
869 
870 }
871 
872 #define RXCPP_UNWIND(Name, Function) \
873  RXCPP_UNWIND_EXPLICIT(uwfunc_ ## Name, Name, Function)
874 
875 #define RXCPP_UNWIND_AUTO(Function) \
876  RXCPP_UNWIND_EXPLICIT(RXCPP_MAKE_IDENTIFIER(uwfunc_), RXCPP_MAKE_IDENTIFIER(unwind_), Function)
877 
878 #define RXCPP_UNWIND_EXPLICIT(FunctionName, UnwinderName, Function) \
879  auto FunctionName = (Function); \
880  rxcpp::util::detail::unwinder<decltype(FunctionName)> UnwinderName(std::addressof(FunctionName))
881 
882 #endif
typename std::enable_if< all_true< BN... >::value >::type enable_if_all_true_t
Definition: rx-util.hpp:97
Definition: rx-util.hpp:791
bool operator()(Value0 v0) const
Definition: rx-util.hpp:136
Definition: rx-util.hpp:161
Definition: rx-util.hpp:100
bool operator()(Value0 v0, ValueN...vn) const
Definition: rx-util.hpp:141
bool operator()(Value0 v0, ValueN...vn) const
Definition: rx-util.hpp:126
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:513
Definition: rx-util.hpp:179
Definition: rx-util.hpp:328
Definition: rx-util.hpp:359
Definition: rx-all.hpp:26
Definition: rx-util.hpp:307
Definition: rx-util.hpp:168
int operator()(int cnt, T &&) const
Definition: rx-util.hpp:407
typename std::decay< T >::type::value_type value_type_t
Definition: rx-util.hpp:35
Definition: rx-util.hpp:345
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:312
R type
Definition: rx-util.hpp:328
auto println(OStream &os) -> decltype(detail::print_followed_with(os, endline(os)))
Definition: rx-util.hpp:508
Definition: rx-util.hpp:859
typename std::decay< T >::type decay_t
Definition: rx-util.hpp:36
auto pack() -> detail::pack
Definition: rx-util.hpp:273
Definition: rx-util.hpp:342
bool operator()(Value0 v0) const
Definition: rx-util.hpp:121
tag_type::type type
Definition: rx-util.hpp:337
typename expand_value_types< types< TN... >>::type value_types_t
Definition: rx-util.hpp:175
Definition: rx-util.hpp:816
Definition: rx-util.hpp:404
auto operator()(LHS &&lhs, RHS &&rhs) const -> decltype(std::forward< LHS >(lhs)+std::forward< RHS >(rhs))
Definition: rx-util.hpp:399
Definition: rx-util.hpp:362
Definition: rx-util.hpp:154
defer_seed_type< Deferred, AN... >::type type
Definition: rx-util.hpp:393
auto apply_to(F f) -> detail::apply_to< F >
Definition: rx-util.hpp:250
auto operator()(LHS &&lhs, RHS &&rhs) const -> decltype(std::forward< LHS >(lhs)==std::forward< RHS >(rhs))
Definition: rx-util.hpp:429
Definition: rx-util.hpp:396
typename std::enable_if< all_true_type< BN... >::value >::type enable_if_all_true_type_t
Definition: rx-util.hpp:114
T const & as_const(T &t)
Definition: rx-util.hpp:57
Definition: rx-util.hpp:147
D type
Definition: rx-util.hpp:378
Definition: rx-util.hpp:325
auto operator()(LHS &&lhs, RHS &&rhs) const -> decltype(std::forward< LHS >(lhs)< std::forward< RHS >(rhs))
Definition: rx-util.hpp:414
defer_type< Deferred, AN... >::type type
Definition: rx-util.hpp:383
auto endline(OStream &os) -> detail::endline< OStream >
Definition: rx-util.hpp:502
Deferred< typename resolve_type< AN >::type... > resolved_type
Definition: rx-util.hpp:347
Deferred< typename resolve_type< AN >::type... > resolved_type
Definition: rx-util.hpp:364
auto surely(const std::tuple< T... > &tpl) -> decltype(apply(tpl, detail::surely()))
Definition: rx-util.hpp:678
void type
Definition: rx-util.hpp:329
auto take_at() -> detail::take_at< Index >
Definition: rx-util.hpp:298
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:206
Definition: rx-util.hpp:83
Definition: rx-util.hpp:329
Definition: rx-util.hpp:411
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:518
Definition: rx-util.hpp:304
typename types_checked_from< TN... >::type types_checked_t
Definition: rx-util.hpp:164
detail::types_checked_from< TN... >::type type
Definition: rx-util.hpp:161
values_from< T, Remaining-1, Step, Cursor+Step, ValueN..., Cursor >::type type
Definition: rx-util.hpp:79
values< T, ValueN... > type
Definition: rx-util.hpp:73
Definition: rx-util.hpp:310
Deferred< typename resolve_type< AN >::type... > resolved_type
Definition: rx-util.hpp:330
bool operator()(const T &lhs, const T &rhs) const
Definition: rx-util.hpp:422
Definition: rx-util.hpp:65
Definition: rx-util.hpp:311
Definition: rx-util.hpp:420
Definition: rx-util.hpp:131
std::string what(std::exception_ptr ep)
Definition: rx-util.hpp:523
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:218
typename std::result_of< TN... >::type result_of_t
Definition: rx-util.hpp:37
defer_value_type< Deferred, AN... >::type type
Definition: rx-util.hpp:388
Definition: rx-util.hpp:802
Definition: rx-util.hpp:116
types_checked type
Definition: rx-util.hpp:179
std::vector< T > to_vector(const T(&arr)[size])
Definition: rx-util.hpp:40
Definition: rx-util.hpp:763
Definition: rx-util.hpp:68
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:212