5 #if !defined(RXCPP_RX_UTIL_HPP)
6 #define RXCPP_RX_UTIL_HPP
10 #if !defined(RXCPP_ON_IOS) && !defined(RXCPP_ON_ANDROID) && !defined(RXCPP_THREAD_LOCAL)
12 #define RXCPP_THREAD_LOCAL __declspec(thread)
14 #define RXCPP_THREAD_LOCAL __thread
18 #if !defined(RXCPP_DELETE)
20 #define RXCPP_DELETE __pragma(warning(disable: 4822)) =delete
22 #define RXCPP_DELETE =delete
26 #define RXCPP_CONCAT(Prefix, Suffix) Prefix ## Suffix
27 #define RXCPP_CONCAT_EVALUATE(Prefix, Suffix) RXCPP_CONCAT(Prefix, Suffix)
29 #define RXCPP_MAKE_IDENTIFIER(Prefix) RXCPP_CONCAT_EVALUATE(Prefix, __LINE__)
33 #if RXCPP_USE_EXCEPTIONS
35 #define RXCPP_CATCH(...) catch(__VA_ARGS__)
38 #define RXCPP_TRY if ((true))
39 #define RXCPP_CATCH(...) if ((false))
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;
51 template<
class T, std::
size_t size>
53 return std::vector<T>(std::begin(arr), std::end(arr));
57 std::vector<T>
to_vector(std::initializer_list<T> il) {
58 return std::vector<T>(il);
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) {
76 template<
class T, T... ValueN>
79 template<
class T,
int Remaining, T Step = 1, T Cursor = 0, T... ValueN>
82 template<
class T, T Step, T Cursor, T... ValueN>
88 template<
class T,
int Remaining, T Step, T Cursor, T... ValueN>
100 static const bool value = B;
102 template<
bool B,
bool... BN>
105 static const bool value = B &&
all_true<BN...>::value;
111 template<
class... BN>
117 static const bool value = B::value;
119 template<
class B,
class... BN>
125 template<
class... BN>
129 template<
class... ValueN>
132 template<
class Value0>
137 template<
class Value0,
class... ValueN>
144 template<
class... ValueN>
147 template<
class Value0>
152 template<
class Value0,
class... ValueN>
158 template<
class... TN>
172 template<
class... TN>
175 template<
class... TN>
179 template<
class Types,
class =types_checked>
181 template<
class... TN>
186 template<
class... TN>
190 template<
class T,
class C = types_checked>
198 template<
class F,
class... ParamN,
int... IndexN>
200 -> decltype(f(std::forward<ParamN>(std::get<IndexN>(p))...)) {
201 return f(std::forward<ParamN>(std::get<IndexN>(p))...);
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)))...);
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)))...);
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))) {
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)
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)
247 template<
class... ParamN>
248 auto operator()(std::tuple<ParamN...> p)
252 template<
class... ParamN>
253 auto operator()(std::tuple<ParamN...> p)
const
263 -> detail::apply_to<F> {
264 return detail::apply_to<F>(std::move(f));
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)...);
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)...);
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)...));
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)...));
311 -> detail::take_at<Index> {
312 return detail::take_at<Index>();
318 template <
template<
class... TN>
class Deferred, class...
AN>
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;};
325 template<
class... CN>
327 template<
class... CN>
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;
336 template <template<class... TN> class Deferred, class...
AN>
343 template<
class... CN>
345 template<
class... CN>
348 typedef decltype(check<AN...>(0)) tag_type;
350 static const
bool value = tag_type::value;
353 template <template<class... TN> class Deferred, class...
AN>
360 template<
class... CN>
362 template<
class... CN>
365 typedef decltype(check<AN...>(0)) tag_type;
367 static const
bool value = tag_type::value;
370 template <template<class... TN> class Deferred, class...
AN>
377 template<
class... CN>
379 template<
class... CN>
382 typedef decltype(check<AN...>(0)) tag_type;
384 static const
bool value = tag_type::value;
392 template <
template<
class... TN>
class Deferred, class...
AN>
397 template <
template<
class... TN>
class Deferred, class...
AN>
402 template <
template<
class... TN>
class Deferred, class...
AN>
410 template <
class LHS,
class RHS>
412 -> decltype(std::forward<LHS>(lhs) + std::forward<RHS>(rhs))
413 {
return std::forward<LHS>(lhs) + std::forward<RHS>(rhs); }
425 template <
class LHS,
class RHS>
427 -> decltype(std::forward<LHS>(lhs) < std::forward<RHS>(rhs))
428 {
return std::forward<LHS>(lhs) < std::forward<RHS>(rhs); }
440 template<
class T =
void>
443 bool operator()(
const T& lhs,
const T& rhs)
const {
return lhs == rhs; }
449 template<
class LHS,
class RHS>
451 -> decltype(std::forward<LHS>(lhs) == std::forward<RHS>(rhs))
452 {
return std::forward<LHS>(lhs) == std::forward<RHS>(rhs); }
456 template<
class OStream,
class Delimit>
457 struct print_function
461 print_function(OStream& os, Delimit d) : os(os), delimit(std::move(d)) {}
463 template<
class... TN>
464 void operator()(
const TN&... tn)
const {
465 bool inserts[] = {(os << tn,
true)...};
466 inserts[0] = *
reinterpret_cast<bool*
>(inserts);
470 template<
class... TN>
471 void operator()(
const std::tuple<TN...>& tpl)
const {
476 template<
class OStream>
480 endline(OStream& os) : os(os) {}
481 void operator()()
const {
488 template<
class OStream,
class ValueType>
493 insert_value(OStream& os, ValueType v) : os(os), value(std::move(v)) {}
494 void operator()()
const {
498 insert_value& operator=(
const insert_value&) RXCPP_DELETE;
501 template<
class OStream,
class Function>
502 struct insert_function
506 insert_function(OStream& os, Function f) : os(os), call(std::move(f)) {}
507 void operator()()
const {
511 insert_function& operator=(
const insert_function&) RXCPP_DELETE;
514 template<
class OStream,
class Delimit>
516 -> detail::print_function<OStream, Delimit> {
517 return detail::print_function<OStream, Delimit>(os, std::move(d));
522 template<
class OStream>
524 -> detail::endline<OStream> {
525 return detail::endline<OStream>(os);
528 template<
class OStream>
533 template<
class OStream,
class Delimit>
538 template<
class OStream,
class DelimitValue>
544 inline std::string
what(std::exception_ptr ep) {
545 #if RXCPP_USE_EXCEPTIONS
547 catch (
const std::exception& ex) {
550 return std::string(
"<not derived from std::exception>");
554 return std::string(
"<exceptions are disabled>");
563 typename std::aligned_storage<
sizeof(T), std::alignment_of<T>::value>::type
574 new (
reinterpret_cast<T*
>(&storage)) T(value);
578 maybe(
const maybe& other)
582 new (
reinterpret_cast<T*
>(&storage)) T(other.get());
590 new (
reinterpret_cast<T*
>(&storage)) T(std::move(other.get()));
601 typedef T value_type;
603 typedef const T* const_iterator;
609 std::size_t size()
const {
610 return is_set ? 1 : 0;
614 return reinterpret_cast<T*
>(&storage);
616 const_iterator begin()
const {
617 return reinterpret_cast<T*
>(&storage);
621 return reinterpret_cast<T*
>(&storage) + size();
623 const_iterator end()
const {
624 return reinterpret_cast<T*
>(&storage) + size();
628 if (!is_set) std::terminate();
629 return reinterpret_cast<T*
>(&storage);
631 const T* operator->()
const {
632 if (!is_set) std::terminate();
633 return reinterpret_cast<T*
>(&storage);
637 if (!is_set) std::terminate();
638 return *
reinterpret_cast<T*
>(&storage);
640 const T& operator*()
const {
641 if (!is_set) std::terminate();
642 return *
reinterpret_cast<T*
>(&storage);
646 if (!is_set) std::terminate();
647 return *
reinterpret_cast<T*
>(&storage);
649 const T& get()
const {
650 if (!is_set) std::terminate();
651 return *
reinterpret_cast<const T*
>(&storage);
658 reinterpret_cast<T*
>(&storage)->~T();
664 void reset(U&& value) {
666 new (
reinterpret_cast<T*
>(&storage)) T(std::forward<U>(value));
670 maybe& operator=(
const T& other) {
674 maybe& operator=(
const maybe& other) {
675 if (!other.empty()) {
691 auto operator()(T... t)
692 -> decltype(std::make_tuple(t.get()...)) {
693 return std::make_tuple(t.get()...);
696 auto operator()(T... t)
const
697 -> decltype(std::make_tuple(t.get()...)) {
698 return std::make_tuple(t.get()...);
704 inline auto surely(
const std::tuple<T...>& tpl)
711 template<
typename Function>
727 explicit unwinder(Function* functionArg)
728 : function(functionArg)
739 unwinder(
const unwinder&);
740 unwinder& operator=(
const unwinder&);
747 #if !defined(RXCPP_THREAD_LOCAL)
749 class thread_local_storage
755 thread_local_storage()
757 pthread_key_create(&key, NULL);
760 ~thread_local_storage()
762 pthread_key_delete(key);
765 thread_local_storage& operator =(T* p)
767 pthread_setspecific(key, p);
773 return pthread_getspecific(key) == NULL;
778 return static_cast<T*
>(pthread_getspecific(key));
783 return static_cast<T*
>(pthread_getspecific(key));
788 template<
typename,
typename C = types_checked>
792 template <
typename T>
795 typename T::value_type,
796 typename T::traits_type,
797 typename T::allocator_type>::type>
800 typename T::value_type,
801 typename T::traits_type,
802 typename T::allocator_type>, T> {
807 template <
class T,
class = types_checked>
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>*> {};
816 template <
class T,
class Decayed = decay_t<T>>
823 struct not_value : std::conditional<T::value, std::false_type, std::true_type>::type {
832 #if !RXCPP_USE_EXCEPTIONS
838 virtual const char*
what() = 0;
839 virtual ~error_base() {}
848 struct error_specific :
public error_base {
849 error_specific(
const E& e) : data(e) {}
850 error_specific(E&& e) : data(std::move(e)) {}
852 virtual ~error_specific() {}
854 virtual const char*
what() {
868 #if RXCPP_USE_EXCEPTIONS
874 using error_ptr = std::shared_ptr<util::detail::error_base>;
877 return std::string(ep->what());
891 #if RXCPP_USE_EXCEPTIONS
892 return std::make_exception_ptr(std::forward<E>(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);
903 #if RXCPP_USE_EXCEPTIONS
919 template <
typename E>
921 #if RXCPP_USE_EXCEPTIONS
922 throw std::forward<E>(e);
934 #if RXCPP_USE_EXCEPTIONS
944 #if RXCPP_USE_EXCEPTIONS
964 template <
class T,
typename =
void>
969 struct filtered_hash<T, typename std::enable_if<std::is_enum<T>::value>::type> : std::hash<T> {
971 #elif RXCPP_HASH_ENUM_UNDERLYING
973 struct filtered_hash<T, typename std::enable_if<std::is_enum<T>::value>::type> : std::hash<typename std::underlying_type<T>::type> {
978 struct filtered_hash<T, typename std::enable_if<std::is_integral<T>::value>::type> : std::hash<T> {
981 struct filtered_hash<T, typename std::enable_if<std::is_pointer<T>::value>::type> : std::hash<T> {
984 struct filtered_hash<T, typename std::enable_if<rxu::is_string<T>::value>::type> : std::hash<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> {
993 return std::hash<typename argument_type::rep>{}(dur.count());
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> {
1003 return std::hash<typename argument_type::rep>{}(tp.time_since_epoch().count());
1007 template<
typename,
typename C = rxu::types_checked>
1009 : std::false_type {};
1011 template<
typename 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 {};
1021 #define RXCPP_UNWIND(Name, Function) \
1022 RXCPP_UNWIND_EXPLICIT(uwfunc_ ## Name, Name, Function)
1024 #define RXCPP_UNWIND_AUTO(Function) \
1025 RXCPP_UNWIND_EXPLICIT(RXCPP_MAKE_IDENTIFIER(uwfunc_), RXCPP_MAKE_IDENTIFIER(unwind_), Function)
1027 #define RXCPP_UNWIND_EXPLICIT(FunctionName, UnwinderName, Function) \
1028 auto FunctionName = (Function); \
1029 rxcpp::util::detail::unwinder<decltype(FunctionName)> UnwinderName(std::addressof(FunctionName))