123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455 |
- //////////////////////////////////////////////////////////////////////////////
- //
- // (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/container/detail/placement_new.hpp>
- #include <boost/move/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/container/detail/mpl.hpp>
- #include <boost/assert.hpp>
- //GCC 12 is confused about maybe uninitialized allocators
- #if defined(BOOST_GCC) && (BOOST_GCC >= 120000) && (BOOST_GCC < 130000)
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
- #endif
- //!\file
- namespace boost {
- namespace container {
- ///@cond
- template<class Value, class KeyMapped>
- struct node_handle_keymapped_traits
- {
- typedef typename KeyMapped::key_type key_type;
- typedef typename KeyMapped::mapped_type mapped_type;
- };
- template<class Value>
- struct node_handle_keymapped_traits<Value, void>
- {
- typedef Value key_type;
- typedef Value mapped_type;
- };
- class node_handle_friend
- {
- public:
- template<class NH>
- inline static void destroy_alloc(NH &nh) BOOST_NOEXCEPT
- { nh.destroy_alloc(); }
- template<class NH>
- inline static typename NH::node_pointer &get_node_pointer(NH &nh) BOOST_NOEXCEPT
- { return nh.get_node_pointer(); }
- };
- ///@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 NodeAllocator, class KeyMapped = void>
- class node_handle
- {
- typedef NodeAllocator nallocator_type;
- typedef allocator_traits<NodeAllocator> nator_traits;
- typedef typename nator_traits::value_type priv_node_t;
- typedef typename priv_node_t::value_type priv_value_t;
- typedef node_handle_keymapped_traits<priv_value_t, KeyMapped> keymapped_t;
- public:
- typedef priv_value_t value_type;
- typedef typename keymapped_t::key_type key_type;
- typedef typename keymapped_t::mapped_type mapped_type;
- typedef typename nator_traits::template portable_rebind_alloc
- <value_type>::type allocator_type;
- typedef priv_node_t container_node_type;
- friend class node_handle_friend;
- ///@cond
- private:
- BOOST_MOVABLE_BUT_NOT_COPYABLE(node_handle)
- typedef typename nator_traits::pointer node_pointer;
- typedef typename dtl::aligned_storage
- < sizeof(nallocator_type)
- , dtl::alignment_of<nallocator_type>::value
- >::type nalloc_storage_t;
- node_pointer m_ptr;
- nalloc_storage_t m_nalloc_storage;
- void move_construct_alloc(nallocator_type &al)
- { ::new((void*)m_nalloc_storage.data, boost_container_new_t()) nallocator_type(::boost::move(al)); }
- void destroy_deallocate_node()
- {
- boost::movelib::to_raw_pointer(m_ptr)->destructor(this->node_alloc());
- nator_traits::deallocate(this->node_alloc(), m_ptr, 1u);
- }
- template<class OtherNodeHandle>
- void move_construct_end(OtherNodeHandle &nh)
- {
- if(m_ptr){
- ::new ((void*)m_nalloc_storage.data, boost_container_new_t()) nallocator_type(::boost::move(nh.node_alloc()));
- node_handle_friend::destroy_alloc(nh);
- node_handle_friend::get_node_pointer(nh) = node_pointer();
- }
- BOOST_ASSERT(nh.empty());
- }
- void destroy_alloc() BOOST_NOEXCEPT
- { static_cast<nallocator_type*>((void*)m_nalloc_storage.data)->~nallocator_type(); }
- node_pointer &get_node_pointer() BOOST_NOEXCEPT
- { return m_ptr; }
- ///@endcond
- public:
- //! <b>Effects</b>: Initializes m_ptr to nullptr.
- //!
- //! <b>Postcondition</b>: this->empty()
- BOOST_CXX14_CONSTEXPR node_handle() BOOST_NOEXCEPT
- : m_ptr()
- { }
- //! <b>Effects</b>: Constructs a node_handle object initializing internal pointer with p.
- //! If p != nullptr copy constructs internal allocator from al.
- node_handle(node_pointer p, const nallocator_type &al) BOOST_NOEXCEPT
- : m_ptr(p)
- {
- if(m_ptr){
- ::new ((void*)m_nalloc_storage.data, 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<NodeAllocator, KeyMapped2> BOOST_RV_REF_END nh
- , typename dtl::enable_if_c
- < ((unsigned)dtl::is_same<KeyMapped, void>::value +
- (unsigned)dtl::is_same<KeyMapped2, void>::value) == 1u
- >::type* = 0) BOOST_NOEXCEPT
- : m_ptr(nh.get())
- { 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)
- { 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
- //! nator_traits::rebind_traits<container_node_type>::deallocate.
- ~node_handle() BOOST_NOEXCEPT
- {
- if(!this->empty()){
- this->destroy_deallocate_node();
- this->destroy_alloc();
- }
- }
- //! <b>Requires</b>: Either this->empty(), or nator_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 nator_traits::destroy, then deallocates m_ptr by calling
- //! nator_traits::deallocate. Assigns nh.m_ptr to m_ptr. If this->empty()
- //! or nator_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_NOEXCEPT
- {
- BOOST_ASSERT(this->empty() || nator_traits::propagate_on_container_move_assignment::value
- || nator_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_deallocate_node();
- if(nator_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_deallocate_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_CONTAINER_STATIC_ASSERT((dtl::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_CONTAINER_STATIC_ASSERT((!dtl::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_CONTAINER_STATIC_ASSERT((!dtl::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
- inline explicit operator bool
- #else
- private: struct bool_conversion {int for_bool; int for_arg(); }; typedef int bool_conversion::* explicit_bool_arg;
- public: inline 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 nator_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 nator_traits::propagate_on_-
- //! container_swap is true calls swap(node_alloc(), nh.node_alloc()).
- void swap(node_handle &nh)
- BOOST_NOEXCEPT_IF(nator_traits::propagate_on_container_swap::value || nator_traits::is_always_equal::value)
- {
- BOOST_ASSERT(this->empty() || nh.empty() || nator_traits::propagate_on_container_swap::value
- || nator_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(nator_traits::propagate_on_container_swap::value){
- ::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());
- this->destroy_alloc();
- }
- ::boost::adl_move_swap(m_ptr, nh.m_ptr);
- }
- //! <b>Effects</b>: If this->empty() returns nullptr, otherwise returns m_ptr
- //! resets m_ptr to nullptr and destroys the internal allocator.
- //!
- //! <b>Postcondition</b>: this->empty()
- //!
- //! <b>Note</b>: Non-standard extensions
- node_pointer release() BOOST_NOEXCEPT
- {
- node_pointer p(m_ptr);
- m_ptr = node_pointer();
- if(p)
- this->destroy_alloc();
- return p;
- }
- //! <b>Effects</b>: Returns m_ptr.
- //!
- //! <b>Note</b>: Non-standard extensions
- node_pointer get() const BOOST_NOEXCEPT
- {
- return m_ptr;
- }
- //! <b>Effects</b>: Returns a reference to the internal node allocator.
- //!
- //! <b>Note</b>: Non-standard extensions
- nallocator_type &node_alloc() BOOST_NOEXCEPT
- {
- BOOST_ASSERT(!empty());
- return *static_cast<nallocator_type*>((void*)m_nalloc_storage.data);
- }
- //! <b>Effects</b>: Returns a reference to the internal node allocator.
- //!
- //! <b>Note</b>: Non-standard extensions
- const nallocator_type &node_alloc() const BOOST_NOEXCEPT
- {
- BOOST_ASSERT(!empty());
- return *static_cast<const nallocator_type*>((const void*)m_nalloc_storage.data);
- }
- //! <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) n)
- : inserted(insert), position(it), node(boost::move(n))
- {}
- 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 {
- #if defined(BOOST_GCC) && (BOOST_GCC >= 120000) && (BOOST_GCC < 130000)
- #pragma GCC diagnostic pop
- #endif
- #include <boost/container/detail/config_end.hpp>
- #endif //BOOST_CONTAINER_NODE_HANDLE_HPP
|