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