1 /* Copyright (C) 2012-2021 by László Nagy 2 This file is part of Bear. 3 4 Bear is a tool to generate compilation database for clang tooling. 5 6 Bear is free software: you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation, either version 3 of the License, or 9 (at your option) any later version. 10 11 Bear is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #pragma once 21 22 #include <functional> 23 #include <stdexcept> 24 #include <type_traits> 25 #include <cstring> 26 27 namespace rust { 28 29 namespace types { 30 31 template <typename T> 32 struct Ok { OkOk33 explicit Ok(const T& value) 34 : value_(value) 35 { 36 } 37 OkOk38 explicit Ok(T&& value) noexcept 39 : value_(std::move(value)) 40 { 41 } 42 43 T value_; 44 }; 45 46 template <typename E> 47 struct Err { ErrErr48 explicit Err(const E& value) 49 : value_(value) 50 { 51 } 52 ErrErr53 explicit Err(E&& value) noexcept 54 : value_(value) 55 { 56 } 57 58 E value_; 59 }; 60 } 61 62 // Most of the internal is about to implement a storage for the values. 63 // 64 // This can be done with `std::variant` which is available in C++17. 65 // To make this code more portable the implementation is using C++14 66 // language constructs only. 67 namespace internals { 68 69 template <typename T, typename E> 70 struct Storage { 71 static constexpr size_t Size = sizeof(T) > sizeof(E) ? sizeof(T) : sizeof(E); 72 static constexpr size_t Align = sizeof(T) > sizeof(E) ? alignof(T) : alignof(E); 73 74 typedef typename std::aligned_storage<Size, Align>::type type; 75 StorageStorage76 Storage() 77 : initialized_(false) 78 { 79 } 80 constructStorage81 void construct(types::Ok<T> ok) 82 { 83 new (&storage_) T(std::move(ok.value_)); 84 initialized_ = true; 85 } 86 constructStorage87 void construct(types::Err<E> err) 88 { 89 new (&storage_) E(std::move(err.value_)); 90 initialized_ = true; 91 } 92 93 template <typename U> raw_constructStorage94 void raw_construct(U&& value) 95 { 96 typedef typename std::decay<U>::type CleanU; 97 98 new (&storage_) CleanU(std::forward<U>(value)); 99 initialized_ = true; 100 } 101 102 template <typename U> getStorage103 const U& get() const 104 { 105 return *reinterpret_cast<const U*>(&storage_); 106 } 107 108 template <typename U> getStorage109 U& get() 110 { 111 return *reinterpret_cast<U*>(&storage_); 112 } 113 destroy_okStorage114 void destroy_ok() 115 { 116 if (initialized_) { 117 get<T>().~T(); 118 initialized_ = false; 119 } 120 } 121 destroy_errStorage122 void destroy_err() 123 { 124 if (initialized_) { 125 get<E>().~E(); 126 initialized_ = false; 127 } 128 } 129 130 type storage_; 131 bool initialized_; 132 }; 133 } 134 135 // Util methods which help to create `Result` types easier. 136 template <typename T, typename CleanT = typename std::decay<T>::type> Ok(T && value)137 types::Ok<CleanT> Ok(T&& value) 138 { 139 return types::Ok<CleanT>(std::forward<T>(value)); 140 } 141 142 template <typename E, typename CleanE = typename std::decay<E>::type> Err(E && value)143 types::Err<CleanE> Err(E&& value) 144 { 145 return types::Err<CleanE>(std::forward<E>(value)); 146 } 147 148 // This class represent a result of a computation. 149 // 150 // It's planned to implement such construct in later C++ language dialects. 151 // That is referred as `std::expected` in proposals. 152 // 153 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0323r3.pdf 154 // 155 // This implementation is more close to the rust language `std::result::Result` 156 // type. Where the public functions are following the namings of the rust 157 // implementation. 158 // 159 // The public interface is also trimmed down. The main motivation was: 160 // 161 // * remove the access methods `ok()` or `err()` methods. 162 // (std::optional in C++17 only) 163 // * remove the access methods `unwrap()` or `expect(...)` methods. 164 // (no exception, would be hard to signal wrong access.) 165 // 166 // Contrast to the C++ std::expected, this type is encourage to use 167 // higher order functions (monadic methods) to use the results. 168 // 169 // https://doc.rust-lang.org/std/result/enum.Result.html 170 template <typename T, typename E = std::runtime_error> 171 class Result { 172 public: 173 Result() = delete; 174 ~Result(); 175 176 Result(Result&& other) noexcept; 177 Result(const Result& other); 178 179 Result& operator=(Result&& other) noexcept; 180 Result& operator=(const Result& other); 181 182 Result(types::Ok<T>&& ok) noexcept; 183 Result(types::Err<E>&& err) noexcept; 184 185 public: 186 [[nodiscard]] bool is_ok() const; 187 [[nodiscard]] bool is_err() const; 188 189 template <typename U> 190 Result<U, E> map(std::function<U(const T&)> const& f) const; 191 192 template <typename U> 193 Result<U, E> map_or(U&& value, std::function<U(const T&)> const& func) const; 194 195 template <typename U> 196 Result<U, E> map_or_else(std::function<U(const E&)> const& provider, std::function<U(const T&)> const& f) const; 197 198 template <typename F> 199 Result<T, F> map_err(std::function<F(const E&)> const& f) const; 200 201 template <typename U> 202 Result<U, E> and_(const Result<U, E>& rhs) const; 203 204 template <typename U> 205 Result<U, E> and_then(std::function<Result<U, E>(const T&)> const& f) const; 206 207 Result<T, E> or_(const Result<T, E>& rhs) const; 208 209 Result<T, E> or_else(std::function<Result<T, E>(const E&)> const& f) const; 210 211 const T& unwrap() const; 212 const E& unwrap_err() const; 213 const T& unwrap_or(const T& value) const; 214 215 T unwrap_or_else(std::function<T(const E&)> const& provider) const; 216 217 const Result<T, E>& on_success(std::function<void(const T&)> const& f) const; 218 const Result<T, E>& on_error(std::function<void(const E&)> const& f) const; 219 220 private: 221 bool ok_; 222 internals::Storage<T, E> storage_; 223 }; 224 225 template <typename T> 226 bool operator==(Result<T, std::runtime_error> const &lhs, Result<T, std::runtime_error> const &rhs) { 227 return (lhs.is_ok() && rhs.is_ok() && (lhs.unwrap() == rhs.unwrap())) || 228 (lhs.is_err() && rhs.is_err() && (std::strcmp(lhs.unwrap_err().what(), rhs.unwrap_err().what()) == 0)); 229 } 230 231 template <typename T, typename E> 232 bool operator==(Result<T, E> const &lhs, Result<T, E> const &rhs) { 233 return (lhs.is_ok() && rhs.is_ok() && (lhs.unwrap() == rhs.unwrap())) || 234 (lhs.is_err() && rhs.is_err() && (lhs.unwrap_err() == rhs.unwrap_err())); 235 } 236 237 template <typename T1, typename T2> merge(const Result<T1> & t1,const Result<T2> & t2)238 Result<std::tuple<T1, T2>> merge(const Result<T1>& t1, const Result<T2>& t2) 239 { 240 return t1.template and_then<std::tuple<T1, T2>>([&t2](auto& t1_value) { 241 return t2.template map<std::tuple<T1, T2>>([&t1_value](auto& t2_value) { 242 return std::make_tuple(t1_value, t2_value); 243 }); 244 }); 245 } 246 247 template <typename T1, typename T2, typename T3> merge(const Result<T1> & t1,const Result<T2> & t2,const Result<T3> & t3)248 Result<std::tuple<T1, T2, T3>> merge(const Result<T1>& t1, const Result<T2>& t2, const Result<T3>& t3) 249 { 250 return t1.template and_then<std::tuple<T1, T2, T3>>([&t2, &t3](auto& t1_value) { 251 return t2.template and_then<std::tuple<T1, T2, T3>>([&t1_value, &t3](auto& t2_value) { 252 return t3.template map<std::tuple<T1, T2, T3>>([&t1_value, &t2_value](auto& t3_value) { 253 return std::make_tuple(t1_value, t2_value, t3_value); 254 }); 255 }); 256 }); 257 } 258 259 template<typename T1, typename T2, typename T3, typename T4> 260 Result<std::tuple<T1, T2, T3, T4>> merge(const Result<T1> & t1,const Result<T2> & t2,const Result<T3> & t3,const Result<T4> & t4)261 merge(const Result<T1> &t1, const Result<T2> &t2, const Result<T3> &t3, const Result<T4> &t4) { 262 return merge(merge(t1, t2), merge(t3, t4)) 263 .template map<std::tuple<T1, T2, T3, T4>>([](auto tuple) { 264 const auto&[t12, t34] = tuple; 265 const auto&[t1, t2] = t12; 266 const auto&[t3, t4] = t34; 267 return std::make_tuple(t1, t2, t3, t4); 268 }); 269 } 270 271 template <typename T, typename E> ~Result()272 Result<T, E>::~Result() 273 { 274 if (ok_) { 275 storage_.destroy_ok(); 276 } else { 277 storage_.destroy_err(); 278 } 279 } 280 281 template <typename T, typename E> Result(Result<T,E> && other)282 Result<T, E>::Result(Result<T, E>&& other) noexcept 283 : ok_(other.ok_) 284 , storage_() 285 { 286 if (other.ok_) { 287 storage_.raw_construct(std::move(other.storage_.template get<T>())); 288 other.storage_.destroy_ok(); 289 } else { 290 storage_.raw_construct(std::move(other.storage_.template get<E>())); 291 other.storage_.destroy_err(); 292 } 293 } 294 295 template <typename T, typename E> Result(const Result<T,E> & other)296 Result<T, E>::Result(const Result<T, E>& other) 297 : ok_(other.ok_) 298 , storage_() 299 { 300 if (other.ok_) { 301 storage_.raw_construct(other.storage_.template get<T>()); 302 } else { 303 storage_.raw_construct(other.storage_.template get<E>()); 304 } 305 } 306 307 template <typename T, typename E> 308 Result<T, E>& Result<T, E>::operator=(Result<T, E>&& other) noexcept 309 { 310 if (this != &other) { 311 if (ok_) { 312 storage_.destroy_ok(); 313 ok_ = other.ok_; 314 if (other.ok_) { 315 storage_.raw_construct(std::move(other.storage_.template get<T>())); 316 other.storage_.destroy_ok(); 317 } else { 318 storage_.raw_construct(std::move(other.storage_.template get<E>())); 319 other.storage_.destroy_err(); 320 } 321 } else { 322 storage_.destroy_err(); 323 ok_ = other.ok_; 324 if (other.ok_) { 325 storage_.raw_construct(std::move(other.storage_.template get<T>())); 326 other.storage_.destroy_ok(); 327 } else { 328 storage_.raw_construct(std::move(other.storage_.template get<E>())); 329 other.storage_.destroy_err(); 330 } 331 } 332 } 333 return *this; 334 } 335 336 template <typename T, typename E> 337 Result<T, E>& Result<T, E>::operator=(const Result<T, E>& other) 338 { 339 if (this != &other) { 340 if (ok_) { 341 storage_.destroy_ok(); 342 ok_ = other.ok_; 343 if (other.ok_) { 344 storage_.raw_construct(other.storage_.template get<T>()); 345 } else { 346 storage_.raw_construct(other.storage_.template get<E>()); 347 } 348 } else { 349 storage_.destroy_err(); 350 ok_ = other.ok_; 351 if (other.ok_) { 352 storage_.raw_construct(other.storage_.template get<T>()); 353 } else { 354 storage_.raw_construct(other.storage_.template get<E>()); 355 } 356 } 357 } 358 return *this; 359 } 360 361 template <typename T, typename E> Result(types::Ok<T> && ok)362 Result<T, E>::Result(types::Ok<T>&& ok) noexcept 363 : ok_(true) 364 , storage_() 365 { 366 storage_.construct(std::move(ok)); 367 } 368 369 template <typename T, typename E> Result(types::Err<E> && err)370 Result<T, E>::Result(types::Err<E>&& err) noexcept 371 : ok_(false) 372 , storage_() 373 { 374 storage_.construct(std::move(err)); 375 } 376 377 template <typename T, typename E> is_ok()378 bool Result<T, E>::is_ok() const 379 { 380 return ok_; 381 } 382 383 template <typename T, typename E> is_err()384 bool Result<T, E>::is_err() const 385 { 386 return !ok_; 387 } 388 389 template <typename T, typename E> 390 template <typename U> map(const std::function<U (const T &)> & f)391 Result<U, E> Result<T, E>::map(const std::function<U(const T&)>& f) const 392 { 393 if (ok_) { 394 auto res = f(storage_.template get<T>()); 395 return types::Ok<U>(std::move(res)); 396 } else { 397 return types::Err<E>(storage_.template get<E>()); 398 } 399 } 400 401 template <typename T, typename E> 402 template <typename U> map_or(U && value,const std::function<U (const T &)> & f)403 Result<U, E> Result<T, E>::map_or(U&& value, const std::function<U(const T&)>& f) const 404 { 405 if (ok_) { 406 auto res = f(storage_.template get<T>()); 407 return types::Ok<U>(std::move(res)); 408 } else { 409 return types::Ok<U>(value); 410 } 411 } 412 413 template <typename T, typename E> 414 template <typename U> map_or_else(const std::function<U (const E &)> & provider,const std::function<U (const T &)> & f)415 Result<U, E> Result<T, E>::map_or_else(const std::function<U(const E&)>& provider, const std::function<U(const T&)>& f) const 416 { 417 if (ok_) { 418 auto res = f(storage_.template get<T>()); 419 return types::Ok<U>(std::move(res)); 420 } else { 421 auto res = provider(storage_.template get<E>()); 422 return types::Ok<U>(std::move(res)); 423 } 424 } 425 426 template <typename T, typename E> 427 template <typename F> map_err(const std::function<F (const E &)> & f)428 Result<T, F> Result<T, E>::map_err(const std::function<F(const E&)>& f) const 429 { 430 if (ok_) { 431 auto res = storage_.template get<T>(); 432 return types::Ok<T>(std::move(res)); 433 } else { 434 auto res = f(storage_.template get<E>()); 435 return types::Err<F>(std::move(res)); 436 } 437 } 438 439 template <typename T, typename E> 440 template <typename U> and_(const Result<U,E> & rhs)441 Result<U, E> Result<T, E>::and_(const Result<U, E>& rhs) const 442 { 443 if (ok_) { 444 return rhs; 445 } else { 446 auto res = storage_.template get<E>(); 447 return types::Err<E>(std::move(res)); 448 } 449 } 450 451 template <typename T, typename E> 452 template <typename U> and_then(const std::function<Result<U,E> (const T &)> & f)453 Result<U, E> Result<T, E>::and_then(const std::function<Result<U, E>(const T&)>& f) const 454 { 455 if (ok_) { 456 return f(storage_.template get<T>()); 457 } else { 458 return types::Err<E>(storage_.template get<E>()); 459 } 460 } 461 462 template <typename T, typename E> or_(const Result<T,E> & rhs)463 Result<T, E> Result<T, E>::or_(const Result<T, E>& rhs) const 464 { 465 if (ok_) { 466 return *this; 467 } else { 468 return rhs; 469 } 470 } 471 472 template <typename T, typename E> or_else(const std::function<Result<T,E> (const E &)> & f)473 Result<T, E> Result<T, E>::or_else(const std::function<Result<T, E>(const E&)>& f) const 474 { 475 if (ok_) { 476 return *this; 477 } else { 478 return f(storage_.template get<E>()); 479 } 480 } 481 482 template <typename T, typename E> unwrap()483 const T& Result<T, E>::unwrap() const 484 { 485 return storage_.template get<T>(); 486 } 487 488 template <typename T, typename E> unwrap_err()489 const E& Result<T, E>::unwrap_err() const 490 { 491 return storage_.template get<E>(); 492 } 493 494 template <typename T, typename E> unwrap_or(const T & value)495 const T& Result<T, E>::unwrap_or(const T& value) const 496 { 497 if (ok_) { 498 return storage_.template get<T>(); 499 } else { 500 return value; 501 } 502 } 503 504 template <typename T, typename E> unwrap_or_else(const std::function<T (const E &)> & provider)505 T Result<T, E>::unwrap_or_else(const std::function<T(const E&)>& provider) const 506 { 507 if (ok_) { 508 return storage_.template get<T>(); 509 } else { 510 return provider(storage_.template get<E>()); 511 } 512 } 513 514 template <typename T, typename E> on_success(const std::function<void (const T &)> & f)515 const Result<T, E>& Result<T, E>::on_success(const std::function<void(const T&)>& f) const 516 { 517 if (ok_) { 518 f(storage_.template get<T>()); 519 } 520 return *this; 521 } 522 523 template <typename T, typename E> on_error(const std::function<void (const E &)> & f)524 const Result<T, E>& Result<T, E>::on_error(const std::function<void(const E&)>& f) const 525 { 526 if (!ok_) { 527 f(storage_.template get<E>()); 528 } 529 return *this; 530 } 531 } 532