copy_map.hpp 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. /* Copyright 2003-2020 Joaquin M Lopez Munoz.
  2. * Distributed under the Boost Software License, Version 1.0.
  3. * (See accompanying file LICENSE_1_0.txt or copy at
  4. * http://www.boost.org/LICENSE_1_0.txt)
  5. *
  6. * See http://www.boost.org/libs/multi_index for library home page.
  7. */
  8. #ifndef BOOST_MULTI_INDEX_DETAIL_COPY_MAP_HPP
  9. #define BOOST_MULTI_INDEX_DETAIL_COPY_MAP_HPP
  10. #if defined(_MSC_VER)
  11. #pragma once
  12. #endif
  13. #include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
  14. #include <algorithm>
  15. #include <boost/core/addressof.hpp>
  16. #include <boost/detail/no_exceptions_support.hpp>
  17. #include <boost/move/core.hpp>
  18. #include <boost/multi_index/detail/allocator_traits.hpp>
  19. #include <boost/multi_index/detail/auto_space.hpp>
  20. #include <boost/multi_index/detail/raw_ptr.hpp>
  21. #include <boost/noncopyable.hpp>
  22. #include <functional>
  23. namespace boost{
  24. namespace multi_index{
  25. namespace detail{
  26. /* copy_map is used as an auxiliary structure during copy_() operations.
  27. * When a container with n nodes is replicated, node_map holds the pairings
  28. * between original and copied nodes, and provides a fast way to find a
  29. * copied node from an original one.
  30. * The semantics of the class are not simple, and no attempt has been made
  31. * to enforce it: multi_index_container handles it right. On the other hand,
  32. * the const interface, which is the one provided to index implementations,
  33. * only allows for:
  34. * - Enumeration of pairs of (original,copied) nodes (excluding the headers),
  35. * - fast retrieval of copied nodes (including the headers.)
  36. */
  37. template <typename Node>
  38. struct copy_map_entry
  39. {
  40. copy_map_entry(Node* f,Node* s):first(f),second(s){}
  41. Node* first;
  42. Node* second;
  43. bool operator<(const copy_map_entry<Node>& x)const
  44. {
  45. return std::less<Node*>()(first,x.first);
  46. }
  47. };
  48. struct copy_map_value_copier
  49. {
  50. template<typename Value>
  51. const Value& operator()(Value& x)const{return x;}
  52. };
  53. struct copy_map_value_mover
  54. {
  55. template<typename Value>
  56. BOOST_RV_REF(Value) operator()(Value& x)const{return boost::move(x);}
  57. };
  58. template <typename Node,typename Allocator>
  59. class copy_map:private noncopyable
  60. {
  61. typedef typename rebind_alloc_for<
  62. Allocator,Node
  63. >::type allocator_type;
  64. typedef allocator_traits<allocator_type> alloc_traits;
  65. typedef typename alloc_traits::pointer pointer;
  66. public:
  67. typedef const copy_map_entry<Node>* const_iterator;
  68. typedef typename alloc_traits::size_type size_type;
  69. copy_map(
  70. const Allocator& al,size_type size,Node* header_org,Node* header_cpy):
  71. al_(al),size_(size),spc(al_,size_),n(0),
  72. header_org_(header_org),header_cpy_(header_cpy),released(false)
  73. {}
  74. ~copy_map()
  75. {
  76. if(!released){
  77. for(size_type i=0;i<n;++i){
  78. alloc_traits::destroy(
  79. al_,boost::addressof((spc.data()+i)->second->value()));
  80. deallocate((spc.data()+i)->second);
  81. }
  82. }
  83. }
  84. const_iterator begin()const{return raw_ptr<const_iterator>(spc.data());}
  85. const_iterator end()const{return raw_ptr<const_iterator>(spc.data()+n);}
  86. void copy_clone(Node* node){clone(node,copy_map_value_copier());}
  87. void move_clone(Node* node){clone(node,copy_map_value_mover());}
  88. Node* find(Node* node)const
  89. {
  90. if(node==header_org_)return header_cpy_;
  91. return std::lower_bound(
  92. begin(),end(),copy_map_entry<Node>(node,0))->second;
  93. }
  94. void release()
  95. {
  96. released=true;
  97. }
  98. private:
  99. allocator_type al_;
  100. size_type size_;
  101. auto_space<copy_map_entry<Node>,Allocator> spc;
  102. size_type n;
  103. Node* header_org_;
  104. Node* header_cpy_;
  105. bool released;
  106. pointer allocate()
  107. {
  108. return alloc_traits::allocate(al_,1);
  109. }
  110. void deallocate(Node* node)
  111. {
  112. alloc_traits::deallocate(al_,static_cast<pointer>(node),1);
  113. }
  114. template<typename ValueAccess>
  115. void clone(Node* node,ValueAccess access)
  116. {
  117. (spc.data()+n)->first=node;
  118. (spc.data()+n)->second=raw_ptr<Node*>(allocate());
  119. BOOST_TRY{
  120. alloc_traits::construct(
  121. al_,boost::addressof((spc.data()+n)->second->value()),
  122. access(node->value()));
  123. }
  124. BOOST_CATCH(...){
  125. deallocate((spc.data()+n)->second);
  126. BOOST_RETHROW;
  127. }
  128. BOOST_CATCH_END
  129. ++n;
  130. if(n==size_){
  131. std::sort(
  132. raw_ptr<copy_map_entry<Node>*>(spc.data()),
  133. raw_ptr<copy_map_entry<Node>*>(spc.data())+size_);
  134. }
  135. }
  136. };
  137. } /* namespace multi_index::detail */
  138. } /* namespace multi_index */
  139. } /* namespace boost */
  140. #endif