mirror of
https://github.com/ETLCPP/etl.git
synced 2026-10-28 18:07:10 +08:00
Topic/optional monadic operations (#1501)
* Topic/optional monadic operations * topic/optional-monadic-operations: - added and_then, or_else, and transform to etl::optional with unit tests - added is_optional to optional.h, used in and_then and or_else to ensure that the returned type is an optional - implemented as ref-qualified overloads with C++11 compatible trailing return types, following the etl::expected implementation * Convert to C++11 style type traits * Coderabbit changes Constrain transform before forming etl::optional<U>. Remove references from monadic result types. * clang-format updates --------- Co-authored-by: John Wellbelove <john.wellbelove@etlcpp.com> Co-authored-by: John Wellbelove <jwellbelove@users.noreply.github.com>
This commit is contained in:
parent
01a07a1728
commit
f7520ad0bd
@ -36,6 +36,7 @@ SOFTWARE.
|
|||||||
#include "error_handler.h"
|
#include "error_handler.h"
|
||||||
#include "exception.h"
|
#include "exception.h"
|
||||||
#include "initializer_list.h"
|
#include "initializer_list.h"
|
||||||
|
#include "invoke.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "placement_new.h"
|
#include "placement_new.h"
|
||||||
#include "type_traits.h"
|
#include "type_traits.h"
|
||||||
@ -49,6 +50,16 @@ namespace etl
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
class optional;
|
class optional;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct is_optional : etl::false_type
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct is_optional<optional<T> > : etl::true_type
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
//*****************************************************************************
|
//*****************************************************************************
|
||||||
/// A null option type.
|
/// A null option type.
|
||||||
///\ingroup utilities
|
///\ingroup utilities
|
||||||
@ -174,10 +185,9 @@ namespace etl
|
|||||||
/// Constructs T in-place from U&&, without requiring T to be
|
/// Constructs T in-place from U&&, without requiring T to be
|
||||||
/// copy/move constructible.
|
/// copy/move constructible.
|
||||||
//***************************************************************************
|
//***************************************************************************
|
||||||
template <typename U,
|
template <typename U, etl::enable_if_t< etl::is_constructible<T, U&&>::value && !etl::is_same<etl::decay_t<U>, etl::in_place_t>::value
|
||||||
typename etl::enable_if< etl::is_constructible<T, U&&>::value && !etl::is_same<typename etl::decay<U>::type, etl::in_place_t>::value
|
&& !etl::is_same<etl::decay_t<U>, optional_impl>::value,
|
||||||
&& !etl::is_same<typename etl::decay<U>::type, optional_impl>::value,
|
int> = 0>
|
||||||
int>::type = 0>
|
|
||||||
ETL_CONSTEXPR20_STL optional_impl(U&& value_) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible<T, U&&>::value))
|
ETL_CONSTEXPR20_STL optional_impl(U&& value_) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible<T, U&&>::value))
|
||||||
{
|
{
|
||||||
storage.construct(etl::forward<U>(value_));
|
storage.construct(etl::forward<U>(value_));
|
||||||
@ -276,9 +286,7 @@ namespace etl
|
|||||||
/// Assignment operator from value type.
|
/// Assignment operator from value type.
|
||||||
//***************************************************************************
|
//***************************************************************************
|
||||||
#if ETL_USING_CPP11
|
#if ETL_USING_CPP11
|
||||||
template <typename U,
|
template <typename U, etl::enable_if_t< etl::is_constructible<T, U&&>::value && !etl::is_same<etl::decay_t<U>, optional_impl>::value, int> = 0>
|
||||||
typename etl::enable_if< etl::is_constructible<T, U&&>::value && !etl::is_same<typename etl::decay<U>::type, optional_impl>::value,
|
|
||||||
int>::type = 0>
|
|
||||||
ETL_CONSTEXPR20_STL optional_impl& operator=(U&& value_) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible<T, U&&>::value))
|
ETL_CONSTEXPR20_STL optional_impl& operator=(U&& value_) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible<T, U&&>::value))
|
||||||
{
|
{
|
||||||
storage.construct(etl::forward<U>(value_));
|
storage.construct(etl::forward<U>(value_));
|
||||||
@ -511,8 +519,7 @@ namespace etl
|
|||||||
//*******************************************
|
//*******************************************
|
||||||
/// Emplaces a value from initializer_list and arbitrary constructor arguments.
|
/// Emplaces a value from initializer_list and arbitrary constructor arguments.
|
||||||
//*******************************************
|
//*******************************************
|
||||||
template <typename U, typename... Args,
|
template <typename U, typename... Args, etl::enable_if_t< etl::is_constructible<T, std::initializer_list<U>&, Args...>::value, int> = 0 >
|
||||||
typename etl::enable_if< etl::is_constructible<T, std::initializer_list<U>&, Args...>::value, int>::type = 0 >
|
|
||||||
ETL_CONSTEXPR20_STL T& emplace(std::initializer_list<U> ilist, Args&&... args)
|
ETL_CONSTEXPR20_STL T& emplace(std::initializer_list<U> ilist, Args&&... args)
|
||||||
ETL_NOEXCEPT_IF((etl::is_nothrow_constructible<T, std::initializer_list<U>&, Args...>::value))
|
ETL_NOEXCEPT_IF((etl::is_nothrow_constructible<T, std::initializer_list<U>&, Args...>::value))
|
||||||
{
|
{
|
||||||
@ -1217,8 +1224,8 @@ namespace etl
|
|||||||
};
|
};
|
||||||
} // namespace private_optional
|
} // namespace private_optional
|
||||||
|
|
||||||
#define ETL_OPTIONAL_ENABLE_CPP14 typename etl::enable_if< etl::is_pod<typename etl::remove_cv<U>::type>::value, int>::type = 0
|
#define ETL_OPTIONAL_ENABLE_CPP14 etl::enable_if_t< etl::is_pod<typename etl::remove_cv<U>::type>::value, int> = 0
|
||||||
#define ETL_OPTIONAL_ENABLE_CPP20_STL typename etl::enable_if< !etl::is_pod<typename etl::remove_cv<U>::type>::value, int>::type = 0
|
#define ETL_OPTIONAL_ENABLE_CPP20_STL etl::enable_if_t< !etl::is_pod<typename etl::remove_cv<U>::type>::value, int> = 0
|
||||||
|
|
||||||
#define ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP14 \
|
#define ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP14 \
|
||||||
ETL_CONSTEXPR14 typename etl::enable_if< etl::is_pod<typename etl::remove_cv<T>::type>::value, bool>::type
|
ETL_CONSTEXPR14 typename etl::enable_if< etl::is_pod<typename etl::remove_cv<T>::type>::value, bool>::type
|
||||||
@ -1319,12 +1326,10 @@ namespace etl
|
|||||||
/// Constructs T in-place from U&&, without requiring T to be
|
/// Constructs T in-place from U&&, without requiring T to be
|
||||||
/// copy/move constructible.
|
/// copy/move constructible.
|
||||||
//***************************************************************************
|
//***************************************************************************
|
||||||
template < typename U,
|
template < typename U, etl::enable_if_t< etl::is_constructible<T, U&&>::value && !etl::is_same<etl::decay_t<U>, etl::optional<T>>::value
|
||||||
typename etl::enable_if< etl::is_constructible<T, U&&>::value && !etl::is_same<typename etl::decay<U>::type, etl::optional<T>>::value
|
&& !etl::is_same<etl::decay_t<U>, etl::in_place_t>::value
|
||||||
&& !etl::is_same<typename etl::decay<U>::type, etl::in_place_t>::value
|
&& !etl::is_same<etl::decay_t<U>, etl::nullopt_t>::value && etl::is_pod<etl::remove_cvref_t<T>>::value,
|
||||||
&& !etl::is_same<typename etl::decay<U>::type, etl::nullopt_t>::value
|
int> = 0>
|
||||||
&& etl::is_pod<typename etl::remove_cv<T>::type>::value,
|
|
||||||
int>::type = 0>
|
|
||||||
ETL_CONSTEXPR14 optional(U&& value_) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible<T, U&&>::value))
|
ETL_CONSTEXPR14 optional(U&& value_) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible<T, U&&>::value))
|
||||||
: impl_t(etl::forward<U>(value_))
|
: impl_t(etl::forward<U>(value_))
|
||||||
{
|
{
|
||||||
@ -1334,11 +1339,10 @@ namespace etl
|
|||||||
/// Converting constructor from value type.
|
/// Converting constructor from value type.
|
||||||
//***************************************************************************
|
//***************************************************************************
|
||||||
template < typename U,
|
template < typename U,
|
||||||
typename etl::enable_if< etl::is_constructible<T, U&&>::value && !etl::is_same<typename etl::decay<U>::type, etl::optional<T>>::value
|
etl::enable_if_t< etl::is_constructible<T, U&&>::value && !etl::is_same<etl::decay_t<U>, etl::optional<T>>::value
|
||||||
&& !etl::is_same<typename etl::decay<U>::type, etl::in_place_t>::value
|
&& !etl::is_same<etl::decay_t<U>, etl::in_place_t>::value && !etl::is_same<etl::decay_t<U>, etl::nullopt_t>::value
|
||||||
&& !etl::is_same<typename etl::decay<U>::type, etl::nullopt_t>::value
|
&& !etl::is_pod<etl::remove_cvref_t<T>>::value,
|
||||||
&& !etl::is_pod<typename etl::remove_cv<T>::type>::value,
|
int> = 0>
|
||||||
int>::type = 0>
|
|
||||||
ETL_CONSTEXPR20_STL optional(U&& value_) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible<T, U&&>::value))
|
ETL_CONSTEXPR20_STL optional(U&& value_) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible<T, U&&>::value))
|
||||||
: impl_t(etl::forward<U>(value_))
|
: impl_t(etl::forward<U>(value_))
|
||||||
{
|
{
|
||||||
@ -1446,11 +1450,9 @@ namespace etl
|
|||||||
//***************************************************************************
|
//***************************************************************************
|
||||||
/// Converting assignment operator from value type.
|
/// Converting assignment operator from value type.
|
||||||
//***************************************************************************
|
//***************************************************************************
|
||||||
template < typename U,
|
template < typename U, etl::enable_if_t< etl::is_constructible<T, U&&>::value && !etl::is_same<etl::decay_t<U>, etl::optional<T>>::value
|
||||||
typename etl::enable_if< etl::is_constructible<T, U&&>::value && !etl::is_same<typename etl::decay<U>::type, etl::optional<T>>::value
|
&& !etl::is_same<etl::decay_t<U>, etl::nullopt_t>::value && etl::is_pod<etl::remove_cvref_t<T>>::value,
|
||||||
&& !etl::is_same<typename etl::decay<U>::type, etl::nullopt_t>::value
|
int> = 0>
|
||||||
&& etl::is_pod<typename etl::remove_cv<T>::type>::value,
|
|
||||||
int>::type = 0>
|
|
||||||
ETL_CONSTEXPR14 optional& operator=(U&& value_) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible<T, U&&>::value))
|
ETL_CONSTEXPR14 optional& operator=(U&& value_) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible<T, U&&>::value))
|
||||||
{
|
{
|
||||||
impl_t::operator=(etl::forward<U>(value_));
|
impl_t::operator=(etl::forward<U>(value_));
|
||||||
@ -1462,10 +1464,9 @@ namespace etl
|
|||||||
/// Converting assignment operator from value type.
|
/// Converting assignment operator from value type.
|
||||||
//***************************************************************************
|
//***************************************************************************
|
||||||
template < typename U,
|
template < typename U,
|
||||||
typename etl::enable_if< etl::is_constructible<T, U&&>::value && !etl::is_same<typename etl::decay<U>::type, etl::optional<T>>::value
|
etl::enable_if_t< etl::is_constructible<T, U&&>::value && !etl::is_same<etl::decay_t<U>, etl::optional<T>>::value
|
||||||
&& !etl::is_same<typename etl::decay<U>::type, etl::nullopt_t>::value
|
&& !etl::is_same<etl::decay_t<U>, etl::nullopt_t>::value && !etl::is_pod<etl::remove_cvref_t<T>>::value,
|
||||||
&& !etl::is_pod<typename etl::remove_cv<T>::type>::value,
|
int> = 0>
|
||||||
int>::type = 0>
|
|
||||||
ETL_CONSTEXPR20_STL optional& operator=(U&& value_) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible<T, U&&>::value))
|
ETL_CONSTEXPR20_STL optional& operator=(U&& value_) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible<T, U&&>::value))
|
||||||
{
|
{
|
||||||
impl_t::operator=(etl::forward<U>(value_));
|
impl_t::operator=(etl::forward<U>(value_));
|
||||||
@ -1519,6 +1520,124 @@ namespace etl
|
|||||||
{
|
{
|
||||||
return this->has_value() ? this->operator->() + 1 : ETL_NULLPTR;
|
return this->has_value() ? this->operator->() + 1 : ETL_NULLPTR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ETL_USING_CPP11
|
||||||
|
template <typename F, typename U = etl::remove_cvref_t<etl::invoke_result_t<F, T&>>, etl::enable_if_t<!etl::is_void<U>::value, int> = 0>
|
||||||
|
auto transform(F&& f) & -> etl::optional<U>
|
||||||
|
{
|
||||||
|
return transform_impl<F, optional&, U, T&>(etl::forward<F>(f), *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F, typename U = etl::remove_cvref_t<etl::invoke_result_t<F, const T&>>, etl::enable_if_t<!etl::is_void<U>::value, int> = 0>
|
||||||
|
auto transform(F&& f) const& -> etl::optional<U>
|
||||||
|
{
|
||||||
|
return transform_impl<F, const optional&, U, const T&>(etl::forward<F>(f), *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F, typename U = etl::remove_cvref_t<etl::invoke_result_t<F, T&&>>, etl::enable_if_t<!etl::is_void<U>::value, int> = 0>
|
||||||
|
auto transform(F&& f) && -> etl::optional<U>
|
||||||
|
{
|
||||||
|
return transform_impl<F, optional&&, U, T&&>(etl::forward<F>(f), etl::move(*this));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F, typename U = etl::remove_cvref_t<etl::invoke_result_t<F, const T&&>>, etl::enable_if_t<!etl::is_void<U>::value, int> = 0>
|
||||||
|
auto transform(F&& f) const&& -> etl::optional<U>
|
||||||
|
{
|
||||||
|
return transform_impl<F, const optional&&, U, const T&&>(etl::forward<F>(f), etl::move(*this));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F, typename U = etl::remove_cvref_t< etl::invoke_result_t<F, T&>>>
|
||||||
|
auto and_then(F&& f) & -> U
|
||||||
|
{
|
||||||
|
return and_then_impl<F, optional&, U, T&>(etl::forward<F>(f), *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename F, typename U = etl::remove_cvref_t< etl::invoke_result_t<F, const T&>>>
|
||||||
|
auto and_then(F&& f) const& -> U
|
||||||
|
{
|
||||||
|
return and_then_impl<F, const optional&, U, const T&>(etl::forward<F>(f), *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F, typename U = etl::remove_cvref_t< etl::invoke_result_t<F, T&&>>>
|
||||||
|
auto and_then(F&& f) && -> U
|
||||||
|
{
|
||||||
|
return and_then_impl<F, optional&&, U, T&&>(etl::forward<F>(f), etl::move(*this));
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename F, typename U = etl::remove_cvref_t< etl::invoke_result_t<F, const T&&>>>
|
||||||
|
auto and_then(F&& f) const&& -> U
|
||||||
|
{
|
||||||
|
return and_then_impl<F, const optional&&, U, const T&&>(etl::forward<F>(f), etl::move(*this));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F, typename U = etl::remove_cvref_t<etl::invoke_result_t<F>>>
|
||||||
|
auto or_else(F&& f) & -> U
|
||||||
|
{
|
||||||
|
return or_else_impl<F, optional&, U>(etl::forward<F>(f), *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename F, typename U = etl::remove_cvref_t<etl::invoke_result_t<F>>>
|
||||||
|
auto or_else(F&& f) const& -> U
|
||||||
|
{
|
||||||
|
return or_else_impl<F, const optional&, U>(etl::forward<F>(f), *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F, typename U = etl::remove_cvref_t< etl::invoke_result_t<F>>>
|
||||||
|
auto or_else(F&& f) && -> U
|
||||||
|
{
|
||||||
|
return or_else_impl<F, optional&&, U>(etl::forward<F>(f), etl::move(*this));
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename F, typename U = etl::remove_cvref_t< etl::invoke_result_t<F>>>
|
||||||
|
auto or_else(F&& f) const&& -> U
|
||||||
|
{
|
||||||
|
return or_else_impl<F, const optional&&, U>(etl::forward<F>(f), etl::move(*this));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
template < typename F, typename TOpt, typename TRet, typename TValueRef, typename = etl::enable_if_t<!etl::is_void<TRet>::value>>
|
||||||
|
auto transform_impl(F&& f, TOpt&& opt) const -> etl::optional<TRet>
|
||||||
|
{
|
||||||
|
if (opt.has_value())
|
||||||
|
{
|
||||||
|
return etl::optional<TRet>(etl::invoke(etl::forward<F>(f), etl::forward<TValueRef>(*opt)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return etl::optional<TRet>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename F, typename TOpt, typename TRet, typename TValueRef,
|
||||||
|
typename = etl::enable_if_t<!etl::is_void<TRet>::value && etl::is_optional<TRet>::value>>
|
||||||
|
auto and_then_impl(F&& f, TOpt&& opt) const -> TRet
|
||||||
|
{
|
||||||
|
if (opt.has_value())
|
||||||
|
{
|
||||||
|
return etl::invoke(etl::forward<F>(f), etl::forward<TValueRef>(*opt));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return TRet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename F, typename TOpt, typename TRet,
|
||||||
|
typename = etl::enable_if_t< !etl::is_void<TRet>::value && etl::is_optional<TRet>::value && etl::is_same<typename TRet::value_type, T>::value>>
|
||||||
|
auto or_else_impl(F&& f, TOpt&& opt) const -> TRet
|
||||||
|
{
|
||||||
|
if (opt.has_value())
|
||||||
|
{
|
||||||
|
return TRet(etl::forward<TOpt>(opt));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return etl::invoke(etl::forward<F>(f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#include "private/diagnostic_uninitialized_push.h"
|
#include "private/diagnostic_uninitialized_push.h"
|
||||||
@ -2132,17 +2251,17 @@ namespace etl
|
|||||||
/// This overload participates in overload resolution only if
|
/// This overload participates in overload resolution only if
|
||||||
/// `etl::is_constructible_v<T, Args...>` is true.
|
/// `etl::is_constructible_v<T, Args...>` is true.
|
||||||
//***************************************************************************
|
//***************************************************************************
|
||||||
template <typename T, typename... Args, //
|
template <typename T, typename... Args, //
|
||||||
typename etl::enable_if< etl::is_constructible<T, Args...>::value, int>::type = 0, //
|
etl::enable_if_t< etl::is_constructible<T, Args...>::value, int> = 0, //
|
||||||
typename U = T, ETL_OPTIONAL_ENABLE_CPP14>
|
typename U = T, ETL_OPTIONAL_ENABLE_CPP14>
|
||||||
ETL_CONSTEXPR14 etl::optional<T> make_optional(Args&&... args) //
|
ETL_CONSTEXPR14 etl::optional<T> make_optional(Args&&... args) //
|
||||||
ETL_NOEXCEPT_IF((etl::is_nothrow_constructible<T, Args...>::value))
|
ETL_NOEXCEPT_IF((etl::is_nothrow_constructible<T, Args...>::value))
|
||||||
{
|
{
|
||||||
return etl::optional<T>(etl::in_place_t{}, etl::forward<Args>(args)...);
|
return etl::optional<T>(etl::in_place_t{}, etl::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
template <typename T, typename... Args, //
|
template <typename T, typename... Args, //
|
||||||
typename etl::enable_if< etl::is_constructible<T, Args...>::value, int>::type = 0, //
|
etl::enable_if_t< etl::is_constructible<T, Args...>::value, int> = 0, //
|
||||||
typename U = T, ETL_OPTIONAL_ENABLE_CPP20_STL>
|
typename U = T, ETL_OPTIONAL_ENABLE_CPP20_STL>
|
||||||
ETL_CONSTEXPR20_STL etl::optional<T> make_optional(Args&&... args) //
|
ETL_CONSTEXPR20_STL etl::optional<T> make_optional(Args&&... args) //
|
||||||
ETL_NOEXCEPT_IF((etl::is_nothrow_constructible<T, Args...>::value))
|
ETL_NOEXCEPT_IF((etl::is_nothrow_constructible<T, Args...>::value))
|
||||||
{
|
{
|
||||||
@ -2156,17 +2275,17 @@ namespace etl
|
|||||||
/// This overload participates in overload resolution only if
|
/// This overload participates in overload resolution only if
|
||||||
/// `etl::is_constructible_v<T, std::initializer_list<U>&, Args...>` is true.
|
/// `etl::is_constructible_v<T, std::initializer_list<U>&, Args...>` is true.
|
||||||
//***************************************************************************
|
//***************************************************************************
|
||||||
template <typename T, typename TL, typename... Args, //
|
template <typename T, typename TL, typename... Args, //
|
||||||
typename etl::enable_if< etl::is_constructible<T, std::initializer_list<TL>&, Args...>::value, int>::type = 0, //
|
etl::enable_if_t< etl::is_constructible<T, std::initializer_list<TL>&, Args...>::value, int> = 0, //
|
||||||
typename U = T, ETL_OPTIONAL_ENABLE_CPP14>
|
typename U = T, ETL_OPTIONAL_ENABLE_CPP14>
|
||||||
ETL_CONSTEXPR14 etl::optional<T> make_optional(std::initializer_list<TL> ilist, Args&&... args)
|
ETL_CONSTEXPR14 etl::optional<T> make_optional(std::initializer_list<TL> ilist, Args&&... args)
|
||||||
ETL_NOEXCEPT_IF((etl::is_nothrow_constructible<T, std::initializer_list<TL>&, Args...>::value))
|
ETL_NOEXCEPT_IF((etl::is_nothrow_constructible<T, std::initializer_list<TL>&, Args...>::value))
|
||||||
{
|
{
|
||||||
return etl::optional<T>(etl::in_place_t{}, ilist, etl::forward<Args>(args)...);
|
return etl::optional<T>(etl::in_place_t{}, ilist, etl::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
template <typename T, typename TL, typename... Args, //
|
template <typename T, typename TL, typename... Args, //
|
||||||
typename etl::enable_if< etl::is_constructible<T, std::initializer_list<TL>&, Args...>::value, int>::type = 0, //
|
etl::enable_if_t< etl::is_constructible<T, std::initializer_list<TL>&, Args...>::value, int> = 0, //
|
||||||
typename U = T, ETL_OPTIONAL_ENABLE_CPP20_STL>
|
typename U = T, ETL_OPTIONAL_ENABLE_CPP20_STL>
|
||||||
ETL_CONSTEXPR20_STL etl::optional<T> make_optional(std::initializer_list<TL> ilist, Args&&... args)
|
ETL_CONSTEXPR20_STL etl::optional<T> make_optional(std::initializer_list<TL> ilist, Args&&... args)
|
||||||
ETL_NOEXCEPT_IF((etl::is_nothrow_constructible<T, std::initializer_list<TL>&, Args...>::value))
|
ETL_NOEXCEPT_IF((etl::is_nothrow_constructible<T, std::initializer_list<TL>&, Args...>::value))
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1603,5 +1603,218 @@ namespace
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if ETL_USING_CPP11
|
||||||
|
//*************************************************************************
|
||||||
|
TEST(test_transform)
|
||||||
|
{
|
||||||
|
etl::optional<int> engaged(42);
|
||||||
|
etl::optional<int> empty;
|
||||||
|
|
||||||
|
etl::optional<int> doubled = engaged.transform([](int i) { return i * 2; });
|
||||||
|
CHECK_TRUE(doubled.has_value());
|
||||||
|
CHECK_EQUAL(84, doubled.value());
|
||||||
|
|
||||||
|
etl::optional<int> from_empty = empty.transform([](int i) { return i * 2; });
|
||||||
|
CHECK_FALSE(from_empty.has_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
//*************************************************************************
|
||||||
|
TEST(test_transform_const)
|
||||||
|
{
|
||||||
|
const etl::optional<int> engaged(42);
|
||||||
|
const etl::optional<int> empty;
|
||||||
|
|
||||||
|
etl::optional<int> doubled = engaged.transform([](int i) { return i * 2; });
|
||||||
|
CHECK_TRUE(doubled.has_value());
|
||||||
|
CHECK_EQUAL(84, doubled.value());
|
||||||
|
|
||||||
|
etl::optional<int> from_empty = empty.transform([](int i) { return i * 2; });
|
||||||
|
CHECK_FALSE(from_empty.has_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
//*************************************************************************
|
||||||
|
TEST(test_transform_change_type)
|
||||||
|
{
|
||||||
|
etl::optional<int> engaged(42);
|
||||||
|
etl::optional<int> empty;
|
||||||
|
|
||||||
|
etl::optional<std::string> text = engaged.transform([](int) { return std::string("forty two"); });
|
||||||
|
CHECK_TRUE(text.has_value());
|
||||||
|
CHECK_EQUAL("forty two", text.value());
|
||||||
|
|
||||||
|
etl::optional<std::string> text_from_empty = empty.transform([](int) { return std::string("forty two"); });
|
||||||
|
CHECK_FALSE(text_from_empty.has_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
//*************************************************************************
|
||||||
|
TEST(test_transform_non_pod)
|
||||||
|
{
|
||||||
|
etl::optional<Data> engaged(Data("transform"));
|
||||||
|
etl::optional<Data> empty;
|
||||||
|
|
||||||
|
etl::optional<size_t> length = engaged.transform([](const Data& d) { return d.value.size(); });
|
||||||
|
CHECK_TRUE(length.has_value());
|
||||||
|
CHECK_EQUAL(9U, length.value());
|
||||||
|
|
||||||
|
etl::optional<size_t> length_from_empty = empty.transform([](const Data& d) { return d.value.size(); });
|
||||||
|
CHECK_FALSE(length_from_empty.has_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
//*************************************************************************
|
||||||
|
TEST(test_transform_move)
|
||||||
|
{
|
||||||
|
etl::optional<DataM> engaged(DataM(42U));
|
||||||
|
|
||||||
|
etl::optional<DataM> moved = etl::move(engaged).transform([](DataM&& d) { return DataM(etl::move(d)); });
|
||||||
|
CHECK_TRUE(moved.has_value());
|
||||||
|
CHECK_TRUE(moved.value().valid);
|
||||||
|
CHECK_EQUAL(42U, moved.value().value);
|
||||||
|
CHECK_FALSE(engaged.value().valid);
|
||||||
|
|
||||||
|
etl::optional<DataM> empty;
|
||||||
|
etl::optional<DataM> from_empty = etl::move(empty).transform([](DataM&& d) { return DataM(etl::move(d)); });
|
||||||
|
CHECK_FALSE(from_empty.has_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
//*************************************************************************
|
||||||
|
TEST(test_and_then)
|
||||||
|
{
|
||||||
|
etl::optional<int> engaged(42);
|
||||||
|
etl::optional<int> empty;
|
||||||
|
|
||||||
|
etl::optional<int> incremented = engaged.and_then([](int i) { return etl::optional<int>(i + 1); });
|
||||||
|
CHECK_TRUE(incremented.has_value());
|
||||||
|
CHECK_EQUAL(43, incremented.value());
|
||||||
|
|
||||||
|
etl::optional<int> from_empty = empty.and_then([](int i) { return etl::optional<int>(i + 1); });
|
||||||
|
CHECK_FALSE(from_empty.has_value());
|
||||||
|
|
||||||
|
etl::optional<int> rejected = engaged.and_then([](int) { return etl::optional<int>(); });
|
||||||
|
CHECK_FALSE(rejected.has_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
//*************************************************************************
|
||||||
|
TEST(test_and_then_const)
|
||||||
|
{
|
||||||
|
const etl::optional<int> engaged(42);
|
||||||
|
const etl::optional<int> empty;
|
||||||
|
|
||||||
|
etl::optional<int> incremented = engaged.and_then([](int i) { return etl::optional<int>(i + 1); });
|
||||||
|
CHECK_TRUE(incremented.has_value());
|
||||||
|
CHECK_EQUAL(43, incremented.value());
|
||||||
|
|
||||||
|
etl::optional<int> from_empty = empty.and_then([](int i) { return etl::optional<int>(i + 1); });
|
||||||
|
CHECK_FALSE(from_empty.has_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
//*************************************************************************
|
||||||
|
TEST(test_and_then_change_type)
|
||||||
|
{
|
||||||
|
etl::optional<int> engaged(42);
|
||||||
|
etl::optional<int> empty;
|
||||||
|
|
||||||
|
etl::optional<std::string> text = engaged.and_then([](int) { return etl::optional<std::string>("forty two"); });
|
||||||
|
CHECK_TRUE(text.has_value());
|
||||||
|
CHECK_EQUAL("forty two", text.value());
|
||||||
|
|
||||||
|
etl::optional<std::string> text_from_empty = empty.and_then([](int) { return etl::optional<std::string>("forty two"); });
|
||||||
|
CHECK_FALSE(text_from_empty.has_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
//*************************************************************************
|
||||||
|
TEST(test_and_then_move)
|
||||||
|
{
|
||||||
|
etl::optional<DataM> engaged(DataM(42U));
|
||||||
|
|
||||||
|
etl::optional<uint32_t> value = etl::move(engaged).and_then([](DataM&& d) { return etl::optional<uint32_t>(d.value); });
|
||||||
|
CHECK_TRUE(value.has_value());
|
||||||
|
CHECK_EQUAL(42U, value.value());
|
||||||
|
|
||||||
|
etl::optional<DataM> empty;
|
||||||
|
etl::optional<uint32_t> from_empty = etl::move(empty).and_then([](DataM&& d) { return etl::optional<uint32_t>(d.value); });
|
||||||
|
CHECK_FALSE(from_empty.has_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
//*************************************************************************
|
||||||
|
TEST(test_or_else)
|
||||||
|
{
|
||||||
|
etl::optional<int> engaged(42);
|
||||||
|
etl::optional<int> empty;
|
||||||
|
bool called = false;
|
||||||
|
|
||||||
|
etl::optional<int> from_engaged = engaged.or_else(
|
||||||
|
[&called]()
|
||||||
|
{
|
||||||
|
called = true;
|
||||||
|
return etl::optional<int>(99);
|
||||||
|
});
|
||||||
|
CHECK_TRUE(from_engaged.has_value());
|
||||||
|
CHECK_EQUAL(42, from_engaged.value());
|
||||||
|
CHECK_FALSE(called);
|
||||||
|
|
||||||
|
etl::optional<int> from_empty = empty.or_else(
|
||||||
|
[&called]()
|
||||||
|
{
|
||||||
|
called = true;
|
||||||
|
return etl::optional<int>(99);
|
||||||
|
});
|
||||||
|
CHECK_TRUE(from_empty.has_value());
|
||||||
|
CHECK_EQUAL(99, from_empty.value());
|
||||||
|
CHECK_TRUE(called);
|
||||||
|
|
||||||
|
etl::optional<int> still_empty = empty.or_else([]() { return etl::optional<int>(); });
|
||||||
|
CHECK_FALSE(still_empty.has_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
//*************************************************************************
|
||||||
|
TEST(test_or_else_const)
|
||||||
|
{
|
||||||
|
const etl::optional<int> engaged(42);
|
||||||
|
const etl::optional<int> empty;
|
||||||
|
|
||||||
|
etl::optional<int> from_engaged = engaged.or_else([]() { return etl::optional<int>(99); });
|
||||||
|
CHECK_TRUE(from_engaged.has_value());
|
||||||
|
CHECK_EQUAL(42, from_engaged.value());
|
||||||
|
|
||||||
|
etl::optional<int> from_empty = empty.or_else([]() { return etl::optional<int>(99); });
|
||||||
|
CHECK_TRUE(from_empty.has_value());
|
||||||
|
CHECK_EQUAL(99, from_empty.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
//*************************************************************************
|
||||||
|
TEST(test_or_else_move)
|
||||||
|
{
|
||||||
|
etl::optional<DataM> engaged(DataM(42U));
|
||||||
|
|
||||||
|
etl::optional<DataM> from_engaged = etl::move(engaged).or_else([]() { return etl::optional<DataM>(DataM(99U)); });
|
||||||
|
CHECK_TRUE(from_engaged.has_value());
|
||||||
|
CHECK_EQUAL(42U, from_engaged.value().value);
|
||||||
|
|
||||||
|
etl::optional<DataM> empty;
|
||||||
|
etl::optional<DataM> from_empty = etl::move(empty).or_else([]() { return etl::optional<DataM>(DataM(99U)); });
|
||||||
|
CHECK_TRUE(from_empty.has_value());
|
||||||
|
CHECK_EQUAL(99U, from_empty.value().value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//*************************************************************************
|
||||||
|
TEST(test_monadic_chaining)
|
||||||
|
{
|
||||||
|
etl::optional<int> engaged(8);
|
||||||
|
etl::optional<int> empty;
|
||||||
|
|
||||||
|
etl::optional<int> result = engaged.transform([](int i) { return i * 2; })
|
||||||
|
.and_then([](int i) { return etl::optional<int>(i + 1); })
|
||||||
|
.or_else([]() { return etl::optional<int>(0); });
|
||||||
|
CHECK_TRUE(result.has_value());
|
||||||
|
CHECK_EQUAL(17, result.value());
|
||||||
|
|
||||||
|
etl::optional<int> result_from_empty = empty.transform([](int i) { return i * 2; })
|
||||||
|
.and_then([](int i) { return etl::optional<int>(i + 1); })
|
||||||
|
.or_else([]() { return etl::optional<int>(123); });
|
||||||
|
CHECK_TRUE(result_from_empty.has_value());
|
||||||
|
CHECK_EQUAL(123, result_from_empty.value());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user