File indexing completed on 2025-01-19 04:19:12
0001 /* 0002 SPDX-FileCopyrightText: 2014-2015 Daniel Vrátil <dvratil@redhat.com> 0003 SPDX-FileCopyrightText: 2016-2019 Daniel Vrátil <dvratil@kde.org> 0004 SPDX-FileCopyrightText: 2016 Christian Mollekopf <mollekopf@kolabsystems.com> 0005 0006 SPDX-License-Identifier: LGPL-2.0-or-later 0007 */ 0008 0009 #ifndef KASYNC_CONTINUATIONS_P_H_ 0010 #define KASYNC_CONTINUATIONS_P_H_ 0011 0012 #include <limits> 0013 #include <functional> 0014 #include <type_traits> 0015 0016 namespace KAsync 0017 { 0018 0019 template<typename Out, typename ... In> 0020 class Job; 0021 0022 template<typename T> 0023 class Future; 0024 0025 struct Error; 0026 0027 //@cond PRIVATE 0028 namespace detail { 0029 template<typename T> 0030 struct identity { 0031 using type = T; 0032 }; 0033 template<typename T> 0034 using identity_t = typename identity<T>::type; 0035 } 0036 //@endcond 0037 0038 template<typename Out, typename ... In> 0039 using AsyncContinuation = detail::identity_t<std::function<void(In ..., KAsync::Future<Out>&)>>; 0040 0041 template<typename Out, typename ... In> 0042 using AsyncErrorContinuation = detail::identity_t<std::function<void(const KAsync::Error &, In ..., KAsync::Future<Out>&)>>; 0043 0044 template<typename Out, typename ... In> 0045 using SyncContinuation = detail::identity_t<std::function<Out(In ...)>>; 0046 0047 template<typename Out, typename ... In> 0048 using SyncErrorContinuation = detail::identity_t<std::function<Out(const KAsync::Error &, In ...)>>; 0049 0050 template<typename Out, typename ... In> 0051 using JobContinuation = detail::identity_t<std::function<KAsync::Job<Out>(In ...)>>; 0052 0053 template<typename Out, typename ... In> 0054 using JobErrorContinuation = detail::identity_t<std::function<KAsync::Job<Out>(const KAsync::Error &, In ...)>>; 0055 0056 //@cond PRIVATE 0057 namespace Private 0058 { 0059 /** 0060 * FIXME: This should be a simple alias to std::variant once we can depend on C++17. 0061 */ 0062 template<typename Out, typename ... In> 0063 struct ContinuationHolder 0064 { 0065 #ifndef KASYNC_TEST 0066 private: 0067 #endif 0068 using Tuple = std::tuple< 0069 AsyncContinuation<Out, In ...>, 0070 AsyncErrorContinuation<Out, In ...>, 0071 SyncContinuation<Out, In ...>, 0072 SyncErrorContinuation<Out, In ...>, 0073 JobContinuation<Out, In ...>, 0074 JobErrorContinuation<Out, In ...> 0075 >; 0076 0077 template<typename T> 0078 struct tuple_max; 0079 0080 template<typename T> 0081 struct tuple_max<std::tuple<T>> { 0082 static constexpr std::size_t size = sizeof(T); 0083 static constexpr std::size_t alignment = alignof(T); 0084 }; 0085 template<typename T, typename ... Types> 0086 struct tuple_max<std::tuple<T, Types ...>> { 0087 static constexpr std::size_t size = std::max(sizeof(T), tuple_max<std::tuple<Types ...>>::size); 0088 static constexpr std::size_t alignment = std::max(alignof(T), tuple_max<std::tuple<Types ...>>::alignment); 0089 }; 0090 0091 template<typename T, typename Tuple> 0092 struct tuple_index; 0093 0094 template<typename T, typename ... Types> 0095 struct tuple_index<T, std::tuple<T, Types ...>> { 0096 static constexpr std::size_t value = 0; 0097 }; 0098 template<typename T, typename U, typename ... Types> 0099 struct tuple_index<T, std::tuple<U, Types ...>> { 0100 static constexpr std::size_t value = tuple_index<T, std::tuple<Types ...>>::value + 1; 0101 }; 0102 0103 template<typename T> 0104 inline static void move_helper(void *storage, void *data) { 0105 new (storage) T(std::move(*reinterpret_cast<T*>(data))); 0106 } 0107 0108 template<typename T> 0109 inline static void destroy_helper(void *storage) { 0110 reinterpret_cast<T*>(storage)->~T(); 0111 } 0112 0113 template<typename Tuple, 0114 std::size_t I = std::tuple_size<Tuple>::value - 1> 0115 struct storage_helper { 0116 using T = std::tuple_element_t<I, Tuple>; 0117 inline static void move(std::size_t index, void *storage, void *data) { 0118 if (I == index) { 0119 move_helper<T>(storage, data); 0120 } else { 0121 storage_helper<Tuple, I - 1>::move(index, storage, data); 0122 } 0123 } 0124 inline static void destroy(std::size_t index, void *storage) { 0125 if (I == index) { 0126 destroy_helper<T>(storage); 0127 } else { 0128 storage_helper<Tuple, I - 1>::destroy(index, storage); 0129 } 0130 } 0131 }; 0132 0133 template<typename Tuple> 0134 struct storage_helper<Tuple, 0> { 0135 using T = std::tuple_element_t<0, Tuple>; 0136 inline static void move(std::size_t, void *storage, void *data) { 0137 move_helper<T>(storage, data); 0138 } 0139 inline static void destroy(std::size_t, void *storage) { 0140 destroy_helper<T>(storage); 0141 } 0142 }; 0143 0144 enum { 0145 Invalid = std::numeric_limits<std::size_t>::max() - 1 0146 }; 0147 0148 std::size_t mIndex = Invalid; 0149 std::aligned_storage_t<tuple_max<Tuple>::size, tuple_max<Tuple>::alignment> mStorage = {}; 0150 0151 public: 0152 #define KASYNC_P_DEFINE_CONSTRUCTOR(type) \ 0153 ContinuationHolder(type<Out, In ...> &&cont) \ 0154 : mIndex(tuple_index<type<Out, In ...>, Tuple>::value) \ 0155 { \ 0156 move_helper<type<Out, In ...>>(&mStorage, &cont); \ 0157 } 0158 KASYNC_P_DEFINE_CONSTRUCTOR(AsyncContinuation) 0159 KASYNC_P_DEFINE_CONSTRUCTOR(AsyncErrorContinuation) 0160 KASYNC_P_DEFINE_CONSTRUCTOR(SyncContinuation) 0161 KASYNC_P_DEFINE_CONSTRUCTOR(SyncErrorContinuation) 0162 KASYNC_P_DEFINE_CONSTRUCTOR(JobContinuation) 0163 KASYNC_P_DEFINE_CONSTRUCTOR(JobErrorContinuation) 0164 #undef KASYNC_P_DEFINE_CONSTRUCTOR 0165 0166 ContinuationHolder(ContinuationHolder &&other) noexcept { 0167 std::swap(mIndex, other.mIndex); 0168 storage_helper<Tuple>::move(mIndex, &mStorage, &other.mStorage); 0169 } 0170 0171 ContinuationHolder &operator=(ContinuationHolder &&other) noexcept { 0172 std::swap(mIndex, other.mIndex); 0173 storage_helper<Tuple>::move(mIndex, &mStorage, &other.mStorage); 0174 return *this; 0175 } 0176 0177 ContinuationHolder(const ContinuationHolder &) = delete; 0178 ContinuationHolder &operator=(const ContinuationHolder &) = delete; 0179 0180 ~ContinuationHolder() { 0181 if (mIndex != Invalid) { 0182 storage_helper<Tuple>::destroy(mIndex, &mStorage); 0183 mIndex = Invalid; 0184 } 0185 } 0186 0187 template<typename T> 0188 inline bool is() const { 0189 return mIndex == tuple_index<T, Tuple>::value; 0190 } 0191 0192 template<typename T> 0193 inline const T &get() const { 0194 if (!is<T>()) { 0195 throw std::bad_cast(); 0196 } 0197 return *reinterpret_cast<const T *>(&mStorage); 0198 } 0199 0200 template<typename T> 0201 inline T &&get() { 0202 if (!is<T>()) { 0203 throw std::bad_cast(); 0204 } 0205 return std::move(*reinterpret_cast<T *>(&mStorage)); 0206 } 0207 }; 0208 0209 template<typename T, typename Holder> 0210 inline bool continuationIs(const Holder &holder) { 0211 return holder.template is<T>(); 0212 } 0213 0214 template<typename T, typename Holder> 0215 inline const T &continuationGet(const Holder &holder) { 0216 return holder.template get<T>(); 0217 } 0218 0219 template<typename T, typename Holder> 0220 inline T &&continuationGet(Holder &holder) { 0221 return holder.template get<T>(); 0222 } 0223 0224 } // namespace Private 0225 //@endcond 0226 0227 0228 } 0229 0230 0231 #endif