rnd_index_loader.hpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. /* Copyright 2003-2013 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_RND_INDEX_LOADER_HPP
  9. #define BOOST_MULTI_INDEX_DETAIL_RND_INDEX_LOADER_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/detail/allocator_utilities.hpp>
  16. #include <boost/multi_index/detail/auto_space.hpp>
  17. #include <boost/multi_index/detail/rnd_index_ptr_array.hpp>
  18. #include <boost/noncopyable.hpp>
  19. #include <cstddef>
  20. namespace boost{
  21. namespace multi_index{
  22. namespace detail{
  23. /* This class implements a serialization rearranger for random access
  24. * indices. In order to achieve O(n) performance, the following strategy
  25. * is followed: the nodes of the index are handled as if in a bidirectional
  26. * list, where the next pointers are stored in the original
  27. * random_access_index_ptr_array and the prev pointers are stored in
  28. * an auxiliary array. Rearranging of nodes in such a bidirectional list
  29. * is constant time. Once all the arrangements are performed (on destruction
  30. * time) the list is traversed in reverse order and
  31. * pointers are swapped and set accordingly so that they recover its
  32. * original semantics ( *(node->up())==node ) while retaining the
  33. * new order.
  34. */
  35. template<typename Allocator>
  36. class random_access_index_loader_base:private noncopyable
  37. {
  38. protected:
  39. typedef random_access_index_node_impl<
  40. typename boost::detail::allocator::rebind_to<
  41. Allocator,
  42. char
  43. >::type
  44. > node_impl_type;
  45. typedef typename node_impl_type::pointer node_impl_pointer;
  46. typedef random_access_index_ptr_array<Allocator> ptr_array;
  47. random_access_index_loader_base(const Allocator& al_,ptr_array& ptrs_):
  48. al(al_),
  49. ptrs(ptrs_),
  50. header(*ptrs.end()),
  51. prev_spc(al,0),
  52. preprocessed(false)
  53. {}
  54. ~random_access_index_loader_base()
  55. {
  56. if(preprocessed)
  57. {
  58. node_impl_pointer n=header;
  59. next(n)=n;
  60. for(std::size_t i=ptrs.size();i--;){
  61. n=prev(n);
  62. std::size_t d=position(n);
  63. if(d!=i){
  64. node_impl_pointer m=prev(next_at(i));
  65. std::swap(m->up(),n->up());
  66. next_at(d)=next_at(i);
  67. std::swap(prev_at(d),prev_at(i));
  68. }
  69. next(n)=n;
  70. }
  71. }
  72. }
  73. void rearrange(node_impl_pointer position_,node_impl_pointer x)
  74. {
  75. preprocess(); /* only incur this penalty if rearrange() is ever called */
  76. if(position_==node_impl_pointer(0))position_=header;
  77. next(prev(x))=next(x);
  78. prev(next(x))=prev(x);
  79. prev(x)=position_;
  80. next(x)=next(position_);
  81. next(prev(x))=prev(next(x))=x;
  82. }
  83. private:
  84. void preprocess()
  85. {
  86. if(!preprocessed){
  87. /* get space for the auxiliary prev array */
  88. auto_space<node_impl_pointer,Allocator> tmp(al,ptrs.size()+1);
  89. prev_spc.swap(tmp);
  90. /* prev_spc elements point to the prev nodes */
  91. std::rotate_copy(
  92. &*ptrs.begin(),&*ptrs.end(),&*ptrs.end()+1,&*prev_spc.data());
  93. /* ptrs elements point to the next nodes */
  94. std::rotate(&*ptrs.begin(),&*ptrs.begin()+1,&*ptrs.end()+1);
  95. preprocessed=true;
  96. }
  97. }
  98. std::size_t position(node_impl_pointer x)const
  99. {
  100. return (std::size_t)(x->up()-ptrs.begin());
  101. }
  102. node_impl_pointer& next_at(std::size_t n)const
  103. {
  104. return *ptrs.at(n);
  105. }
  106. node_impl_pointer& prev_at(std::size_t n)const
  107. {
  108. return *(prev_spc.data()+n);
  109. }
  110. node_impl_pointer& next(node_impl_pointer x)const
  111. {
  112. return *(x->up());
  113. }
  114. node_impl_pointer& prev(node_impl_pointer x)const
  115. {
  116. return prev_at(position(x));
  117. }
  118. Allocator al;
  119. ptr_array& ptrs;
  120. node_impl_pointer header;
  121. auto_space<node_impl_pointer,Allocator> prev_spc;
  122. bool preprocessed;
  123. };
  124. template<typename Node,typename Allocator>
  125. class random_access_index_loader:
  126. private random_access_index_loader_base<Allocator>
  127. {
  128. typedef random_access_index_loader_base<Allocator> super;
  129. typedef typename super::node_impl_pointer node_impl_pointer;
  130. typedef typename super::ptr_array ptr_array;
  131. public:
  132. random_access_index_loader(const Allocator& al_,ptr_array& ptrs_):
  133. super(al_,ptrs_)
  134. {}
  135. void rearrange(Node* position_,Node *x)
  136. {
  137. super::rearrange(
  138. position_?position_->impl():node_impl_pointer(0),x->impl());
  139. }
  140. };
  141. } /* namespace multi_index::detail */
  142. } /* namespace multi_index */
  143. } /* namespace boost */
  144. #endif