diff --git a/doc/1A_on_performance.qbk b/doc/1A_on_performance.qbk index 5fd749a..6459ffe 100644 --- a/doc/1A_on_performance.qbk +++ b/doc/1A_on_performance.qbk @@ -1,7 +1,7 @@  [section Performance considerations] -Technical details aside, the memory layout of `optional` is more-less this: +Technical details aside, the memory layout of `optional` for a generic `T` is more-less this: template class optional @@ -9,8 +9,33 @@ Technical details aside, the memory layout of `optional` is more-less this: bool _initialized; std::aligned_storage_t _storage; }; + +Lifetime of the `T` inside `_storage` is manually controlled with placement-`new`s and pseudo-destructor calls. However, for trivial `T`s we use a different way of storage, by simply holding a `T`: -But for the purpose of this analysis, considering memory layouts, we can think of it as: + template + class optional + { + bool _initialized; + T _storage; + }; + +We call it a ['direct] storage. This makes `optional` a trivially-copyable type for trivial `T`s. This only works for compilers that support defaulted functions and type traits. On compilers without defaulted functions we still use the direct storage, but `optional` is no longer recognized as trivially-copyable. On compilers that do not fully support type traits, we still use the direct storage for scalar types, but we leave the programmer a way of customizing her type, so that it is reconized by `optional` as trivial, by specializing type trait `boost::opitonal_config::is_type_trivial`: + + struct X // not trivial + { + X() {} + }; + + namespace boost { namespace optional_config { + + template <> struct is_type_trivial : boost::true_type {}; + + }} + + +[heading Controlling the size] + +For the purpose of the followin analysis, considering memory layouts, we can think of it as: template class optional diff --git a/doc/91_relnotes.qbk b/doc/91_relnotes.qbk index d9ca103..0c18f93 100644 --- a/doc/91_relnotes.qbk +++ b/doc/91_relnotes.qbk @@ -11,6 +11,11 @@ [section:relnotes Release Notes] +[heading Boost Release 1.66] + +* On newer compilers `optional` is now trivially-copyable for trivial `T`s. This uses a different storage (just `T` rather than `aligned_storage`). We require the compiler to support defaulted functions and type traits. Otherwise, we still use the the plain storage for scalar types. + + [heading Boost Release 1.63] * Added two new in-place constructors. They work similarly to `emplace()` functions: they initialize the contained value by perfect-forwarding the obtained arguments. One constructor always initializes the contained value, the other based on a boolean condition. * Syntax `o = {}` now correctly un-initializes optional, just like in `std::optional`. diff --git a/doc/html/boost_optional/relnotes.html b/doc/html/boost_optional/relnotes.html index 1b161ed..5ccc2d7 100644 --- a/doc/html/boost_optional/relnotes.html +++ b/doc/html/boost_optional/relnotes.html @@ -28,6 +28,19 @@

+ Boost + Release 1.66 +

+
  • + On newer compilers optional + is now trivially-copyable for trivial Ts. + This uses a different storage (just T + rather than aligned_storage). + We require the compiler to support defaulted functions and type traits. + Otherwise, we still use the the plain storage for scalar types. +
+

+ Boost Release 1.63

@@ -51,7 +64,7 @@

- + Boost Release 1.62

@@ -59,7 +72,7 @@ Fixed Trac #12179.

- + Boost Release 1.61

@@ -102,7 +115,7 @@

- + Boost Release 1.60

@@ -113,7 +126,7 @@ #11203.

- + Boost Release 1.59

@@ -127,7 +140,7 @@

- + Boost Release 1.58

@@ -163,7 +176,7 @@

- + Boost Release 1.57

@@ -173,7 +186,7 @@ to fix C++03 compile error on logic_error("...")".

- + Boost Release 1.56

diff --git a/doc/html/boost_optional/tutorial/performance_considerations.html b/doc/html/boost_optional/tutorial/performance_considerations.html index 5ce93f9..2c796da 100644 --- a/doc/html/boost_optional/tutorial/performance_considerations.html +++ b/doc/html/boost_optional/tutorial/performance_considerations.html @@ -29,7 +29,8 @@

Technical details aside, the memory layout of optional<T> - is more-less this: + for a generic T is more-less + this:

template <typename T>
 class optional
@@ -39,8 +40,50 @@
 };
 

