index_saver.hpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  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_INDEX_SAVER_HPP
  9. #define BOOST_MULTI_INDEX_DETAIL_INDEX_SAVER_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 <boost/multi_index/detail/index_matcher.hpp>
  15. #include <boost/noncopyable.hpp>
  16. #include <boost/serialization/nvp.hpp>
  17. #include <cstddef>
  18. namespace boost{
  19. namespace multi_index{
  20. namespace detail{
  21. /* index_saver accepts a base sequence of previously saved elements
  22. * and saves a possibly reordered subsequence in an efficient manner,
  23. * serializing only the information needed to rearrange the subsequence
  24. * based on the original order of the base.
  25. * multi_index_container is in charge of supplying the info about the
  26. * base sequence, and each index can subsequently save itself using the
  27. * const interface of index_saver.
  28. */
  29. template<typename Node,typename Allocator>
  30. class index_saver:private noncopyable
  31. {
  32. public:
  33. index_saver(const Allocator& al,std::size_t size):alg(al,size){}
  34. template<class Archive>
  35. void add(Node* node,Archive& ar,const unsigned int)
  36. {
  37. ar<<serialization::make_nvp("position",*node);
  38. alg.add(node);
  39. }
  40. template<class Archive>
  41. void add_track(Node* node,Archive& ar,const unsigned int)
  42. {
  43. ar<<serialization::make_nvp("position",*node);
  44. }
  45. template<typename IndexIterator,class Archive>
  46. void save(
  47. IndexIterator first,IndexIterator last,Archive& ar,
  48. const unsigned int)const
  49. {
  50. /* calculate ordered positions */
  51. alg.execute(first,last);
  52. /* Given a consecutive subsequence of displaced elements
  53. * x1,...,xn, the following information is serialized:
  54. *
  55. * p0,p1,...,pn,0
  56. *
  57. * where pi is a pointer to xi and p0 is a pointer to the element
  58. * preceding x1. Crealy, from this information is possible to
  59. * restore the original order on loading time. If x1 is the first
  60. * element in the sequence, the following is serialized instead:
  61. *
  62. * p1,p1,...,pn,0
  63. *
  64. * For each subsequence of n elements, n+2 pointers are serialized.
  65. * An optimization policy is applied: consider for instance the
  66. * sequence
  67. *
  68. * a,B,c,D
  69. *
  70. * where B and D are displaced, but c is in its correct position.
  71. * Applying the schema described above we would serialize 6 pointers:
  72. *
  73. * p(a),p(B),0
  74. * p(c),p(D),0
  75. *
  76. * but this can be reduced to 5 pointers by treating c as a displaced
  77. * element:
  78. *
  79. * p(a),p(B),p(c),p(D),0
  80. */
  81. std::size_t last_saved=3; /* distance to last pointer saved */
  82. for(IndexIterator it=first,prev=first;it!=last;prev=it++,++last_saved){
  83. if(!alg.is_ordered(get_node(it))){
  84. if(last_saved>1)save_node(get_node(prev),ar);
  85. save_node(get_node(it),ar);
  86. last_saved=0;
  87. }
  88. else if(last_saved==2)save_node(null_node(),ar);
  89. }
  90. if(last_saved<=2)save_node(null_node(),ar);
  91. /* marks the end of the serialization info for [first,last) */
  92. save_node(null_node(),ar);
  93. }
  94. private:
  95. template<typename IndexIterator>
  96. static Node* get_node(IndexIterator it)
  97. {
  98. return it.get_node();
  99. }
  100. static Node* null_node(){return 0;}
  101. template<typename Archive>
  102. static void save_node(Node* node,Archive& ar)
  103. {
  104. ar<<serialization::make_nvp("pointer",node);
  105. }
  106. index_matcher::algorithm<Node,Allocator> alg;
  107. };
  108. } /* namespace multi_index::detail */
  109. } /* namespace multi_index */
  110. } /* namespace boost */
  111. #endif