Get references compiling, initial tests

This commit is contained in:
Simon Brand
2017-12-14 14:53:35 +00:00
parent bdaa41ce8c
commit c4e3b3ee14
4 changed files with 106 additions and 249 deletions

View File

@ -1,7 +1,7 @@
#include "catch.hpp"
#include "optional.hpp"
TEST_CASE("Assignment", "[assignment]") {
TEST_CASE("Assignment value", "[assignment.value]") {
tl::optional<int> o1 = 42;
tl::optional<int> o2 = 12;
tl::optional<int> o3;
@ -32,3 +32,37 @@ TEST_CASE("Assignment", "[assignment]") {
o1 = std::move(o4);
REQUIRE(*o1 == 42);
}
TEST_CASE("Assignment reference", "[assignment.ref]") {
auto i = 42;
auto j = 12;
tl::optional<int&> o1 = i;
tl::optional<int&> o2 = j;
tl::optional<int&> o3;
o1 = o1;
REQUIRE(*o1 == 42);
REQUIRE(&*o1 == &i);
o1 = o2;
REQUIRE(*o1 == 12);
o1 = o3;
REQUIRE(!o1);
auto k = 42;
o1 = k;
REQUIRE(*o1 == 42);
REQUIRE(*o1 == i);
REQUIRE(*o1 == k);
REQUIRE(&*o1 != &i);
REQUIRE(&*o1 == &k);
o1 = tl::nullopt;
REQUIRE(!o1);
o1 = std::move(o2);
REQUIRE(*o1 == 12);
}

View File

@ -2,30 +2,49 @@
#include "optional.hpp"
TEST_CASE("Constructors", "[constructors]") {
tl::optional<int> o1;
REQUIRE(!o1);
tl::optional<int> o1;
REQUIRE(!o1);
tl::optional<int> o2 = tl::nullopt;
REQUIRE(!o2);
tl::optional<int> o2 = tl::nullopt;
REQUIRE(!o2);
tl::optional<int> o3 = 42;
REQUIRE(*o3 == 42);
tl::optional<int> o3 = 42;
REQUIRE(*o3 == 42);
tl::optional<int> o4 = o3;
REQUIRE(*o4 == 42);
tl::optional<int> o4 = o3;
REQUIRE(*o4 == 42);
tl::optional<int> o5 = o1;
REQUIRE(!o5);
tl::optional<int> o5 = o1;
REQUIRE(!o5);
tl::optional<int> o6 = std::move(o3);
REQUIRE(*o6 == 42);
tl::optional<int> o6 = std::move(o3);
REQUIRE(*o6 == 42);
tl::optional<short> o7 = 42;
REQUIRE(*o7 == 42);
tl::optional<short> o7 = 42;
REQUIRE(*o7 == 42);
tl::optional<int> o8 = o7;
REQUIRE(*o8 == 42);
tl::optional<int> o8 = o7;
REQUIRE(*o8 == 42);
tl::optional<int> o9 = std::move(o7);
REQUIRE(*o9 == 42);
tl::optional<int> o9 = std::move(o7);
REQUIRE(*o9 == 42);
{
tl::optional<int &> o;
REQUIRE(!o);
tl::optional<int &> oo = o;
REQUIRE(!oo);
}
{
auto i = 42;
tl::optional<int &> o = i;
REQUIRE(o);
REQUIRE(*o == 42);
tl::optional<int &> oo = o;
REQUIRE(oo);
REQUIRE(*oo == 42);
}
}

View File

@ -37,4 +37,8 @@ TEST_CASE("Make optional", "[make_optional]") {
REQUIRE(o5->v[1] == 1);
REQUIRE(std::get<0>(o5->t) == 2);
REQUIRE(std::get<1>(o5->t) == 3);
auto i = 42;
auto o6 = tl::make_optional<int&>(i);
REQUIRE((std::is_same<decltype(o6), tl::optional<int&>>::value));
}

View File

@ -1573,10 +1573,18 @@ void swap(optional<T> &lhs,
return lhs.swap(rhs);
}
template <class T>
inline constexpr optional<detail::decay_t<T>> make_optional(T &&v) {
return optional<detail::decay_t<T>>(std::forward<T>(v));
namespace detail {
struct i_am_secret {};
} // namespace detail
template <class T = detail::i_am_secret, class U,
class Ret =
detail::conditional_t<std::is_same<T, detail::i_am_secret>::value,
detail::decay_t<U>, T>>
inline constexpr optional<Ret> make_optional(U &&v) {
return optional<Ret>(std::forward<U>(v));
}
template <class T, class... Args>
inline constexpr optional<T> make_optional(Args &&... args) {
return optional<T>(in_place, std::forward<Args>(args)...);
@ -2056,18 +2064,14 @@ public:
/// \synopsis template <class U=T> constexpr optional(U &&u);
template <
class U = T,
detail::enable_if_t<std::is_convertible<U &&, T &>::value> * = nullptr,
detail::enable_if_t<!detail::is_optional<detail::decay_t<U>>> * = nullptr>
constexpr optional(U &&u) : m_value(std::addressof(u)) {}
detail::enable_if_t<!detail::is_optional<detail::decay_t<U>>::value> * =
nullptr>
constexpr optional(U &&u) : m_value(std::addressof(u)) {
static_assert(std::is_lvalue_reference<U>::value, "U must be an lvalue");
}
/// \exclude
template <class U = T, detail::enable_if_t<
!std::is_convertible<U &, T &>::value> * = nullptr>
constexpr optional(U &&u) : base(in_place, std::forward<U>(u)) {}
/// \exclude
template <class U, detail::enable_if_t<
!std::is_convertible<const U &, T>::value> * = nullptr>
template <class U>
constexpr explicit optional(const optional<U> &rhs) : optional(*rhs) {}
/// No-op
@ -2091,9 +2095,10 @@ public:
/// one.
/// \synopsis optional &operator=(U &&u);
template <class U = T,
detail::enable_if<!detail::is_optional<detail::decay_t<U>>::value>
detail::enable_if_t<!detail::is_optional<detail::decay_t<U>>::value>
* = nullptr>
optional &operator=(U &&u) {
static_assert(std::is_lvalue_reference<U>::value, "U must be an lvalue");
m_value = std::addressof(u);
return *this;
}
@ -2103,10 +2108,9 @@ public:
/// Copies the value from `rhs` if there is one. Otherwise resets the stored
/// value in `*this`.
/// \synopsis optional &operator=(const optional<U> & rhs);
template <class U,
detail::enable_if<std::is_convertible<U &, T &>::value> * = nullptr>
template <class U>
optional &operator=(const optional<U> &rhs) {
m_value = std::addressof(rhs.value());
m_value = std::addressof(rhs.value());
return *this;
}
@ -2126,24 +2130,17 @@ public:
/// If both have a value, the values are swapped.
/// If one has a value, it is moved to the other and the movee is left
/// valueless.
void
swap(optional &rhs) noexcept {
std::swap(m_value, rhs.m_value);
}
void swap(optional &rhs) noexcept { std::swap(m_value, rhs.m_value); }
/// \returns a pointer to the stored value
/// \requires a value is stored
/// \group pointer
/// \synopsis constexpr const T *operator->() const;
constexpr const T *operator->() const {
return m_value;
}
constexpr const T *operator->() const { return m_value; }
/// \group pointer
/// \synopsis constexpr T *operator->();
TL_OPTIONAL_11_CONSTEXPR T *operator->() {
return m_value;
}
TL_OPTIONAL_11_CONSTEXPR T *operator->() { return m_value; }
/// \returns the stored value
/// \requires a value is stored
@ -2156,9 +2153,7 @@ public:
constexpr const T &operator*() const & { return *m_value; }
/// \exclude
TL_OPTIONAL_11_CONSTEXPR T &&operator*() && {
return std::move(*m_value);
}
TL_OPTIONAL_11_CONSTEXPR T &&operator*() && { return std::move(*m_value); }
#ifndef TL_OPTIONAL_NO_CONSTRR
/// \exclude
@ -2193,7 +2188,7 @@ public:
/// \exclude
TL_OPTIONAL_11_CONSTEXPR T &&value() && {
if (has_value())
return std::move(*m_value);
return std::move(*m_value);
throw bad_optional_access();
}
@ -2224,207 +2219,12 @@ public:
}
/// Destroys the stored value if one exists, making the optional empty
void reset() noexcept {
m_value = nullptr;
}
void reset() noexcept { m_value = nullptr; }
private:
T *m_value;
}; // namespace tl
/// \group relop
/// \brief Compares two optional objects
/// \details If both optionals contain a value, they are compared with `T`s
/// relational operators. Otherwise `lhs` and `rhs` are equal only if they are
/// both empty, and `lhs` is less than `rhs` only if `rhs` is empty and `lhs`
/// is not.
template <class T, class U>
inline constexpr bool operator==(const optional<T> &lhs,
const optional<U> &rhs) {
return lhs.has_value() == rhs.has_value() &&
(!lhs.has_value() || *lhs == *rhs);
}
/// \group relop
template <class T, class U>
inline constexpr bool operator!=(const optional<T> &lhs,
const optional<U> &rhs) {
return lhs.has_value() != rhs.has_value() ||
(lhs.has_value() && *lhs != *rhs);
}
/// \group relop
template <class T, class U>
inline constexpr bool operator<(const optional<T> &lhs,
const optional<U> &rhs) {
return rhs.has_value() && (!lhs.has_value() || *lhs < *rhs);
}
/// \group relop
template <class T, class U>
inline constexpr bool operator>(const optional<T> &lhs,
const optional<U> &rhs) {
return lhs.has_value() && (!rhs.has_value() || *lhs > *rhs);
}
/// \group relop
template <class T, class U>
inline constexpr bool operator<=(const optional<T> &lhs,
const optional<U> &rhs) {
return !lhs.has_value() || (rhs.has_value() && *lhs <= *rhs);
}
/// \group relop
template <class T, class U>
inline constexpr bool operator>=(const optional<T> &lhs,
const optional<U> &rhs) {
return !rhs.has_value() || (lhs.has_value() && *lhs >= *rhs);
}
/// \group relop_nullopt
/// \brief Compares an optional to a `nullopt`
/// \details Equivalent to comparing the optional to an empty optional
template <class T>
inline constexpr bool operator==(const optional<T> &lhs, nullopt_t) noexcept {
return !lhs.has_value();
}
/// \group relop_nullopt
template <class T>
inline constexpr bool operator==(nullopt_t, const optional<T> &rhs) noexcept {
return !rhs.has_value();
}
/// \group relop_nullopt
template <class T>
inline constexpr bool operator!=(const optional<T> &lhs, nullopt_t) noexcept {
return lhs.has_value();
}
/// \group relop_nullopt
template <class T>
inline constexpr bool operator!=(nullopt_t, const optional<T> &rhs) noexcept {
return rhs.has_value();
}
/// \group relop_nullopt
template <class T>
inline constexpr bool operator<(const optional<T> &, nullopt_t) noexcept {
return false;
}
/// \group relop_nullopt
template <class T>
inline constexpr bool operator<(nullopt_t, const optional<T> &rhs) noexcept {
return rhs.has_value();
}
/// \group relop_nullopt
template <class T>
inline constexpr bool operator<=(const optional<T> &lhs, nullopt_t) noexcept {
return !lhs.has_value();
}
/// \group relop_nullopt
template <class T>
inline constexpr bool operator<=(nullopt_t, const optional<T> &) noexcept {
return true;
}
/// \group relop_nullopt
template <class T>
inline constexpr bool operator>(const optional<T> &lhs, nullopt_t) noexcept {
return lhs.has_value();
}
/// \group relop_nullopt
template <class T>
inline constexpr bool operator>(nullopt_t, const optional<T> &) noexcept {
return false;
}
/// \group relop_nullopt
template <class T>
inline constexpr bool operator>=(const optional<T> &, nullopt_t) noexcept {
return true;
}
/// \group relop_nullopt
template <class T>
inline constexpr bool operator>=(nullopt_t, const optional<T> &rhs) noexcept {
return !rhs.has_value();
}
/// \group relop_t
/// \brief Compares the optional with a value.
/// \details If the optional has a value, it is compared with the other value
/// using `T`s relational operators. Otherwise, the optional is considered
/// less than the value.
template <class T, class U>
inline constexpr bool operator==(const optional<T> &lhs, const U &rhs) {
return lhs.has_value() ? *lhs == rhs : false;
}
/// \group relop_t
template <class T, class U>
inline constexpr bool operator==(const U &lhs, const optional<T> &rhs) {
return rhs.has_value() ? lhs == *rhs : false;
}
/// \group relop_t
template <class T, class U>
inline constexpr bool operator!=(const optional<T> &lhs, const U &rhs) {
return lhs.has_value() ? *lhs != rhs : true;
}
/// \group relop_t
template <class T, class U>
inline constexpr bool operator!=(const U &lhs, const optional<T> &rhs) {
return rhs.has_value() ? lhs != *rhs : true;
}
/// \group relop_t
template <class T, class U>
inline constexpr bool operator<(const optional<T> &lhs, const U &rhs) {
return lhs.has_value() ? *lhs < rhs : true;
}
/// \group relop_t
template <class T, class U>
inline constexpr bool operator<(const U &lhs, const optional<T> &rhs) {
return rhs.has_value() ? lhs < *rhs : false;
}
/// \group relop_t
template <class T, class U>
inline constexpr bool operator<=(const optional<T> &lhs, const U &rhs) {
return lhs.has_value() ? *lhs <= rhs : true;
}
/// \group relop_t
template <class T, class U>
inline constexpr bool operator<=(const U &lhs, const optional<T> &rhs) {
return rhs.has_value() ? lhs <= *rhs : false;
}
/// \group relop_t
template <class T, class U>
inline constexpr bool operator>(const optional<T> &lhs, const U &rhs) {
return lhs.has_value() ? *lhs > rhs : false;
}
/// \group relop_t
template <class T, class U>
inline constexpr bool operator>(const U &lhs, const optional<T> &rhs) {
return rhs.has_value() ? lhs > *rhs : true;
}
/// \group relop_t
template <class T, class U>
inline constexpr bool operator>=(const optional<T> &lhs, const U &rhs) {
return lhs.has_value() ? *lhs >= rhs : false;
}
/// \group relop_t
template <class T, class U>
inline constexpr bool operator>=(const U &lhs, const optional<T> &rhs) {
return rhs.has_value() ? lhs >= *rhs : true;
}
/// \synopsis template <class T>\nvoid swap(optional<T> &lhs, optional<T>
/// &rhs);
template <class T,
detail::enable_if_t<std::is_move_constructible<T>::value> * = nullptr,
detail::enable_if_t<detail::is_swappable<T>::value> * = nullptr>
void swap(optional<T> &lhs,
optional<T> &rhs) noexcept(noexcept(lhs.swap(rhs))) {
return lhs.swap(rhs);
}
template <class T>
inline constexpr optional<detail::decay_t<T>> make_optional(T &&v) {
return optional<detail::decay_t<T>>(std::forward<T>(v));
}
template <class T, class... Args>
inline constexpr optional<T> make_optional(Args &&... args) {
return optional<T>(in_place, std::forward<Args>(args)...);
}
template <class T, class U, class... Args>
inline constexpr optional<T> make_optional(std::initializer_list<U> il,
Args &&... args) {
return optional<T>(in_place, il, std::forward<Args>(args)...);
}
/// \exclude
namespace detail {
#ifdef TL_OPTIONAL_CX14