Home | History | Annotate | Download | only in rxcpp
      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>
    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>
    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 
    143 struct any_value_true {
    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 {
    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>
    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>
    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>
    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).
    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>
    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.
    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>
    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
    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.
    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 
    991     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 
   1001     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