397 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
		
		
			
		
	
	
			397 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
|   | ////////////////////////////////////////////////////////////////////////////// | ||
|  | // | ||
|  | // (C) Copyright Ion Gaztanaga 2016-2016. 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/container for documentation. | ||
|  | // | ||
|  | ////////////////////////////////////////////////////////////////////////////// | ||
|  | 
 | ||
|  | #ifndef BOOST_CONTAINER_NODE_HANDLE_HPP | ||
|  | #define BOOST_CONTAINER_NODE_HANDLE_HPP | ||
|  | 
 | ||
|  | #ifndef BOOST_CONFIG_HPP | ||
|  | #  include <boost/config.hpp> | ||
|  | #endif | ||
|  | 
 | ||
|  | #if defined(BOOST_HAS_PRAGMA_ONCE) | ||
|  | #  pragma once | ||
|  | #endif | ||
|  | 
 | ||
|  | #include <boost/container/detail/config_begin.hpp> | ||
|  | #include <boost/container/detail/workaround.hpp> | ||
|  | #include <boost/static_assert.hpp> | ||
|  | #include <boost/container/detail/placement_new.hpp> | ||
|  | #include <boost/container/detail/to_raw_pointer.hpp> | ||
|  | #include <boost/container/allocator_traits.hpp> | ||
|  | #include <boost/container/detail/mpl.hpp> | ||
|  | 
 | ||
|  | #include <boost/move/utility_core.hpp> | ||
|  | #include <boost/move/adl_move_swap.hpp> | ||
|  | 
 | ||
|  | #include <boost/type_traits/aligned_storage.hpp> | ||
|  | 
 | ||
|  | 
 | ||
|  | //!\file | ||
|  | 
 | ||
