Clang format

This commit is contained in:
Simon Brand
2017-10-02 08:58:09 +01:00
parent 7ca0facc75
commit 17f646355d
2 changed files with 611 additions and 565 deletions

1
.clang-format Normal file
View File

@ -0,0 +1 @@
BasedOnStyle: LLVM

View File

@ -7,39 +7,52 @@
// public domain worldwide. This software is distributed without any warranty. // public domain worldwide. This software is distributed without any warranty.
// //
// You should have received a copy of the CC0 Public Domain Dedication // You should have received a copy of the CC0 Public Domain Dedication
// along with this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>. // along with this software. If not, see
// <http://creativecommons.org/publicdomain/zero/1.0/>.
/// ///
#include <exception>
#include <functional>
#include <new>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include <exception>
#include <new>
#include <functional>
namespace tl { namespace tl {
namespace detail { namespace detail {
template <class T> using remove_cv_t = typename std::remove_cv<T>::type; template <class T> using remove_cv_t = typename std::remove_cv<T>::type;
template <class T> using remove_const_t = typename std::remove_const<T>::type; template <class T> using remove_const_t = typename std::remove_const<T>::type;
template <class T> using remove_volatile_t = typename std::remove_volatile<T>::type; template <class T>
using remove_volatile_t = typename std::remove_volatile<T>::type;
template <class T> using add_cv_t = typename std::add_cv<T>::type; template <class T> using add_cv_t = typename std::add_cv<T>::type;
template <class T> using add_const_t = typename std::add_const<T>::type; template <class T> using add_const_t = typename std::add_const<T>::type;
template <class T> using add_volatile_t = typename std::add_volatile<T>::type; template <class T> using add_volatile_t = typename std::add_volatile<T>::type;
template <class T> using remove_reference_t = typename std::remove_reference<T>::type; template <class T>
template <class T> using add_lvalue_reference_t = typename std::add_lvalue_reference<T>::type; using remove_reference_t = typename std::remove_reference<T>::type;
template <class T> using add_rvalue_reference_t = typename std::add_rvalue_reference<T>::type; template <class T>
template <class T> using remove_pointer_t = typename std::remove_pointer<T>::type; using add_lvalue_reference_t = typename std::add_lvalue_reference<T>::type;
template <class T>
using add_rvalue_reference_t = typename std::add_rvalue_reference<T>::type;
template <class T>
using remove_pointer_t = typename std::remove_pointer<T>::type;
template <class T> using add_pointer_t = typename std::add_pointer<T>::type; template <class T> using add_pointer_t = typename std::add_pointer<T>::type;
template <class T> using make_signed_t = typename std::make_signed<T>::type; template <class T> using make_signed_t = typename std::make_signed<T>::type;
template <class T> using make_unsigned_t = typename std::make_unsigned<T>::type; template <class T> using make_unsigned_t = typename std::make_unsigned<T>::type;
template <class T> using remove_extent_t = typename std::remove_extent<T>::type; template <class T> using remove_extent_t = typename std::remove_extent<T>::type;
template <class T> using remove_all_extents_t = typename std::remove_all_extents<T>::type; template <class T>
template <std::size_t N, std::size_t A=N> using aligned_storage_t = typename std::aligned_storage<N,A>::type; using remove_all_extents_t = typename std::remove_all_extents<T>::type;
template <std::size_t N, class... Ts> using aligned_union_t = typename std::aligned_union<N,Ts...>::type; template <std::size_t N, std::size_t A = N>
using aligned_storage_t = typename std::aligned_storage<N, A>::type;
template <std::size_t N, class... Ts>
using aligned_union_t = typename std::aligned_union<N, Ts...>::type;
template <class T> using decay_t = typename std::decay<T>::type; template <class T> using decay_t = typename std::decay<T>::type;
template <bool E, class T=void> using enable_if_t = typename std::enable_if<E,T>::type; template <bool E, class T = void>
template <bool B, class T, class F> using conditional_t = typename std::conditional<B,T,F>::type; using enable_if_t = typename std::enable_if<E, T>::type;
template <class... Ts> using common_type_t = typename std::common_type<Ts...>::type; template <bool B, class T, class F>
template <class T> using underlying_type_t = typename std::underlying_type<T>::type; using conditional_t = typename std::conditional<B, T, F>::type;
template <class... Ts>
using common_type_t = typename std::common_type<Ts...>::type;
template <class T>
using underlying_type_t = typename std::underlying_type<T>::type;
template <class T> using result_of_t = typename std::result_of<T>::type; template <class T> using result_of_t = typename std::result_of<T>::type;
template <class...> struct conjunction : std::true_type {}; template <class...> struct conjunction : std::true_type {};
@ -58,16 +71,14 @@ namespace tl {
static constexpr in_place_t in_place{}; static constexpr in_place_t in_place{};
// [optional.optional], class template optional // [optional.optional], class template optional
template <class T> template <class T> class optional;
class optional;
namespace detail { namespace detail {
template <class T, class U> template <class T, class U>
using enable_forward_value = detail::enable_if_t< using enable_forward_value =
std::is_constructible<T, U&&>::value && detail::enable_if_t<std::is_constructible<T, U &&>::value &&
!std::is_same<detail::decay_t<U>, in_place_t>::value && !std::is_same<detail::decay_t<U>, in_place_t>::value &&
!std::is_same<optional<T>, detail::decay_t<U>>::value !std::is_same<optional<T>, detail::decay_t<U>>::value>;
>;
template <class T, class U, class Other> template <class T, class U, class Other>
using enable_from_other = detail::enable_if_t< using enable_from_other = detail::enable_if_t<
@ -79,16 +90,14 @@ namespace tl {
!std::is_convertible<optional<U> &, T>::value && !std::is_convertible<optional<U> &, T>::value &&
!std::is_convertible<optional<U> &&, T>::value && !std::is_convertible<optional<U> &&, T>::value &&
!std::is_convertible<const optional<U> &, T>::value && !std::is_convertible<const optional<U> &, T>::value &&
!std::is_convertible<const optional<U>&&, T>::value !std::is_convertible<const optional<U> &&, T>::value>;
>;
template <class T, class U> template <class T, class U>
using enable_assign_forward = detail::enable_if_t< using enable_assign_forward = detail::enable_if_t<
!std::is_same<optional<T>, detail::decay_t<U>>::value && !std::is_same<optional<T>, detail::decay_t<U>>::value &&
!detail::conjunction<std::is_scalar<T>, std::is_same<T, detail::decay_t<U>>>::value && !detail::conjunction<std::is_scalar<T>,
std::is_constructible<T, U>::value && std::is_same<T, detail::decay_t<U>>>::value &&
std::is_assignable<T&, U>::value std::is_constructible<T, U>::value && std::is_assignable<T &, U>::value>;
>;
template <class T, class U, class Other> template <class T, class U, class Other>
using enable_assign_from_other = detail::enable_if_t< using enable_assign_from_other = detail::enable_if_t<
@ -105,66 +114,73 @@ namespace tl {
!std::is_assignable<T &, optional<U> &>::value && !std::is_assignable<T &, optional<U> &>::value &&
!std::is_assignable<T &, optional<U> &&>::value && !std::is_assignable<T &, optional<U> &&>::value &&
!std::is_assignable<T &, const optional<U> &>::value && !std::is_assignable<T &, const optional<U> &>::value &&
!std::is_assignable<T&, const optional<U>&&>::value !std::is_assignable<T &, const optional<U> &&>::value>;
>;
// https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept // https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept
namespace swap_adl_tests { namespace swap_adl_tests {
// if swap ADL finds this then it would call std::swap otherwise (same signature) // if swap ADL finds this then it would call std::swap otherwise (same
// signature)
struct tag {}; struct tag {};
template <class T> tag swap(T &, T &); template <class T> tag swap(T &, T &);
template <class T, std::size_t N> tag swap(T (&a)[N], T (&b)[N]); template <class T, std::size_t N> tag swap(T (&a)[N], T (&b)[N]);
// helper functions to test if an unqualified swap is possible, and if it becomes std::swap // helper functions to test if an unqualified swap is possible, and if it
// becomes std::swap
template <class, class> std::false_type can_swap(...) noexcept(false); template <class, class> std::false_type can_swap(...) noexcept(false);
template<class T, class U, class = decltype(swap(std::declval<T&>(), std::declval<U&>()))> template <class T, class U,
std::true_type can_swap(int) noexcept( class = decltype(swap(std::declval<T &>(), std::declval<U &>()))>
noexcept(swap(std::declval<T&>(), std::declval<U&>())) std::true_type can_swap(int) noexcept(noexcept(swap(std::declval<T &>(),
); std::declval<U &>())));
template <class, class> std::false_type uses_std(...); template <class, class> std::false_type uses_std(...);
template <class T, class U> template <class T, class U>
std::is_same<decltype(swap(std::declval<T&>(), std::declval<U&>())), tag> uses_std(int); std::is_same<decltype(swap(std::declval<T &>(), std::declval<U &>())), tag>
uses_std(int);
template <class T> template <class T>
struct is_std_swap_noexcept : std::integral_constant<bool, struct is_std_swap_noexcept
: std::integral_constant<bool,
std::is_nothrow_move_constructible<T>::value && std::is_nothrow_move_constructible<T>::value &&
std::is_nothrow_move_assignable<T>::value std::is_nothrow_move_assignable<T>::value> {};
> { };
template <class T, std::size_t N> template <class T, std::size_t N>
struct is_std_swap_noexcept<T[N]> : is_std_swap_noexcept<T> {}; struct is_std_swap_noexcept<T[N]> : is_std_swap_noexcept<T> {};
template <class T, class U> template <class T, class U>
struct is_adl_swap_noexcept : std::integral_constant<bool, noexcept(can_swap<T, U>(0))> { }; struct is_adl_swap_noexcept
: std::integral_constant<bool, noexcept(can_swap<T, U>(0))> {};
} }
template <class T, class U = T> template <class T, class U = T>
struct is_swappable : std::integral_constant<bool, struct is_swappable
: std::integral_constant<
bool,
decltype(detail::swap_adl_tests::can_swap<T, U>(0))::value && decltype(detail::swap_adl_tests::can_swap<T, U>(0))::value &&
(!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value || (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value ||
(std::is_move_assignable<T>::value && std::is_move_constructible<T>::value)) (std::is_move_assignable<T>::value &&
> {}; std::is_move_constructible<T>::value))> {};
template <class T, std::size_t N> template <class T, std::size_t N>
struct is_swappable<T[N], T[N]> : std::integral_constant<bool, struct is_swappable<T[N], T[N]>
: std::integral_constant<
bool,
decltype(detail::swap_adl_tests::can_swap<T[N], T[N]>(0))::value && decltype(detail::swap_adl_tests::can_swap<T[N], T[N]>(0))::value &&
(!decltype(detail::swap_adl_tests::uses_std<T[N], T[N]>(0))::value || (!decltype(
is_swappable<T, T>::value) detail::swap_adl_tests::uses_std<T[N], T[N]>(0))::value ||
> {}; is_swappable<T, T>::value)> {};
template <class T, class U = T> template <class T, class U = T>
struct is_nothrow_swappable : std::integral_constant<bool, struct is_nothrow_swappable
is_swappable<T, U>::value && ( : std::integral_constant<
(decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value && bool,
detail::swap_adl_tests::is_std_swap_noexcept<T>::value) is_swappable<T, U>::value &&
|| ((decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value
&&detail::swap_adl_tests::is_std_swap_noexcept<T>::value) ||
(!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value && (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value &&
detail::swap_adl_tests::is_adl_swap_noexcept<T, U>::value) detail::swap_adl_tests::is_adl_swap_noexcept<T,
) U>::value))> {
> {}; };
} }
// [optional.nullopt], no-value state indicator // [optional.nullopt], no-value state indicator
@ -172,124 +188,156 @@ namespace tl {
struct do_not_use {}; struct do_not_use {};
constexpr explicit nullopt_t(do_not_use, do_not_use) noexcept {} constexpr explicit nullopt_t(do_not_use, do_not_use) noexcept {}
}; };
static constexpr nullopt_t nullopt{nullopt_t::do_not_use{}, nullopt_t::do_not_use{}}; static constexpr nullopt_t nullopt{nullopt_t::do_not_use{},
nullopt_t::do_not_use{}};
// [optional.bad.access], class bad_optional_access // [optional.bad.access], class bad_optional_access
class bad_optional_access : public std::exception { class bad_optional_access : public std::exception {
public: public:
bad_optional_access() = default; bad_optional_access() = default;
const char* what() const noexcept { const char *what() const noexcept { return "Optional has no value"; }
return "Optional has no value";
}
}; };
// [optional.relops], relational operators // [optional.relops], relational operators
template <class T, class U> template <class T, class U>
inline constexpr bool operator==(const optional<T>& lhs, const optional<U>& rhs) { inline constexpr bool operator==(const optional<T> &lhs,
return lhs.has_value() == rhs.has_value() && (!lhs.has_value() || *lhs == *rhs); const optional<U> &rhs) {
return lhs.has_value() == rhs.has_value() &&
(!lhs.has_value() || *lhs == *rhs);
} }
template <class T, class U> template <class T, class U>
inline constexpr bool operator!=(const optional<T>& lhs, const optional<U>& rhs) { inline constexpr bool operator!=(const optional<T> &lhs,
return lhs.has_value() != rhs.has_value() || (lhs.has_value() && *lhs != *rhs); const optional<U> &rhs) {
return lhs.has_value() != rhs.has_value() ||
(lhs.has_value() && *lhs != *rhs);
} }
template <class T, class U> template <class T, class U>
inline constexpr bool operator<(const optional<T>& lhs, const optional<U>& rhs) { inline constexpr bool operator<(const optional<T> &lhs,
const optional<U> &rhs) {
return rhs.has_value() && (!lhs.has_value() || *lhs < *rhs); return rhs.has_value() && (!lhs.has_value() || *lhs < *rhs);
} }
template <class T, class U> template <class T, class U>
inline constexpr bool operator>(const optional<T>& lhs, const optional<U>& rhs) { inline constexpr bool operator>(const optional<T> &lhs,
const optional<U> &rhs) {
return lhs.has_value() && (!rhs.has_value() || *lhs > *rhs); return lhs.has_value() && (!rhs.has_value() || *lhs > *rhs);
} }
template <class T, class U> template <class T, class U>
inline constexpr bool operator<=(const optional<T>& lhs, const optional<U>& rhs) { inline constexpr bool operator<=(const optional<T> &lhs,
const optional<U> &rhs) {
return !lhs.has_value() || (rhs.has_value() && *lhs <= *rhs); return !lhs.has_value() || (rhs.has_value() && *lhs <= *rhs);
} }
template <class T, class U> template <class T, class U>
inline constexpr bool operator>=(const optional<T>& lhs, const optional<U>& rhs) { inline constexpr bool operator>=(const optional<T> &lhs,
const optional<U> &rhs) {
return !rhs.has_value() || (lhs.has_value() && *lhs >= *rhs); return !rhs.has_value() || (lhs.has_value() && *lhs >= *rhs);
} }
// [optional.nullops], comparison with nullopt // [optional.nullops], comparison with nullopt
template <class T> inline constexpr bool operator==(const optional<T>& lhs, nullopt_t) noexcept { template <class T>
inline constexpr bool operator==(const optional<T> &lhs, nullopt_t) noexcept {
return !lhs.has_value(); return !lhs.has_value();
} }
template <class T> inline constexpr bool operator==(nullopt_t, const optional<T>& rhs) noexcept { template <class T>
inline constexpr bool operator==(nullopt_t, const optional<T> &rhs) noexcept {
return !rhs.has_value(); return !rhs.has_value();
} }
template <class T> inline constexpr bool operator!=(const optional<T>& lhs, nullopt_t) noexcept { template <class T>
inline constexpr bool operator!=(const optional<T> &lhs, nullopt_t) noexcept {
return lhs.has_value(); return lhs.has_value();
} }
template <class T> inline constexpr bool operator!=(nullopt_t, const optional<T>& rhs) noexcept { template <class T>
inline constexpr bool operator!=(nullopt_t, const optional<T> &rhs) noexcept {
return rhs.has_value(); return rhs.has_value();
} }
template <class T> inline constexpr bool operator<(const optional<T>&, nullopt_t) noexcept { template <class T>
inline constexpr bool operator<(const optional<T> &, nullopt_t) noexcept {
return false; return false;
} }
template <class T> inline constexpr bool operator<(nullopt_t, const optional<T>& rhs) noexcept { template <class T>
inline constexpr bool operator<(nullopt_t, const optional<T> &rhs) noexcept {
return rhs.has_value(); return rhs.has_value();
} }
template <class T> inline constexpr bool operator<=(const optional<T>& lhs, nullopt_t) noexcept { template <class T>
inline constexpr bool operator<=(const optional<T> &lhs, nullopt_t) noexcept {
return !lhs.has_value(); return !lhs.has_value();
} }
template <class T> inline constexpr bool operator<=(nullopt_t, const optional<T>&) noexcept { template <class T>
inline constexpr bool operator<=(nullopt_t, const optional<T> &) noexcept {
return true; return true;
} }
template <class T> inline constexpr bool operator>(const optional<T>& lhs, nullopt_t) noexcept { template <class T>
inline constexpr bool operator>(const optional<T> &lhs, nullopt_t) noexcept {
return lhs.has_value(); return lhs.has_value();
} }
template <class T> inline constexpr bool operator>(nullopt_t, const optional<T>&) noexcept { template <class T>
inline constexpr bool operator>(nullopt_t, const optional<T> &) noexcept {
return false; return false;
} }
template <class T> inline constexpr bool operator>=(const optional<T>&, nullopt_t) noexcept { template <class T>
inline constexpr bool operator>=(const optional<T> &, nullopt_t) noexcept {
return true; return true;
} }
template <class T> inline constexpr bool operator>=(nullopt_t, const optional<T>& rhs) noexcept { template <class T>
inline constexpr bool operator>=(nullopt_t, const optional<T> &rhs) noexcept {
return !rhs.has_value(); return !rhs.has_value();
} }
// [optional.comp_with_t], comparison with T // [optional.comp_with_t], comparison with T
template <class T, class U> inline constexpr bool operator==(const optional<T>& lhs, const U& rhs) { template <class T, class U>
inline constexpr bool operator==(const optional<T> &lhs, const U &rhs) {
return lhs.has_value() ? *lhs == rhs : false; return lhs.has_value() ? *lhs == rhs : false;
} }
template <class T, class U> inline constexpr bool operator==(const U& lhs, const optional<T>& rhs) { template <class T, class U>
inline constexpr bool operator==(const U &lhs, const optional<T> &rhs) {
return rhs.has_value() ? lhs == *rhs : false; return rhs.has_value() ? lhs == *rhs : false;
} }
template <class T, class U> inline constexpr bool operator!=(const optional<T>& lhs, const U& rhs) { template <class T, class U>
inline constexpr bool operator!=(const optional<T> &lhs, const U &rhs) {
return lhs.has_value() ? *lhs != lhs : true; return lhs.has_value() ? *lhs != lhs : true;
} }
template <class T, class U> inline constexpr bool operator!=(const U& lhs, const optional<T>& rhs) { template <class T, class U>
inline constexpr bool operator!=(const U &lhs, const optional<T> &rhs) {
return rhs.has_value() ? lhs != *rhs : true; return rhs.has_value() ? lhs != *rhs : true;
} }
template <class T, class U> inline constexpr bool operator<(const optional<T>& lhs, const U& rhs) { template <class T, class U>
inline constexpr bool operator<(const optional<T> &lhs, const U &rhs) {
return lhs.has_value() ? *lhs < lhs : true; return lhs.has_value() ? *lhs < lhs : true;
} }
template <class T, class U> inline constexpr bool operator<(const U& lhs, const optional<T>& rhs) { template <class T, class U>
inline constexpr bool operator<(const U &lhs, const optional<T> &rhs) {
return rhs.has_value() ? lhs < *rhs : false; return rhs.has_value() ? lhs < *rhs : false;
} }
template <class T, class U> inline constexpr bool operator<=(const optional<T>& lhs, const U& rhs) { template <class T, class U>
inline constexpr bool operator<=(const optional<T> &lhs, const U &rhs) {
return lhs.has_value() ? *lhs <= lhs : true; return lhs.has_value() ? *lhs <= lhs : true;
} }
template <class T, class U> inline constexpr bool operator<=(const U& lhs, const optional<T>& rhs) { template <class T, class U>
inline constexpr bool operator<=(const U &lhs, const optional<T> &rhs) {
return rhs.has_value() ? lhs <= *rhs : false; return rhs.has_value() ? lhs <= *rhs : false;
} }
template <class T, class U> inline constexpr bool operator>(const optional<T>& lhs, const U& rhs) { template <class T, class U>
inline constexpr bool operator>(const optional<T> &lhs, const U &rhs) {
return lhs.has_value() ? *lhs > lhs : false; return lhs.has_value() ? *lhs > lhs : false;
} }
template <class T, class U> inline constexpr bool operator>(const U& lhs, const optional<T>& rhs) { template <class T, class U>
inline constexpr bool operator>(const U &lhs, const optional<T> &rhs) {
return rhs.has_value() ? lhs > *rhs : true; return rhs.has_value() ? lhs > *rhs : true;
} }
template <class T, class U> inline constexpr bool operator>=(const optional<T>& lhs, const U& rhs) { template <class T, class U>
inline constexpr bool operator>=(const optional<T> &lhs, const U &rhs) {
return lhs.has_value() ? *lhs >= lhs : false; return lhs.has_value() ? *lhs >= lhs : false;
} }
template <class T, class U> inline constexpr bool operator>=(const U& lhs, const optional<T>& rhs) { template <class T, class U>
inline constexpr bool operator>=(const U &lhs, const optional<T> &rhs) {
return rhs.has_value() ? lhs >= *rhs : true; return rhs.has_value() ? lhs >= *rhs : true;
} }
// [optional.specalg], specialized algorithms // [optional.specalg], specialized algorithms
template <class T, detail::enable_if_t<std::is_move_constructible<T>::value>* = nullptr, template <class T,
detail::enable_if_t<std::is_move_constructible<T>::value> * = nullptr,
detail::enable_if_t<detail::is_swappable<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))) { void swap(optional<T> &lhs,
optional<T> &rhs) noexcept(noexcept(lhs.swap(rhs))) {
return lhs.swap(rhs); return lhs.swap(rhs);
} }
@ -302,7 +350,8 @@ namespace tl {
return optional<T>(in_place, std::forward<Args>(args)...); return optional<T>(in_place, std::forward<Args>(args)...);
} }
template <class T, class U, class... Args> template <class T, class U, class... Args>
inline constexpr optional<T> make_optional(std::initializer_list<U> il, Args&&... args) { inline constexpr optional<T> make_optional(std::initializer_list<U> il,
Args &&... args) {
return optional<T>(in_place, il, std::forward<Args>(args)...); return optional<T>(in_place, il, std::forward<Args>(args)...);
} }
} }
@ -310,8 +359,7 @@ namespace tl {
// [optional.hash], hash support // [optional.hash], hash support
namespace std { namespace std {
// TODO SFINAE // TODO SFINAE
template <class T> template <class T> struct hash<tl::optional<T>> {
struct hash<tl::optional<T>> {
::std::size_t operator()(const tl::optional<T> &o) const { ::std::size_t operator()(const tl::optional<T> &o) const {
if (!o.has_value()) if (!o.has_value())
return 0; return 0;
@ -325,8 +373,7 @@ namespace tl {
namespace detail { namespace detail {
template <class T, bool = ::std::is_trivially_destructible<T>::value> template <class T, bool = ::std::is_trivially_destructible<T>::value>
struct optional_storage_base { struct optional_storage_base {
constexpr optional_storage_base() noexcept constexpr optional_storage_base() noexcept : m_dummy(), m_has_value(false) {}
: m_dummy(), m_has_value(false) {}
template <class... U> template <class... U>
constexpr optional_storage_base(in_place_t, U &&... u) noexcept constexpr optional_storage_base(in_place_t, U &&... u) noexcept
@ -348,11 +395,8 @@ namespace tl {
bool m_has_value; bool m_has_value;
}; };
template <class T> template <class T> struct optional_storage_base<T, true> {
struct optional_storage_base<T, true> { constexpr optional_storage_base() noexcept : m_dummy(), m_has_value(false) {}
constexpr optional_storage_base() noexcept
: m_dummy(), m_has_value(false) {}
template <class... U> template <class... U>
constexpr optional_storage_base(in_place_t, U &&... u) noexcept constexpr optional_storage_base(in_place_t, U &&... u) noexcept
@ -370,9 +414,9 @@ namespace tl {
}; };
} }
template <class T> template <class T> class optional : private detail::optional_storage_base<T> {
class optional : private detail::optional_storage_base<T> {
using base = detail::optional_storage_base<T>; using base = detail::optional_storage_base<T>;
public: public:
using value_type = T; using value_type = T;
@ -387,33 +431,42 @@ namespace tl {
} }
// TODO conditionally disable // TODO conditionally disable
constexpr optional(optional&& rhs) noexcept(std::is_nothrow_move_constructible<T>::value) { constexpr optional(optional &&rhs) noexcept(
std::is_nothrow_move_constructible<T>::value) {
if (rhs.has_value()) { if (rhs.has_value()) {
this->m_has_value = true; this->m_has_value = true;
new (std::addressof(this->m_value)) T(std::move(*rhs)); new (std::addressof(this->m_value)) T(std::move(*rhs));
} }
} }
template <class... Args> template <class... Args>
constexpr explicit optional(detail::enable_if_t<std::is_constructible<T, Args...>::value, in_place_t>, constexpr explicit optional(
detail::enable_if_t<std::is_constructible<T, Args...>::value, in_place_t>,
Args &&... args) Args &&... args)
: base(in_place, std::forward<Args>(args)...) {} : base(in_place, std::forward<Args>(args)...) {}
template <class U, class... Args> template <class U, class... Args>
constexpr explicit optional( constexpr explicit optional(
detail::enable_if_t<std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value, in_place_t>, detail::enable_if_t<std::is_constructible<T, std::initializer_list<U> &,
Args &&...>::value,
in_place_t>,
std::initializer_list<U> il, Args &&... args) { std::initializer_list<U> il, Args &&... args) {
this->m_has_value = true; this->m_has_value = true;
new (std::addressof(this->m_value)) T(il, std::forward<Args>(args)...); new (std::addressof(this->m_value)) T(il, std::forward<Args>(args)...);
} }
template <class U = T, detail::enable_if_t<std::is_convertible<U&&, T>::value>* = nullptr, template <
class U = T,
detail::enable_if_t<std::is_convertible<U &&, T>::value> * = nullptr,
detail::enable_forward_value<T, U> * = nullptr> detail::enable_forward_value<T, U> * = nullptr>
constexpr optional(U &&u) : base(in_place, std::forward<U>(u)) {} constexpr optional(U &&u) : base(in_place, std::forward<U>(u)) {}
template <class U = T, detail::enable_if_t<!std::is_convertible<U&&, T>::value>* = nullptr, template <
class U = T,
detail::enable_if_t<!std::is_convertible<U &&, T>::value> * = nullptr,
detail::enable_forward_value<T, U> * = nullptr> detail::enable_forward_value<T, U> * = nullptr>
constexpr explicit optional(U &&u) : base(in_place, std::forward<U>(u)) {} constexpr explicit optional(U &&u) : base(in_place, std::forward<U>(u)) {}
template <class U, detail::enable_from_other<T,U,const U&>* = nullptr, template <
class U, detail::enable_from_other<T, U, const U &> * = nullptr,
detail::enable_if_t<std::is_convertible<const U &, T>::value> * = nullptr> detail::enable_if_t<std::is_convertible<const U &, T>::value> * = nullptr>
optional(const optional<U> &rhs) { optional(const optional<U> &rhs) {
this->m_has_value = true; this->m_has_value = true;
@ -421,21 +474,23 @@ namespace tl {
} }
template <class U, detail::enable_from_other<T, U, const U &> * = nullptr, template <class U, detail::enable_from_other<T, U, const U &> * = nullptr,
detail::enable_if_t<!std::is_convertible<const U&, T>::value>* = nullptr> detail::enable_if_t<!std::is_convertible<const U &, T>::value> * =
nullptr>
optional(const optional<U> &rhs) { optional(const optional<U> &rhs) {
this->m_has_value = true; this->m_has_value = true;
new (std::addressof(this->m_value)) T(*rhs); new (std::addressof(this->m_value)) T(*rhs);
} }
template <class U, detail::enable_from_other<T,U,U&&>* = nullptr, template <
class U, detail::enable_from_other<T, U, U &&> * = nullptr,
detail::enable_if_t<std::is_convertible<U &&, T>::value> * = nullptr> detail::enable_if_t<std::is_convertible<U &&, T>::value> * = nullptr>
optional(optional<U> &&rhs) { optional(optional<U> &&rhs) {
this->m_has_value = true; this->m_has_value = true;
new (std::addressof(this->m_value)) T(std::move(*rhs)); new (std::addressof(this->m_value)) T(std::move(*rhs));
} }
template <
template <class U, detail::enable_from_other<T,U,U&&>* = nullptr, class U, detail::enable_from_other<T, U, U &&> * = nullptr,
detail::enable_if_t<!std::is_convertible<U &&, T>::value> * = nullptr> detail::enable_if_t<!std::is_convertible<U &&, T>::value> * = nullptr>
explicit optional(optional<U> &&rhs) { explicit optional(optional<U> &&rhs) {
this->m_has_value = true; this->m_has_value = true;
@ -458,8 +513,7 @@ namespace tl {
if (has_value()) { if (has_value()) {
if (rhs.has_value()) { if (rhs.has_value()) {
this->m_value = rhs.m_value; this->m_value = rhs.m_value;
} } else {
else {
this->m_value.~T(); this->m_value.~T();
this->m_has_value = false; this->m_has_value = false;
} }
@ -472,13 +526,13 @@ namespace tl {
} }
// TODO conditionally delete, check exception guarantee // TODO conditionally delete, check exception guarantee
optional& operator=(optional&& rhs) optional &operator=(optional &&rhs) noexcept(
noexcept(std::is_nothrow_move_assignable<T>::value && std::is_nothrow_move_constructible<T>::value) { std::is_nothrow_move_assignable<T>::value
&&std::is_nothrow_move_constructible<T>::value) {
if (has_value()) { if (has_value()) {
if (rhs.has_value()) { if (rhs.has_value()) {
this->m_value = std::move(rhs.m_value); this->m_value = std::move(rhs.m_value);
} } else {
else {
this->m_value.~T(); this->m_value.~T();
this->m_has_value = false; this->m_has_value = false;
} }
@ -491,26 +545,24 @@ namespace tl {
} }
// TODO conditionally delete, check exception guarantee // TODO conditionally delete, check exception guarantee
template <class U = T, template <class U = T, detail::enable_assign_forward<T, U> * = nullptr>
detail::enable_assign_forward<T,U>* = nullptr>
optional &operator=(U &&u) { optional &operator=(U &&u) {
if (has_value()) { if (has_value()) {
this->m_value = std::forward<U>(u); this->m_value = std::forward<U>(u);
} } else {
else {
new (std::addressof(this->m_value)) T(std::forward<U>(u)); new (std::addressof(this->m_value)) T(std::forward<U>(u));
this->m_has_value = true; this->m_has_value = true;
} }
} }
// TODO check exception guarantee // TODO check exception guarantee
template <class U, detail::enable_assign_from_other<T,U,const U&>* = nullptr> template <class U,
detail::enable_assign_from_other<T, U, const U &> * = nullptr>
optional &operator=(const optional<U> &rhs) { optional &operator=(const optional<U> &rhs) {
if (has_value()) { if (has_value()) {
if (rhs.has_value()) { if (rhs.has_value()) {
this->m_value = rhs.m_value; this->m_value = rhs.m_value;
} } else {
else {
this->m_value.~T(); this->m_value.~T();
this->m_has_value = false; this->m_has_value = false;
} }
@ -528,8 +580,7 @@ namespace tl {
if (has_value()) { if (has_value()) {
if (rhs.has_value()) { if (rhs.has_value()) {
this->m_value = std::move(rhs.m_value); this->m_value = std::move(rhs.m_value);
} } else {
else {
this->m_value.~T(); this->m_value.~T();
this->m_has_value = false; this->m_has_value = false;
} }
@ -550,27 +601,27 @@ namespace tl {
} }
template <class U, class... Args> template <class U, class... Args>
detail::enable_if_t<std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value, T&> detail::enable_if_t<
std::is_constructible<T, std::initializer_list<U> &, Args &&...>::value,
T &>
emplace(std::initializer_list<U> il, Args &&... args) { emplace(std::initializer_list<U> il, Args &&... args) {
*this = nullopt; *this = nullopt;
new (std::addressof(this->m_value)) T(il, std::forward<Args>(args)...); new (std::addressof(this->m_value)) T(il, std::forward<Args>(args)...);
} }
// [optional.swap], swap // [optional.swap], swap
void swap(optional& rhs) void
noexcept(std::is_nothrow_move_constructible<T>::value && detail::is_nothrow_swappable<T>::value) swap(optional &rhs) noexcept(std::is_nothrow_move_constructible<T>::value
{ &&detail::is_nothrow_swappable<T>::value) {
if (has_value()) { if (has_value()) {
if (rhs.has_value()) { if (rhs.has_value()) {
using std::swap; using std::swap;
swap(**this, *rhs); swap(**this, *rhs);
} } else {
else {
new (&rhs.m_value) T(std::move(this->m_value)); new (&rhs.m_value) T(std::move(this->m_value));
this->m_value.T::~T(); this->m_value.T::~T();
} }
} } else if (rhs.has_value()) {
else if (rhs.has_value()) {
new (std::addressof(this->m_value)) T(std::move(rhs.m_value)); new (std::addressof(this->m_value)) T(std::move(rhs.m_value));
rhs.m_value.T::~T(); rhs.m_value.T::~T();
} }
@ -580,50 +631,44 @@ namespace tl {
constexpr const T *operator->() const { constexpr const T *operator->() const {
return std::addressof(this->m_value); return std::addressof(this->m_value);
} }
constexpr T* operator->() { constexpr T *operator->() { return std::addressof(this->m_value); }
return std::addressof(this->m_value); constexpr const T &operator*() const & { return this->m_value; }
} constexpr T &operator*() & { return this->m_value; }
constexpr const T& operator*() const& { constexpr T &&operator*() && { return std::move(this->m_value); }
return this->m_value; constexpr const T &&operator*() const && { return std::move(this->m_value); }
}
constexpr T& operator*() & {
return this->m_value;
}
constexpr T&& operator*() && {
return std::move(this->m_value);
}
constexpr const T&& operator*() const&& {
return std::move(this->m_value);
}
constexpr explicit operator bool() const noexcept { constexpr explicit operator bool() const noexcept {
return this->m_has_value; return this->m_has_value;
} }
constexpr bool has_value() const noexcept { constexpr bool has_value() const noexcept { return this->m_has_value; }
return this->m_has_value;
}
constexpr const T &value() const & { constexpr const T &value() const & {
if (has_value()) return this->m_value; if (has_value())
return this->m_value;
throw bad_optional_access(); throw bad_optional_access();
} }
constexpr T &value() & { constexpr T &value() & {
if (has_value()) return this->m_value; if (has_value())
return this->m_value;
throw bad_optional_access(); throw bad_optional_access();
} }
constexpr T &&value() && { constexpr T &&value() && {
if (has_value()) return std::move(this->m_value); if (has_value())
return std::move(this->m_value);
throw bad_optional_access(); throw bad_optional_access();
} }
constexpr const T &&value() const && { constexpr const T &&value() const && {
if (has_value()) return std::move(this->m_value); if (has_value())
return std::move(this->m_value);
throw bad_optional_access(); throw bad_optional_access();
} }
template <class U> constexpr T value_or(U &&u) const & { template <class U> constexpr T value_or(U &&u) const & {
static_assert(std::is_copy_constructible<T>::value && std::is_convertible<U&&, T>::value, static_assert(std::is_copy_constructible<T>::value &&
std::is_convertible<U &&, T>::value,
"T must be copy constructible and convertible from U"); "T must be copy constructible and convertible from U");
return has_value() ? **this : static_cast<T>(std::forward<U>(u)); return has_value() ? **this : static_cast<T>(std::forward<U>(u));
} }
template <class U> constexpr T value_or(U &&u) && { template <class U> constexpr T value_or(U &&u) && {
static_assert(std::is_move_constructible<T>::value && std::is_convertible<U&&, T>::value, static_assert(std::is_move_constructible<T>::value &&
std::is_convertible<U &&, T>::value,
"T must be move constructible and convertible from U"); "T must be move constructible and convertible from U");
return has_value() ? **this : static_cast<T>(std::forward<U>(u)); return has_value() ? **this : static_cast<T>(std::forward<U>(u));
} }