copy_map.hpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. /* Copyright 2003-2018 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/multi_index/detail/auto_space.hpp>
  18. #include <boost/multi_index/detail/raw_ptr.hpp>
  19. #include <boost/noncopyable.hpp>
  20. #include <cstddef>
  21. #include <functional>
  22. #include <memory>
  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. template <typename Node,typename Allocator>
  49. class copy_map:private noncopyable
  50. {
  51. public:
  52. typedef const copy_map_entry<Node>* const_iterator;
  53. copy_map(
  54. const Allocator& al,std::size_t size,Node* header_org,Node* header_cpy):
  55. al_(al),size_(size),spc(al_,size_),n(0),
  56. header_org_(header_org),header_cpy_(header_cpy),released(false)
  57. {}
  58. ~copy_map()
  59. {
  60. if(!released){
  61. for(std::size_t i=0;i<n;++i){
  62. boost::detail::allocator::destroy(
  63. boost::addressof((spc.data()+i)->second->value()));
  64. deallocate((spc.data()+i)->second);
  65. }
  66. }
  67. }
  68. const_iterator begin()const{return raw_ptr<const_iterator>(spc.data());}
  69. const_iterator end()const{return raw_ptr<const_iterator>(spc.data()+n);}
  70. void clone(Node* node)
  71. {
  72. (spc.data()+n)->first=node;
  73. (spc.data()+n)->second=raw_ptr<Node*>(allocate());
  74. BOOST_TRY{
  75. boost::detail::allocator::construct(
  76. boost::addressof((spc.data()+n)->second->value()),node->value());
  77. }
  78. BOOST_CATCH(...){
  79. deallocate((spc.data()+n)->second);
  80. BOOST_RETHROW;
  81. }
  82. BOOST_CATCH_END
  83. ++n;
  84. if(n==size_){
  85. std::sort(
  86. raw_ptr<copy_map_entry<Node>*>(spc.data()),
  87. raw_ptr<copy_map_entry<Node>*>(spc.data())+size_);
  88. }
  89. }
  90. Node* find(Node* node)const
  91. {
  92. if(node==header_org_)return header_cpy_;
  93. return std::lower_bound(
  94. begin(),end(),copy_map_entry<Node>(node,0))->second;
  95. }
  96. void release()
  97. {
  98. released=true;
  99. }
  100. private:
  101. typedef typename boost::detail::allocator::rebind_to<
  102. Allocator,Node
  103. >::type allocator_type;
  104. #ifdef BOOST_NO_CXX11_ALLOCATOR
  105. typedef typename allocator_type::pointer allocator_pointer;
  106. #else
  107. typedef std::allocator_traits<allocator_type> allocator_traits;
  108. typedef typename allocator_traits::pointer allocator_pointer;
  109. #endif
  110. allocator_type al_;
  111. std::size_t size_;
  112. auto_space<copy_map_entry<Node>,Allocator> spc;
  113. std::size_t n;
  114. Node* header_org_;
  115. Node* header_cpy_;
  116. bool released;
  117. allocator_pointer allocate()
  118. {
  119. #ifdef BOOST_NO_CXX11_ALLOCATOR
  120. return al_.allocate(1);
  121. #else
  122. return allocator_traits::allocate(al_,1);
  123. #endif
  124. }
  125. void deallocate(Node* node)
  126. {
  127. #ifdef BOOST_NO_CXX11_ALLOCATOR
  128. al_.deallocate(static_cast<allocator_pointer>(node),1);
  129. #else
  130. allocator_traits::deallocate(al_,static_cast<allocator_pointer>(node),1);
  131. #endif
  132. }
  133. };
  134. } /* namespace multi_index::detail */
  135. } /* namespace multi_index */
  136. } /* namespace boost */
  137. #endif