copy_map.hpp 4.6 KB

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