aboutsummaryrefslogtreecommitdiffstats
path: root/util/generic/maybe.h
diff options
context:
space:
mode:
authornedaiborschd <nedaiborschd@yandex-team.com>2024-02-02 09:29:53 +0300
committernedaiborschd <nedaiborschd@yandex-team.com>2024-02-02 09:47:20 +0300
commit1f22973dc28fb6b54a1e0827cae6f5dec464945b (patch)
treeea0bd4a1b7dc244923da65f8f6f792a2c49877f6 /util/generic/maybe.h
parent08647fb29bf35a7ae39ef78a53a673e268b5a436 (diff)
downloadydb-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.h135
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>();