From 2dfaeab7c22f5026817135f72e2b74411e80d114 Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Fri, 4 Apr 2025 12:45:12 +0200 Subject: [PATCH] util/attempt.h: add 'Unique_attempt' utility The new variant combines the attempt with unique-pointer semantics and is thereby usable for returning non-copyable objects such as RAM 'Allocation'. Issue #5502 --- repos/base/include/util/attempt.h | 70 ++++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) 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 struct Attempt; } +#include + +namespace Genode { + template struct Attempt; + template 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 +class Genode::Unique_attempt : Noncopyable +{ + private: + + Constructible _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 + RET convert(auto const &access_fn, auto const &fail_fn) + { + return _result.constructed() ? RET { access_fn(*_result) } + : RET { fail_fn(_error) }; + } + + template + 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_ */