- But for the purpose of this analysis, considering memory layouts, we can - think of it as: + Lifetime of the T inside + _storage is manually controlled + with placement-news and pseudo-destructor + calls. However, for trivial Ts + we use a different way of storage, by simply holding a T: +

+
template <typename T>
+class optional
+{
+  bool _initialized;
+  T _storage;
+};
+
+

+ We call it a direct storage. This makes optional<T> a + trivially-copyable type for trivial Ts. + This only works for compilers that support defaulted functions and type traits. + On compilers without defaulted functions we still use the direct storage, + but optional<T> is + no longer recognized as trivially-copyable. On compilers that do not fully + support type traits, we still use the direct storage for scalar types, but + we leave the programmer a way of customizing her type, so that it is reconized + by optional as trivial, by + specializing type trait boost::opitonal_config::is_type_trivial: +

+
struct X // not trivial
+{
+  X() {}
+};
+
+namespace boost { namespace optional_config {
+
+  template <> struct is_type_trivial<X> : boost::true_type {};
+
+}}
+
+
+ + Controlling + the size +
+

+ For the purpose of the followin analysis, considering memory layouts, we + can think of it as:

template <typename T>
 class optional
@@ -143,7 +186,7 @@
         opt_align4
       

- + Optional function parameters
diff --git a/doc/html/index.html b/doc/html/index.html index 1429a21..de3b006 100644 --- a/doc/html/index.html +++ b/doc/html/index.html @@ -146,7 +146,7 @@ - +

Last revised: May 17, 2017 at 23:01:39 GMT

Last revised: October 28, 2017 at 14:38:14 GMT


