forked from enlightenment/efl
eina_cxx: Fix compatibility between eina::optionals of convertible types
Now an eina::optional that wraps a specific type can be constructed or have content assigned to it using another eina::optional that wraps a different type, provided that the two wrapped types are convertible between each other. Added "disengage" member function to be able to disengage a R-value eina::optional of different contained type. It also adds for increased convenience. Fix constructing an engaged eina::optional from an disengaged one. Fix small assertion problem of trying to construct an eina::optional already flagged as engaged. Fix incorrect use of std::move. Changed it to std::forward. Added constexpr property for trivial constructors. Added auxiliary function "make_optional". Added unit test to check compatibility between eina::optionals of convertible types.
This commit is contained in:
parent
5043dcb830
commit
5619c6bc8d
|
@ -66,15 +66,15 @@ struct optional
|
|||
* @brief Create a disengaged object.
|
||||
*
|
||||
* This constructor creates a disengaged <tt>eina::optional</tt>
|
||||
* object, since null pointer is meant to be a valid object type.
|
||||
* object.
|
||||
*/
|
||||
optional(std::nullptr_t) : engaged(false)
|
||||
constexpr optional(std::nullptr_t) : engaged(false)
|
||||
{}
|
||||
|
||||
/**
|
||||
* @brief Default constructor. Create a disengaged object.
|
||||
*/
|
||||
optional() : engaged(false)
|
||||
constexpr optional() : engaged(false)
|
||||
{}
|
||||
|
||||
/**
|
||||
|
@ -158,10 +158,43 @@ struct optional
|
|||
optional(optional<T>&& other)
|
||||
: engaged(false)
|
||||
{
|
||||
_construct(std::move(*other));
|
||||
if(other.engaged) _construct(std::move(*other));
|
||||
other._destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Move constructor. Create an object containing the same value as @p other and in the same state.
|
||||
* @param other R-value reference to another <tt>eina::optional</tt> object that holds a different, but convertible, value type.
|
||||
*
|
||||
* This constructor creates an <tt>eina::optional</tt> object with
|
||||
* the same engagement state of @p other. If @p other is engaged then
|
||||
* the contained value of the newly created object is initialized by
|
||||
* moving the contained value of @p other.
|
||||
*/
|
||||
template <typename U>
|
||||
optional(optional<U>&& other, typename std::enable_if<std::is_convertible<U, T>::value>::type* = 0)
|
||||
: engaged(false)
|
||||
{
|
||||
if (other.is_engaged()) _construct(std::move(*other));
|
||||
other.disengage();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Copy constructor. Create an object containing the same value as @p other and in the same state.
|
||||
* @param other Constant reference to another <tt>eina::optional</tt> object that holds a different, but convertible, value type.
|
||||
*
|
||||
* This constructor creates an <tt>eina::optional</tt> object with
|
||||
* the same engagement state of @p other. If @p other is engaged then
|
||||
* the contained value of the newly created object is initialized by
|
||||
* converting and copying the contained value of @p other.
|
||||
*/
|
||||
template <typename U>
|
||||
optional(optional<U> const& other, typename std::enable_if<std::is_convertible<U, T>::value>::type* = 0)
|
||||
: engaged(false)
|
||||
{
|
||||
if (other.is_engaged()) _construct(*other);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assign new content to the object.
|
||||
* @param other R-value reference to another <tt>eina::optional</tt> object that holds the same value type.
|
||||
|
@ -175,8 +208,7 @@ struct optional
|
|||
_self_type& operator=(optional<T>&& other)
|
||||
{
|
||||
_destroy();
|
||||
engaged = other.engaged;
|
||||
if(engaged)
|
||||
if (other.engaged)
|
||||
_construct(std::move(*other));
|
||||
other._destroy();
|
||||
return *this;
|
||||
|
@ -199,6 +231,53 @@ struct optional
|
|||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assign new content to the object.
|
||||
* @param other R-value reference to another <tt>eina::optional</tt> object that holds a different, but convertible, value type.
|
||||
*
|
||||
* This operator replaces the current content of the object. If
|
||||
* @p other is engaged its contained value is moved to this object,
|
||||
* making <tt>*this</tt> be considered engaged too. If @p other is
|
||||
* disengaged <tt>*this</tt> is also made disengaged and its
|
||||
* contained value, if any, is simple destroyed.
|
||||
*/
|
||||
template <typename U>
|
||||
typename std::enable_if<std::is_convertible<U, T>::value, _self_type>::type& operator=(optional<U>&& other)
|
||||
{
|
||||
_destroy();
|
||||
if (other.is_engaged())
|
||||
_construct(std::move(*other));
|
||||
other.disengage();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assign new content to the object.
|
||||
* @param other Constant reference to another <tt>eina::optional</tt> object that holds a different, but convertible, value type.
|
||||
*
|
||||
* This operator replaces the current content of the object. If
|
||||
* @p other is engaged its contained value is converted and copied to this
|
||||
* object, making <tt>*this</tt> be considered engaged too. If @p other is
|
||||
* disengaged <tt>*this</tt> is also made disengaged and its
|
||||
* contained value, if any, is simple destroyed.
|
||||
*/
|
||||
template <typename U>
|
||||
typename std::enable_if<std::is_convertible<U, T>::value, _self_type>::type& operator=(optional<U>const& other)
|
||||
{
|
||||
_destroy();
|
||||
if (other.is_engaged())
|
||||
_construct(*other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disengage the object, destroying the current contained value, if any.
|
||||
*/
|
||||
void disengage()
|
||||
{
|
||||
_destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Releases the contained value if the object is engaged.
|
||||
*/
|
||||
|
@ -308,7 +387,7 @@ private:
|
|||
void _construct(U&& object)
|
||||
{
|
||||
assert(!is_engaged());
|
||||
new (&buffer) T(std::move(object));
|
||||
new (&buffer) T(std::forward<U>(object));
|
||||
engaged = true;
|
||||
}
|
||||
|
||||
|
@ -338,6 +417,13 @@ private:
|
|||
bool engaged;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
constexpr optional<typename std::decay<T>::type>
|
||||
make_optional(T&& value)
|
||||
{
|
||||
return optional<typename std::decay<T>::type>(std::forward<T>(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Swap content with another <tt>eina::optional</tt> object.
|
||||
*
|
||||
|
|
|
@ -137,10 +137,64 @@ START_TEST(eina_cxx_optional_assignment)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(eina_cxx_optional_convertible_types)
|
||||
{
|
||||
namespace eina = efl::eina;
|
||||
|
||||
eina::eina_init init;
|
||||
|
||||
eina::optional<int> a(1.0);
|
||||
eina::optional<eina::string_view> b("2");
|
||||
eina::optional<std::string> c(eina::string_view("3"));
|
||||
|
||||
ck_assert(!!a && !!b && !!c);
|
||||
|
||||
eina::optional<double> a_s(a);
|
||||
eina::optional<std::string> b_s(b);
|
||||
eina::optional<eina::string_view> c_s(c);
|
||||
|
||||
ck_assert(!!a_s && !!b_s && !!c_s);
|
||||
|
||||
fail_if(1.0 != *a_s);
|
||||
fail_if(std::string("2") != *b_s);
|
||||
fail_if(eina::string_view("3") != *c_s);
|
||||
|
||||
fail_if(1 != *a);
|
||||
fail_if("2" != *b);
|
||||
fail_if("3" != *c);
|
||||
|
||||
fail_if(*a != *a_s);
|
||||
fail_if(*b != *b_s);
|
||||
fail_if(*c != *c_s);
|
||||
|
||||
a_s = 4;
|
||||
b_s = "5";
|
||||
c_s = "6";
|
||||
|
||||
a = a_s;
|
||||
b = b_s;
|
||||
c = c_s;
|
||||
|
||||
fail_if(*a != *a_s);
|
||||
fail_if(*b != *b_s);
|
||||
fail_if(*c != *c_s);
|
||||
|
||||
a = *a_s;
|
||||
b = *b_s;
|
||||
c = *c_s;
|
||||
|
||||
fail_if(*a != *a_s);
|
||||
fail_if(*b != *b_s);
|
||||
fail_if(*c != *c_s);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
void
|
||||
eina_test_optional(TCase* tc)
|
||||
{
|
||||
tcase_add_test(tc, eina_cxx_optional_constructors);
|
||||
tcase_add_test(tc, eina_cxx_optional_rel_ops);
|
||||
tcase_add_test(tc, eina_cxx_optional_assignment);
|
||||
tcase_add_test(tc, eina_cxx_optional_convertible_types);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue