diff options
author | nedaiborschd <nedaiborschd@yandex-team.com> | 2024-02-02 09:29:53 +0300 |
---|---|---|
committer | nedaiborschd <nedaiborschd@yandex-team.com> | 2024-02-02 09:47:20 +0300 |
commit | 1f22973dc28fb6b54a1e0827cae6f5dec464945b (patch) | |
tree | ea0bd4a1b7dc244923da65f8f6f792a2c49877f6 /util/generic/maybe.h | |
parent | 08647fb29bf35a7ae39ef78a53a673e268b5a436 (diff) | |
download | ydb-1f22973dc28fb6b54a1e0827cae6f5dec464945b.tar.gz |
TMaybe Monadic operations
Add monadic operations to TMaybe.
Added methods: AndThen, OrElse, Transform.
Diffstat (limited to 'util/generic/maybe.h')
-rw-r--r-- | util/generic/maybe.h | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/util/generic/maybe.h b/util/generic/maybe.h index 8498afda34..b10c07e5fb 100644 --- a/util/generic/maybe.h +++ b/util/generic/maybe.h @@ -152,6 +152,29 @@ private: (!std::is_scalar<T>::value || !std::is_same<UDec, T>::value); }; + template <typename> + struct TIsMaybe { + static constexpr bool value = false; + }; + + template <typename U, typename P> + struct TIsMaybe<TMaybe<U, P>> { + static constexpr bool value = true; + }; + + template <typename F, typename... Args> + static auto Call(F&& f, Args&&... args) -> decltype(std::forward<F>(f)(std::forward<Args>(args)...)); + + template <typename F, typename... Args> + using TCallResult = std::remove_reference_t<std::remove_cv_t<decltype(Call(std::declval<F>(), std::declval<Args>()...))>>; + + template <typename U, typename F> + static constexpr F&& CheckReturnsMaybe(F&& f) { + using ReturnType = TCallResult<F, U>; + static_assert(TIsMaybe<ReturnType>::value, "Function must return TMaybe"); + return f; + } + using TBase = TMaybeBase<T>; public: @@ -378,6 +401,118 @@ public: return Defined() ? *this : elseValue; } + template <typename F> + constexpr auto AndThen(F&& func) & { + using ReturnType = TCallResult<F, T&>; + + if (Defined()) { + return std::forward<F>(CheckReturnsMaybe<T&>(func))(*Data()); + } + + return ReturnType{}; + } + + template <typename F> + constexpr auto AndThen(F&& func) const& { + using ReturnType = TCallResult<F, const T&>; + + if (Defined()) { + return std::forward<F>(CheckReturnsMaybe<const T&>(func))(*Data()); + } + + return ReturnType{}; + } + + template <typename F> + constexpr auto AndThen(F&& func) && { + using ReturnType = TCallResult<F, T&&>; + + if (Defined()) { + return std::forward<F>(CheckReturnsMaybe<T&&>(func))(std::move(*Data())); + } + + return ReturnType{}; + } + + template <typename F> + constexpr auto AndThen(F&& func) const&& { + using ReturnType = TCallResult<F, const T&&>; + + if (Defined()) { + return std::forward<F>(CheckReturnsMaybe<const T&&>(func))(std::move(*Data())); + } + + return ReturnType{}; + } + + template <typename F> + constexpr auto Transform(F&& func) & { + using ReturnType = TMaybe<TCallResult<F, T&>>; + + if (Defined()) { + return ReturnType(std::forward<F>(func)(*Data())); + } + + return ReturnType{}; + } + + template <typename F> + constexpr auto Transform(F&& func) const& { + using ReturnType = TMaybe<TCallResult<F, const T&>>; + + if (Defined()) { + return ReturnType(std::forward<F>(func)(*Data())); + } + + return ReturnType{}; + } + + template <typename F> + constexpr auto Transform(F&& func) && { + using ReturnType = TMaybe<TCallResult<F, T&&>>; + + if (Defined()) { + return ReturnType(std::forward<F>(func)(std::move(*Data()))); + } + + return ReturnType{}; + } + + template <typename F> + constexpr auto Transform(F&& func) const&& { + using ReturnType = TMaybe<TCallResult<F, const T&&>>; + + if (Defined()) { + return ReturnType(std::forward<F>(func)(std::move(*Data()))); + } + + return ReturnType{}; + } + + template <typename F> + constexpr TMaybe Or(F&& func) const& { + using ResultType = TCallResult<F>; + static_assert(std::is_same<ResultType, TMaybe>::value, "Function must return TMaybe with the same type"); + + if (Defined()) { + return *this; + } + + return std::forward<F>(func)(); + } + + template <typename F> + constexpr TMaybe Or(F&& func) && { + using ResultType = TCallResult<F>; + static_assert(std::is_same<ResultType, TMaybe>::value, "Function must return TMaybe with the same type"); + + if (Defined()) { + return std::move(*this); + } + + return std::forward<F>(func)(); + } + template <typename U> TMaybe<U, Policy> Cast() const { return Defined() ? TMaybe<U, Policy>(*Data()) : TMaybe<U, Policy>(); |