diff --git a/include/boost/optional/detail/optional_trivially_copyable_base.hpp b/include/boost/optional/detail/optional_trivially_copyable_base.hpp new file mode 100644 index 0000000..1deaeab --- /dev/null +++ b/include/boost/optional/detail/optional_trivially_copyable_base.hpp @@ -0,0 +1,499 @@ +// trivilally-copyable version of the storage + +template +class tc_optional_base : public optional_tag +{ + private : + + typedef tc_optional_base this_type ; + + protected : + + typedef T value_type ; + + protected: + typedef T & reference_type ; + typedef T const& reference_const_type ; +#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES + typedef T && rval_reference_type ; + typedef T && reference_type_of_temporary_wrapper ; +#endif + typedef T * pointer_type ; + typedef T const* pointer_const_type ; + typedef T const& argument_type ; + + tc_optional_base() + : + m_initialized(false) {} + + tc_optional_base ( none_t ) + : + m_initialized(false) {} + + tc_optional_base ( argument_type val ) + : + m_initialized(true), m_storage(val) {} + + tc_optional_base ( bool cond, argument_type val ) + : + m_initialized(cond), m_storage(val) {} + + // tc_optional_base ( tc_optional_base const& ) = default; + + +#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES + + template + explicit tc_optional_base ( Expr&& expr, PtrExpr const* tag ) + : + m_initialized(false) + { + construct(boost::forward(expr),tag); + } + +#else + // This is used for both converting and in-place constructions. + // Derived classes use the 'tag' to select the appropriate + // implementation (the correct 'construct()' overload) + template + explicit tc_optional_base ( Expr const& expr, Expr const* tag ) + : + m_initialized(false) + { + construct(expr,tag); + } + +#endif + + // tc_optional_base& operator= ( tc_optional_base const& ) = default; + // ~tc_optional_base() = default; + + // Assigns from another optional (deep-copies the rhs value) + void assign ( tc_optional_base const& rhs ) + { + this->operator=(rhs); + } + + // Assigns from another _convertible_ optional (deep-copies the rhs value) + template + void assign ( optional const& rhs ) + { + if ( rhs.is_initialized() ) +#ifndef BOOST_OPTIONAL_CONFIG_RESTORE_ASSIGNMENT_OF_NONCONVERTIBLE_TYPES + m_storage = rhs.get(); +#else + m_storage = static_cast(rhs.get()); +#endif + + m_initialized = rhs.is_initialized(); + } + +#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES + // move-assigns from another _convertible_ optional (deep-moves from the rhs value) + template + void assign ( optional&& rhs ) + { + typedef BOOST_DEDUCED_TYPENAME optional::rval_reference_type ref_type; + if ( rhs.is_initialized() ) + m_storage = static_cast(rhs.get()); + m_initialized = rhs.is_initialized(); + } +#endif + + void assign ( argument_type val ) + { + construct(val); + } + + void assign ( none_t ) { destroy(); } + +#ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT + +#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES + template + void assign_expr ( Expr&& expr, ExprPtr const* tag ) + { + construct(boost::forward(expr),tag); + } +#else + template + void assign_expr ( Expr const& expr, Expr const* tag ) + { + construct(expr,tag); + } +#endif + +#endif + + public : + + // **DEPPRECATED** Destroys the current value, if any, leaving this UNINITIALIZED + // No-throw (assuming T::~T() doesn't) + void reset() BOOST_NOEXCEPT { destroy(); } + + // **DEPPRECATED** Replaces the current value -if any- with 'val' + void reset ( argument_type val ) BOOST_NOEXCEPT { assign(val); } + + // Returns a pointer to the value if this is initialized, otherwise, + // returns NULL. + // No-throw + pointer_const_type get_ptr() const { return m_initialized ? get_ptr_impl() : 0 ; } + pointer_type get_ptr() { return m_initialized ? get_ptr_impl() : 0 ; } + + bool is_initialized() const { return m_initialized ; } + + protected : + + void construct ( argument_type val ) + { + m_storage = val ; + m_initialized = true ; + } + + +#if (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES) && (!defined BOOST_NO_CXX11_VARIADIC_TEMPLATES) + // Constructs in-place + // upon exception *this is always uninitialized + template + void construct ( in_place_init_t, Args&&... args ) + { + m_storage = value_type( boost::forward(args)... ) ; + m_initialized = true ; + } + + template + void emplace_assign ( Args&&... args ) + { + construct(in_place_init, boost::forward(args)...); + } + + template + explicit tc_optional_base ( in_place_init_t, Args&&... args ) + : + m_initialized(false) + { + construct(in_place_init, boost::forward(args)...); + } + + template + explicit tc_optional_base ( in_place_init_if_t, bool cond, Args&&... args ) + : + m_initialized(false) + { + if ( cond ) + construct(in_place_init, boost::forward(args)...); + } +#elif (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES) + template + void construct ( in_place_init_t, Arg&& arg ) + { + m_storage = value_type( boost::forward(arg) ); + m_initialized = true ; + } + + void construct ( in_place_init_t ) + { + m_storage = value_type(); + m_initialized = true ; + } + + template + void emplace_assign ( Arg&& arg ) + { + construct(in_place_init, boost::forward(arg)) ; + } + + void emplace_assign () + { + construct(in_place_init) ; + } + + template + explicit tc_optional_base ( in_place_init_t, Arg&& arg ) + : + m_initialized(false) + { + construct(in_place_init, boost::forward(arg)); + } + + explicit tc_optional_base ( in_place_init_t ) + : + m_initialized(false), m_storage() {} + + template + explicit tc_optional_base ( in_place_init_if_t, bool cond, Arg&& arg ) + : + m_initialized(false) + { + if ( cond ) + construct(in_place_init, boost::forward(arg)); + } + + explicit tc_optional_base ( in_place_init_if_t, bool cond ) + : + m_initialized(false) + { + if ( cond ) + construct(in_place_init); + } + +#else + + template + void construct ( in_place_init_t, const Arg& arg ) + { + m_storage = value_type( arg ); + m_initialized = true ; + } + + template + void construct ( in_place_init_t, Arg& arg ) + { + m_storage = value_type( arg ); + m_initialized = true ; + } + + void construct ( in_place_init_t ) + { + m_storage = value_type(); + m_initialized = true ; + } + + template + void emplace_assign ( const Arg& arg ) + { + construct(in_place_init, arg); + } + + template + void emplace_assign ( Arg& arg ) + { + construct(in_place_init, arg); + } + + void emplace_assign () + { + construct(in_place_init); + } + + template + explicit tc_optional_base ( in_place_init_t, const Arg& arg ) + : m_initialized(false) + { + construct(in_place_init, arg); + } + + template + explicit tc_optional_base ( in_place_init_t, Arg& arg ) + : m_initialized(false) + { + construct(in_place_init, arg); + } + + explicit tc_optional_base ( in_place_init_t ) + : m_initialized(false) + { + construct(in_place_init); + } + + template + explicit tc_optional_base ( in_place_init_if_t, bool cond, const Arg& arg ) + : m_initialized(false) + { + if ( cond ) + construct(in_place_init, arg); + } + + template + explicit tc_optional_base ( in_place_init_if_t, bool cond, Arg& arg ) + : m_initialized(false) + { + if ( cond ) + construct(in_place_init, arg); + } + + explicit tc_optional_base ( in_place_init_if_t, bool cond ) + : m_initialized(false) + { + if ( cond ) + construct(in_place_init); + } +#endif + +#ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT + +#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES + // Constructs in-place using the given factory + template + void construct ( Expr&& factory, in_place_factory_base const* ) + { + boost_optional_detail::construct(factory, boost::addressof(m_storage)); + m_initialized = true ; + } + + // Constructs in-place using the given typed factory + template + void construct ( Expr&& factory, typed_in_place_factory_base const* ) + { + factory.apply(boost::addressof(m_storage)) ; + m_initialized = true ; + } + + template + void assign_expr_to_initialized ( Expr&& factory, in_place_factory_base const* tag ) + { + destroy(); + construct(factory,tag); + } + + // Constructs in-place using the given typed factory + template + void assign_expr_to_initialized ( Expr&& factory, typed_in_place_factory_base const* tag ) + { + destroy(); + construct(factory,tag); + } + +#else + // Constructs in-place using the given factory + template + void construct ( Expr const& factory, in_place_factory_base const* ) + { + boost_optional_detail::construct(factory, m_storage.address()); + m_initialized = true ; + } + + // Constructs in-place using the given typed factory + template + void construct ( Expr const& factory, typed_in_place_factory_base const* ) + { + factory.apply(boost::addressof(m_storage)) ; + m_initialized = true ; + } + + template + void assign_expr_to_initialized ( Expr const& factory, in_place_factory_base const* tag ) + { + destroy(); + construct(factory,tag); + } + + // Constructs in-place using the given typed factory + template + void assign_expr_to_initialized ( Expr const& factory, typed_in_place_factory_base const* tag ) + { + destroy(); + construct(factory,tag); + } +#endif + +#endif + +#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES + // Constructs using any expression implicitly convertible to the single argument + // of a one-argument T constructor. + // Converting constructions of optional from optional uses this function with + // 'Expr' being of type 'U' and relying on a converting constructor of T from U. + template + void construct ( Expr&& expr, void const* ) + { + m_storage = value_type(boost::forward(expr)) ; + m_initialized = true ; + } + + // Assigns using a form any expression implicitly convertible to the single argument + // of a T's assignment operator. + // Converting assignments of optional from optional uses this function with + // 'Expr' being of type 'U' and relying on a converting assignment of T from U. + template + void assign_expr_to_initialized ( Expr&& expr, void const* ) + { + assign_value( boost::forward(expr) ); + } +#else + // Constructs using any expression implicitly convertible to the single argument + // of a one-argument T constructor. + // Converting constructions of optional from optional uses this function with + // 'Expr' being of type 'U' and relying on a converting constructor of T from U. + template + void construct ( Expr const& expr, void const* ) + { + m_storage = value_type(expr) ; + m_initialized = true ; + } + + // Assigns using a form any expression implicitly convertible to the single argument + // of a T's assignment operator. + // Converting assignments of optional from optional uses this function with + // 'Expr' being of type 'U' and relying on a converting assignment of T from U. + template + void assign_expr_to_initialized ( Expr const& expr, void const* ) + { + assign_value(expr); + } + +#endif + +#ifdef BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION + // BCB5.64 (and probably lower versions) workaround. + // The in-place factories are supported by means of catch-all constructors + // and assignment operators (the functions are parameterized in terms of + // an arbitrary 'Expr' type) + // This compiler incorrectly resolves the overload set and sinks optional and optional + // to the 'Expr'-taking functions even though explicit overloads are present for them. + // Thus, the following overload is needed to properly handle the case when the 'lhs' + // is another optional. + // + // For VC<=70 compilers this workaround dosen't work becasue the comnpiler issues and error + // instead of choosing the wrong overload + // +#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES + // Notice that 'Expr' will be optional or optional (but not tc_optional_base<..>) + template + void construct ( Expr&& expr, optional_tag const* ) + { + if ( expr.is_initialized() ) + { + // An exception can be thrown here. + // It it happens, THIS will be left uninitialized. + m_storage = value_type(boost::move(expr.get())) ; + m_initialized = true ; + } + } +#else + // Notice that 'Expr' will be optional or optional (but not tc_optional_base<..>) + template + void construct ( Expr const& expr, optional_tag const* ) + { + if ( expr.is_initialized() ) + { + // An exception can be thrown here. + // It it happens, THIS will be left uninitialized. + m_storage = value_type(expr.get()) ; + m_initialized = true ; + } + } +#endif +#endif // defined BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION + + void assign_value ( argument_type val ) { m_storage = val; } +#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES + void assign_value ( rval_reference_type val ) { m_storage = static_cast(val); } +#endif + + void destroy() + { + m_initialized = false; + } + + reference_const_type get_impl() const { return m_storage ; } + reference_type get_impl() { return m_storage ; } + + pointer_const_type get_ptr_impl() const { return boost::addressof(m_storage); } + pointer_type get_ptr_impl() { return boost::addressof(m_storage); } + + private : + + bool m_initialized ; + T m_storage ; +} ; \ No newline at end of file diff --git a/include/boost/optional/optional.hpp b/include/boost/optional/optional.hpp index a75bf90..54fca4e 100644 --- a/include/boost/optional/optional.hpp +++ b/include/boost/optional/optional.hpp @@ -1,5 +1,5 @@ // Copyright (C) 2003, 2008 Fernando Luis Cacciola Carballal. -// Copyright (C) 2014 - 2016 Andrzej Krzemienski. +// Copyright (C) 2014 - 2017 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 @@ -36,13 +36,22 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include +#include #include #include #include #include #include #include +#include +#include #include #include #include @@ -178,6 +187,7 @@ class optional_base : public optional_tag // Creates a deep move of another optional // Can throw if T::T(T&&) does optional_base ( optional_base&& rhs ) + BOOST_NOEXCEPT_IF(::boost::is_nothrow_move_constructible::value) : m_initialized(false) { @@ -210,6 +220,20 @@ class optional_base : public optional_tag #endif + optional_base& operator= ( optional_base const& rhs ) + { + this->assign(rhs); + return *this; + } + +#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES + optional_base& operator= ( optional_base && rhs ) + BOOST_NOEXCEPT_IF(::boost::is_nothrow_move_constructible::value && ::boost::is_nothrow_move_assignable::value) + { + this->assign(static_cast(rhs)); + return *this; + } +#endif // No-throw (assuming T::~T() doesn't) ~optional_base() { destroy() ; } @@ -735,6 +759,10 @@ class optional_base : public optional_tag storage_type m_storage ; } ; + + +#include + // definition of metafunciton is_optional_val_init_candidate template struct is_optional_related @@ -776,13 +804,46 @@ struct is_optional_val_init_candidate : boost::conditional< !is_optional_related::value && is_convertible_to_T_or_factory::value , boost::true_type, boost::false_type>::type {}; - + + +template +struct is_type_trivially_copyable + : boost::conditional<(boost::has_trivial_copy_constructor::value && + boost::has_trivial_move_constructor::value && + boost::has_trivial_destructor::value && + boost::has_trivial_move_assign::value && + boost::has_trivial_assign::value), + boost::true_type, boost::false_type>::type +{}; + } // namespace optional_detail +namespace optional_config { + +template +struct is_type_trivial + : boost::conditional< (optional_detail::is_type_trivially_copyable::value && boost::has_trivial_default_constructor::value) || + (boost::is_scalar::value && !boost::is_const::value && !boost::is_volatile::value) + , boost::true_type, boost::false_type>::type +{}; + +} // namespace optional_config + + +#ifndef BOOST_OPTIONAL_CONFIG_NO_SPEC_FOR_TRIVIAL_TYPES +# define BOOST_OPTIONAL_BASE_TYPE(T) boost::conditional< optional_config::is_type_trivial::value, \ + optional_detail::tc_optional_base, \ + optional_detail::optional_base \ + >::type +#else +# define BOOST_OPTIONAL_BASE_TYPE(T) optional_detail::optional_base +#endif + template -class optional : public optional_detail::optional_base +class optional + : public BOOST_OPTIONAL_BASE_TYPE(T) { - typedef optional_detail::optional_base base ; + typedef typename BOOST_OPTIONAL_BASE_TYPE(T) base ; public : @@ -842,7 +903,7 @@ class optional : public optional_detail::optional_base ) : base() - { + { if ( rhs.is_initialized() ) this->construct(rhs.get()); } @@ -893,15 +954,24 @@ class optional : public optional_detail::optional_base // Creates a deep copy of another optional // Can throw if T::T(T const&) does +#ifndef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS + optional ( optional const& ) = default; +#else optional ( optional const& rhs ) : base( static_cast(rhs) ) {} +#endif #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES // Creates a deep move of another optional // Can throw if T::T(T&&) does + +#ifndef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS + optional ( optional && rhs ) = default; +#else optional ( optional && rhs ) BOOST_NOEXCEPT_IF(::boost::is_nothrow_move_constructible::value) : base( boost::move(rhs) ) {} +#endif #endif @@ -959,21 +1029,30 @@ class optional : public optional_detail::optional_base // Assigns from another optional (deep-copies the rhs value) // Basic Guarantee: If T::T( T const& ) throws, this is left UNINITIALIZED // (NOTE: On BCB, this operator is not actually called and left is left UNMODIFIED in case of a throw) +#ifndef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS + optional& operator= ( optional const& rhs ) = default; +#else optional& operator= ( optional const& rhs ) { this->assign( static_cast(rhs) ) ; return *this ; } +#endif #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES // Assigns from another optional (deep-moves the rhs value) +#ifndef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS + optional& operator= ( optional && ) = default; +#else optional& operator= ( optional && rhs ) BOOST_NOEXCEPT_IF(::boost::is_nothrow_move_constructible::value && ::boost::is_nothrow_move_assignable::value) { this->assign( static_cast(rhs) ) ; return *this ; } -#endif +#endif + +#endif // BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES #ifndef BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index d081abc..fd3c7e2 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -1,7 +1,7 @@ # Boost.Optional Library test Jamfile # # Copyright (C) 2003, Fernando Luis Cacciola Carballal. -# Copyright (C) 2014 - 2016 Andrzej Krzemienski +# Copyright (C) 2014 - 2017 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 @@ -66,6 +66,7 @@ import testing ; [ compile-fail optional_test_fail_io_without_io.cpp ] [ compile-fail optional_test_fail_none_io_without_io.cpp ] [ compile-fail optional_test_fail_convert_assign_of_enums.cpp ] + [ run optional_test_static_properties.cpp ] [ run optional_xconfig_NO_PROPER_ASSIGN_FROM_CONST_INT_pass.cpp ] [ run-fail optional_xconfig_NO_PROPER_ASSIGN_FROM_CONST_INT_fail.cpp ] [ run optional_xconfig_NO_PROPER_CONVERT_FROM_CONST_INT_pass.cpp ] diff --git a/test/optional_test_static_properties.cpp b/test/optional_test_static_properties.cpp new file mode 100644 index 0000000..02695c7 --- /dev/null +++ b/test/optional_test_static_properties.cpp @@ -0,0 +1,140 @@ +// Copyright (C) 2017 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) +// +// See http://www.boost.org/lib/optional for documentation. +// +// You are welcome to contact the author at: +// akrzemi1@gmail.com + +#include "boost/optional/optional.hpp" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#include "boost/core/lightweight_test.hpp" +#include "boost/core/lightweight_test_trait.hpp" +#include "boost/type_traits/is_base_of.hpp" + +#ifndef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS + +#if (defined BOOST_HAS_TRIVIAL_MOVE_ASSIGN) && (defined BOOST_HAS_TRIVIAL_MOVE_CONSTRUCTOR) && (defined BOOST_HAS_TRIVIAL_CONSTRUCTOR) && (defined BOOST_HAS_TRIVIAL_COPY) && (defined BOOST_HAS_TRIVIAL_ASSIGN) && (defined BOOST_HAS_TRIVIAL_DESTRUCTOR) +#else +# define BOOST_OPTIONAL_NO_TRIVIALITY_DETECTION +#endif + +struct PrivDefault +{ + private: PrivDefault() {} +}; + +struct CustDefault +{ + CustDefault() {} +}; + +struct CustomizedTrivial +{ + CustomizedTrivial() {} +}; + +namespace boost { namespace optional_config { + +template <> struct is_type_trivial : boost::true_type {}; + +}} + +struct CustDtor +{ + ~CustDtor() {} +}; + +struct NoDefault +{ + explicit NoDefault(int) {} +}; + +struct Empty {}; + +template +struct Aggregate { T t; U u; }; + +struct CustAssign +{ + CustAssign& operator=(CustAssign const&) { return *this; } +}; + +struct CustMove +{ + CustMove(CustMove &&) {} +}; + +void test_type_traits() +{ + // this only tests if type traits are implemented correctly + BOOST_TEST_TRAIT_TRUE(( boost::optional_config::is_type_trivial )); + BOOST_TEST_TRAIT_TRUE(( boost::optional_config::is_type_trivial )); + BOOST_TEST_TRAIT_TRUE(( boost::optional_config::is_type_trivial )); + BOOST_TEST_TRAIT_TRUE(( boost::optional_config::is_type_trivial > )); + BOOST_TEST_TRAIT_TRUE(( boost::optional_config::is_type_trivial, double> > )); + + BOOST_TEST_TRAIT_TRUE(( boost::optional_config::is_type_trivial )); + + BOOST_TEST_TRAIT_FALSE(( boost::optional_config::is_type_trivial )); + BOOST_TEST_TRAIT_FALSE(( boost::optional_config::is_type_trivial )); + BOOST_TEST_TRAIT_FALSE(( boost::optional_config::is_type_trivial )); + BOOST_TEST_TRAIT_FALSE(( boost::optional_config::is_type_trivial > )); + + BOOST_TEST_TRAIT_FALSE(( boost::optional_config::is_type_trivial )); + BOOST_TEST_TRAIT_FALSE(( boost::optional_config::is_type_trivial )); + BOOST_TEST_TRAIT_FALSE(( boost::optional_config::is_type_trivial )); + BOOST_TEST_TRAIT_FALSE(( boost::optional_config::is_type_trivial > )); + + BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable )); + BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable )); + BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable )); + BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable > )); + BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable, double> > )); + +#ifndef BOOST_OPTIONAL_NO_TRIVIALITY_DETECTION + BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable )); + BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable )); + BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable )); + BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable > )); +#endif + + BOOST_TEST_TRAIT_FALSE(( boost::optional_detail::is_type_trivially_copyable )); + BOOST_TEST_TRAIT_FALSE(( boost::optional_detail::is_type_trivially_copyable )); + BOOST_TEST_TRAIT_FALSE(( boost::optional_detail::is_type_trivially_copyable )); + BOOST_TEST_TRAIT_FALSE(( boost::optional_detail::is_type_trivially_copyable > )); +} + +void test_trivial_copyability() +{ + BOOST_TEST_TRAIT_TRUE((boost::is_base_of, boost::optional > )); + BOOST_TEST_TRAIT_TRUE((boost::is_base_of, boost::optional > )); + BOOST_TEST_TRAIT_TRUE((boost::is_base_of, boost::optional > )); + +#ifndef BOOST_OPTIONAL_NO_TRIVIALITY_DETECTION + BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable > )); + BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable > )); + BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable > )); + BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable > )); + BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable > > )); + BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable, double> > > )); +#endif +} + +#endif + +int main() +{ +#ifndef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS + test_type_traits(); + test_trivial_copyability(); +#endif + return boost::report_errors(); +} \ No newline at end of file