Skip to content

Commit

Permalink
Add assertions for cases where the API documents undefined behaviour.
Browse files Browse the repository at this point in the history
This affects operator->, operator*, and error() on a tl::expected
instance. The performance impact is likely negligible for typical uses.
refs TartanLlama#113

Signed-off-by: Daira Hopwood <[email protected]>
  • Loading branch information
daira committed Sep 5, 2022
1 parent 0aa2fe6 commit 218fe76
Showing 1 changed file with 33 additions and 6 deletions.
39 changes: 33 additions & 6 deletions include/tl/expected.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@
#include <type_traits>
#include <utility>

#if !defined(TL_ASSERT)
#include <cassert>
#define TL_ASSERT assert
#endif

#if defined(__EXCEPTIONS) || defined(_CPPUNWIND)
#define TL_EXPECTED_EXCEPTIONS_ENABLED
#endif
Expand Down Expand Up @@ -1862,27 +1867,37 @@ class expected : private detail::expected_move_assign_base<T, E>,
}
}

constexpr const T *operator->() const { return valptr(); }
TL_EXPECTED_11_CONSTEXPR T *operator->() { return valptr(); }
constexpr const T *operator->() const {
TL_ASSERT(has_value());
return valptr();
}
TL_EXPECTED_11_CONSTEXPR T *operator->() {
TL_ASSERT(has_value());
return valptr();
}

template <class U = T,
detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
constexpr const U &operator*() const & {
TL_ASSERT(has_value());
return val();
}
template <class U = T,
detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
TL_EXPECTED_11_CONSTEXPR U &operator*() & {
TL_ASSERT(has_value());
return val();
}
template <class U = T,
detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
constexpr const U &&operator*() const && {
TL_ASSERT(has_value());
return std::move(val());
}
template <class U = T,
detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
TL_EXPECTED_11_CONSTEXPR U &&operator*() && {
TL_ASSERT(has_value());
return std::move(val());
}

Expand Down Expand Up @@ -1918,10 +1933,22 @@ class expected : private detail::expected_move_assign_base<T, E>,
return std::move(val());
}

constexpr const E &error() const & { return err().value(); }
TL_EXPECTED_11_CONSTEXPR E &error() & { return err().value(); }
constexpr const E &&error() const && { return std::move(err().value()); }
TL_EXPECTED_11_CONSTEXPR E &&error() && { return std::move(err().value()); }
constexpr const E &error() const & {
TL_ASSERT(!has_value());
return err().value();
}
TL_EXPECTED_11_CONSTEXPR E &error() & {
TL_ASSERT(!has_value());
return err().value();
}
constexpr const E &&error() const && {
TL_ASSERT(!has_value());
return std::move(err().value());
}
TL_EXPECTED_11_CONSTEXPR E &&error() && {
TL_ASSERT(!has_value());
return std::move(err().value());
}

template <class U> constexpr T value_or(U &&v) const & {
static_assert(std::is_copy_constructible<T>::value &&
Expand Down

0 comments on commit 218fe76

Please sign in to comment.