1 #ifndef BOOST_LEAF_RESULT_HPP_INCLUDED 2 #define BOOST_LEAF_RESULT_HPP_INCLUDED 3 4 // Copyright (c) 2018-2020 Emil Dotchevski and Reverge Studios, Inc. 5 6 // Distributed under the Boost Software License, Version 1.0. (See accompanying 7 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 8 9 #ifndef BOOST_LEAF_ENABLE_WARNINGS 10 # if defined(__clang__) 11 # pragma clang system_header 12 # elif (__GNUC__*100+__GNUC_MINOR__>301) 13 # pragma GCC system_header 14 # elif defined(_MSC_VER) 15 # pragma warning(push,1) 16 # endif 17 #endif 18 19 #include <boost/leaf/error.hpp> 20 #include <climits> 21 22 namespace boost { namespace leaf { 23 24 class bad_result: 25 public std::exception, 26 public error_id 27 { what() const28 char const * what() const noexcept final override 29 { 30 return "boost::leaf::bad_result"; 31 } 32 33 public: 34 bad_result(error_id id)35 explicit bad_result( error_id id ) noexcept: 36 error_id(id) 37 { 38 BOOST_LEAF_ASSERT(value()); 39 } 40 }; 41 42 //////////////////////////////////////// 43 44 namespace leaf_detail 45 { 46 template <class T> 47 struct stored 48 { 49 using type = T; 50 using value_type = T; 51 using value_type_const = T const; 52 using value_cref = T const &; 53 using value_ref = T &; 54 using value_rv_cref = T const &&; 55 using value_rv_ref = T &&; 56 }; 57 58 template <class T> 59 struct stored<T &> 60 { 61 using type = std::reference_wrapper<T>; 62 using value_type_const = T; 63 using value_type = T; 64 using value_ref = T &; 65 using value_cref = T &; 66 using value_rv_ref = T &; 67 using value_rv_cref = T &; 68 }; 69 70 class result_discriminant 71 { 72 unsigned state_; 73 74 public: 75 76 enum kind_t 77 { 78 no_error = 0, 79 err_id = 1, 80 ctx_ptr = 2, 81 val = 3 82 }; 83 result_discriminant(error_id id)84 explicit result_discriminant( error_id id ) noexcept: 85 state_(id.value()) 86 { 87 BOOST_LEAF_ASSERT(state_==0 || (state_&3)==1); 88 } 89 90 struct kind_val { }; result_discriminant(kind_val)91 explicit result_discriminant( kind_val ) noexcept: 92 state_(val) 93 { 94 } 95 96 struct kind_ctx_ptr { }; result_discriminant(kind_ctx_ptr)97 explicit result_discriminant( kind_ctx_ptr ) noexcept: 98 state_(ctx_ptr) 99 { 100 } 101 kind() const102 kind_t kind() const noexcept 103 { 104 return kind_t(state_&3); 105 } 106 get_error_id() const107 error_id get_error_id() const noexcept 108 { 109 BOOST_LEAF_ASSERT(kind()==no_error || kind()==err_id); 110 return make_error_id(state_); 111 } 112 }; 113 } 114 115 //////////////////////////////////////// 116 117 template <class T> 118 class result 119 { 120 template <class U> 121 friend class result; 122 123 using result_discriminant = leaf_detail::result_discriminant; 124 125 struct error_result 126 { 127 error_result( error_result && ) = default; 128 error_result( error_result const & ) = delete; 129 error_result & operator=( error_result const & ) = delete; 130 131 result & r_; 132 error_resultboost::leaf::result::error_result133 error_result( result & r ) noexcept: 134 r_(r) 135 { 136 } 137 138 template <class U> operator result<U>boost::leaf::result::error_result139 operator result<U>() noexcept 140 { 141 switch(r_.what_.kind()) 142 { 143 case result_discriminant::val: 144 return result<U>(error_id()); 145 case result_discriminant::ctx_ptr: 146 return result<U>(std::move(r_.ctx_)); 147 default: 148 return result<U>(std::move(r_.what_)); 149 } 150 } 151 operator error_idboost::leaf::result::error_result152 operator error_id() noexcept 153 { 154 switch(r_.what_.kind()) 155 { 156 case result_discriminant::val: 157 return error_id(); 158 case result_discriminant::ctx_ptr: 159 { 160 error_id captured_id = r_.ctx_->propagate_captured_errors(); 161 leaf_detail::id_factory<>::current_id = captured_id.value(); 162 return captured_id; 163 } 164 default: 165 return r_.what_.get_error_id(); 166 } 167 } 168 }; 169 170 using stored_type = typename leaf_detail::stored<T>::type; 171 using value_type = typename leaf_detail::stored<T>::value_type; 172 using value_type_const = typename leaf_detail::stored<T>::value_type_const; 173 using value_ref = typename leaf_detail::stored<T>::value_ref; 174 using value_cref = typename leaf_detail::stored<T>::value_cref; 175 using value_rv_ref = typename leaf_detail::stored<T>::value_rv_ref; 176 using value_rv_cref = typename leaf_detail::stored<T>::value_rv_cref; 177 178 union 179 { 180 stored_type stored_; 181 context_ptr ctx_; 182 }; 183 184 result_discriminant what_; 185 destroy() const186 void destroy() const noexcept 187 { 188 switch(this->what_.kind()) 189 { 190 case result_discriminant::val: 191 stored_.~stored_type(); 192 break; 193 case result_discriminant::ctx_ptr: 194 BOOST_LEAF_ASSERT(!ctx_ || ctx_->captured_id_); 195 ctx_.~context_ptr(); 196 default: 197 break; 198 } 199 } 200 201 template <class U> move_from(result<U> && x)202 result_discriminant move_from( result<U> && x ) noexcept 203 { 204 auto x_what = x.what_; 205 switch(x_what.kind()) 206 { 207 case result_discriminant::val: 208 (void) new(&stored_) stored_type(std::move(x.stored_)); 209 break; 210 case result_discriminant::ctx_ptr: 211 BOOST_LEAF_ASSERT(!x.ctx_ || x.ctx_->captured_id_); 212 (void) new(&ctx_) context_ptr(std::move(x.ctx_)); 213 default: 214 break; 215 } 216 return x_what; 217 } 218 result(result_discriminant && what)219 result( result_discriminant && what ) noexcept: 220 what_(std::move(what)) 221 { 222 BOOST_LEAF_ASSERT(what_.kind()==result_discriminant::err_id || what_.kind()==result_discriminant::no_error); 223 } 224 get_error_id() const225 error_id get_error_id() const noexcept 226 { 227 BOOST_LEAF_ASSERT(what_.kind()!=result_discriminant::val); 228 return what_.kind()==result_discriminant::ctx_ptr ? ctx_->captured_id_ : what_.get_error_id(); 229 } 230 231 static int init_T_with_U( T && ); 232 233 protected: 234 enforce_value_state() const235 void enforce_value_state() const 236 { 237 if( what_.kind() != result_discriminant::val ) 238 ::boost::leaf::throw_exception(bad_result(get_error_id())); 239 } 240 241 public: 242 result(result && x)243 result( result && x ) noexcept: 244 what_(move_from(std::move(x))) 245 { 246 } 247 248 template <class U> result(result<U> && x)249 result( result<U> && x ) noexcept: 250 what_(move_from(std::move(x))) 251 252 { 253 } 254 result()255 result(): 256 stored_(stored_type()), 257 what_(result_discriminant::kind_val{}) 258 { 259 } 260 result(value_type && v)261 result( value_type && v ) noexcept: 262 stored_(std::forward<value_type>(v)), 263 what_(result_discriminant::kind_val{}) 264 { 265 } 266 result(value_type const & v)267 result( value_type const & v ): 268 stored_(v), 269 what_(result_discriminant::kind_val{}) 270 { 271 } 272 result(error_id err)273 result( error_id err ) noexcept: 274 what_(err) 275 { 276 } 277 278 // SFINAE: T can be initialized with a U, e.g. result<std::string>("literal"). 279 // Not using is_constructible on purpose, bug with COMPILER=/usr/bin/clang++ CXXSTD=11 clang 3.3. 280 template <class U> result(U && u,decltype(init_T_with_U (std::forward<U> (u)))* =0)281 result( U && u, decltype(init_T_with_U(std::forward<U>(u))) * = 0 ): 282 stored_(std::forward<U>(u)), 283 what_(result_discriminant::kind_val{}) 284 { 285 } 286 result(std::error_code const & ec)287 result( std::error_code const & ec ) noexcept: 288 what_(error_id(ec)) 289 { 290 } 291 292 template <class Enum> result(Enum e,typename std::enable_if<std::is_error_code_enum<Enum>::value,int>::type * =0)293 result( Enum e, typename std::enable_if<std::is_error_code_enum<Enum>::value, int>::type * = 0 ) noexcept: 294 what_(error_id(e)) 295 { 296 } 297 result(context_ptr && ctx)298 result( context_ptr && ctx ) noexcept: 299 ctx_(std::move(ctx)), 300 what_(result_discriminant::kind_ctx_ptr{}) 301 { 302 } 303 ~result()304 ~result() noexcept 305 { 306 destroy(); 307 } 308 operator =(result && x)309 result & operator=( result && x ) noexcept 310 { 311 destroy(); 312 what_ = move_from(std::move(x)); 313 return *this; 314 } 315 316 template <class U> operator =(result<U> && x)317 result & operator=( result<U> && x ) noexcept 318 { 319 destroy(); 320 what_ = move_from(std::move(x)); 321 return *this; 322 } 323 operator bool() const324 explicit operator bool() const noexcept 325 { 326 return what_.kind() == result_discriminant::val; 327 } 328 value() const329 value_cref value() const & 330 { 331 enforce_value_state(); 332 return stored_; 333 } 334 value()335 value_ref value() & 336 { 337 enforce_value_state(); 338 return stored_; 339 } 340 value() const341 value_rv_cref value() const && 342 { 343 enforce_value_state(); 344 return std::move(stored_); 345 } 346 value()347 value_rv_ref value() && 348 { 349 enforce_value_state(); 350 return std::move(stored_); 351 } 352 operator *() const353 value_cref operator*() const & 354 { 355 return value(); 356 } 357 operator *()358 value_ref operator*() & 359 { 360 return value(); 361 } 362 operator *() const363 value_rv_cref operator*() const && 364 { 365 return value(); 366 } 367 operator *()368 value_rv_ref operator*() && 369 { 370 return value(); 371 } 372 operator ->() const373 value_type_const * operator->() const 374 { 375 return &value(); 376 } 377 operator ->()378 value_type * operator->() 379 { 380 return &value(); 381 } 382 error()383 error_result error() noexcept 384 { 385 return error_result{*this}; 386 } 387 388 template <class... Item> load(Item &&...item)389 error_id load( Item && ... item ) noexcept 390 { 391 return error_id(error()).load(std::forward<Item>(item)...); 392 } 393 }; 394 395 //////////////////////////////////////// 396 397 namespace leaf_detail 398 { 399 struct void_ { }; 400 } 401 402 template <> 403 class result<void>: 404 result<leaf_detail::void_> 405 { 406 using result_discriminant = leaf_detail::result_discriminant; 407 using void_ = leaf_detail::void_; 408 using base = result<void_>; 409 410 template <class U> 411 friend class result; 412 result(result_discriminant && what)413 result( result_discriminant && what ) noexcept: 414 base(std::move(what)) 415 { 416 } 417 418 public: 419 420 using value_type = void; 421 result(result && x)422 result( result && x ) noexcept: 423 base(std::move(x)) 424 { 425 } 426 result()427 result() noexcept 428 { 429 } 430 result(error_id err)431 result( error_id err ) noexcept: 432 base(err) 433 { 434 } 435 result(std::error_code const & ec)436 result( std::error_code const & ec ) noexcept: 437 base(ec) 438 { 439 } 440 441 template <class Enum> result(Enum e,typename std::enable_if<std::is_error_code_enum<Enum>::value,Enum>::type * =0)442 result( Enum e, typename std::enable_if<std::is_error_code_enum<Enum>::value, Enum>::type * = 0 ) noexcept: 443 base(e) 444 { 445 } 446 result(context_ptr && ctx)447 result( context_ptr && ctx ) noexcept: 448 base(std::move(ctx)) 449 { 450 } 451 ~result()452 ~result() noexcept 453 { 454 } 455 value() const456 void value() const 457 { 458 base::enforce_value_state(); 459 } 460 461 using base::operator=; 462 using base::operator bool; 463 using base::get_error_id; 464 using base::error; 465 using base::load; 466 }; 467 468 //////////////////////////////////////// 469 470 template <class R> 471 struct is_result_type; 472 473 template <class T> 474 struct is_result_type<result<T>>: std::true_type 475 { 476 }; 477 478 } } 479 480 #endif 481