File indexing completed on 2024-05-05 05:37:16
0001 /* 0002 * SPDX-FileCopyrightText: 2017 Ivan Čukić <ivan.cukic(at)kde.org> 0003 * 0004 * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0005 */ 0006 0007 #ifndef ASYNQT_EXPECTED_H 0008 #define ASYNQT_EXPECTED_H 0009 0010 namespace AsynQt 0011 { 0012 // Based on expected<T> by Alexandrescu, 0013 // with some nice syntax sugar on top 0014 0015 template<typename T, typename E> 0016 class Expected 0017 { 0018 protected: 0019 union { 0020 T m_value; 0021 E m_error; 0022 }; 0023 0024 bool m_isValid; 0025 0026 Expected() // used internally 0027 { 0028 } 0029 0030 public: 0031 ~Expected() 0032 { 0033 if (m_isValid) { 0034 m_value.~T(); 0035 } else { 0036 m_error.~E(); 0037 } 0038 } 0039 0040 Expected(const Expected &other) 0041 : m_isValid(other.m_isValid) 0042 { 0043 if (m_isValid) { 0044 new (&m_value) T(other.m_value); 0045 } else { 0046 new (&m_error) E(other.m_error); 0047 } 0048 } 0049 0050 Expected(Expected &&other) 0051 : m_isValid(other.m_isValid) 0052 { 0053 if (m_isValid) { 0054 new (&m_value) T(std::move(other.m_value)); 0055 } else { 0056 new (&m_error) E(std::move(other.m_error)); 0057 } 0058 } 0059 0060 Expected &operator=(Expected other) 0061 { 0062 swap(other); 0063 return *this; 0064 } 0065 0066 void swap(Expected &other) 0067 { 0068 using std::swap; 0069 if (m_isValid) { 0070 if (other.m_isValid) { 0071 // Both are valid, just swap the values 0072 swap(m_value, other.m_value); 0073 0074 } else { 0075 // We are valid, but the other one is not 0076 // we need to do the whole dance 0077 auto temp = std::move(other.m_error); // moving the error into the temp 0078 other.m_error.~E(); // destroying the original error object 0079 new (&other.m_value) T(std::move(m_value)); // moving our value into the other 0080 m_value.~T(); // destroying our value object 0081 new (&m_error) E(std::move(temp)); // moving the error saved to the temp into us 0082 std::swap(m_isValid, other.m_isValid); // swap the isValid flags 0083 } 0084 0085 } else { 0086 if (other.m_isValid) { 0087 // We are not valid, but the other one is, 0088 // just call swap on other and rely on the 0089 // implementation in the previous case 0090 other.swap(*this); 0091 0092 } else { 0093 // Everything is rotten, just swap the errors 0094 swap(m_error, other.m_error); 0095 std::swap(m_isValid, other.m_isValid); 0096 } 0097 } 0098 } 0099 0100 template<typename... ConsParams> 0101 static Expected success(ConsParams &&...params) 0102 { 0103 Expected result; 0104 result.m_isValid = true; 0105 new (&result.m_value) T(std::forward<ConsParams>(params)...); 0106 return result; 0107 } 0108 0109 template<typename... ConsParams> 0110 static Expected error(ConsParams &&...params) 0111 { 0112 Expected result; 0113 result.m_isValid = false; 0114 new (&result.m_error) E(std::forward<ConsParams>(params)...); 0115 return result; 0116 } 0117 0118 operator bool() const 0119 { 0120 return m_isValid; 0121 } 0122 0123 #ifdef QT_NO_EXCEPTIONS 0124 #define THROW_IF_EXCEPTIONS_ARE_ENABLED(WHAT) std::terminate() 0125 #else 0126 #define THROW_IF_EXCEPTIONS_ARE_ENABLED(WHAT) throw std::logic_error(WHAT) 0127 #endif 0128 0129 T &get() 0130 { 0131 if (!m_isValid) 0132 THROW_IF_EXCEPTIONS_ARE_ENABLED("expected<T, E> contains no value"); 0133 return m_value; 0134 } 0135 0136 const T &get() const 0137 { 0138 if (!m_isValid) 0139 THROW_IF_EXCEPTIONS_ARE_ENABLED("expected<T, E> contains no value"); 0140 return m_value; 0141 } 0142 0143 T *operator->() 0144 { 0145 return &get(); 0146 } 0147 0148 const T *operator->() const 0149 { 0150 return &get(); 0151 } 0152 0153 E &error() 0154 { 0155 if (m_isValid) 0156 THROW_IF_EXCEPTIONS_ARE_ENABLED("There is no error in this expected<T, E>"); 0157 return m_error; 0158 } 0159 0160 const E &error() const 0161 { 0162 if (m_isValid) 0163 THROW_IF_EXCEPTIONS_ARE_ENABLED("There is no error in this expected<T, E>"); 0164 return m_error; 0165 } 0166 0167 #undef THROW_IF_EXCEPTIONS_ARE_ENABLED 0168 0169 template<typename F> 0170 void visit(F f) 0171 { 0172 if (m_isValid) { 0173 f(m_value); 0174 } else { 0175 f(m_error); 0176 } 0177 } 0178 }; 0179 0180 template<typename E> 0181 class Expected<void, E> 0182 { 0183 private: 0184 union { 0185 void *m_value; 0186 E m_error; 0187 }; 0188 0189 bool m_isValid; 0190 0191 Expected() 0192 { 0193 } // used internally 0194 0195 public: 0196 ~Expected() 0197 { 0198 if (m_isValid) { 0199 // m_value.~T(); 0200 } else { 0201 m_error.~E(); 0202 } 0203 } 0204 0205 Expected(const Expected &other) 0206 : m_isValid(other.m_isValid) 0207 { 0208 if (m_isValid) { 0209 // new (&m_value) T(other.m_value); 0210 } else { 0211 new (&m_error) E(other.m_error); 0212 } 0213 } 0214 0215 Expected(Expected &&other) 0216 : m_isValid(other.m_isValid) 0217 { 0218 if (m_isValid) { 0219 // new (&m_value) T(std::move(other.m_value)); 0220 } else { 0221 new (&m_error) E(std::move(other.m_error)); 0222 } 0223 } 0224 0225 Expected &operator=(Expected other) 0226 { 0227 swap(other); 0228 return *this; 0229 } 0230 0231 void swap(Expected &other) 0232 { 0233 using std::swap; 0234 if (m_isValid) { 0235 if (other.m_isValid) { 0236 // Both are valid, we do not have any values 0237 // to swap 0238 0239 } else { 0240 // We are valid, but the other one is not. 0241 // We need to move the error into us 0242 auto temp = std::move(other.m_error); // moving the error into the temp 0243 other.m_error.~E(); // destroying the original error object 0244 new (&m_error) E(std::move(temp)); // moving the error into us 0245 std::swap(m_isValid, other.m_isValid); // swapping the isValid flags 0246 } 0247 0248 } else { 0249 if (other.m_isValid) { 0250 // We are not valid, but the other one is, 0251 // just call swap on other and rely on the 0252 // implementation in the previous case 0253 other.swap(*this); 0254 0255 } else { 0256 // Everything is rotten, just swap the errors 0257 swap(m_error, other.m_error); 0258 std::swap(m_isValid, other.m_isValid); 0259 } 0260 } 0261 } 0262 0263 static Expected success() 0264 { 0265 Expected result; 0266 result.m_isValid = true; 0267 result.m_value = nullptr; 0268 return result; 0269 } 0270 0271 template<typename... ConsParams> 0272 static Expected error(ConsParams &&...params) 0273 { 0274 Expected result; 0275 result.m_isValid = false; 0276 new (&result.m_error) E(std::forward<ConsParams>(params)...); 0277 return result; 0278 } 0279 0280 operator bool() const 0281 { 0282 return m_isValid; 0283 } 0284 0285 #ifdef QT_NO_EXCEPTIONS 0286 #define THROW_IF_EXCEPTIONS_ARE_ENABLED(WHAT) std::terminate() 0287 #else 0288 #define THROW_IF_EXCEPTIONS_ARE_ENABLED(WHAT) throw std::logic_error(WHAT) 0289 #endif 0290 0291 E &error() 0292 { 0293 if (m_isValid) 0294 THROW_IF_EXCEPTIONS_ARE_ENABLED("There is no error in this expected<T, E>"); 0295 return m_error; 0296 } 0297 0298 const E &error() const 0299 { 0300 if (m_isValid) 0301 THROW_IF_EXCEPTIONS_ARE_ENABLED("There is no error in this expected<T, E>"); 0302 return m_error; 0303 } 0304 0305 #undef THROW_IF_EXCEPTIONS_ARE_ENABLED 0306 0307 template<typename F> 0308 void visit(F f) 0309 { 0310 if (m_isValid) { 0311 // f(m_value); 0312 } else { 0313 f(m_error); 0314 } 0315 } 0316 }; 0317 0318 } // namespace AsynQt 0319 0320 #endif // ASYNQT_EXPECTED_H