diff --git a/src/bindings/eina_cxx/eina_optional.hh b/src/bindings/eina_cxx/eina_optional.hh
index 64e42d7d8d..7cb2075e0a 100644
--- a/src/bindings/eina_cxx/eina_optional.hh
+++ b/src/bindings/eina_cxx/eina_optional.hh
@@ -66,15 +66,15 @@ struct optional
* @brief Create a disengaged object.
*
* This constructor creates a disengaged eina::optional
- * 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&& 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 eina::optional object that holds a different, but convertible, value type.
+ *
+ * This constructor creates an eina::optional 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
+ optional(optional&& other, typename std::enable_if::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 eina::optional object that holds a different, but convertible, value type.
+ *
+ * This constructor creates an eina::optional 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
+ optional(optional const& other, typename std::enable_if::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 eina::optional object that holds the same value type.
@@ -175,8 +208,7 @@ struct optional
_self_type& operator=(optional&& 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 eina::optional 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 *this be considered engaged too. If @p other is
+ * disengaged *this is also made disengaged and its
+ * contained value, if any, is simple destroyed.
+ */
+ template
+ typename std::enable_if::value, _self_type>::type& operator=(optional&& 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 eina::optional 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 *this be considered engaged too. If @p other is
+ * disengaged *this is also made disengaged and its
+ * contained value, if any, is simple destroyed.
+ */
+ template
+ typename std::enable_if::value, _self_type>::type& operator=(optionalconst& 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(object));
engaged = true;
}
@@ -338,6 +417,13 @@ private:
bool engaged;
};
+template
+constexpr optional::type>
+make_optional(T&& value)
+{
+ return optional::type>(std::forward(value));
+}
+
/**
* @brief Swap content with another eina::optional object.
*
diff --git a/src/tests/eina_cxx/eina_cxx_test_optional.cc b/src/tests/eina_cxx/eina_cxx_test_optional.cc
index 6619ee96ba..4043cb064c 100644
--- a/src/tests/eina_cxx/eina_cxx_test_optional.cc
+++ b/src/tests/eina_cxx/eina_cxx_test_optional.cc
@@ -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 a(1.0);
+ eina::optional b("2");
+ eina::optional c(eina::string_view("3"));
+
+ ck_assert(!!a && !!b && !!c);
+
+ eina::optional a_s(a);
+ eina::optional b_s(b);
+ eina::optional 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);
}