diff --git a/repos/base/include/util/attempt.h b/repos/base/include/util/attempt.h index 4df518e352..7066a92002 100644 --- a/repos/base/include/util/attempt.h +++ b/repos/base/include/util/attempt.h @@ -14,7 +14,12 @@ #ifndef _INCLUDE__UTIL__ATTEMPT_H_ #define _INCLUDE__UTIL__ATTEMPT_H_ -namespace Genode { template <typename, typename> struct Attempt; } +#include <util/reconstructible.h> + +namespace Genode { + template <typename, typename> struct Attempt; + template <typename, typename> struct Unique_attempt; +} /** @@ -80,4 +85,67 @@ class Genode::Attempt bool failed() const { return !_ok; } }; + +/** + * Base type for the result of constrained RAM allocations + * + * The type is a unique pointer to the allocated RAM while also holding + * allocation-error information, following the conventions of 'Attempt'. + */ +template <typename RESULT, typename ERROR> +class Genode::Unique_attempt : Noncopyable +{ + private: + + Constructible<RESULT> _result { }; + + ERROR _error { }; + + protected: + + void _construct(auto &&... args) { _result.construct(args...); } + void _destruct (ERROR e) { _result.destruct(); _error = e; } + + public: + + Unique_attempt(auto &&... args) { _result.construct(args...); } + Unique_attempt(ERROR error) { _destruct(error); } + + template <typename RET> + RET convert(auto const &access_fn, auto const &fail_fn) + { + return _result.constructed() ? RET { access_fn(*_result) } + : RET { fail_fn(_error) }; + } + + template <typename RET> + RET convert(auto const &access_fn, auto const &fail_fn) const + { + return _result.constructed() ? RET { access_fn(*_result) } + : RET { fail_fn(_error) }; + } + + void with_result(auto const &access_fn, auto const &fail_fn) + { + _result.constructed() ? access_fn(*_result) : fail_fn(_error); + } + + void with_result(auto const &access_fn, auto const &fail_fn) const + { + _result.constructed() ? access_fn(*_result) : fail_fn(_error); + } + + void with_error(auto const &fail_fn) const + { + if (!_result.constructed()) + fail_fn(_error); + } + + bool operator == (ERROR const &rhs) const { + return failed() && (_error == rhs); } + + bool ok() const { return _result.constructed(); } + bool failed() const { return !_result.constructed(); } +}; + #endif /* _INCLUDE__UTIL__ATTEMPT_H_ */