AK: Add a functional-style Optional::map(mapper_function) API

This allows the user to transform the contents of the optional (if any
exists), without manually unwrapping and then rewrapping it.
This is needed by the Jakt runtime.
This commit is contained in:
Ali Mohammad Pur 2022-12-09 20:12:24 +03:30 committed by Ali Mohammad Pur
parent 5809b4aafa
commit cc948d06a6

View file

@ -9,11 +9,30 @@
#include <AK/Assertions.h>
#include <AK/StdLibExtras.h>
#include <AK/Try.h>
#include <AK/Types.h>
#include <AK/kmalloc.h>
namespace AK {
namespace Detail {
template<auto condition, typename T>
struct ConditionallyResultType;
template<typename T>
struct ConditionallyResultType<true, T> {
using Type = typename T::ResultType;
};
template<typename T>
struct ConditionallyResultType<false, T> {
using Type = T;
};
}
template<auto condition, typename T>
using ConditionallyResultType = typename Detail::ConditionallyResultType<condition, T>::Type;
// NOTE: If you're here because of an internal compiler error in GCC 10.3.0+,
// it's because of the following bug:
//
@ -214,6 +233,36 @@ public:
ALWAYS_INLINE T const* operator->() const { return &value(); }
ALWAYS_INLINE T* operator->() { return &value(); }
template<typename F, typename MappedType = decltype(declval<F>()(declval<T&>())), auto IsErrorOr = IsSpecializationOf<MappedType, ErrorOr>, typename OptionalType = Optional<ConditionallyResultType<IsErrorOr, MappedType>>>
ALWAYS_INLINE Conditional<IsErrorOr, ErrorOr<OptionalType>, OptionalType> map(F&& mapper)
{
if constexpr (IsErrorOr) {
if (m_has_value)
return OptionalType { TRY(mapper(value())) };
return OptionalType {};
} else {
if (m_has_value)
return OptionalType { mapper(value()) };
return OptionalType {};
}
}
template<typename F, typename MappedType = decltype(declval<F>()(declval<T&>())), auto IsErrorOr = IsSpecializationOf<MappedType, ErrorOr>, typename OptionalType = Optional<ConditionallyResultType<IsErrorOr, MappedType>>>
ALWAYS_INLINE Conditional<IsErrorOr, ErrorOr<OptionalType>, OptionalType> map(F&& mapper) const
{
if constexpr (IsErrorOr) {
if (m_has_value)
return OptionalType { TRY(mapper(value())) };
return OptionalType {};
} else {
if (m_has_value)
return OptionalType { mapper(value()) };
return OptionalType {};
}
}
private:
alignas(T) u8 m_storage[sizeof(T)];
bool m_has_value { false };
@ -375,6 +424,36 @@ public:
return {};
}
template<typename F, typename MappedType = decltype(declval<F>()(declval<T&>())), auto IsErrorOr = IsSpecializationOf<MappedType, ErrorOr>, typename OptionalType = Optional<ConditionallyResultType<IsErrorOr, MappedType>>>
ALWAYS_INLINE Conditional<IsErrorOr, ErrorOr<OptionalType>, OptionalType> map(F&& mapper)
{
if constexpr (IsErrorOr) {
if (m_pointer != nullptr)
return OptionalType { TRY(mapper(value())) };
return OptionalType {};
} else {
if (m_pointer != nullptr)
return OptionalType { mapper(value()) };
return OptionalType {};
}
}
template<typename F, typename MappedType = decltype(declval<F>()(declval<T&>())), auto IsErrorOr = IsSpecializationOf<MappedType, ErrorOr>, typename OptionalType = Optional<ConditionallyResultType<IsErrorOr, MappedType>>>
ALWAYS_INLINE Conditional<IsErrorOr, ErrorOr<OptionalType>, OptionalType> map(F&& mapper) const
{
if constexpr (IsErrorOr) {
if (m_pointer != nullptr)
return OptionalType { TRY(mapper(value())) };
return OptionalType {};
} else {
if (m_pointer != nullptr)
return OptionalType { mapper(value()) };
return OptionalType {};
}
}
private:
RemoveReference<T>* m_pointer { nullptr };
};