From 9be41447baaa8c7d398189d8f98a574beec9c750 Mon Sep 17 00:00:00 2001 From: chentianyu03 Date: Tue, 17 Aug 2021 16:22:23 +0800 Subject: [PATCH] Copy boost optional to Paddle (#34780) * copy boost optional.hpp to paddle * copy boost optional.hpp to paddle * move directions * del fluid/utils * modify .hpp to .h * move directions * modify to paddle::optional * add modification description * format code stype for the files in paddle/utils * format code stype --- .../fluid/framework/details/build_strategy.cc | 6 +- .../fluid/framework/details/build_strategy.h | 8 +- .../conv_elementwise_add_mkldnn_fuse_pass.cc | 4 +- .../conv_elementwise_add_mkldnn_fuse_pass.h | 2 +- paddle/fluid/framework/mixed_vector.h | 12 +- paddle/fluid/framework/op_version_registry.h | 5 +- paddle/fluid/operators/flip_op.cc | 2 +- .../operators/mkldnn/concat_mkldnn_op.cc | 2 +- .../fluid/operators/mkldnn/conv_mkldnn_op.cc | 2 +- paddle/fluid/operators/mkldnn/fc_mkldnn_op.cc | 9 +- .../fluid/operators/mkldnn/mul_mkldnn_op.cc | 8 +- .../sequence_ops/sequence_concat_op.h | 4 +- paddle/fluid/platform/mkldnn_reuse.h | 2 +- paddle/fluid/pybind/pybind.cc | 9 +- paddle/fluid/pybind/reader_py.cc | 6 +- paddle/utils/any.h | 295 +++--- paddle/utils/none.h | 42 + paddle/utils/optional.h | 869 ++++++++++++++++++ 18 files changed, 1075 insertions(+), 212 deletions(-) create mode 100644 paddle/utils/none.h create mode 100644 paddle/utils/optional.h diff --git a/paddle/fluid/framework/details/build_strategy.cc b/paddle/fluid/framework/details/build_strategy.cc index b517c232755..0d55882953d 100644 --- a/paddle/fluid/framework/details/build_strategy.cc +++ b/paddle/fluid/framework/details/build_strategy.cc @@ -36,8 +36,8 @@ static inline bool SeqOnlyAllReduceOps(const BuildStrategy &strategy) { !strategy.enable_parallel_graph_; } -static inline void ConvertDefaultValue(boost::optional *default_value) { - if (*default_value == boost::none) { +static inline void ConvertDefaultValue(paddle::optional *default_value) { + if (*default_value == paddle::none) { *default_value = true; } } @@ -247,7 +247,7 @@ class ParallelExecutorPassBuilder : public ir::PassBuilder { } } - void AppendPassWithCheck(const boost::optional &append_pass, + void AppendPassWithCheck(const paddle::optional &append_pass, const std::string &pass_name) { AppendPassWithCheck(append_pass == true, pass_name); } diff --git a/paddle/fluid/framework/details/build_strategy.h b/paddle/fluid/framework/details/build_strategy.h index 9dcfb0ff32d..e1e9db2ece6 100644 --- a/paddle/fluid/framework/details/build_strategy.h +++ b/paddle/fluid/framework/details/build_strategy.h @@ -112,8 +112,8 @@ struct BuildStrategy { bool enable_auto_fusion_{false}; // Fuse_all_optimizer_ops and fuse_all_reduce_ops require that gradients // should not be sparse types - boost::optional fuse_all_optimizer_ops_{false}; - boost::optional fuse_all_reduce_ops_{boost::none}; + paddle::optional fuse_all_optimizer_ops_{false}; + paddle::optional fuse_all_reduce_ops_{boost::none}; // fuse_relu_depthwise_conv can fuse the `relu -> // depthwise_conv` bool fuse_relu_depthwise_conv_{false}; @@ -121,7 +121,7 @@ struct BuildStrategy { // faster. Because fusing broadcast OP equals delaying the execution of all // broadcast Ops, in this case, all nccl streams are used only for reduce // operations for a period of time. - boost::optional fuse_broadcast_ops_{boost::none}; + paddle::optional fuse_broadcast_ops_{boost::none}; // replace batch_norm with sync_batch_norm. bool sync_batch_norm_{false}; @@ -135,7 +135,7 @@ struct BuildStrategy { // By default, memory_optimize would be opened if gc is disabled, and // be closed if gc is enabled. // Users can forcely enable/disable memory_optimize by setting True/False. - boost::optional memory_optimize_{boost::none}; + paddle::optional memory_optimize_{boost::none}; // Turn on inplace by default. bool enable_inplace_{true}; diff --git a/paddle/fluid/framework/ir/mkldnn/conv_elementwise_add_mkldnn_fuse_pass.cc b/paddle/fluid/framework/ir/mkldnn/conv_elementwise_add_mkldnn_fuse_pass.cc index b07cc58959f..8031f56752a 100644 --- a/paddle/fluid/framework/ir/mkldnn/conv_elementwise_add_mkldnn_fuse_pass.cc +++ b/paddle/fluid/framework/ir/mkldnn/conv_elementwise_add_mkldnn_fuse_pass.cc @@ -74,11 +74,11 @@ bool IsReachable(ir::Graph* graph, Node* from, Node* to) { } template -boost::optional HasAttribute(const Node& op, const std::string& attr) { +paddle::optional HasAttribute(const Node& op, const std::string& attr) { if (op.Op()->HasAttr(attr)) return BOOST_GET_CONST(T, op.Op()->GetAttr(attr)); else - return boost::none; + return paddle::none; } ResidualConnectionMKLDNNFusePass::ResidualConnectionMKLDNNFusePass() { diff --git a/paddle/fluid/framework/ir/mkldnn/conv_elementwise_add_mkldnn_fuse_pass.h b/paddle/fluid/framework/ir/mkldnn/conv_elementwise_add_mkldnn_fuse_pass.h index 5b4f941836c..c83335da2f6 100644 --- a/paddle/fluid/framework/ir/mkldnn/conv_elementwise_add_mkldnn_fuse_pass.h +++ b/paddle/fluid/framework/ir/mkldnn/conv_elementwise_add_mkldnn_fuse_pass.h @@ -40,7 +40,7 @@ using GraphWithStats = std::pair; void CorrectGraphEdges(Graph* graph, Node* from, Node* to); bool IsReachable(ir::Graph* graph, Node* from, Node* to); -boost::optional HasBias(const Node& op, const std::string& bias_name); +paddle::optional HasBias(const Node& op, const std::string& bias_name); class ResidualConnectionMKLDNNFusePass : public FusePassBase { private: diff --git a/paddle/fluid/framework/mixed_vector.h b/paddle/fluid/framework/mixed_vector.h index 1e9b498bb2b..cf71cdfc6d6 100644 --- a/paddle/fluid/framework/mixed_vector.h +++ b/paddle/fluid/framework/mixed_vector.h @@ -27,6 +27,8 @@ limitations under the License. */ #include "paddle/fluid/framework/tensor_util.h" #include "paddle/fluid/memory/malloc.h" #include "paddle/fluid/memory/memcpy.h" +#include "paddle/utils/none.h" +#include "paddle/utils/optional.h" namespace paddle { namespace framework { @@ -195,10 +197,10 @@ class Vector { std::mutex &Mutex() const { return mtx_; } - boost::optional CUDAPlace() const { + paddle::optional CUDAPlace() const { return gpu_ == nullptr - ? boost::none - : boost::optional( + ? paddle::none + : paddle::optional( BOOST_GET_CONST(platform::CUDAPlace, gpu_->place())); } @@ -389,7 +391,7 @@ class Vector { auto &mtx = m_.Data().Mutex(); std::lock_guard guard(mtx); auto cuda_place = m_.Data().CUDAPlace(); - if (cuda_place == boost::none || + if (cuda_place == paddle::none || cuda_place == BOOST_GET(platform::CUDAPlace, place)) { return m_.Data().CUDAData(place); } @@ -405,7 +407,7 @@ class Vector { auto &mtx = m_.Data().Mutex(); std::lock_guard guard(mtx); auto cuda_place = m_.Data().CUDAPlace(); - if (cuda_place == boost::none || + if (cuda_place == paddle::none || cuda_place == BOOST_GET(platform::CUDAPlace, place)) { return m_.MutableData()->CUDAMutableData(place); } diff --git a/paddle/fluid/framework/op_version_registry.h b/paddle/fluid/framework/op_version_registry.h index 5ae8f255d63..45ec01868d9 100644 --- a/paddle/fluid/framework/op_version_registry.h +++ b/paddle/fluid/framework/op_version_registry.h @@ -22,6 +22,7 @@ limitations under the License. */ #include "paddle/fluid/framework/op_version_proto.h" #include "paddle/fluid/platform/enforce.h" +#include "paddle/utils/none.h" namespace paddle { namespace framework { @@ -42,7 +43,7 @@ using OpAttrVariantT = std::vector, /* AttrType::INTS */ std::vector, /* AttrType::LONGS */ std::vector, /* AttrType::STRINGS */ - boost::none_t /* None */ + paddle::none_t /* None */ >; struct OpUpdateInfo { @@ -51,7 +52,7 @@ struct OpUpdateInfo { struct OpAttrInfo : OpUpdateInfo { OpAttrInfo(const std::string& name, const std::string& remark, - const OpAttrVariantT& default_value = boost::none) + const OpAttrVariantT& default_value = paddle::none) : name_{name}, default_value_{default_value}, remark_{remark} {} const std::string& name() const { return name_; } diff --git a/paddle/fluid/operators/flip_op.cc b/paddle/fluid/operators/flip_op.cc index d7ed5fb767c..d062243acf3 100644 --- a/paddle/fluid/operators/flip_op.cc +++ b/paddle/fluid/operators/flip_op.cc @@ -161,5 +161,5 @@ REGISTER_OP_VERSION(flip) R"ROC(Upgrade flip, add new attr [axis] and delete attr [dims].)ROC", paddle::framework::compatible::OpVersionDesc() .NewAttr("axis", "The added attr 'axis' doesn't set default value.", - boost::none) + paddle::none) .DeleteAttr("dims", "The attr 'dims' is deleted.")); diff --git a/paddle/fluid/operators/mkldnn/concat_mkldnn_op.cc b/paddle/fluid/operators/mkldnn/concat_mkldnn_op.cc index df4750321e3..8901c0afb36 100644 --- a/paddle/fluid/operators/mkldnn/concat_mkldnn_op.cc +++ b/paddle/fluid/operators/mkldnn/concat_mkldnn_op.cc @@ -137,7 +137,7 @@ class ConcatPrimitiveFactory { private: std::vector srcs_d; std::vector srcs; - boost::optional dst_mem; + paddle::optional dst_mem; }; template diff --git a/paddle/fluid/operators/mkldnn/conv_mkldnn_op.cc b/paddle/fluid/operators/mkldnn/conv_mkldnn_op.cc index 0065f3ae394..b353ce4c322 100644 --- a/paddle/fluid/operators/mkldnn/conv_mkldnn_op.cc +++ b/paddle/fluid/operators/mkldnn/conv_mkldnn_op.cc @@ -893,7 +893,7 @@ class ConvMKLDNNOpKernel : public paddle::framework::OpKernel { fuse_residual_conn, propagation, output_shift_scale, sum_scale); } else { conv_pd = handler->AcquireConvolutionPrimitiveDescriptor( - src_md, weights_md, boost::none, dst_md, strides, dilations, + src_md, weights_md, paddle::none, dst_md, strides, dilations, paddings, mkldnn_engine, fuse_activation, fuse_alpha, fuse_beta, fuse_residual_conn, propagation, output_shift_scale, sum_scale); } diff --git a/paddle/fluid/operators/mkldnn/fc_mkldnn_op.cc b/paddle/fluid/operators/mkldnn/fc_mkldnn_op.cc index d7e5d9b9e02..08fdd3b74c7 100644 --- a/paddle/fluid/operators/mkldnn/fc_mkldnn_op.cc +++ b/paddle/fluid/operators/mkldnn/fc_mkldnn_op.cc @@ -89,7 +89,8 @@ class FCPrimitiveFactory { // descriptor has been divided into separate cases, based on the number // of input dimensions. size_t input_dim_num = input->dims().size(); - boost::optional fc_prim_desc; + paddle::optional + fc_prim_desc; memory::desc usr_weights_desc = {}; switch (input_dim_num) { case 2: @@ -545,11 +546,11 @@ class FCPrimitiveFactory { private: const mkldnn::engine& engine_; - boost::optional input_; - boost::optional output_; + paddle::optional input_; + paddle::optional output_; std::shared_ptr bias_; std::shared_ptr weights_; - boost::optional fc_; + paddle::optional fc_; }; // Attempt to fetch cached primitive factory based on provided parameters diff --git a/paddle/fluid/operators/mkldnn/mul_mkldnn_op.cc b/paddle/fluid/operators/mkldnn/mul_mkldnn_op.cc index b3d970c7f05..422944107fb 100644 --- a/paddle/fluid/operators/mkldnn/mul_mkldnn_op.cc +++ b/paddle/fluid/operators/mkldnn/mul_mkldnn_op.cc @@ -290,10 +290,10 @@ class MulPrimitiveFactory { } const mkldnn::engine &engine_; - boost::optional x_input_; - boost::optional y_input_; - boost::optional output_; - boost::optional mul_; + paddle::optional x_input_; + paddle::optional y_input_; + paddle::optional output_; + paddle::optional mul_; static constexpr bool is_int8_ = std::is_same::value || std::is_same::value; }; diff --git a/paddle/fluid/operators/sequence_ops/sequence_concat_op.h b/paddle/fluid/operators/sequence_ops/sequence_concat_op.h index 339db996fc9..1b8525febe2 100644 --- a/paddle/fluid/operators/sequence_ops/sequence_concat_op.h +++ b/paddle/fluid/operators/sequence_ops/sequence_concat_op.h @@ -123,7 +123,7 @@ class SeqConcatGradKernel : public framework::OpKernel { } std::vector sliced_x; - std::vector> sliced_dx; + std::vector> sliced_dx; for (size_t i = 1; i < xs[0]->lod()[0].size(); ++i) { for (size_t j = 0; j < xs.size(); ++j) { @@ -145,7 +145,7 @@ class SeqConcatGradKernel : public framework::OpKernel { if (dx) { sliced_dx.emplace_back(dx->Slice(prev_lod, next_lod)); } else { - sliced_dx.emplace_back(boost::none); + sliced_dx.emplace_back(paddle::none); } } } diff --git a/paddle/fluid/platform/mkldnn_reuse.h b/paddle/fluid/platform/mkldnn_reuse.h index 0b7e96a2547..c27bc6c6e55 100644 --- a/paddle/fluid/platform/mkldnn_reuse.h +++ b/paddle/fluid/platform/mkldnn_reuse.h @@ -1426,7 +1426,7 @@ class ConvMKLDNNTemplateHandler : public MKLDNNHandler { std::shared_ptr AcquireConvolutionPrimitiveDescriptor( const mkldnn::memory::desc& src, const mkldnn::memory::desc& weights, - boost::optional bias, + paddle::optional bias, const mkldnn::memory::desc& dst, const std::vector& strides, const std::vector& dilations, const std::vector& paddings, const mkldnn::engine& engine, diff --git a/paddle/fluid/pybind/pybind.cc b/paddle/fluid/pybind/pybind.cc index 5001cc4a017..0663da88ac7 100644 --- a/paddle/fluid/pybind/pybind.cc +++ b/paddle/fluid/pybind/pybind.cc @@ -73,6 +73,7 @@ limitations under the License. */ #include "paddle/fluid/platform/profiler.h" #include "paddle/fluid/pybind/cuda_streams_py.h" #include "paddle/fluid/pybind/io.h" +#include "paddle/utils/none.h" #ifdef PADDLE_WITH_ASCEND #include "paddle/fluid/pybind/ascend_wrapper_py.h" #endif @@ -2910,7 +2911,7 @@ All parameter, weight, gradient are variables in Paddle. .def_property("fuse_broadcast_ops", [](const BuildStrategy &self) { return self.fuse_broadcast_ops_ == true || - self.fuse_broadcast_ops_ == boost::none; + self.fuse_broadcast_ops_ == paddle::none; }, [](BuildStrategy &self, bool b) { PADDLE_ENFORCE_NE(self.IsFinalized(), true, @@ -2940,7 +2941,7 @@ All parameter, weight, gradient are variables in Paddle. .def_property("fuse_all_optimizer_ops", [](const BuildStrategy &self) { return self.fuse_all_optimizer_ops_ == true || - self.fuse_all_optimizer_ops_ == boost::none; + self.fuse_all_optimizer_ops_ == paddle::none; }, [](BuildStrategy &self, bool b) { PADDLE_ENFORCE_NE(self.IsFinalized(), true, @@ -2989,7 +2990,7 @@ All parameter, weight, gradient are variables in Paddle. [](BuildStrategy &self, const py::handle &value) { auto *py_obj = value.ptr(); if (py_obj == nullptr || py_obj == Py_None) { - self.memory_optimize_ = boost::none; + self.memory_optimize_ = paddle::none; } else if (PyBool_Check(py_obj)) { self.memory_optimize_ = (py_obj == Py_True); } else { @@ -3046,7 +3047,7 @@ All parameter, weight, gradient are variables in Paddle. "fuse_all_reduce_ops", [](const BuildStrategy &self) { return self.fuse_all_reduce_ops_ == true || - self.fuse_all_reduce_ops_ == boost::none; + self.fuse_all_reduce_ops_ == paddle::none; }, [](BuildStrategy &self, bool b) { self.fuse_all_reduce_ops_ = b; }) .def_property("enable_backward_optimizer_op_deps", diff --git a/paddle/fluid/pybind/reader_py.cc b/paddle/fluid/pybind/reader_py.cc index abe1977eb69..9ed1ed30324 100644 --- a/paddle/fluid/pybind/reader_py.cc +++ b/paddle/fluid/pybind/reader_py.cc @@ -44,7 +44,7 @@ namespace reader = operators::reader; // Check whether the tensor shape matches the VarDesc shape // Return the different shape if exists -static boost::optional> DiffTensorShapeWithVarDesc( +static paddle::optional> DiffTensorShapeWithVarDesc( const framework::LoDTensor &tensor, const framework::VarDesc &var_desc, size_t num_places) { auto tensor_shape = tensor.dims(); @@ -56,7 +56,7 @@ static boost::optional> DiffTensorShapeWithVarDesc( if (desc_shape.size() != 0) { // Tensor rank = 0 but desc does not match return framework::vectorize(tensor_shape); } else { - return boost::none; + return paddle::none; } } @@ -92,7 +92,7 @@ static boost::optional> DiffTensorShapeWithVarDesc( } } - return boost::none; + return paddle::none; } static const std::shared_ptr &GetQueue( diff --git a/paddle/utils/any.h b/paddle/utils/any.h index ec803647c11..d0e72b70635 100644 --- a/paddle/utils/any.h +++ b/paddle/utils/any.h @@ -1,8 +1,8 @@ -//This file copy from boost/any.hpp and boost version: 1.41.0 -//Modified the following points: -//1. modify namespace from boost::any to paddle::any -//2. remove the depending boost header files -//3. remove/modify some macro +// This file copy from boost/any.hpp and boost version: 1.41.0 +// Modified the following points: +// 1. modify namespace from boost::any to paddle::any +// 2. remove the depending boost header files +// 3. remove/modify some macro // See http://www.boost.org/libs/any for Documentation. @@ -17,210 +17,157 @@ // where: tested with BCC 5.5, MSVC 6.0, and g++ 2.95 #include -#include #include +#include // See boost/python/type_id.hpp // TODO: add BOOST_TYPEID_COMPARE_BY_NAME to config.hpp -# if (defined(__GNUC__) && __GNUC__ >= 3) \ - || defined(_AIX) \ - || ( defined(__sgi) && defined(__host_mips)) \ - || (defined(__hpux) && defined(__HP_aCC)) \ - || (defined(linux) && defined(__INTEL_COMPILER) && defined(__ICC)) -# define BOOST_AUX_ANY_TYPE_ID_NAME +#if (defined(__GNUC__) && __GNUC__ >= 3) || defined(_AIX) || \ + (defined(__sgi) && defined(__host_mips)) || \ + (defined(__hpux) && defined(__HP_aCC)) || \ + (defined(linux) && defined(__INTEL_COMPILER) && defined(__ICC)) +#define BOOST_AUX_ANY_TYPE_ID_NAME #include -# endif - -namespace paddle -{ - class any - { - public: // structors - - any() - : content(0) - { - } +#endif - template - any(const ValueType & value) - : content(new holder(value)) - { - } +namespace paddle { +class any { + public: // structors + any() : content(0) {} - any(const any & other) - : content(other.content ? other.content->clone() : 0) - { - } + template + any(const ValueType &value) : content(new holder(value)) {} - ~any() - { - delete content; - } + any(const any &other) : content(other.content ? other.content->clone() : 0) {} - public: // modifiers + ~any() { delete content; } - any & swap(any & rhs) - { - std::swap(content, rhs.content); - return *this; - } + public: // modifiers + any &swap(any &rhs) { + std::swap(content, rhs.content); + return *this; + } - template - any & operator=(const ValueType & rhs) - { - any(rhs).swap(*this); - return *this; - } + template + any &operator=(const ValueType &rhs) { + any(rhs).swap(*this); + return *this; + } - any & operator=(any rhs) - { - rhs.swap(*this); - return *this; - } + any &operator=(any rhs) { + rhs.swap(*this); + return *this; + } - public: // queries + public: // queries + bool empty() const { return !content; } - bool empty() const - { - return !content; - } + const std::type_info &type() const { + return content ? content->type() : typeid(void); + } - const std::type_info & type() const - { - return content ? content->type() : typeid(void); - } + public: // types (public so any_cast can be non-friend) + class placeholder { + public: // structors + virtual ~placeholder() {} - public: // types (public so any_cast can be non-friend) + public: // queries + virtual const std::type_info &type() const = 0; - class placeholder - { - public: // structors + virtual placeholder *clone() const = 0; + }; - virtual ~placeholder() - { - } + template + class holder : public placeholder { + public: // structors + holder(const ValueType &value) : held(value) {} - public: // queries + public: // queries + virtual const std::type_info &type() const { return typeid(ValueType); } - virtual const std::type_info & type() const = 0; + virtual placeholder *clone() const { return new holder(held); } - virtual placeholder * clone() const = 0; + public: // representation + ValueType held; - }; + private: // intentionally left unimplemented + holder &operator=(const holder &); + }; - template - class holder : public placeholder - { - public: // structors + public: // representation (public so any_cast can be non-friend) + placeholder *content; +}; - holder(const ValueType & value) - : held(value) - { - } +class bad_any_cast : public std::bad_cast { + public: + virtual const char *what() const throw() { + return "paddle::bad_any_cast: " + "failed conversion using paddle::any_cast"; + } +}; - public: // queries +template +ValueType *any_cast(any *operand) { + return operand && +#ifdef BOOST_AUX_ANY_TYPE_ID_NAME + std::strcmp(operand->type().name(), + typeid(ValueType).name()) == 0 +#else + operand->type() == typeid(ValueType) +#endif + ? &static_cast *>(operand->content)->held + : 0; +} - virtual const std::type_info & type() const - { - return typeid(ValueType); - } +template +inline const ValueType *any_cast(const any *operand) { + return any_cast(const_cast(operand)); +} - virtual placeholder * clone() const - { - return new holder(held); - } +template +ValueType any_cast(any &operand) { + typedef typename std::remove_reference::type nonref; - public: // representation + // If 'nonref' is still reference type, it means the user has not + // specialized 'remove_reference'. - ValueType held; + // Please use BOOST_BROKEN_COMPILER_TYPE_TRAITS_SPECIALIZATION macro + // to generate specialization of remove_reference for your class + // See type traits library documentation for details + static_assert(!std::is_reference::value, + "!std::is_reference::value"); - private: // intentionally left unimplemented - holder & operator=(const holder &); - }; + nonref *result = any_cast(&operand); + if (!result) throw bad_any_cast(); + return *result; +} - public: // representation (public so any_cast can be non-friend) +template +inline ValueType any_cast(const any &operand) { + typedef typename std::remove_reference::type nonref; - placeholder * content; + // The comment in the above version of 'any_cast' explains when this + // assert is fired and what to do. + static_assert(!std::is_reference::value, + "!std::is_reference::value"); - }; + return any_cast(const_cast(operand)); +} - class bad_any_cast : public std::bad_cast - { - public: - virtual const char * what() const throw() - { - return "paddle::bad_any_cast: " - "failed conversion using paddle::any_cast"; - } - }; +// Note: The "unsafe" versions of any_cast are not part of the +// public interface and may be removed at any time. They are +// required where we know what type is stored in the any and can't +// use typeid() comparison, e.g., when our types may travel across +// different shared libraries. +template +inline ValueType *unsafe_any_cast(any *operand) { + return &static_cast *>(operand->content)->held; +} - template - ValueType * any_cast(any * operand) - { - return operand && -#ifdef BOOST_AUX_ANY_TYPE_ID_NAME - std::strcmp(operand->type().name(), typeid(ValueType).name()) == 0 -#else - operand->type() == typeid(ValueType) -#endif - ? &static_cast *>(operand->content)->held - : 0; - } - - template - inline const ValueType * any_cast(const any * operand) - { - return any_cast(const_cast(operand)); - } - - template - ValueType any_cast(any & operand) - { - typedef typename std::remove_reference::type nonref; - - // If 'nonref' is still reference type, it means the user has not - // specialized 'remove_reference'. - - // Please use BOOST_BROKEN_COMPILER_TYPE_TRAITS_SPECIALIZATION macro - // to generate specialization of remove_reference for your class - // See type traits library documentation for details - static_assert(!std::is_reference::value, "!std::is_reference::value"); - - nonref * result = any_cast(&operand); - if(!result) - throw bad_any_cast(); - return *result; - } - - template - inline ValueType any_cast(const any & operand) - { - typedef typename std::remove_reference::type nonref; - - // The comment in the above version of 'any_cast' explains when this - // assert is fired and what to do. - static_assert(!std::is_reference::value, "!std::is_reference::value"); - - return any_cast(const_cast(operand)); - } - - // Note: The "unsafe" versions of any_cast are not part of the - // public interface and may be removed at any time. They are - // required where we know what type is stored in the any and can't - // use typeid() comparison, e.g., when our types may travel across - // different shared libraries. - template - inline ValueType * unsafe_any_cast(any * operand) - { - return &static_cast *>(operand->content)->held; - } - - template - inline const ValueType * unsafe_any_cast(const any * operand) - { - return unsafe_any_cast(const_cast(operand)); - } +template +inline const ValueType *unsafe_any_cast(const any *operand) { + return unsafe_any_cast(const_cast(operand)); +} } // Copyright Kevlin Henney, 2000, 2001, 2002. All rights reserved. diff --git a/paddle/utils/none.h b/paddle/utils/none.h new file mode 100644 index 00000000000..20d6f4d2c7d --- /dev/null +++ b/paddle/utils/none.h @@ -0,0 +1,42 @@ +// This file copy from boost/none_t.hpp and boost/none.hpp and boost version: +// 1.41.0 +// Modified the following points: +// 1. modify namespace from boost::none to paddle::none +// 2. modify namespace from boost::none_t to paddle::none_t + +// Copyright (C) 2003, Fernando Luis Cacciola Carballal. +// +// Distributed under 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/libs/optional for documentation. +// +// You are welcome to contact the author at: +// fernando_cacciola@hotmail.com +// +#ifndef PADDLE_NONE_17SEP2003_HPP +#define PADDLE_NONE_17SEP2003_HPP + +namespace paddle { + +namespace detail { +struct none_helper {}; +} + +typedef int detail::none_helper::*none_t; + +} // namespace boost + +// NOTE: Borland users have to include this header outside any precompiled +// headers +// (bcc<=5.64 cannot include instance data in a precompiled header) +// -- * To be verified, now that there's no unnamed namespace + +namespace paddle { + +none_t const none = ((none_t)0); + +} // namespace boost + +#endif diff --git a/paddle/utils/optional.h b/paddle/utils/optional.h new file mode 100644 index 00000000000..00d8ae28ee8 --- /dev/null +++ b/paddle/utils/optional.h @@ -0,0 +1,869 @@ +// This file copy from boost/optional/optional.hpp and boost version: 1.41.0 +// Modified the following points: +// 1. modify namespace from boost::optional to paddle::optional +// 2. remove the depending boost header files +// 3. remove/modify some macro +// 4. copy some necessary data structures which are the depended by optional +// 5. replace type_with_alignment with std::aligned_storage + +// Copyright (C) 2003, Fernando Luis Cacciola Carballal. +// +// 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: +// fernando_cacciola@hotmail.com +// +#ifndef PADDLE_OPTIONAL_OPTIONAL_FLC_19NOV2002_HPP +#define PADDLE_OPTIONAL_OPTIONAL_FLC_19NOV2002_HPP + +#include +#include +#include +#include + +#include "none.h" + +// Daniel Wallin discovered that bind/apply.hpp badly interacts with the apply<> +// member template of a factory as used in the optional<> implementation. +// He proposed this simple fix which is to move the call to apply<> outside +// namespace boost. +namespace paddle_optional_detail { +template +void construct(Factory const& factory, void* address) { + factory.template apply(address); +} +} + +namespace paddle { +template +class optional; + +class in_place_factory_base {}; +class typed_in_place_factory_base {}; + +// template bool equal_pointees(OP const& x, OP const& y); +// template struct equal_pointees_t; +// +// Being OP a model of OptionalPointee (either a pointer or an optional): +// +// If both x and y have valid pointees, returns the result of (*x == *y) +// If only one has a valid pointee, returns false. +// If none have valid pointees, returns true. +// No-throw +template +inline bool equal_pointees(OptionalPointee const& x, OptionalPointee const& y) { + return (!x) != (!y) ? false : (!x ? true : (*x) == (*y)); +} + +template +struct equal_pointees_t + : std::binary_function { + bool operator()(OptionalPointee const& x, OptionalPointee const& y) const { + return equal_pointees(x, y); + } +}; + +// template bool less_pointees(OP const& x, OP const& y); +// template struct less_pointees_t; +// +// Being OP a model of OptionalPointee (either a pointer or an optional): +// +// If y has not a valid pointee, returns false. +// ElseIf x has not a valid pointee, returns true. +// ElseIf both x and y have valid pointees, returns the result of (*x < *y) +// No-throw +template +inline bool less_pointees(OptionalPointee const& x, OptionalPointee const& y) { + return !y ? false : (!x ? true : (*x) < (*y)); +} + +template +struct less_pointees_t + : std::binary_function { + bool operator()(OptionalPointee const& x, OptionalPointee const& y) const { + return less_pointees(x, y); + } +}; + +namespace detail { + +template +class reference_content { + private: // representation + RefT content_; + + public: // structors + ~reference_content() {} + + reference_content(RefT r) : content_(r) {} + + reference_content(const reference_content& operand) + : content_(operand.content_) {} + + private: // non-Assignable + reference_content& operator=(const reference_content&); + + public: // queries + RefT get() const { return content_; } +}; + +template +struct make_reference_content { + typedef T type; +}; + +template +struct make_reference_content { + typedef reference_content type; +}; + +} // namespace detail + +namespace optional_detail { + +// This local class is used instead of that in "aligned_storage.hpp" +// because I've found the 'official' class to ICE BCB5.5 +// when some types are used with optional<> +// (due to sizeof() passed down as a non-type template parameter) +template +class aligned_storage { + // Borland ICEs if unnamed unions are used for this! + union dummy_u { + char data[sizeof(T)]; + typename std::aligned_storage<::std::alignment_of::value>::type aligner_; + } dummy_; + + public: + void const* address() const { return &dummy_.data[0]; } + void* address() { return &dummy_.data[0]; } +}; + +template +struct types_when_isnt_ref { + typedef T const& reference_const_type; + typedef T& reference_type; + typedef T const* pointer_const_type; + typedef T* pointer_type; + typedef T const& argument_type; +}; +template +struct types_when_is_ref { + typedef typename std::remove_reference::type raw_type; + + typedef raw_type& reference_const_type; + typedef raw_type& reference_type; + typedef raw_type* pointer_const_type; + typedef raw_type* pointer_type; + typedef raw_type& argument_type; +}; + +struct optional_tag {}; + +template +class optional_base : public optional_tag { + private: + typedef + typename ::paddle::detail::make_reference_content::type internal_type; + + typedef aligned_storage storage_type; + + typedef types_when_isnt_ref types_when_not_ref; + typedef types_when_is_ref types_when_ref; + + typedef optional_base this_type; + + protected: + typedef T value_type; + + typedef std::true_type is_reference_tag; + typedef std::false_type is_not_reference_tag; + + typedef typename std::is_reference::type is_reference_predicate; + + typedef typename std::conditional::type types; + + typedef bool (this_type::*unspecified_bool_type)() const; + + typedef typename types::reference_type reference_type; + typedef typename types::reference_const_type reference_const_type; + typedef typename types::pointer_type pointer_type; + typedef typename types::pointer_const_type pointer_const_type; + typedef typename types::argument_type argument_type; + + // Creates an optional uninitialized. + // No-throw + optional_base() : m_initialized(false) {} + + // Creates an optional uninitialized. + // No-throw + optional_base(none_t) : m_initialized(false) {} + + // Creates an optional initialized with 'val'. + // Can throw if T::T(T const&) does + optional_base(argument_type val) : m_initialized(false) { construct(val); } + + // Creates an optional initialized with 'val' IFF cond is true, otherwise + // creates an uninitialzed optional. + // Can throw if T::T(T const&) does + optional_base(bool cond, argument_type val) : m_initialized(false) { + if (cond) construct(val); + } + + // Creates a deep copy of another optional + // Can throw if T::T(T const&) does + optional_base(optional_base const& rhs) : m_initialized(false) { + if (rhs.is_initialized()) construct(rhs.get_impl()); + } + + // 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 optional_base(Expr const& expr, Expr const* tag) + : m_initialized(false) { + construct(expr, tag); + } + + // No-throw (assuming T::~T() doesn't) + ~optional_base() { destroy(); } + + // Assigns from another optional (deep-copies the rhs value) + void assign(optional_base const& rhs) { + if (is_initialized()) { + if (rhs.is_initialized()) + assign_value(rhs.get_impl(), is_reference_predicate()); + else + destroy(); + } else { + if (rhs.is_initialized()) construct(rhs.get_impl()); + } + } + + // Assigns from another _convertible_ optional (deep-copies the rhs value) + template + void assign(optional const& rhs) { + if (is_initialized()) { + if (rhs.is_initialized()) + assign_value(static_cast(rhs.get()), + is_reference_predicate()); + else + destroy(); + } else { + if (rhs.is_initialized()) construct(static_cast(rhs.get())); + } + } + + // Assigns from a T (deep-copies the rhs value) + void assign(argument_type val) { + if (is_initialized()) + assign_value(val, is_reference_predicate()); + else + construct(val); + } + + // Assigns from "none", destroying the current value, if any, leaving this + // UNINITIALIZED + // No-throw (assuming T::~T() doesn't) + void assign(none_t) { destroy(); } + + template + void assign_expr(Expr const& expr, Expr const* tag) { + if (is_initialized()) + assign_expr_to_initialized(expr, tag); + else + construct(expr, tag); + } + + public: + // Destroys the current value, if any, leaving this UNINITIALIZED + // No-throw (assuming T::~T() doesn't) + void reset() { destroy(); } + + // Replaces the current value -if any- with 'val' + void reset(argument_type val) { 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) { + new (m_storage.address()) internal_type(val); + m_initialized = true; + } + + // Constructs in-place using the given factory + template + void construct(Expr const& factory, in_place_factory_base const*) { + static_assert(!is_reference_predicate::value, + "!is_reference_predicate::value"); + paddle_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*) { + static_assert(!is_reference_predicate::value, + "!is_reference_predicate::value"); + factory.apply(m_storage.address()); + 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); + } + + // Constructs using any expression implicitely 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*) { + new (m_storage.address()) internal_type(expr); + m_initialized = true; + } + + // Assigns using a form any expression implicitely 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, is_reference_predicate()); + } + + void assign_value(argument_type val, is_not_reference_tag) { + get_impl() = val; + } + void assign_value(argument_type val, is_reference_tag) { construct(val); } + + void destroy() { + if (m_initialized) destroy_impl(is_reference_predicate()); + } + + unspecified_bool_type safe_bool() const { + return m_initialized ? &this_type::is_initialized : 0; + } + + reference_const_type get_impl() const { + return dereference(get_object(), is_reference_predicate()); + } + reference_type get_impl() { + return dereference(get_object(), is_reference_predicate()); + } + + pointer_const_type get_ptr_impl() const { + return cast_ptr(get_object(), is_reference_predicate()); + } + pointer_type get_ptr_impl() { + return cast_ptr(get_object(), is_reference_predicate()); + } + + private: + // internal_type can be either T or reference_content + internal_type const* get_object() const { + return static_cast(m_storage.address()); + } + internal_type* get_object() { + return static_cast(m_storage.address()); + } + + // reference_content lacks an implicit conversion to T&, so the following + // is needed to obtain a proper reference. + reference_const_type dereference(internal_type const* p, + is_not_reference_tag) const { + return *p; + } + reference_type dereference(internal_type* p, is_not_reference_tag) { + return *p; + } + reference_const_type dereference(internal_type const* p, + is_reference_tag) const { + return p->get(); + } + reference_type dereference(internal_type* p, is_reference_tag) { + return p->get(); + } + + void destroy_impl(is_not_reference_tag) { + get_ptr_impl()->T::~T(); + m_initialized = false; + } + + void destroy_impl(is_reference_tag) { m_initialized = false; } + + // If T is of reference type, trying to get a pointer to the held value must + // result in a compile-time error. + // Decent compilers should disallow conversions from reference_content* to + // T*, but just in case, + // the following olverloads are used to filter out the case and guarantee an + // error in case of T being a reference. + pointer_const_type cast_ptr(internal_type const* p, + is_not_reference_tag) const { + return p; + } + pointer_type cast_ptr(internal_type* p, is_not_reference_tag) { return p; } + pointer_const_type cast_ptr(internal_type const* p, is_reference_tag) const { + return &p->get(); + } + pointer_type cast_ptr(internal_type* p, is_reference_tag) { + return &p->get(); + } + + bool m_initialized; + storage_type m_storage; +}; + +} // namespace optional_detail + +template +class optional : public optional_detail::optional_base { + typedef optional_detail::optional_base base; + + typedef typename base::unspecified_bool_type unspecified_bool_type; + + public: + typedef optional this_type; + + typedef typename base::value_type value_type; + typedef typename base::reference_type reference_type; + typedef typename base::reference_const_type reference_const_type; + typedef typename base::pointer_type pointer_type; + typedef typename base::pointer_const_type pointer_const_type; + typedef typename base::argument_type argument_type; + + // Creates an optional uninitialized. + // No-throw + optional() : base() {} + + // Creates an optional uninitialized. + // No-throw + optional(none_t none_) : base(none_) {} + + // Creates an optional initialized with 'val'. + // Can throw if T::T(T const&) does + optional(argument_type val) : base(val) {} + + // Creates an optional initialized with 'val' IFF cond is true, otherwise + // creates an uninitialized optional. + // Can throw if T::T(T const&) does + optional(bool cond, argument_type val) : base(cond, val) {} + + // Creates a deep copy of another convertible optional + // Requires a valid conversion from U to T. + // Can throw if T::T(U const&) does + template + explicit optional(optional const& rhs) : base() { + if (rhs.is_initialized()) this->construct(rhs.get()); + } + + // Creates an optional with an expression which can be either + // (a) An instance of InPlaceFactory (i.e. in_place(a,b,...,n); + // (b) An instance of TypedInPlaceFactory ( i.e. in_place(a,b,...,n); + // (c) Any expression implicitely convertible to the single type + // of a one-argument T's constructor. + // (d*) Weak compilers (BCB) might also resolved Expr as optional and + // optional + // even though explicit overloads are present for these. + // Depending on the above some T ctor is called. + // Can throw is the resolved T ctor throws. + template + explicit optional(Expr const& expr) : base(expr, &expr) {} + + // Creates a deep copy of another optional + // Can throw if T::T(T const&) does + optional(optional const& rhs) : base(rhs) {} + + // No-throw (assuming T::~T() doesn't) + ~optional() {} + + // Assigns from an expression. See corresponding constructor. + // Basic Guarantee: If the resolved T ctor throws, this is left UNINITIALIZED + template + optional& operator=(Expr expr) { + this->assign_expr(expr, &expr); + return *this; + } + + // Assigns from another convertible optional (converts && deep-copies the + // rhs value) + // Requires a valid conversion from U to T. + // Basic Guarantee: If T::T( U const& ) throws, this is left UNINITIALIZED + template + optional& operator=(optional const& rhs) { + this->assign(rhs); + return *this; + } + + // 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) + optional& operator=(optional const& rhs) { + this->assign(rhs); + return *this; + } + + // Assigns from a T (deep-copies the rhs value) + // Basic Guarantee: If T::( T const& ) throws, this is left UNINITIALIZED + optional& operator=(argument_type val) { + this->assign(val); + return *this; + } + + // Assigns from a "none" + // Which destroys the current value, if any, leaving this UNINITIALIZED + // No-throw (assuming T::~T() doesn't) + optional& operator=(none_t none_) { + this->assign(none_); + return *this; + } + + // Returns a reference to the value if this is initialized, otherwise, + // the behaviour is UNDEFINED + // No-throw + reference_const_type get() const { + assert(this->is_initialized()); + return this->get_impl(); + } + reference_type get() { + assert(this->is_initialized()); + return this->get_impl(); + } + + // Returns a copy of the value if this is initialized, 'v' otherwise + reference_const_type get_value_or(reference_const_type v) const { + return this->is_initialized() ? get() : v; + } + reference_type get_value_or(reference_type v) { + return this->is_initialized() ? get() : v; + } + + // Returns a pointer to the value if this is initialized, otherwise, + // the behaviour is UNDEFINED + // No-throw + pointer_const_type operator->() const { + assert(this->is_initialized()); + return this->get_ptr_impl(); + } + pointer_type operator->() { + assert(this->is_initialized()); + return this->get_ptr_impl(); + } + + // Returns a reference to the value if this is initialized, otherwise, + // the behaviour is UNDEFINED + // No-throw + reference_const_type operator*() const { return this->get(); } + reference_type operator*() { return this->get(); } + + // implicit conversion to "bool" + // No-throw + operator unspecified_bool_type() const { return this->safe_bool(); } + + // This is provided for those compilers which don't like the conversion to + // bool + // on some contexts. + bool operator!() const { return !this->is_initialized(); } +}; + +// Returns optional(v) +template +inline optional make_optional(T const& v) { + return optional(v); +} + +// Returns optional(cond,v) +template +inline optional make_optional(bool cond, T const& v) { + return optional(cond, v); +} + +// Returns a reference to the value if this is initialized, otherwise, the +// behaviour is UNDEFINED. +// No-throw +template +inline typename optional::reference_const_type get(optional const& opt) { + return opt.get(); +} + +template +inline typename optional::reference_type get(optional& opt) { + return opt.get(); +} + +// Returns a pointer to the value if this is initialized, otherwise, returns +// NULL. +// No-throw +template +inline typename optional::pointer_const_type get(optional const* opt) { + return opt->get_ptr(); +} + +template +inline typename optional::pointer_type get(optional* opt) { + return opt->get_ptr(); +} + +// Returns a reference to the value if this is initialized, otherwise, the +// behaviour is UNDEFINED. +// No-throw +template +inline typename optional::reference_const_type get_optional_value_or( + optional const& opt, typename optional::reference_const_type v) { + return opt.get_value_or(v); +} + +template +inline typename optional::reference_type get_optional_value_or( + optional& opt, typename optional::reference_type v) { + return opt.get_value_or(v); +} + +// Returns a pointer to the value if this is initialized, otherwise, returns +// NULL. +// No-throw +template +inline typename optional::pointer_const_type get_pointer( + optional const& opt) { + return opt.get_ptr(); +} + +template +inline typename optional::pointer_type get_pointer(optional& opt) { + return opt.get_ptr(); +} + +// optional's relational operators ( ==, !=, <, >, <=, >= ) have deep-semantics +// (compare values). +// WARNING: This is UNLIKE pointers. Use equal_pointees()/less_pointess() in +// generic code instead. + +// +// optional vs optional cases +// + +template +inline bool operator==(optional const& x, optional const& y) { + return equal_pointees(x, y); +} + +template +inline bool operator<(optional const& x, optional const& y) { + return less_pointees(x, y); +} + +template +inline bool operator!=(optional const& x, optional const& y) { + return !(x == y); +} + +template +inline bool operator>(optional const& x, optional const& y) { + return y < x; +} + +template +inline bool operator<=(optional const& x, optional const& y) { + return !(y < x); +} + +template +inline bool operator>=(optional const& x, optional const& y) { + return !(x < y); +} + +// +// optional vs T cases +// +template +inline bool operator==(optional const& x, T const& y) { + return equal_pointees(x, optional(y)); +} + +template +inline bool operator<(optional const& x, T const& y) { + return less_pointees(x, optional(y)); +} + +template +inline bool operator!=(optional const& x, T const& y) { + return !(x == y); +} + +template +inline bool operator>(optional const& x, T const& y) { + return y < x; +} + +template +inline bool operator<=(optional const& x, T const& y) { + return !(y < x); +} + +template +inline bool operator>=(optional const& x, T const& y) { + return !(x < y); +} + +// +// T vs optional cases +// + +template +inline bool operator==(T const& x, optional const& y) { + return equal_pointees(optional(x), y); +} + +template +inline bool operator<(T const& x, optional const& y) { + return less_pointees(optional(x), y); +} + +template +inline bool operator!=(T const& x, optional const& y) { + return !(x == y); +} + +template +inline bool operator>(T const& x, optional const& y) { + return y < x; +} + +template +inline bool operator<=(T const& x, optional const& y) { + return !(y < x); +} + +template +inline bool operator>=(T const& x, optional const& y) { + return !(x < y); +} + +// +// optional vs none cases +// + +template +inline bool operator==(optional const& x, none_t) { + return equal_pointees(x, optional()); +} + +template +inline bool operator<(optional const& x, none_t) { + return less_pointees(x, optional()); +} + +template +inline bool operator!=(optional const& x, none_t y) { + return !(x == y); +} + +template +inline bool operator>(optional const& x, none_t y) { + return y < x; +} + +template +inline bool operator<=(optional const& x, none_t y) { + return !(y < x); +} + +template +inline bool operator>=(optional const& x, none_t y) { + return !(x < y); +} + +// +// none vs optional cases +// + +template +inline bool operator==(none_t x, optional const& y) { + return equal_pointees(optional(), y); +} + +template +inline bool operator<(none_t x, optional const& y) { + return less_pointees(optional(), y); +} + +template +inline bool operator!=(none_t x, optional const& y) { + return !(x == y); +} + +template +inline bool operator>(none_t x, optional const& y) { + return y < x; +} + +template +inline bool operator<=(none_t x, optional const& y) { + return !(y < x); +} + +template +inline bool operator>=(none_t x, optional const& y) { + return !(x < y); +} + +namespace optional_detail { + +// optional's swap: +// If both are initialized, calls swap(T&, T&). If this swap throws, both will +// remain initialized but their values are now unspecified. +// If only one is initialized, calls U.reset(*I), THEN I.reset(). +// If U.reset(*I) throws, both are left UNCHANGED (U is kept uinitialized and I +// is never reset) +// If both are uninitialized, do nothing (no-throw) +template +inline void optional_swap(optional& x, optional& y) { + if (!x && !!y) { + x.reset(*y); + y.reset(); + } else if (!!x && !y) { + y.reset(*x); + x.reset(); + } else if (!!x && !!y) { + // allow for Koenig lookup + using std::swap; + swap(*x, *y); + } +} + +} // namespace optional_detail + +} // namespace paddle + +#endif -- GitLab