diff options
author | Eike Ziller <eike.ziller@qt.io> | 2016-07-13 11:19:24 +0200 |
---|---|---|
committer | Eike Ziller <eike.ziller@qt.io> | 2017-06-16 12:19:27 +0000 |
commit | 93f4fb771fbfcb8499601b497a4b2b436d872c1d (patch) | |
tree | 2778fa04bc9a160ab4a639910627065cd408f9ef /src/libs/3rdparty | |
parent | 42580c7d0ca703f216bcb19e12259b1022d8b423 (diff) | |
download | qt-creator-93f4fb771fbfcb8499601b497a4b2b436d872c1d.tar.gz |
Add std::experimental::optional as Utils::optional
Uses the reference implementation of the proposal, which later
can be replaced by the std lib implementation depending on compiler
and used C++ version.
Change-Id: I23f2f8077f4cb26c3d9a403b1ce438b6cdb163f2
Reviewed-by: Tobias Hunger <tobias.hunger@qt.io>
Diffstat (limited to 'src/libs/3rdparty')
-rw-r--r-- | src/libs/3rdparty/optional/CMakeLists.txt | 11 | ||||
-rw-r--r-- | src/libs/3rdparty/optional/LICENSE_1_0.txt | 23 | ||||
-rw-r--r-- | src/libs/3rdparty/optional/README.md | 39 | ||||
-rw-r--r-- | src/libs/3rdparty/optional/copyright.txt | 10 | ||||
-rw-r--r-- | src/libs/3rdparty/optional/optional.hpp | 1042 | ||||
-rw-r--r-- | src/libs/3rdparty/optional/test_optional.cpp | 1459 | ||||
-rw-r--r-- | src/libs/3rdparty/optional/test_type_traits.cpp | 66 |
7 files changed, 2650 insertions, 0 deletions
diff --git a/src/libs/3rdparty/optional/CMakeLists.txt b/src/libs/3rdparty/optional/CMakeLists.txt new file mode 100644 index 0000000000..07f38f7993 --- /dev/null +++ b/src/libs/3rdparty/optional/CMakeLists.txt @@ -0,0 +1,11 @@ +project(optional) +cmake_minimum_required(VERSION 2.8) +enable_testing() + +set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wextra") + +add_executable(test_optional test_optional.cpp) +add_executable(test_type_traits test_type_traits.cpp) + +add_test(test_optional test_optional) +add_test(test_type_traits test_type_traits) diff --git a/src/libs/3rdparty/optional/LICENSE_1_0.txt b/src/libs/3rdparty/optional/LICENSE_1_0.txt new file mode 100644 index 0000000000..36b7cd93cd --- /dev/null +++ b/src/libs/3rdparty/optional/LICENSE_1_0.txt @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/libs/3rdparty/optional/README.md b/src/libs/3rdparty/optional/README.md new file mode 100644 index 0000000000..948516d1ba --- /dev/null +++ b/src/libs/3rdparty/optional/README.md @@ -0,0 +1,39 @@ +Optional +======== + +A single-header header-only library for representing optional (nullable) objects for C++14 (and C++11 to some extent) and passing them by value. This is the reference implementation of proposal N3793 (see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3793.html). Optional is now accepted into Library Fundamentals Technical Specification (see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3848.html). The interface is based on Fernando Cacciola's Boost.Optional library (see http://www.boost.org/doc/libs/1_52_0/libs/optional/doc/html/index.html) + + +Usage +----- + +```cpp +optional<int> readInt(); // this function may return int or a not-an-int + +if (optional<int> oi = readInt()) // did I get a real int + cout << "my int is: " << *oi; // use my int +else + cout << "I have no int"; +``` + +For more usage examples and the overview see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3527.html + + +Supported compilers +------------------- + +Clang 3.2, Clang 3.4, G++ 4.7.2, G++ 4.8.1. Tested only with libstdc++, versions 20130531, 20120920, 20110428. Others have reported it also works with libc++. + + + +Known Issues +------------ + + - Currently, the reference (and the only known) implementation of certain pieces of functionality explore what C++11 identifies as undefined behavior (see national body comment FI 15: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3770.html#FI15). This is mostly why Optional was removed from C++14 and put into Library Fundamentals TS. Luckily what the Standard identifies as UB is well defined on all known platforms. We expect that the C++14 wil fix this problem, so that our trick becomes well-defined. + - In libstdc++ versions below 20130531 the constructor taking `initializer_list` argument is not `constexpr`. This is because `initializer_list` operations are not `constexpr` in C++11. This works however in version 20130531. It is also not enabled for libc++ because I do not have access to it and do nto know if it provides `constexpr` `initializer_list`. + - In G++ 4.7.2 and 4.8.0 member function `value_or` does not have rvalue reference overload. These compilers do not support rvalue overloding on `*this`. + - In order for the library to work with slightly older compilers, we emulate some missing type traits. On some platforms we cannot correctly detect the available features, and attempts at workarounds for missing type trait definitions can cause compile-time errors. Define macro `TR2_OPTIONAL_DISABLE_EMULATION_OF_TYPE_TRAITS` if you know that all the necessary type traits are defined, and no emulation is required. + +License +------- +Distributed under the [Boost Software License, Version 1.0](http://www.boost.org/LICENSE_1_0.txt). diff --git a/src/libs/3rdparty/optional/copyright.txt b/src/libs/3rdparty/optional/copyright.txt new file mode 100644 index 0000000000..1641c3cdd0 --- /dev/null +++ b/src/libs/3rdparty/optional/copyright.txt @@ -0,0 +1,10 @@ +Copyright (C) 2011-2012 Andrzej Krzemienski + +Distributed under the Boost Software License, Version 1.0 +(see accompanying file LICENSE_1_0.txt or a copy at +http://www.boost.org/LICENSE_1_0.txt) + +The idea and interface is based on Boost.Optional library +authored by Fernando Luis Cacciola Carballal + +Home at https://github.com/akrzemi1/Optional
\ No newline at end of file diff --git a/src/libs/3rdparty/optional/optional.hpp b/src/libs/3rdparty/optional/optional.hpp new file mode 100644 index 0000000000..26d806450b --- /dev/null +++ b/src/libs/3rdparty/optional/optional.hpp @@ -0,0 +1,1042 @@ +// Copyright (C) 2011 - 2012 Andrzej Krzemienski. +// +// Use, modification, and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// The idea and interface is based on Boost.Optional library +// authored by Fernando Luis Cacciola Carballal + +# ifndef ___OPTIONAL_HPP___ +# define ___OPTIONAL_HPP___ + +# include <utility> +# include <type_traits> +# include <initializer_list> +# include <cassert> +# include <functional> +# include <string> +# include <stdexcept> + +# define TR2_OPTIONAL_REQUIRES(...) typename enable_if<__VA_ARGS__::value, bool>::type = false + +# if defined __GNUC__ // NOTE: GNUC is also defined for Clang +# if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 8) +# define TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ +# elif (__GNUC__ > 4) +# define TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ +# endif +# +# if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 7) +# define TR2_OPTIONAL_GCC_4_7_AND_HIGHER___ +# elif (__GNUC__ > 4) +# define TR2_OPTIONAL_GCC_4_7_AND_HIGHER___ +# endif +# +# if (__GNUC__ == 4) && (__GNUC_MINOR__ == 8) && (__GNUC_PATCHLEVEL__ >= 1) +# define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ +# elif (__GNUC__ == 4) && (__GNUC_MINOR__ >= 9) +# define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ +# elif (__GNUC__ > 4) +# define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ +# endif +# endif +# +# if defined __clang_major__ +# if (__clang_major__ == 3 && __clang_minor__ >= 5) +# define TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ +# elif (__clang_major__ > 3) +# define TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ +# endif +# if defined TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ +# define TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ +# elif (__clang_major__ == 3 && __clang_minor__ == 4 && __clang_patchlevel__ >= 2) +# define TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ +# endif +# endif +# +# if defined _MSC_VER +# if (_MSC_VER >= 1900) +# define TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ +# endif +# endif + +# if defined __clang__ +# if (__clang_major__ > 2) || (__clang_major__ == 2) && (__clang_minor__ >= 9) +# define OPTIONAL_HAS_THIS_RVALUE_REFS 1 +# else +# define OPTIONAL_HAS_THIS_RVALUE_REFS 0 +# endif +# elif defined TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ +# define OPTIONAL_HAS_THIS_RVALUE_REFS 1 +# elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ +# define OPTIONAL_HAS_THIS_RVALUE_REFS 1 +# else +# define OPTIONAL_HAS_THIS_RVALUE_REFS 0 +# endif + + +# if defined TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ +# define OPTIONAL_HAS_CONSTEXPR_INIT_LIST 1 +# define OPTIONAL_CONSTEXPR_INIT_LIST constexpr +# else +# define OPTIONAL_HAS_CONSTEXPR_INIT_LIST 0 +# define OPTIONAL_CONSTEXPR_INIT_LIST +# endif + +# if defined TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ && (defined __cplusplus) && (__cplusplus != 201103L) +# define OPTIONAL_HAS_MOVE_ACCESSORS 1 +# else +# define OPTIONAL_HAS_MOVE_ACCESSORS 0 +# endif + +# // In C++11 constexpr implies const, so we need to make non-const members also non-constexpr +# if (defined __cplusplus) && (__cplusplus == 201103L) +# define OPTIONAL_MUTABLE_CONSTEXPR +# else +# define OPTIONAL_MUTABLE_CONSTEXPR constexpr +# endif + +namespace std{ + +namespace experimental{ + +// BEGIN workaround for missing is_trivially_destructible +# if defined TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ + // leave it: it is already there +# elif defined TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ + // leave it: it is already there +# elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ + // leave it: it is already there +# elif defined TR2_OPTIONAL_DISABLE_EMULATION_OF_TYPE_TRAITS + // leave it: the user doesn't want it +# else + template <typename T> + using is_trivially_destructible = std::has_trivial_destructor<T>; +# endif +// END workaround for missing is_trivially_destructible + +# if (defined TR2_OPTIONAL_GCC_4_7_AND_HIGHER___) + // leave it; our metafunctions are already defined. +# elif defined TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ + // leave it; our metafunctions are already defined. +# elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ + // leave it: it is already there +# elif defined TR2_OPTIONAL_DISABLE_EMULATION_OF_TYPE_TRAITS + // leave it: the user doesn't want it +# else + + +// workaround for missing traits in GCC and CLANG +template <class T> +struct is_nothrow_move_constructible +{ + constexpr static bool value = std::is_nothrow_constructible<T, T&&>::value; +}; + + +template <class T, class U> +struct is_assignable +{ + template <class X, class Y> + constexpr static bool has_assign(...) { return false; } + + template <class X, class Y, size_t S = sizeof((std::declval<X>() = std::declval<Y>(), true)) > + // the comma operator is necessary for the cases where operator= returns void + constexpr static bool has_assign(bool) { return true; } + + constexpr static bool value = has_assign<T, U>(true); +}; + + +template <class T> +struct is_nothrow_move_assignable +{ + template <class X, bool has_any_move_assign> + struct has_nothrow_move_assign { + constexpr static bool value = false; + }; + + template <class X> + struct has_nothrow_move_assign<X, true> { + constexpr static bool value = noexcept( std::declval<X&>() = std::declval<X&&>() ); + }; + + constexpr static bool value = has_nothrow_move_assign<T, is_assignable<T&, T&&>::value>::value; +}; +// end workaround + + +# endif + + + +// 20.5.4, optional for object types +template <class T> class optional; + +// 20.5.5, optional for lvalue reference types +template <class T> class optional<T&>; + + +// workaround: std utility functions aren't constexpr yet +template <class T> inline constexpr T&& constexpr_forward(typename std::remove_reference<T>::type& t) noexcept +{ + return static_cast<T&&>(t); +} + +template <class T> inline constexpr T&& constexpr_forward(typename std::remove_reference<T>::type&& t) noexcept +{ + static_assert(!std::is_lvalue_reference<T>::value, "!!"); + return static_cast<T&&>(t); +} + +template <class T> inline constexpr typename std::remove_reference<T>::type&& constexpr_move(T&& t) noexcept +{ + return static_cast<typename std::remove_reference<T>::type&&>(t); +} + + +#if defined NDEBUG +# define TR2_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) (EXPR) +#else +# define TR2_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) ((CHECK) ? (EXPR) : ([]{assert(!#CHECK);}(), (EXPR))) +#endif + + +namespace detail_ +{ + +// static_addressof: a constexpr version of addressof +template <typename T> +struct has_overloaded_addressof +{ + template <class X> + constexpr static bool has_overload(...) { return false; } + + template <class X, size_t S = sizeof(std::declval<X&>().operator&()) > + constexpr static bool has_overload(bool) { return true; } + + constexpr static bool value = has_overload<T>(true); +}; + +template <typename T, TR2_OPTIONAL_REQUIRES(!has_overloaded_addressof<T>)> +constexpr T* static_addressof(T& ref) +{ + return &ref; +} + +template <typename T, TR2_OPTIONAL_REQUIRES(has_overloaded_addressof<T>)> +T* static_addressof(T& ref) +{ + return std::addressof(ref); +} + + +// the call to convert<A>(b) has return type A and converts b to type A iff b decltype(b) is implicitly convertible to A +template <class U> +constexpr U convert(U v) { return v; } + +} // namespace detail + + +constexpr struct trivial_init_t{} trivial_init{}; + + +// 20.5.6, In-place construction +constexpr struct in_place_t{} in_place{}; + + +// 20.5.7, Disengaged state indicator +struct nullopt_t +{ + struct init{}; + constexpr explicit nullopt_t(init){} +}; +constexpr nullopt_t nullopt{nullopt_t::init()}; + + +// 20.5.8, class bad_optional_access +class bad_optional_access : public logic_error { +public: + explicit bad_optional_access(const string& what_arg) : logic_error{what_arg} {} + explicit bad_optional_access(const char* what_arg) : logic_error{what_arg} {} +}; + + +template <class T> +union storage_t +{ + unsigned char dummy_; + T value_; + + constexpr storage_t( trivial_init_t ) noexcept : dummy_() {}; + + template <class... Args> + constexpr storage_t( Args&&... args ) : value_(constexpr_forward<Args>(args)...) {} + + ~storage_t(){} +}; + + +template <class T> +union constexpr_storage_t +{ + unsigned char dummy_; + T value_; + + constexpr constexpr_storage_t( trivial_init_t ) noexcept : dummy_() {}; + + template <class... Args> + constexpr constexpr_storage_t( Args&&... args ) : value_(constexpr_forward<Args>(args)...) {} + + ~constexpr_storage_t() = default; +}; + + +template <class T> +struct optional_base +{ + bool init_; + storage_t<T> storage_; + + constexpr optional_base() noexcept : init_(false), storage_(trivial_init) {}; + + explicit constexpr optional_base(const T& v) : init_(true), storage_(v) {} + + explicit constexpr optional_base(T&& v) : init_(true), storage_(constexpr_move(v)) {} + + template <class... Args> explicit optional_base(in_place_t, Args&&... args) + : init_(true), storage_(constexpr_forward<Args>(args)...) {} + + template <class U, class... Args, TR2_OPTIONAL_REQUIRES(is_constructible<T, std::initializer_list<U>>)> + explicit optional_base(in_place_t, std::initializer_list<U> il, Args&&... args) + : init_(true), storage_(il, std::forward<Args>(args)...) {} + + ~optional_base() { if (init_) storage_.value_.T::~T(); } +}; + + +template <class T> +struct constexpr_optional_base +{ + bool init_; + constexpr_storage_t<T> storage_; + + constexpr constexpr_optional_base() noexcept : init_(false), storage_(trivial_init) {}; + + explicit constexpr constexpr_optional_base(const T& v) : init_(true), storage_(v) {} + + explicit constexpr constexpr_optional_base(T&& v) : init_(true), storage_(constexpr_move(v)) {} + + template <class... Args> explicit constexpr constexpr_optional_base(in_place_t, Args&&... args) + : init_(true), storage_(constexpr_forward<Args>(args)...) {} + + template <class U, class... Args, TR2_OPTIONAL_REQUIRES(is_constructible<T, std::initializer_list<U>>)> + OPTIONAL_CONSTEXPR_INIT_LIST explicit constexpr_optional_base(in_place_t, std::initializer_list<U> il, Args&&... args) + : init_(true), storage_(il, std::forward<Args>(args)...) {} + + ~constexpr_optional_base() = default; +}; + +template <class T> +using OptionalBase = typename std::conditional< + is_trivially_destructible<T>::value, + constexpr_optional_base<typename std::remove_const<T>::type>, + optional_base<typename std::remove_const<T>::type> +>::type; + + + +template <class T> +class optional : private OptionalBase<T> +{ + static_assert( !std::is_same<typename std::decay<T>::type, nullopt_t>::value, "bad T" ); + static_assert( !std::is_same<typename std::decay<T>::type, in_place_t>::value, "bad T" ); + + + constexpr bool initialized() const noexcept { return OptionalBase<T>::init_; } + typename std::remove_const<T>::type* dataptr() { return std::addressof(OptionalBase<T>::storage_.value_); } + constexpr const T* dataptr() const { return detail_::static_addressof(OptionalBase<T>::storage_.value_); } + +# if OPTIONAL_HAS_THIS_RVALUE_REFS == 1 + constexpr const T& contained_val() const& { return OptionalBase<T>::storage_.value_; } +# if OPTIONAL_HAS_MOVE_ACCESSORS == 1 + OPTIONAL_MUTABLE_CONSTEXPR T&& contained_val() && { return std::move(OptionalBase<T>::storage_.value_); } + OPTIONAL_MUTABLE_CONSTEXPR T& contained_val() & { return OptionalBase<T>::storage_.value_; } +# else + T& contained_val() & { return OptionalBase<T>::storage_.value_; } + T&& contained_val() && { return std::move(OptionalBase<T>::storage_.value_); } +# endif +# else + constexpr const T& contained_val() const { return OptionalBase<T>::storage_.value_; } + T& contained_val() { return OptionalBase<T>::storage_.value_; } +# endif + + void clear() noexcept { + if (initialized()) dataptr()->T::~T(); + OptionalBase<T>::init_ = false; + } + + template <class... Args> + void initialize(Args&&... args) noexcept(noexcept(T(std::forward<Args>(args)...))) + { + assert(!OptionalBase<T>::init_); + ::new (static_cast<void*>(dataptr())) T(std::forward<Args>(args)...); + OptionalBase<T>::init_ = true; + } + + template <class U, class... Args> + void initialize(std::initializer_list<U> il, Args&&... args) noexcept(noexcept(T(il, std::forward<Args>(args)...))) + { + assert(!OptionalBase<T>::init_); + ::new (static_cast<void*>(dataptr())) T(il, std::forward<Args>(args)...); + OptionalBase<T>::init_ = true; + } + +public: + typedef T value_type; + + // 20.5.5.1, constructors + constexpr optional() noexcept : OptionalBase<T>() {}; + constexpr optional(nullopt_t) noexcept : OptionalBase<T>() {}; + + optional(const optional& rhs) + : OptionalBase<T>() + { + if (rhs.initialized()) { + ::new (static_cast<void*>(dataptr())) T(*rhs); + OptionalBase<T>::init_ = true; + } + } + + optional(optional&& rhs) noexcept(is_nothrow_move_constructible<T>::value) + : OptionalBase<T>() + { + if (rhs.initialized()) { + ::new (static_cast<void*>(dataptr())) T(std::move(*rhs)); + OptionalBase<T>::init_ = true; + } + } + + constexpr optional(const T& v) : OptionalBase<T>(v) {} + + constexpr optional(T&& v) : OptionalBase<T>(constexpr_move(v)) {} + + template <class... Args> + explicit constexpr optional(in_place_t, Args&&... args) + : OptionalBase<T>(in_place_t{}, constexpr_forward<Args>(args)...) {} + + template <class U, class... Args, TR2_OPTIONAL_REQUIRES(is_constructible<T, std::initializer_list<U>>)> + OPTIONAL_CONSTEXPR_INIT_LIST explicit optional(in_place_t, std::initializer_list<U> il, Args&&... args) + : OptionalBase<T>(in_place_t{}, il, constexpr_forward<Args>(args)...) {} + + // 20.5.4.2, Destructor + ~optional() = default; + + // 20.5.4.3, assignment + optional& operator=(nullopt_t) noexcept + { + clear(); + return *this; + } + + optional& operator=(const optional& rhs) + { + if (initialized() == true && rhs.initialized() == false) clear(); + else if (initialized() == false && rhs.initialized() == true) initialize(*rhs); + else if (initialized() == true && rhs.initialized() == true) contained_val() = *rhs; + return *this; + } + + optional& operator=(optional&& rhs) + noexcept(is_nothrow_move_assignable<T>::value && is_nothrow_move_constructible<T>::value) + { + if (initialized() == true && rhs.initialized() == false) clear(); + else if (initialized() == false && rhs.initialized() == true) initialize(std::move(*rhs)); + else if (initialized() == true && rhs.initialized() == true) contained_val() = std::move(*rhs); + return *this; + } + + template <class U> + auto operator=(U&& v) + -> typename enable_if + < + is_same<typename decay<U>::type, T>::value, + optional& + >::type + { + if (initialized()) { contained_val() = std::forward<U>(v); } + else { initialize(std::forward<U>(v)); } + return *this; + } + + + template <class... Args> + void emplace(Args&&... args) + { + clear(); + initialize(std::forward<Args>(args)...); + } + + template <class U, class... Args> + void emplace(initializer_list<U> il, Args&&... args) + { + clear(); + initialize<U, Args...>(il, std::forward<Args>(args)...); + } + + // 20.5.4.4, Swap + void swap(optional<T>& rhs) noexcept(is_nothrow_move_constructible<T>::value && noexcept(swap(declval<T&>(), declval<T&>()))) + { + if (initialized() == true && rhs.initialized() == false) { rhs.initialize(std::move(**this)); clear(); } + else if (initialized() == false && rhs.initialized() == true) { initialize(std::move(*rhs)); rhs.clear(); } + else if (initialized() == true && rhs.initialized() == true) { using std::swap; swap(**this, *rhs); } + } + + // 20.5.4.5, Observers + + explicit constexpr operator bool() const noexcept { return initialized(); } + + constexpr T const* operator ->() const { + return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), dataptr()); + } + +# if OPTIONAL_HAS_MOVE_ACCESSORS == 1 + + OPTIONAL_MUTABLE_CONSTEXPR T* operator ->() { + assert (initialized()); + return dataptr(); + } + + constexpr T const& operator *() const& { + return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), contained_val()); + } + + OPTIONAL_MUTABLE_CONSTEXPR T& operator *() & { + assert (initialized()); + return contained_val(); + } + + OPTIONAL_MUTABLE_CONSTEXPR T&& operator *() && { + assert (initialized()); + return constexpr_move(contained_val()); + } + + constexpr T const& value() const& { + return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); + } + + OPTIONAL_MUTABLE_CONSTEXPR T& value() & { + return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); + } + + OPTIONAL_MUTABLE_CONSTEXPR T&& value() && { + if (!initialized()) throw bad_optional_access("bad optional access"); + return std::move(contained_val()); + } + +# else + + T* operator ->() { + assert (initialized()); + return dataptr(); + } + + constexpr T const& operator *() const { + return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), contained_val()); + } + + T& operator *() { + assert (initialized()); + return contained_val(); + } + + constexpr T const& value() const { + return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); + } + + T& value() { + return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); + } + +# endif + +# if OPTIONAL_HAS_THIS_RVALUE_REFS == 1 + + template <class V> + constexpr T value_or(V&& v) const& + { + return *this ? **this : detail_::convert<T>(constexpr_forward<V>(v)); + } + +# if OPTIONAL_HAS_MOVE_ACCESSORS == 1 + + template <class V> + OPTIONAL_MUTABLE_CONSTEXPR T value_or(V&& v) && + { + return *this ? constexpr_move(const_cast<optional<T>&>(*this).contained_val()) : detail_::convert<T>(constexpr_forward<V>(v)); + } + +# else + + template <class V> + T value_or(V&& v) && + { + return *this ? constexpr_move(const_cast<optional<T>&>(*this).contained_val()) : detail_::convert<T>(constexpr_forward<V>(v)); + } + +# endif + +# else + + template <class V> + constexpr T value_or(V&& v) const + { + return *this ? **this : detail_::convert<T>(constexpr_forward<V>(v)); + } + +# endif + +}; + + +template <class T> +class optional<T&> +{ + static_assert( !std::is_same<T, nullopt_t>::value, "bad T" ); + static_assert( !std::is_same<T, in_place_t>::value, "bad T" ); + T* ref; + +public: + + // 20.5.5.1, construction/destruction + constexpr optional() noexcept : ref(nullptr) {} + + constexpr optional(nullopt_t) noexcept : ref(nullptr) {} + + constexpr optional(T& v) noexcept : ref(detail_::static_addressof(v)) {} + + optional(T&&) = delete; + + constexpr optional(const optional& rhs) noexcept : ref(rhs.ref) {} + + explicit constexpr optional(in_place_t, T& v) noexcept : ref(detail_::static_addressof(v)) {} + + explicit optional(in_place_t, T&&) = delete; + + ~optional() = default; + + // 20.5.5.2, mutation + optional& operator=(nullopt_t) noexcept { + ref = nullptr; + return *this; + } + + // optional& operator=(const optional& rhs) noexcept { + // ref = rhs.ref; + // return *this; + // } + + // optional& operator=(optional&& rhs) noexcept { + // ref = rhs.ref; + // return *this; + // } + + template <typename U> + auto operator=(U&& rhs) noexcept + -> typename enable_if + < + is_same<typename decay<U>::type, optional<T&>>::value, + optional& + >::type + { + ref = rhs.ref; + return *this; + } + + template <typename U> + auto operator=(U&& rhs) noexcept + -> typename enable_if + < + !is_same<typename decay<U>::type, optional<T&>>::value, + optional& + >::type + = delete; + + void emplace(T& v) noexcept { + ref = detail_::static_addressof(v); + } + + void emplace(T&&) = delete; + + + void swap(optional<T&>& rhs) noexcept + { + std::swap(ref, rhs.ref); + } + + // 20.5.5.3, observers + constexpr T* operator->() const { + return TR2_OPTIONAL_ASSERTED_EXPRESSION(ref, ref); + } + + constexpr T& operator*() const { + return TR2_OPTIONAL_ASSERTED_EXPRESSION(ref, *ref); + } + + constexpr T& value() const { + return ref ? *ref : (throw bad_optional_access("bad optional access"), *ref); + } + + explicit constexpr operator bool() const noexcept { + return ref != nullptr; + } + + template <class V> + constexpr typename decay<T>::type value_or(V&& v) const + { + return *this ? **this : detail_::convert<typename decay<T>::type>(constexpr_forward<V>(v)); + } +}; + + +template <class T> +class optional<T&&> +{ + static_assert( sizeof(T) == 0, "optional rvalue references disallowed" ); +}; + + +// 20.5.8, Relational operators +template <class T> constexpr bool operator==(const optional<T>& x, const optional<T>& y) +{ + return bool(x) != bool(y) ? false : bool(x) == false ? true : *x == *y; +} + +template <class T> constexpr bool operator!=(const optional<T>& x, const optional<T>& y) +{ + return !(x == y); +} + +template <class T> constexpr bool operator<(const optional<T>& x, const optional<T>& y) +{ + return (!y) ? false : (!x) ? true : *x < *y; +} + +template <class T> constexpr bool operator>(const optional<T>& x, const optional<T>& y) +{ + return (y < x); +} + +template <class T> constexpr bool operator<=(const optional<T>& x, const optional<T>& y) +{ + return !(y < x); +} + +template <class T> constexpr bool operator>=(const optional<T>& x, const optional<T>& y) +{ + return !(x < y); +} + + +// 20.5.9, Comparison with nullopt +template <class T> constexpr bool operator==(const optional<T>& x, nullopt_t) noexcept +{ + return (!x); +} + +template <class T> constexpr bool operator==(nullopt_t, const optional<T>& x) noexcept +{ + return (!x); +} + +template <class T> constexpr bool operator!=(const optional<T>& x, nullopt_t) noexcept +{ + return bool(x); +} + +template <class T> constexpr bool operator!=(nullopt_t, const optional<T>& x) noexcept +{ + return bool(x); +} + +template <class T> constexpr bool operator<(const optional<T>&, nullopt_t) noexcept +{ + return false; +} + +template <class T> constexpr bool operator<(nullopt_t, const optional<T>& x) noexcept +{ + return bool(x); +} + +template <class T> constexpr bool operator<=(const optional<T>& x, nullopt_t) noexcept +{ + return (!x); +} + +template <class T> constexpr bool operator<=(nullopt_t, const optional<T>&) noexcept +{ + return true; +} + +template <class T> constexpr bool operator>(const optional<T>& x, nullopt_t) noexcept +{ + return bool(x); +} + +template <class T> constexpr bool operator>(nullopt_t, const optional<T>&) noexcept +{ + return false; +} + +template <class T> constexpr bool operator>=(const optional<T>&, nullopt_t) noexcept +{ + return true; +} + +template <class T> constexpr bool operator>=(nullopt_t, const optional<T>& x) noexcept +{ + return (!x); +} + + + +// 20.5.10, Comparison with T +template <class T> constexpr bool operator==(const optional<T>& x, const T& v) +{ + return bool(x) ? *x == v : false; +} + +template <class T> constexpr bool operator==(const T& v, const optional<T>& x) +{ + return bool(x) ? v == *x : false; +} + +template <class T> constexpr bool operator!=(const optional<T>& x, const T& v) +{ + return bool(x) ? *x != v : true; +} + +template <class T> constexpr bool operator!=(const T& v, const optional<T>& x) +{ + return bool(x) ? v != *x : true; +} + +template <class T> constexpr bool operator<(const optional<T>& x, const T& v) +{ + return bool(x) ? *x < v : true; +} + +template <class T> constexpr bool operator>(const T& v, const optional<T>& x) +{ + return bool(x) ? v > *x : true; +} + +template <class T> constexpr bool operator>(const optional<T>& x, const T& v) +{ + return bool(x) ? *x > v : false; +} + +template <class T> constexpr bool operator<(const T& v, const optional<T>& x) +{ + return bool(x) ? v < *x : false; +} + +template <class T> constexpr bool operator>=(const optional<T>& x, const T& v) +{ + return bool(x) ? *x >= v : false; +} + +template <class T> constexpr bool operator<=(const T& v, const optional<T>& x) +{ + return bool(x) ? v <= *x : false; +} + +template <class T> constexpr bool operator<=(const optional<T>& x, const T& v) +{ + return bool(x) ? *x <= v : true; +} + +template <class T> constexpr bool operator>=(const T& v, const optional<T>& x) +{ + return bool(x) ? v >= *x : true; +} + + +// Comparison of optional<T&> with T +template <class T> constexpr bool operator==(const optional<T&>& x, const T& v) +{ + return bool(x) ? *x == v : false; +} + +template <class T> constexpr bool operator==(const T& v, const optional<T&>& x) +{ + return bool(x) ? v == *x : false; +} + +template <class T> constexpr bool operator!=(const optional<T&>& x, const T& v) +{ + return bool(x) ? *x != v : true; +} + +template <class T> constexpr bool operator!=(const T& v, const optional<T&>& x) +{ + return bool(x) ? v != *x : true; +} + +template <class T> constexpr bool operator<(const optional<T&>& x, const T& v) +{ + return bool(x) ? *x < v : true; +} + +template <class T> constexpr bool operator>(const T& v, const optional<T&>& x) +{ + return bool(x) ? v > *x : true; +} + +template <class T> constexpr bool operator>(const optional<T&>& x, const T& v) +{ + return bool(x) ? *x > v : false; +} + +template <class T> constexpr bool operator<(const T& v, const optional<T&>& x) +{ + return bool(x) ? v < *x : false; +} + +template <class T> constexpr bool operator>=(const optional<T&>& x, const T& v) +{ + return bool(x) ? *x >= v : false; +} + +template <class T> constexpr bool operator<=(const T& v, const optional<T&>& x) +{ + return bool(x) ? v <= *x : false; +} + +template <class T> constexpr bool operator<=(const optional<T&>& x, const T& v) +{ + return bool(x) ? *x <= v : true; +} + +template <class T> constexpr bool operator>=(const T& v, const optional<T&>& x) +{ + return bool(x) ? v >= *x : true; +} + +// Comparison of optional<T const&> with T +template <class T> constexpr bool operator==(const optional<const T&>& x, const T& v) +{ + return bool(x) ? *x == v : false; +} + +template <class T> constexpr bool operator==(const T& v, const optional<const T&>& x) +{ + return bool(x) ? v == *x : false; +} + +template <class T> constexpr bool operator!=(const optional<const T&>& x, const T& v) +{ + return bool(x) ? *x != v : true; +} + +template <class T> constexpr bool operator!=(const T& v, const optional<const T&>& x) +{ + return bool(x) ? v != *x : true; +} + +template <class T> constexpr bool operator<(const optional<const T&>& x, const T& v) +{ + return bool(x) ? *x < v : true; +} + +template <class T> constexpr bool operator>(const T& v, const optional<const T&>& x) +{ + return bool(x) ? v > *x : true; +} + +template <class T> constexpr bool operator>(const optional<const T&>& x, const T& v) +{ + return bool(x) ? *x > v : false; +} + +template <class T> constexpr bool operator<(const T& v, const optional<const T&>& x) +{ + return bool(x) ? v < *x : false; +} + +template <class T> constexpr bool operator>=(const optional<const T&>& x, const T& v) +{ + return bool(x) ? *x >= v : false; +} + +template <class T> constexpr bool operator<=(const T& v, const optional<const T&>& x) +{ + return bool(x) ? v <= *x : false; +} + +template <class T> constexpr bool operator<=(const optional<const T&>& x, const T& v) +{ + return bool(x) ? *x <= v : true; +} + +template <class T> constexpr bool operator>=(const T& v, const optional<const T&>& x) +{ + return bool(x) ? v >= *x : true; +} + + +// 20.5.12, Specialized algorithms +template <class T> +void swap(optional<T>& x, optional<T>& y) noexcept(noexcept(x.swap(y))) +{ + x.swap(y); +} + + +template <class T> +constexpr optional<typename decay<T>::type> make_optional(T&& v) +{ + return optional<typename decay<T>::type>(constexpr_forward<T>(v)); +} + +template <class X> +constexpr optional<X&> make_optional(reference_wrapper<X> v) +{ + return optional<X&>(v.get()); +} + + +} // namespace experimental +} // namespace std + +namespace std +{ + template <typename T> + struct hash<std::experimental::optional<T>> + { + typedef typename hash<T>::result_type result_type; + typedef std::experimental::optional<T> argument_type; + + constexpr result_type operator()(argument_type const& arg) const { + return arg ? std::hash<T>{}(*arg) : result_type{}; + } + }; + + template <typename T> + struct hash<std::experimental::optional<T&>> + { + typedef typename hash<T>::result_type result_type; + typedef std::experimental::optional<T&> argument_type; + + constexpr result_type operator()(argument_type const& arg) const { + return arg ? std::hash<T>{}(*arg) : result_type{}; + } + }; +} + +# undef TR2_OPTIONAL_REQUIRES +# undef TR2_OPTIONAL_ASSERTED_EXPRESSION + +# endif //___OPTIONAL_HPP___ diff --git a/src/libs/3rdparty/optional/test_optional.cpp b/src/libs/3rdparty/optional/test_optional.cpp new file mode 100644 index 0000000000..8ed356a562 --- /dev/null +++ b/src/libs/3rdparty/optional/test_optional.cpp @@ -0,0 +1,1459 @@ +// Copyright (C) 2011 - 2012 Andrzej Krzemienski. +// +// Use, modification, and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// The idea and interface is based on Boost.Optional library +// authored by Fernando Luis Cacciola Carballal + +# include "optional.hpp" +# include <vector> +# include <iostream> +# include <functional> +# include <complex> + + + +struct caller { + template <class T> caller(T fun) { fun(); } +}; +# define CAT2(X, Y) X ## Y +# define CAT(X, Y) CAT2(X, Y) +# define TEST(NAME) caller CAT(__VAR, __LINE__) = [] + +enum State +{ + sDefaultConstructed, + sValueCopyConstructed, + sValueMoveConstructed, + sCopyConstructed, + sMoveConstructed, + sMoveAssigned, + sCopyAssigned, + sValueCopyAssigned, + sValueMoveAssigned, + sMovedFrom, + sValueConstructed +}; + +struct OracleVal +{ + State s; + int i; + OracleVal(int i = 0) : s(sValueConstructed), i(i) {} +}; + +struct Oracle +{ + State s; + OracleVal val; + + Oracle() : s(sDefaultConstructed) {} + Oracle(const OracleVal& v) : s(sValueCopyConstructed), val(v) {} + Oracle(OracleVal&& v) : s(sValueMoveConstructed), val(std::move(v)) {v.s = sMovedFrom;} + Oracle(const Oracle& o) : s(sCopyConstructed), val(o.val) {} + Oracle(Oracle&& o) : s(sMoveConstructed), val(std::move(o.val)) {o.s = sMovedFrom;} + + Oracle& operator=(const OracleVal& v) { s = sValueCopyConstructed; val = v; return *this; } + Oracle& operator=(OracleVal&& v) { s = sValueMoveConstructed; val = std::move(v); v.s = sMovedFrom; return *this; } + Oracle& operator=(const Oracle& o) { s = sCopyConstructed; val = o.val; return *this; } + Oracle& operator=(Oracle&& o) { s = sMoveConstructed; val = std::move(o.val); o.s = sMovedFrom; return *this; } +}; + +struct Guard +{ + std::string val; + Guard() : val{} {} + explicit Guard(std::string s, int = 0) : val(s) {} + Guard(const Guard&) = delete; + Guard(Guard&&) = delete; + void operator=(const Guard&) = delete; + void operator=(Guard&&) = delete; +}; + +struct ExplicitStr +{ + std::string s; + explicit ExplicitStr(const char* chp) : s(chp) {}; +}; + +struct Date +{ + int i; + Date() = delete; + Date(int i) : i{i} {}; + Date(Date&& d) : i(d.i) { d.i = 0; } + Date(const Date&) = delete; + Date& operator=(const Date&) = delete; + Date& operator=(Date&& d) { i = d.i; d.i = 0; return *this;}; +}; + +bool operator==( Oracle const& a, Oracle const& b ) { return a.val.i == b.val.i; } +bool operator!=( Oracle const& a, Oracle const& b ) { return a.val.i != b.val.i; } + + +namespace tr2 = std::experimental; + + +TEST(disengaged_ctor) +{ + tr2::optional<int> o1; + assert (!o1); + + tr2::optional<int> o2 = tr2::nullopt; + assert (!o2); + + tr2::optional<int> o3 = o2; + assert (!o3); + + assert (o1 == tr2::nullopt); + assert (o1 == tr2::optional<int>{}); + assert (!o1); + assert (bool(o1) == false); + + assert (o2 == tr2::nullopt); + assert (o2 == tr2::optional<int>{}); + assert (!o2); + assert (bool(o2) == false); + + assert (o3 == tr2::nullopt); + assert (o3 == tr2::optional<int>{}); + assert (!o3); + assert (bool(o3) == false); + + assert (o1 == o2); + assert (o2 == o1); + assert (o1 == o3); + assert (o3 == o1); + assert (o2 == o3); + assert (o3 == o2); +}; + + +TEST(value_ctor) +{ + OracleVal v; + tr2::optional<Oracle> oo1(v); + assert (oo1 != tr2::nullopt); + assert (oo1 != tr2::optional<Oracle>{}); + assert (oo1 == tr2::optional<Oracle>{v}); + assert (!!oo1); + assert (bool(oo1)); + // NA: assert (oo1->s == sValueCopyConstructed); + assert (oo1->s == sMoveConstructed); + assert (v.s == sValueConstructed); + + tr2::optional<Oracle> oo2(std::move(v)); + assert (oo2 != tr2::nullopt); + assert (oo2 != tr2::optional<Oracle>{}); + assert (oo2 == oo1); + assert (!!oo2); + assert (bool(oo2)); + // NA: assert (oo2->s == sValueMoveConstructed); + assert (oo2->s == sMoveConstructed); + assert (v.s == sMovedFrom); + + { + OracleVal v; + tr2::optional<Oracle> oo1{tr2::in_place, v}; + assert (oo1 != tr2::nullopt); + assert (oo1 != tr2::optional<Oracle>{}); + assert (oo1 == tr2::optional<Oracle>{v}); + assert (!!oo1); + assert (bool(oo1)); + assert (oo1->s == sValueCopyConstructed); + assert (v.s == sValueConstructed); + + tr2::optional<Oracle> oo2{tr2::in_place, std::move(v)}; + assert (oo2 != tr2::nullopt); + assert (oo2 != tr2::optional<Oracle>{}); + assert (oo2 == oo1); + assert (!!oo2); + assert (bool(oo2)); + assert (oo2->s == sValueMoveConstructed); + assert (v.s == sMovedFrom); + } +}; + + +TEST(assignment) +{ + tr2::optional<int> oi; + oi = tr2::optional<int>{1}; + assert (*oi == 1); + + oi = tr2::nullopt; + assert (!oi); + + oi = 2; + assert (*oi == 2); + + oi = {}; + assert (!oi); +}; + + +template <class T> +struct MoveAware +{ + T val; + bool moved; + MoveAware(T val) : val(val), moved(false) {} + MoveAware(MoveAware const&) = delete; + MoveAware(MoveAware&& rhs) : val(rhs.val), moved(rhs.moved) { + rhs.moved = true; + } + MoveAware& operator=(MoveAware const&) = delete; + MoveAware& operator=(MoveAware&& rhs) { + val = (rhs.val); + moved = (rhs.moved); + rhs.moved = true; + return *this; + } +}; + +TEST(moved_from_state) +{ + // first, test mock: + MoveAware<int> i{1}, j{2}; + assert (i.val == 1); + assert (!i.moved); + assert (j.val == 2); + assert (!j.moved); + + MoveAware<int> k = std::move(i); + assert (k.val == 1); + assert (!k.moved); + assert (i.val == 1); + assert (i.moved); + + k = std::move(j); + assert (k.val == 2); + assert (!k.moved); + assert (j.val == 2); + assert (j.moved); + + // now, test optional + tr2::optional<MoveAware<int>> oi{1}, oj{2}; + assert (oi); + assert (!oi->moved); + assert (oj); + assert (!oj->moved); + + tr2::optional<MoveAware<int>> ok = std::move(oi); + assert (ok); + assert (!ok->moved); + assert (oi); + assert (oi->moved); + + ok = std::move(oj); + assert (ok); + assert (!ok->moved); + assert (oj); + assert (oj->moved); +}; + + +TEST(copy_move_ctor_optional_int) +{ + tr2::optional<int> oi; + tr2::optional<int> oj = oi; + + assert (!oj); + assert (oj == oi); + assert (oj == tr2::nullopt); + assert (!bool(oj)); + + oi = 1; + tr2::optional<int> ok = oi; + assert (!!ok); + assert (bool(ok)); + assert (ok == oi); + assert (ok != oj); + assert (*ok == 1); + + tr2::optional<int> ol = std::move(oi); + assert (!!ol); + assert (bool(ol)); + assert (ol == oi); + assert (ol != oj); + assert (*ol == 1); +}; + + +TEST(optional_optional) +{ + tr2::optional<tr2::optional<int>> oi1 = tr2::nullopt; + assert (oi1 == tr2::nullopt); + assert (!oi1); + + { + tr2::optional<tr2::optional<int>> oi2 {tr2::in_place}; + assert (oi2 != tr2::nullopt); + assert (bool(oi2)); + assert (*oi2 == tr2::nullopt); + //assert (!(*oi2)); + //std::cout << typeid(**oi2).name() << std::endl; + } + + { + tr2::optional<tr2::optional<int>> oi2 {tr2::in_place, tr2::nullopt}; + assert (oi2 != tr2::nullopt); + assert (bool(oi2)); + assert (*oi2 == tr2::nullopt); + assert (!*oi2); + } + + { + tr2::optional<tr2::optional<int>> oi2 {tr2::optional<int>{}}; + assert (oi2 != tr2::nullopt); + assert (bool(oi2)); + assert (*oi2 == tr2::nullopt); + assert (!*oi2); + } + + tr2::optional<int> oi; + auto ooi = tr2::make_optional(oi); + static_assert( std::is_same<tr2::optional<tr2::optional<int>>, decltype(ooi)>::value, ""); + +}; + +TEST(example_guard) +{ + using namespace tr2; + //FAILS: optional<Guard> ogx(Guard("res1")); + //FAILS: optional<Guard> ogx = "res1"; + //FAILS: optional<Guard> ogx("res1"); + optional<Guard> oga; // Guard is non-copyable (and non-moveable) + optional<Guard> ogb(in_place, "res1"); // initialzes the contained value with "res1" + assert (bool(ogb)); + assert (ogb->val == "res1"); + + optional<Guard> ogc(in_place); // default-constructs the contained value + assert (bool(ogc)); + assert (ogc->val == ""); + + oga.emplace("res1"); // initialzes the contained value with "res1" + assert (bool(oga)); + assert (oga->val == "res1"); + + oga.emplace(); // destroys the contained value and + // default-constructs the new one + assert (bool(oga)); + assert (oga->val == ""); + + oga = nullopt; // OK: make disengaged the optional Guard + assert (!(oga)); + //FAILS: ogb = {}; // ERROR: Guard is not Moveable +}; + + +void process(){} +void process(int ){} +void processNil(){} + + +TEST(example1) +{ + using namespace tr2; + optional<int> oi; // create disengaged object + optional<int> oj = nullopt; // alternative syntax + oi = oj; // assign disengaged object + optional<int> ok = oj; // ok is disengaged + + if (oi) assert(false); // 'if oi is engaged...' + if (!oi) assert(true); // 'if oi is disengaged...' + + if (oi != nullopt) assert(false); // 'if oi is engaged...' + if (oi == nullopt) assert(true); // 'if oi is disengaged...' + + assert(oi == ok); // two disengaged optionals compare equal + + /////////////////////////////////////////////////////////////////////////// + optional<int> ol{1}; // ol is engaged; its contained value is 1 + ok = 2; // ok becomes engaged; its contained value is 2 + oj = ol; // oj becomes engaged; its contained value is 1 + + assert(oi != ol); // disengaged != engaged + assert(ok != ol); // different contained values + assert(oj == ol); // same contained value + assert(oi < ol); // disengaged < engaged + assert(ol < ok); // less by contained value + + ///////////////////////////////////////////////////////////////////////////// + optional<int> om{1}; // om is engaged; its contained value is 1 + optional<int> on = om; // on is engaged; its contained value is 1 + om = 2; // om is engaged; its contained value is 2 + assert (on != om); // on still contains 3. They are not pointers + + ///////////////////////////////////////////////////////////////////////////// + int i = *ol; // i obtains the value contained in ol + assert (i == 1); + *ol = 9; // the object contained in ol becomes 9 + assert(*ol == 9); + assert(ol == make_optional(9)); + + /////////////////////////////////// + int p = 1; + optional<int> op = p; + assert(*op == 1); + p = 2; + assert(*op == 1); // value contained in op is separated from p + + //////////////////////////////// + if (ol) + process(*ol); // use contained value if present + else + process(); // proceed without contained value + + if (!om) + processNil(); + else + process(*om); + + ///////////////////////////////////////// + process(ol.value_or(0)); // use 0 if ol is disengaged + + //////////////////////////////////////////// + ok = nullopt; // if ok was engaged calls T's dtor + oj = {}; // assigns a temporary disengaged optional +}; + + +TEST(example_guard) +{ + using std::experimental::optional; + const optional<int> c = 4; + int i = *c; // i becomes 4 + assert (i == 4); + // FAILS: *c = i; // ERROR: cannot assign to const int& +}; + + +TEST(example_ref) +{ + using namespace std::experimental; + int i = 1; + int j = 2; + optional<int&> ora; // disengaged optional reference to int + optional<int&> orb = i; // contained reference refers to object i + + *orb = 3; // i becomes 3 + // FAILS: ora = j; // ERROR: optional refs do not have assignment from T + // FAILS: ora = {j}; // ERROR: optional refs do not have copy/move assignment + // FAILS: ora = orb; // ERROR: no copy/move assignment + ora.emplace(j); // OK: contained reference refers to object j + ora.emplace(i); // OK: contained reference now refers to object i + + ora = nullopt; // OK: ora becomes disengaged +}; + + +template <typename T> +T getValue( tr2::optional<T> newVal = tr2::nullopt, tr2::optional<T&> storeHere = tr2::nullopt ) +{ + T cached{}; + + if (newVal) { + cached = *newVal; + + if (storeHere) { + *storeHere = *newVal; // LEGAL: assigning T to T + } + } + return cached; +} + +TEST(example_optional_arg) +{ + int iii = 0; + iii = getValue<int>(iii, iii); + iii = getValue<int>(iii); + iii = getValue<int>(); + + { + using namespace std::experimental; + optional<Guard> grd1{in_place, "res1", 1}; // guard 1 initialized + optional<Guard> grd2; + + grd2.emplace("res2", 2); // guard 2 initialized + grd1 = nullopt; // guard 1 released + + } // guard 2 released (in dtor) +}; + + +std::tuple<Date, Date, Date> getStartMidEnd() { return std::tuple<Date, Date, Date>{Date{1}, Date{2}, Date{3}}; } +void run(Date const&, Date const&, Date const&) {} + +TEST(example_date) +{ + using namespace std::experimental; + optional<Date> start, mid, end; // Date doesn't have default ctor (no good default date) + + std::tie(start, mid, end) = getStartMidEnd(); + run(*start, *mid, *end); +}; + + +std::experimental::optional<char> readNextChar(){ return{}; } + +void run(std::experimental::optional<std::string>) {} +void run(std::complex<double>) {} + + +template <class T> +void assign_norebind(tr2::optional<T&>& optref, T& obj) +{ + if (optref) *optref = obj; + else optref.emplace(obj); +} + +template <typename T> void unused(T&&) {} + +TEST(example_conceptual_model) +{ + using namespace std::experimental; + + optional<int> oi = 0; + optional<int> oj = 1; + optional<int> ok = nullopt; + + oi = 1; + oj = nullopt; + ok = 0; + + unused(oi == nullopt); + unused(oj == 0); + unused(ok == 1); +}; + +TEST(example_rationale) +{ + using namespace std::experimental; + if (optional<char> ch = readNextChar()) { + unused(ch); + // ... + } + + ////////////////////////////////// + optional<int> opt1 = nullopt; + optional<int> opt2 = {}; + + opt1 = nullopt; + opt2 = {}; + + if (opt1 == nullopt) {} + if (!opt2) {} + if (opt2 == optional<int>{}) {} + + + + //////////////////////////////// + + run(nullopt); // pick the second overload + // FAILS: run({}); // ambiguous + + if (opt1 == nullopt) {} // fine + // FAILS: if (opt2 == {}) {} // ilegal + + //////////////////////////////// + assert (optional<unsigned>{} < optional<unsigned>{0}); + assert (optional<unsigned>{0} < optional<unsigned>{1}); + assert (!(optional<unsigned>{} < optional<unsigned>{}) ); + assert (!(optional<unsigned>{1} < optional<unsigned>{1})); + + assert (optional<unsigned>{} != optional<unsigned>{0}); + assert (optional<unsigned>{0} != optional<unsigned>{1}); + assert (optional<unsigned>{} == optional<unsigned>{} ); + assert (optional<unsigned>{0} == optional<unsigned>{0}); + + ///////////////////////////////// + optional<int> o; + o = make_optional(1); // copy/move assignment + o = 1; // assignment from T + o.emplace(1); // emplacement + + //////////////////////////////////// + int isas = 0, i = 9; + optional<int&> asas = i; + assign_norebind(asas, isas); + + ///////////////////////////////////// + ////tr2::optional<std::vector<int>> ov2 = {2, 3}; + ////assert (bool(ov2)); + ////assert ((*ov2)[1] == 3); + //// + //////////////////////////////// + ////std::vector<int> v = {1, 2, 4, 8}; + ////optional<std::vector<int>> ov = {1, 2, 4, 8}; + + ////assert (v == *ov); + //// + ////ov = {1, 2, 4, 8}; + + ////std::allocator<int> a; + ////optional<std::vector<int>> ou { in_place, {1, 2, 4, 8}, a }; + + ////assert (ou == ov); + + ////////////////////////////// + // inconvenient syntax: + { + + tr2::optional<std::vector<int>> ov2{tr2::in_place, {2, 3}}; + + assert (bool(ov2)); + assert ((*ov2)[1] == 3); + + //////////////////////////// + + std::vector<int> v = {1, 2, 4, 8}; + optional<std::vector<int>> ov{tr2::in_place, {1, 2, 4, 8}}; + + assert (v == *ov); + + ov.emplace({1, 2, 4, 8}); +/* + std::allocator<int> a; + optional<std::vector<int>> ou { in_place, {1, 2, 4, 8}, a }; + + assert (ou == ov); +*/ + } + + ///////////////////////////////// + { + typedef int T; + optional<optional<T>> ot {in_place}; + optional<optional<T>> ou {in_place, nullopt}; + optional<optional<T>> ov {optional<T>{}}; + + optional<int> oi; + auto ooi = make_optional(oi); + static_assert( std::is_same<optional<optional<int>>, decltype(ooi)>::value, ""); + } +}; + + +bool fun(std::string , std::experimental::optional<int> oi = std::experimental::nullopt) +{ + return bool(oi); +} + +TEST(example_converting_ctor) +{ + using namespace std::experimental; + + assert (true == fun("dog", 2)); + assert (false == fun("dog")); + assert (false == fun("dog", nullopt)); // just to be explicit +}; + + +TEST(bad_comparison) +{ + tr2::optional<int> oi, oj; + int i; + bool b = (oi == oj); + b = (oi >= i); + b = (oi == i); + unused(b); +}; + + +//// NOT APPLICABLE ANYMORE +////TEST(perfect_ctor) +////{ +//// //tr2::optional<std::string> ois = "OS"; +//// assert (*ois == "OS"); +//// +//// // FAILS: tr2::optional<ExplicitStr> oes = "OS"; +//// tr2::optional<ExplicitStr> oes{"OS"}; +//// assert (oes->s == "OS"); +////}; + +TEST(value_or) +{ + tr2::optional<int> oi = 1; + int i = oi.value_or(0); + assert (i == 1); + + oi = tr2::nullopt; + assert (oi.value_or(3) == 3); + + tr2::optional<std::string> os{"AAA"}; + assert (os.value_or("BBB") == "AAA"); + os = {}; + assert (os.value_or("BBB") == "BBB"); +}; + +TEST(mixed_order) +{ + using namespace std::experimental; + + optional<int> oN {nullopt}; + optional<int> o0 {0}; + optional<int> o1 {1}; + + assert ( (oN < 0)); + assert ( (oN < 1)); + assert (!(o0 < 0)); + assert ( (o0 < 1)); + assert (!(o1 < 0)); + assert (!(o1 < 1)); + + assert (!(oN >= 0)); + assert (!(oN >= 1)); + assert ( (o0 >= 0)); + assert (!(o0 >= 1)); + assert ( (o1 >= 0)); + assert ( (o1 >= 1)); + + assert (!(oN > 0)); + assert (!(oN > 1)); + assert (!(o0 > 0)); + assert (!(o0 > 1)); + assert ( (o1 > 0)); + assert (!(o1 > 1)); + + assert ( (oN <= 0)); + assert ( (oN <= 1)); + assert ( (o0 <= 0)); + assert ( (o0 <= 1)); + assert (!(o1 <= 0)); + assert ( (o1 <= 1)); + + assert ( (0 > oN)); + assert ( (1 > oN)); + assert (!(0 > o0)); + assert ( (1 > o0)); + assert (!(0 > o1)); + assert (!(1 > o1)); + + assert (!(0 <= oN)); + assert (!(1 <= oN)); + assert ( (0 <= o0)); + assert (!(1 <= o0)); + assert ( (0 <= o1)); + assert ( (1 <= o1)); + + assert (!(0 < oN)); + assert (!(1 < oN)); + assert (!(0 < o0)); + assert (!(1 < o0)); + assert ( (0 < o1)); + assert (!(1 < o1)); + + assert ( (0 >= oN)); + assert ( (1 >= oN)); + assert ( (0 >= o0)); + assert ( (1 >= o0)); + assert (!(0 >= o1)); + assert ( (1 >= o1)); +}; + +struct BadRelops +{ + int i; +}; + +constexpr bool operator<(BadRelops a, BadRelops b) { return a.i < b.i; } +constexpr bool operator>(BadRelops a, BadRelops b) { return a.i < b.i; } // intentional error! + +TEST(bad_relops) +{ + using namespace std::experimental; + BadRelops a{1}, b{2}; + assert (a < b); + assert (a > b); + + optional<BadRelops> oa = a, ob = b; + assert (oa < ob); + assert (!(oa > ob)); + + assert (oa < b); + assert (oa > b); + + optional<BadRelops&> ra = a, rb = b; + assert (ra < rb); + assert (!(ra > rb)); + + assert (ra < b); + assert (ra > b); +}; + + +TEST(mixed_equality) +{ + using namespace std::experimental; + + assert (make_optional(0) == 0); + assert (make_optional(1) == 1); + assert (make_optional(0) != 1); + assert (make_optional(1) != 0); + + optional<int> oN {nullopt}; + optional<int> o0 {0}; + optional<int> o1 {1}; + + assert (o0 == 0); + assert ( 0 == o0); + assert (o1 == 1); + assert ( 1 == o1); + assert (o1 != 0); + assert ( 0 != o1); + assert (o0 != 1); + assert ( 1 != o0); + + assert ( 1 != oN); + assert ( 0 != oN); + assert (oN != 1); + assert (oN != 0); + assert (!( 1 == oN)); + assert (!( 0 == oN)); + assert (!(oN == 1)); + assert (!(oN == 0)); + + std::string cat{"cat"}, dog{"dog"}; + optional<std::string> oNil{}, oDog{"dog"}, oCat{"cat"}; + + assert (oCat == cat); + assert ( cat == oCat); + assert (oDog == dog); + assert ( dog == oDog); + assert (oDog != cat); + assert ( cat != oDog); + assert (oCat != dog); + assert ( dog != oCat); + + assert ( dog != oNil); + assert ( cat != oNil); + assert (oNil != dog); + assert (oNil != cat); + assert (!( dog == oNil)); + assert (!( cat == oNil)); + assert (!(oNil == dog)); + assert (!(oNil == cat)); +}; + +TEST(const_propagation) +{ + using namespace std::experimental; + + optional<int> mmi{0}; + static_assert(std::is_same<decltype(*mmi), int&>::value, "WTF"); + + const optional<int> cmi{0}; + static_assert(std::is_same<decltype(*cmi), const int&>::value, "WTF"); + + optional<const int> mci{0}; + static_assert(std::is_same<decltype(*mci), const int&>::value, "WTF"); + + optional<const int> cci{0}; + static_assert(std::is_same<decltype(*cci), const int&>::value, "WTF"); +}; + + +static_assert(std::is_base_of<std::logic_error, std::experimental::bad_optional_access>::value, ""); + +TEST(safe_value) +{ + using namespace std::experimental; + + try { + optional<int> ovN{}, ov1{1}; + + int& r1 = ov1.value(); + assert (r1 == 1); + + try { + ovN.value(); + assert (false); + } + catch (bad_optional_access const&) { + } + + { // ref variant + int i1 = 1; + optional<int&> orN{}, or1{i1}; + + int& r2 = or1.value(); + assert (r2 == 1); + + try { + orN.value(); + assert (false); + } + catch (bad_optional_access const&) { + } + } + } + catch(...) { + assert (false); + } +}; + +TEST(optional_ref) +{ + using namespace tr2; + // FAILS: optional<int&&> orr; + // FAILS: optional<nullopt_t&> on; + int i = 8; + optional<int&> ori; + assert (!ori); + ori.emplace(i); + assert (bool(ori)); + assert (*ori == 8); + assert (&*ori == &i); + *ori = 9; + assert (i == 9); + + // FAILS: int& ir = ori.value_or(i); + int ii = ori.value_or(i); + assert (ii == 9); + ii = 7; + assert (*ori == 9); + + int j = 22; + auto&& oj = make_optional(std::ref(j)); + *oj = 23; + assert (&*oj == &j); + assert (j == 23); +}; + +TEST(optional_ref_const_propagation) +{ + using namespace std::experimental; + + int i = 9; + const optional<int&> mi = i; + int& r = *mi; + optional<const int&> ci = i; + static_assert(std::is_same<decltype(*mi), int&>::value, "WTF"); + static_assert(std::is_same<decltype(*ci), const int&>::value, "WTF"); + + unused(r); +}; + +TEST(optional_ref_assign) +{ + using namespace std::experimental; + + int i = 9; + optional<int&> ori = i; + + int j = 1; + ori = optional<int&>{j}; + ori = {j}; + // FAILS: ori = j; + + optional<int&> orx = ori; + ori = orx; + + optional<int&> orj = j; + + assert (ori); + assert (*ori == 1); + assert (ori == orj); + assert (i == 9); + + *ori = 2; + assert (*ori == 2); + assert (ori == 2); + assert (2 == ori); + assert (ori != 3); + + assert (ori == orj); + assert (j == 2); + assert (i == 9); + + ori = {}; + assert (!ori); + assert (ori != orj); + assert (j == 2); + assert (i == 9); +}; + + +TEST(optional_ref_swap) +{ + using namespace std::experimental; + int i = 0; + int j = 1; + optional<int&> oi = i; + optional<int&> oj = j; + + assert (&*oi == &i); + assert (&*oj == &j); + + swap(oi, oj); + assert (&*oi == &j); + assert (&*oj == &i); +}; + +TEST(optional_initialization) +{ + using namespace tr2; + using std::string; + string s = "STR"; + + optional<string> os{s}; + optional<string> ot = s; + optional<string> ou{"STR"}; + optional<string> ov = string{"STR"}; + +}; + +#include <unordered_set> + +TEST(optional_hashing) +{ + using namespace tr2; + using std::string; + + std::hash<int> hi; + std::hash<optional<int>> hoi; + std::hash<string> hs; + std::hash<optional<string>> hos; + + assert (hi(0) == hoi(optional<int>{0})); + assert (hi(1) == hoi(optional<int>{1})); + assert (hi(3198) == hoi(optional<int>{3198})); + + assert (hs("") == hos(optional<string>{""})); + assert (hs("0") == hos(optional<string>{"0"})); + assert (hs("Qa1#") == hos(optional<string>{"Qa1#"})); + + std::unordered_set<optional<string>> set; + assert(set.find({"Qa1#"}) == set.end()); + + set.insert({"0"}); + assert(set.find({"Qa1#"}) == set.end()); + + set.insert({"Qa1#"}); + assert(set.find({"Qa1#"}) != set.end()); +}; + + +// optional_ref_emulation +template <class T> +struct generic +{ + typedef T type; +}; + +template <class U> +struct generic<U&> +{ + typedef std::reference_wrapper<U> type; +}; + +template <class T> +using Generic = typename generic<T>::type; + +template <class X> +bool generic_fun() +{ + std::experimental::optional<Generic<X>> op; + return bool(op); +} + +TEST(optional_ref_emulation) +{ + using namespace std::experimental; + optional<Generic<int>> oi = 1; + assert (*oi == 1); + + int i = 8; + int j = 4; + optional<Generic<int&>> ori {i}; + assert (*ori == 8); + assert ((void*)&*ori != (void*)&i); // !DIFFERENT THAN optional<T&> + + *ori = j; + assert (*ori == 4); +}; + + +# if OPTIONAL_HAS_THIS_RVALUE_REFS == 1 +TEST(moved_on_value_or) +{ + using namespace tr2; + optional<Oracle> oo{in_place}; + + assert (oo); + assert (oo->s == sDefaultConstructed); + + Oracle o = std::move(oo).value_or( Oracle{OracleVal{}} ); + assert (oo); + assert (oo->s == sMovedFrom); + assert (o.s == sMoveConstructed); + + optional<MoveAware<int>> om {in_place, 1}; + assert (om); + assert (om->moved == false); + + /*MoveAware<int> m =*/ std::move(om).value_or( MoveAware<int>{1} ); + assert (om); + assert (om->moved == true); + +# if OPTIONAL_HAS_MOVE_ACCESSORS == 1 + { + Date d = optional<Date>{in_place, 1}.value(); + assert (d.i); // to silence compiler warning + + Date d2 = *optional<Date>{in_place, 1}; + assert (d2.i); // to silence compiler warning + } +# endif +}; +# endif + + +TEST(optional_ref_hashing) +{ + using namespace tr2; + using std::string; + + std::hash<int> hi; + std::hash<optional<int&>> hoi; + std::hash<string> hs; + std::hash<optional<string&>> hos; + + int i0 = 0; + int i1 = 1; + assert (hi(0) == hoi(optional<int&>{i0})); + assert (hi(1) == hoi(optional<int&>{i1})); + + string s{""}; + string s0{"0"}; + string sCAT{"CAT"}; + assert (hs("") == hos(optional<string&>{s})); + assert (hs("0") == hos(optional<string&>{s0})); + assert (hs("CAT") == hos(optional<string&>{sCAT})); + + std::unordered_set<optional<string&>> set; + assert(set.find({sCAT}) == set.end()); + + set.insert({s0}); + assert(set.find({sCAT}) == set.end()); + + set.insert({sCAT}); + assert(set.find({sCAT}) != set.end()); +}; + +struct Combined +{ + int m = 0; + int n = 1; + + constexpr Combined() : m{5}, n{6} {} + constexpr Combined(int m, int n) : m{m}, n{n} {} +}; + +struct Nasty +{ + int m = 0; + int n = 1; + + constexpr Nasty() : m{5}, n{6} {} + constexpr Nasty(int m, int n) : m{m}, n{n} {} + + int operator&() { return n; } + int operator&() const { return n; } +}; + +TEST(arrow_operator) +{ + using namespace std::experimental; + + optional<Combined> oc1{in_place, 1, 2}; + assert (oc1); + assert (oc1->m == 1); + assert (oc1->n == 2); + + optional<Nasty> on{in_place, 1, 2}; + assert (on); + assert (on->m == 1); + assert (on->n == 2); +}; + +TEST(arrow_wit_optional_ref) +{ + using namespace std::experimental; + + Combined c{1, 2}; + optional<Combined&> oc = c; + assert (oc); + assert (oc->m == 1); + assert (oc->n == 2); + + Nasty n{1, 2}; + Nasty m{3, 4}; + Nasty p{5, 6}; + + optional<Nasty&> on{n}; + assert (on); + assert (on->m == 1); + assert (on->n == 2); + + on = {m}; + assert (on); + assert (on->m == 3); + assert (on->n == 4); + + on.emplace(p); + assert (on); + assert (on->m == 5); + assert (on->n == 6); + + optional<Nasty&> om{in_place, n}; + assert (om); + assert (om->m == 1); + assert (om->n == 2); +}; + +TEST(no_dangling_reference_in_value) +{ + // this mostly tests compiler warnings + using namespace std::experimental; + optional<int> oi {2}; + unused (oi.value()); + const optional<int> coi {3}; + unused (coi.value()); +}; + +struct CountedObject +{ + static int _counter; + bool _throw; + CountedObject(bool b) : _throw(b) { ++_counter; } + CountedObject(CountedObject const& rhs) : _throw(rhs._throw) { if (_throw) throw int(); } + ~CountedObject() { --_counter; } +}; + +int CountedObject::_counter = 0; + +TEST(exception_safety) +{ + using namespace std::experimental; + try { + optional<CountedObject> oo(in_place, true); // throw + optional<CountedObject> o1(oo); + } + catch(...) + { + // + } + assert(CountedObject::_counter == 0); + + try { + optional<CountedObject> oo(in_place, true); // throw + optional<CountedObject> o1(std::move(oo)); // now move + } + catch(...) + { + // + } + assert(CountedObject::_counter == 0); +}; + +//// constexpr tests + +// these 4 classes have different noexcept signatures in move operations +struct NothrowBoth { + NothrowBoth(NothrowBoth&&) noexcept(true) {}; + void operator=(NothrowBoth&&) noexcept(true) {}; +}; +struct NothrowCtor { + NothrowCtor(NothrowCtor&&) noexcept(true) {}; + void operator=(NothrowCtor&&) noexcept(false) {}; +}; +struct NothrowAssign { + NothrowAssign(NothrowAssign&&) noexcept(false) {}; + void operator=(NothrowAssign&&) noexcept(true) {}; +}; +struct NothrowNone { + NothrowNone(NothrowNone&&) noexcept(false) {}; + void operator=(NothrowNone&&) noexcept(false) {}; +}; + +void test_noexcept() +{ + { + tr2::optional<NothrowBoth> b1, b2; + static_assert(noexcept(tr2::optional<NothrowBoth>{tr2::constexpr_move(b1)}), "bad noexcept!"); + static_assert(noexcept(b1 = tr2::constexpr_move(b2)), "bad noexcept!"); + } + { + tr2::optional<NothrowCtor> c1, c2; + static_assert(noexcept(tr2::optional<NothrowCtor>{tr2::constexpr_move(c1)}), "bad noexcept!"); + static_assert(!noexcept(c1 = tr2::constexpr_move(c2)), "bad noexcept!"); + } + { + tr2::optional<NothrowAssign> a1, a2; + static_assert(!noexcept(tr2::optional<NothrowAssign>{tr2::constexpr_move(a1)}), "bad noexcept!"); + static_assert(!noexcept(a1 = tr2::constexpr_move(a2)), "bad noexcept!"); + } + { + tr2::optional<NothrowNone> n1, n2; + static_assert(!noexcept(tr2::optional<NothrowNone>{tr2::constexpr_move(n1)}), "bad noexcept!"); + static_assert(!noexcept(n1 = tr2::constexpr_move(n2)), "bad noexcept!"); + } +} + + +void constexpr_test_disengaged() +{ + constexpr tr2::optional<int> g0{}; + constexpr tr2::optional<int> g1{tr2::nullopt}; + static_assert( !g0, "initialized!" ); + static_assert( !g1, "initialized!" ); + + static_assert( bool(g1) == bool(g0), "ne!" ); + + static_assert( g1 == g0, "ne!" ); + static_assert( !(g1 != g0), "ne!" ); + static_assert( g1 >= g0, "ne!" ); + static_assert( !(g1 > g0), "ne!" ); + static_assert( g1 <= g0, "ne!" ); + static_assert( !(g1 <g0), "ne!" ); + + static_assert( g1 == tr2::nullopt, "!" ); + static_assert( !(g1 != tr2::nullopt), "!" ); + static_assert( g1 <= tr2::nullopt, "!" ); + static_assert( !(g1 < tr2::nullopt), "!" ); + static_assert( g1 >= tr2::nullopt, "!" ); + static_assert( !(g1 > tr2::nullopt), "!" ); + + static_assert( (tr2::nullopt == g0), "!" ); + static_assert( !(tr2::nullopt != g0), "!" ); + static_assert( (tr2::nullopt >= g0), "!" ); + static_assert( !(tr2::nullopt > g0), "!" ); + static_assert( (tr2::nullopt <= g0), "!" ); + static_assert( !(tr2::nullopt < g0), "!" ); + + static_assert( (g1 != tr2::optional<int>(1)), "!" ); + static_assert( !(g1 == tr2::optional<int>(1)), "!" ); + static_assert( (g1 < tr2::optional<int>(1)), "!" ); + static_assert( (g1 <= tr2::optional<int>(1)), "!" ); + static_assert( !(g1 > tr2::optional<int>(1)), "!" ); + static_assert( !(g1 > tr2::optional<int>(1)), "!" ); +} + + +constexpr tr2::optional<int> g0{}; +constexpr tr2::optional<int> g2{2}; +static_assert( g2, "not initialized!" ); +static_assert( *g2 == 2, "not 2!" ); +static_assert( g2 == tr2::optional<int>(2), "not 2!" ); +static_assert( g2 != g0, "eq!" ); + +# if OPTIONAL_HAS_MOVE_ACCESSORS == 1 +static_assert( *tr2::optional<int>{3} == 3, "WTF!" ); +static_assert( tr2::optional<int>{3}.value() == 3, "WTF!" ); +static_assert( tr2::optional<int>{3}.value_or(1) == 3, "WTF!" ); +static_assert( tr2::optional<int>{}.value_or(4) == 4, "WTF!" ); +# endif + +constexpr tr2::optional<Combined> gc0{tr2::in_place}; +static_assert(gc0->n == 6, "WTF!"); + +// optional refs +int gi = 0; +constexpr tr2::optional<int&> gori = gi; +constexpr tr2::optional<int&> gorn{}; +constexpr int& gri = *gori; +static_assert(gori, "WTF"); +static_assert(!gorn, "WTF"); +static_assert(gori != tr2::nullopt, "WTF"); +static_assert(gorn == tr2::nullopt, "WTF"); +static_assert(&gri == &*gori, "WTF"); + +constexpr int gci = 1; +constexpr tr2::optional<int const&> gorci = gci; +constexpr tr2::optional<int const&> gorcn{}; + +static_assert(gorcn < gorci, "WTF"); +static_assert(gorcn <= gorci, "WTF"); +static_assert(gorci == gorci, "WTF"); +static_assert(*gorci == 1, "WTF"); +static_assert(gorci == gci, "WTF"); + +namespace constexpr_optional_ref_and_arrow +{ + using namespace std::experimental; + constexpr Combined c{1, 2}; + constexpr optional<Combined const&> oc = c; + static_assert(oc, "WTF!"); + static_assert(oc->m == 1, "WTF!"); + static_assert(oc->n == 2, "WTF!"); +} + +#if OPTIONAL_HAS_CONSTEXPR_INIT_LIST + +namespace InitList +{ + using namespace std::experimental; + + struct ConstInitLister + { + template <typename T> + constexpr ConstInitLister(std::initializer_list<T> il) : len (il.size()) {} + size_t len; + }; + + constexpr ConstInitLister CIL {2, 3, 4}; + static_assert(CIL.len == 3, "WTF!"); + + constexpr optional<ConstInitLister> oil {in_place, {4, 5, 6, 7}}; + static_assert(oil, "WTF!"); + static_assert(oil->len == 4, "WTF!"); +} + +#endif // OPTIONAL_HAS_CONSTEXPR_INIT_LIST + +// end constexpr tests + + +#include <string> + + +struct VEC +{ + std::vector<int> v; + template <typename... X> + VEC( X&&...x) : v(std::forward<X>(x)...) {} + + template <typename U, typename... X> + VEC(std::initializer_list<U> il, X&&...x) : v(il, std::forward<X>(x)...) {} +}; + + + +int main() { + tr2::optional<int> oi = 1; + assert (bool(oi)); + oi.operator=({}); + assert (!oi); + + VEC v = {5, 6}; + + if (OPTIONAL_HAS_THIS_RVALUE_REFS) + std::cout << "Optional has rvalue references for *this" << std::endl; + else + std::cout << "Optional doesn't have rvalue references for *this" << std::endl; + + if (OPTIONAL_HAS_CONSTEXPR_INIT_LIST) + std::cout << "Optional has constexpr initializer_list" << std::endl; + else + std::cout << "Optional doesn't have constexpr initializer_list" << std::endl; + + if (OPTIONAL_HAS_MOVE_ACCESSORS) + std::cout << "Optional has constexpr move accessors" << std::endl; + else + std::cout << "Optional doesn't have constexpr move accessors" << std::endl; +} + diff --git a/src/libs/3rdparty/optional/test_type_traits.cpp b/src/libs/3rdparty/optional/test_type_traits.cpp new file mode 100644 index 0000000000..8ec82b7087 --- /dev/null +++ b/src/libs/3rdparty/optional/test_type_traits.cpp @@ -0,0 +1,66 @@ +// Copyright (C) 2011 - 2012 Andrzej Krzemienski. +// +// Use, modification, and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if (defined __clang__) + namespace std { class type_info; } +#endif + +# include "optional.hpp" + +namespace std { namespace experimental { + +struct Val +{ + Val(){} + Val( Val const & ){} + Val( Val && ) noexcept {} + + Val & operator=( Val const & ) = delete; + Val & operator=( Val && ) noexcept = delete; +}; + +struct Safe +{ + Safe(){} + Safe( Safe const & ){} + Safe( Safe && ) noexcept {} + + Safe & operator=( Safe const & ){ return *this; } + Safe & operator=( Safe && ) noexcept { return *this; } +}; + +struct Unsafe +{ + Unsafe(){} + Unsafe( Unsafe const & ){} + Unsafe( Unsafe && ){} + + Unsafe & operator=( Unsafe const & ){ return *this; } + Unsafe & operator=( Unsafe && ) { return *this; } +}; + +struct VoidNothrowBoth +{ + VoidNothrowBoth(VoidNothrowBoth&&) noexcept(true) {}; + void operator=(VoidNothrowBoth&&) noexcept(true) {}; // note void return type +}; + + +static_assert(is_nothrow_move_constructible<Safe>::value, "WTF!"); +static_assert(!is_nothrow_move_constructible<Unsafe>::value, "WTF!"); + +static_assert(is_assignable<Safe&, Safe&&>::value, "WTF!"); +static_assert(!is_assignable<Val&, Val&&>::value, "WTF!"); + +static_assert(is_nothrow_move_assignable<Safe>::value, "WTF!"); +static_assert(!is_nothrow_move_assignable<Unsafe>::value, "WTF!"); + +static_assert(is_nothrow_move_constructible<VoidNothrowBoth>::value, "WTF!"); +static_assert(is_nothrow_move_assignable<VoidNothrowBoth>::value, "WTF!"); + +}} // namespace std::experimental + +int main() { } |