|  | namespace boost { | ||
|  | namespace container { | ||
|  | 
 | ||
|  | ///@cond | ||
|  | 
 | ||
|  | template<class Value, class KeyMapped, bool keymapped_is_void = container_detail::is_same<KeyMapped, void>::value> | ||
|  | struct node_handle_keymapped_traits | ||
|  | { | ||
|  |    typedef Value key_type; | ||
|  |    typedef Value mapped_type; | ||
|  | }; | ||
|  | 
 | ||
|  | template<class Value, class KeyMapped> | ||
|  | struct node_handle_keymapped_traits<Value, KeyMapped, false> | ||
|  | { | ||
|  |    typedef typename KeyMapped::key_type      key_type; | ||
|  |    typedef typename KeyMapped::mapped_type   mapped_type; | ||
|  | }; | ||
|  | 
 | ||
|  | ///@endcond | ||
|  | 
 | ||
|  | //! A node_handle is an object that accepts ownership of a single element from an associative container. | ||
|  | //! It may be used to transfer that ownership to another container with compatible nodes. Containers | ||
|  | //! with compatible nodes have the same node handle type. Elements may be transferred in either direction | ||
|  | //! between container types in the same row:. | ||
|  | //! | ||
|  | //! Container types with compatible nodes | ||
|  | //! | ||
|  | //! map<K, T, C1, A> <-> map<K, T, C2, A> | ||
|  | //! | ||
|  | //! map<K, T, C1, A> <-> multimap<K, T, C2, A> | ||
|  | //!  | ||
|  | //! set<K, C1, A> <-> set<K, C2, A> | ||
|  | //!  | ||
|  | //! set<K, C1, A> <-> multiset<K, C2, A> | ||
|  | //!  | ||
|  | //! If a node handle is not empty, then it contains an allocator that is equal to the allocator of the container | ||
|  | //! when the element was extracted. If a node handle is empty, it contains no allocator. | ||
|  | template <class NodeType, class Value, class Allocator, class KeyMapped = void> | ||
|  | class node_handle | ||
|  | { | ||
|  |    typedef node_handle_keymapped_traits<Value, KeyMapped> keymapped_t; | ||
|  | 
 | ||
|  |    public: | ||
|  |    typedef Value                                                  value_type; | ||
|  |    typedef typename keymapped_t::key_type                         key_type; | ||
|  |    typedef typename keymapped_t::mapped_type                      mapped_type; | ||
|  |    typedef Allocator                                              allocator_type; | ||
|  |    typedef NodeType                                               container_node_type; | ||
|  | 
 | ||
|  |    ///@cond | ||
|  |    private: | ||
|  |    BOOST_MOVABLE_BUT_NOT_COPYABLE(node_handle) | ||
|  | 
 | ||
|  |    typedef allocator_traits<allocator_type>                                   ator_traits; | ||
|  |    typedef typename ator_traits::template portable_rebind_alloc | ||
|  |       <container_node_type>::type                                             nallocator_type; | ||
|  |    typedef allocator_traits<nallocator_type>                                  node_ator_traits; | ||
|  |    typedef typename node_ator_traits::pointer                                 node_pointer; | ||
|  |    typedef ::boost::aligned_storage | ||
|  |       <sizeof(allocator_type), boost::alignment_of<nallocator_type>::value>   nalloc_storage_t; | ||
|  | 
 | ||
|  |    node_pointer      m_ptr; | ||
|  |    nalloc_storage_t  m_nalloc_storage; | ||
|  | 
 | ||
|  |    void move_construct_alloc(nallocator_type &al) | ||
|  |    {  ::new(m_nalloc_storage.address(), boost_container_new_t()) allocator_type(::boost::move(al));   } | ||
|  | 
 | ||
|  |    void destroy_node() | ||
|  |    { | ||
|  |       node_ator_traits::destroy(this->node_alloc(), container_detail::to_raw_pointer(m_ptr)); | ||
|  |       node_ator_traits::deallocate(this->node_alloc(), m_ptr, 1u); | ||
|  |    } | ||
|  | 
 | ||
|  |    template<class OtherNodeHandle> | ||
|  |    void move_construct_end(OtherNodeHandle &nh) | ||
|  |    { | ||
|  |       if(m_ptr){ | ||
|  |          ::new (m_nalloc_storage.address(), boost_container_new_t()) allocator_type(::boost::move(nh.node_alloc())); | ||
|  |          nh.destroy_alloc(); | ||
|  |          nh.get_node_pointer() = node_pointer(); | ||
|  |       } | ||
|  |       BOOST_ASSERT(nh.empty()); | ||
|  |    } | ||
|  | 
 | ||
|  |    public: | ||
|  | 
 | ||
|  |    void destroy_alloc() | ||
|  |    {  static_cast<allocator_type*>(m_nalloc_storage.address())->~allocator_type();  } | ||
|  | 
 | ||
|  |    node_pointer &get_node_pointer() | ||
|  |    {  return m_ptr;  } | ||
|  | 
 | ||
|  |    nallocator_type &node_alloc() | ||
|  |    {  return *static_cast<nallocator_type*>(m_nalloc_storage.address()); } | ||
|  | 
 | ||
|  |    node_pointer release() | ||
|  |    { | ||
|  |       node_pointer p(m_ptr); | ||
|  |       m_ptr = node_pointer(); | ||
|  |       if(p) | ||
|  |          this->destroy_alloc(); | ||
|  |       return p; | ||
|  |    } | ||
|  | 
 | ||
|  |    ///@endcond | ||
|  | 
 | ||
|  |    public: | ||
|  |    //! <b>Effects</b>: Initializes m_ptr to nullptr. | ||
|  |    //! | ||
|  |    //! <b>Postcondition</b>: this->empty() | ||
|  |    BOOST_CXX14_CONSTEXPR node_handle() BOOST_NOEXCEPT | ||
|  |       :  m_ptr(), m_nalloc_storage() | ||
|  |    {  BOOST_ASSERT(this->empty()); } | ||
|  | 
 | ||
|  |    //! <b>Effects</b>: Constructs a node_handle object initializing internal pointer with p. | ||
|  |    //!   If p != nullptr copy constructs internal allocator al. | ||
|  |    node_handle(node_pointer p, const nallocator_type &al) BOOST_NOEXCEPT | ||
|  |       :  m_ptr(p), m_nalloc_storage() | ||
|  |    { | ||
|  |       if(m_ptr){ | ||
|  |          ::new (m_nalloc_storage.address(), boost_container_new_t()) nallocator_type(al); | ||
|  |       } | ||
|  |    } | ||
|  | 
 | ||
|  |    //! <b>Effects</b>: Constructs a node_handle object initializing internal pointer with a related nh's internal pointer | ||
|  |    //!   and assigns nullptr to the later. If nh's internal pointer was not nullptr, move constructs internal | ||
|  |    //!   allocator with nh's internal allocator and destroy nh's internal allocator. | ||
|  |    //! | ||
|  |    //! <b>Postcondition</b>: nh.empty() | ||
|  |    //! | ||
|  |    //! <b>Note</b>: Two node_handle's are related if only one of KeyMapped template parameter | ||
|  |    //!   of a node handle is void. | ||
|  |    template<class KeyMapped2> | ||
|  |    node_handle( BOOST_RV_REF_BEG node_handle<NodeType, Value, Allocator, KeyMapped2> BOOST_RV_REF_END nh | ||
|  |                , typename container_detail::enable_if_c | ||
|  |                   < ((unsigned)container_detail::is_same<KeyMapped,  void>::value + | ||
|  |                      (unsigned)container_detail::is_same<KeyMapped2, void>::value) == 1u | ||
|  |                   >::type* = 0) | ||
|  |       :  m_ptr(nh.get_node_pointer()), m_nalloc_storage() | ||
|  |    {  this->move_construct_end(nh);  } | ||
|  | 
 | ||
|  |    //! <b>Effects</b>: Constructs a node_handle object initializing internal pointer with nh's internal pointer | ||
|  |    //!   and assigns nullptr to the later. If nh's internal pointer was not nullptr, move constructs internal | ||
|  |    //!   allocator with nh's internal allocator and destroy nh's internal allocator. | ||
|  |    //! | ||
|  |    //! <b>Postcondition</b>: nh.empty() | ||
|  |    node_handle (BOOST_RV_REF(node_handle) nh) BOOST_NOEXCEPT | ||
|  |       : m_ptr(nh.m_ptr), m_nalloc_storage() | ||
|  |    {  this->move_construct_end(nh);  } | ||
|  | 
 | ||
|  |    //! <b>Effects</b>: If !this->empty(), destroys the value_type subobject in the container_node_type object | ||
|  |    //!   pointed to by c by calling allocator_traits<impl_defined>::destroy, then deallocates m_ptr by calling | ||
|  |    //!   ator_traits::rebind_traits<container_node_type>::deallocate. | ||
|  |    ~node_handle () BOOST_NOEXCEPT | ||
|  |    { | ||
|  |       if(!this->empty()){ | ||
|  |          this->destroy_node(); | ||
|  |          this->destroy_alloc(); | ||
|  |       } | ||
|  |    } | ||
|  | 
 | ||
|  |    //! <b>Requires</b>: Either this->empty(), or ator_traits::propagate_on_container_move_assignment is true, or | ||
|  |    //!   node_alloc() == nh.node_alloc(). | ||
|  |    //! | ||
|  |    //! <b>Effects</b>: If m_ptr != nullptr, destroys the value_type subobject in the container_node_type object | ||
|  |    //!   pointed to by m_ptr by calling ator_traits::destroy, then deallocates m_ptr by calling ator_- | ||
|  |    //!   traits::rebind_traits<container_node_type>::deallocate. Assigns nh.m_ptr to m_ptr. If this->empty() | ||
|  |    //!   or ator_traits::propagate_on_container_move_assignment is true, move assigns nh.node_alloc() to | ||
|  |    //!   node_alloc(). Assigns nullptr to nh.m_ptr and assigns nullopt to nh.node_alloc(). | ||
|  |    //! <b>Returns</b>: *this. | ||
|  |    //! | ||
|  |    //! <b>Throws</b>: Nothing. | ||
|  |    node_handle & operator=(BOOST_RV_REF(node_handle) nh) | ||
|  |    { | ||
|  |       BOOST_ASSERT(this->empty() || nh.empty() || ator_traits::propagate_on_container_move_assignment::value  | ||
|  |                    || ator_traits::equal(node_alloc(), nh.node_alloc())); | ||
|  | 
 | ||
|  |       bool const was_this_non_null = !this->empty(); | ||
|  |       bool const was_nh_non_null   = !nh.empty(); | ||
|  | 
 | ||
|  |       if(was_nh_non_null){ | ||
|  |          if(was_this_non_null){ | ||
|  |             this->destroy_node(); | ||
|  |             if(ator_traits::propagate_on_container_move_assignment::value){ | ||
|  |                this->node_alloc() = ::boost::move(nh.node_alloc()); | ||
|  |             } | ||
|  |          } | ||
|  |          else{ | ||
|  |             this->move_construct_alloc(nh.node_alloc()); | ||
|  |          } | ||
|  |          m_ptr = nh.m_ptr; | ||
|  |          nh.m_ptr = node_pointer(); | ||
|  |          nh.destroy_alloc(); | ||
|  |       } | ||
|  |       else if(was_this_non_null){ | ||
|  |          this->destroy_node(); | ||
|  |          this->destroy_alloc(); | ||
|  |          m_ptr = node_pointer(); | ||
|  |       } | ||
|  |       return *this; | ||
|  |    } | ||
|  | 
 | ||
|  |    //! <b>Requires</b>: empty() == false. | ||
|  |    //! | ||
|  |    //! <b>Returns</b>: A reference to the value_type subobject in the container_node_type object pointed to by m_ptr | ||
|  |    //! | ||
|  |    //! <b>Throws</b>: Nothing. | ||
|  |    value_type& value() const BOOST_NOEXCEPT | ||
|  |    { | ||
|  |       BOOST_STATIC_ASSERT((container_detail::is_same<KeyMapped, void>::value)); | ||
|  |       BOOST_ASSERT(!empty()); | ||
|  |       return m_ptr->get_data(); | ||
|  |    } | ||
|  | 
 | ||
|  |    //! <b>Requires</b>: empty() == false. | ||
|  |    //! | ||
|  |    //! <b>Returns</b>: A non-const reference to the key_type member of the value_type subobject in the  | ||
|  |    //!   container_node_type object pointed to by m_ptr. | ||
|  |    //! | ||
|  |    //! <b>Throws</b>: Nothing. | ||
|  |    //! | ||
|  |    //! <b>Requires</b>: Modifying the key through the returned reference is permitted. | ||
|  |    key_type& key() const BOOST_NOEXCEPT | ||
|  |    { | ||
|  |       BOOST_STATIC_ASSERT((!container_detail::is_same<KeyMapped, void>::value)); | ||
|  |       BOOST_ASSERT(!empty()); | ||
|  |       return const_cast<key_type &>(KeyMapped().key_of_value(m_ptr->get_data())); | ||
|  |    } | ||
|  | 
 | ||
|  |    //! <b>Requires</b>: empty() == false. | ||
|  |    //! | ||
|  |    //! <b>Returns</b>: A reference to the mapped_type member of the value_type subobject | ||
|  |    //!   in the container_node_type object pointed to by m_ptr | ||
|  |    //! | ||
|  |    //! <b>Throws</b>: Nothing. | ||
|  |    mapped_type& mapped() const BOOST_NOEXCEPT | ||
|  |    { | ||
|  |       BOOST_STATIC_ASSERT((!container_detail::is_same<KeyMapped, void>::value)); | ||
|  |       BOOST_ASSERT(!empty()); | ||
|  |       return KeyMapped().mapped_of_value(m_ptr->get_data()); | ||
|  |    } | ||
|  | 
 | ||
|  |    //! <b>Requires</b>: empty() == false. | ||
|  |    //! | ||
|  |    //! <b>Returns</b>: A copy of the internally hold allocator. | ||
|  |    //! | ||
|  |    //! <b>Throws</b>: Nothing. | ||
|  |    allocator_type get_allocator() const | ||
|  |    { | ||
|  |       BOOST_ASSERT(!empty()); | ||
|  |       return this->node_alloc(); | ||
|  |    } | ||
|  | 
 | ||
|  |    //! <b>Returns</b>: m_ptr != nullptr. | ||
|  |    //! | ||
|  |    #ifdef BOOST_CONTAINER_DOXYGEN_INVOKED | ||
|  |    BOOST_CONTAINER_FORCEINLINE explicit operator bool | ||
|  |    #else | ||
|  |    private: struct bool_conversion {int for_bool; int for_arg(); }; typedef int bool_conversion::* explicit_bool_arg; | ||
|  |    public: BOOST_CONTAINER_FORCEINLINE operator explicit_bool_arg | ||
|  |    #endif | ||
|  |       ()const BOOST_NOEXCEPT | ||
|  |    {  return m_ptr ? &bool_conversion::for_bool  : explicit_bool_arg(0);  } | ||
|  | 
 | ||
|  |    //! <b>Returns</b>: m_ptr == nullptr. | ||
|  |    //! | ||
|  |    bool empty() const BOOST_NOEXCEPT | ||
|  |    { | ||
|  |       return !this->m_ptr; | ||
|  |    } | ||
|  | 
 | ||
|  |    //! <b>Requires</b>: this->empty(), or nh.empty(), or ator_traits::propagate_on_container_swap is true, or | ||
|  |    //!   node_alloc() == nh.node_alloc(). | ||
|  |    //! | ||
|  |    //! <b>Effects</b>: Calls swap(m_ptr, nh.m_ptr). If this->empty(), or nh.empty(), or ator_traits::propagate_on_- | ||
|  |    //!   container_swap is true calls swap(node_alloc(), nh.node_alloc()). | ||
|  |    void swap(node_handle &nh) | ||
|  |       BOOST_NOEXCEPT_IF(ator_traits::propagate_on_container_swap::value || ator_traits::is_always_equal::value) | ||
|  |    { | ||
|  |       BOOST_ASSERT(this->empty() || nh.empty() || ator_traits::propagate_on_container_swap::value | ||
|  |                    || ator_traits::equal(node_alloc(), nh.node_alloc())); | ||
|  | 
 | ||
|  |       bool const was_this_non_null = !this->empty(); | ||
|  |       bool const was_nh_non_null   = !nh.empty(); | ||
|  | 
 | ||
|  |       if(was_nh_non_null){ | ||
|  |          if(was_this_non_null){ | ||
|  |             if(ator_traits::propagate_on_container_swap){ | ||
|  |                ::boost::adl_move_swap(this->node_alloc(), nh.node_alloc()); | ||
|  |             } | ||
|  |          } | ||
|  |          else{ | ||
|  |             this->move_construct_alloc(nh.node_alloc()); | ||
|  |             nh.destroy_alloc(); | ||
|  |          } | ||
|  |       } | ||
|  |       else if(was_this_non_null){ | ||
|  |          nh.move_construct_alloc(this->node_alloc()); | ||
|  |          nh.destroy_alloc(); | ||
|  |       } | ||
|  |       ::boost::adl_move_swap(m_ptr, nh.m_ptr); | ||
|  |    } | ||
|  | 
 | ||
|  |    //! <b>Effects</b>: x.swap(y). | ||
|  |    //! | ||
|  |    friend void swap(node_handle & x, node_handle & y) BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT(x.swap(y))) | ||
|  |    {  x.swap(y);  } | ||
|  | }; | ||
|  | 
 | ||
|  | //! A class template used to describe the results of inserting a | ||
|  | //! Container::node_type in a Container with unique keys. | ||
|  | //! Includes at least the following non-static public data members: | ||
|  | //! | ||
|  | //! <ul><li>bool inserted</li>; | ||
|  | //! <li>Iterator position</li>; | ||
|  | //! <li>NodeType node</li></ul> | ||
|  | //! | ||
|  | //! This type is MoveConstructible, MoveAssignable, DefaultConstructible, | ||
|  | //! Destructible, and lvalues of that type are swappable | ||
|  | template<class Iterator, class NodeType> | ||
|  | struct insert_return_type_base | ||
|  | { | ||
|  |    private: | ||
|  |    BOOST_MOVABLE_BUT_NOT_COPYABLE(insert_return_type_base) | ||
|  | 
 | ||
|  |    public: | ||
|  |    insert_return_type_base() | ||
|  |       : inserted(false), position(), node() | ||
|  |    {} | ||
|  | 
 | ||
|  |    insert_return_type_base(BOOST_RV_REF(insert_return_type_base) other) | ||
|  |       : inserted(other.inserted), position(other.position), node(boost::move(other.node)) | ||
|  |    {} | ||
|  | 
 | ||
|  |    template<class RelatedIt, class RelatedNode> | ||
|  |    insert_return_type_base(bool insert, RelatedIt it, BOOST_RV_REF(RelatedNode) node) | ||
|  |       : inserted(insert), position(it), node(boost::move(node)) | ||
|  |    {} | ||
|  | 
 | ||
|  |    insert_return_type_base & operator=(BOOST_RV_REF(insert_return_type_base) other) | ||
|  |    { | ||
|  |       inserted = other.inserted; | ||
|  |       position = other.position; | ||
|  |       node = boost::move(other.node); | ||
|  |       return *this; | ||
|  |    } | ||
|  | 
 | ||
|  |    bool  inserted; | ||
|  |    Iterator position; | ||
|  |    NodeType node; | ||
|  | }; | ||
|  | 
 | ||
|  | }  //namespace container { | ||
|  | }  //namespace boost { | ||
|  | 
 | ||
|  | #include <boost/container/detail/config_end.hpp> | ||
|  | 
 | ||
|  | #endif   //BOOST_CONTAINER_NODE_HANDLE_HPP |