136 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
		
		
			
		
	
	
			136 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
|   | /* Copyright 2003-2013 Joaquin M Lopez Munoz. | ||
|  |  * Distributed under the Boost Software License, Version 1.0. | ||
|  |  * (See accompanying file LICENSE_1_0.txt or copy at | ||
|  |  * http://www.boost.org/LICENSE_1_0.txt) | ||
|  |  * | ||
|  |  * See http://www.boost.org/libs/multi_index for library home page. | ||
|  |  */ | ||
|  | 
 | ||
|  | #ifndef BOOST_MULTI_INDEX_DETAIL_INDEX_SAVER_HPP | ||
|  | #define BOOST_MULTI_INDEX_DETAIL_INDEX_SAVER_HPP | ||
|  | 
 | ||
|  | #if defined(_MSC_VER) | ||
|  | #pragma once | ||
|  | #endif | ||
|  | 
 | ||
|  | #include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */ | ||
|  | #include <boost/multi_index/detail/index_matcher.hpp> | ||
|  | #include <boost/noncopyable.hpp> | ||
|  | #include <boost/serialization/nvp.hpp> | ||
|  | #include <cstddef> | ||
|  | 
 | ||
|  | namespace boost{ | ||
|  | 
 | ||
|  | namespace multi_index{ | ||
|  | 
 | ||
|  | namespace detail{ | ||
|  | 
 | ||
|  | /* index_saver accepts a base sequence of previously saved elements | ||
|  |  * and saves a possibly reordered subsequence in an efficient manner, | ||
|  |  * serializing only the information needed to rearrange the subsequence | ||
|  |  * based on the original order of the base. | ||
|  |  * multi_index_container is in charge of supplying the info about the | ||
|  |  * base sequence, and each index can subsequently save itself using the | ||
|  |  * const interface of index_saver. | ||
|  |  */ | ||
|  | 
 | ||
|  | template<typename Node,typename Allocator> | ||
|  | class index_saver:private noncopyable | ||
|  | { | ||
|  | public: | ||
|  |   index_saver(const Allocator& al,std::size_t size):alg(al,size){} | ||
|  | 
 | ||
|  |   template<class Archive> | ||
|  |   void add(Node* node,Archive& ar,const unsigned int) | ||
|  |   { | ||
|  |     ar<<serialization::make_nvp("position",*node); | ||
|  |     alg.add(node); | ||
|  |   } | ||
|  | 
 | ||
|  |   template<class Archive> | ||
|  |   void add_track(Node* node,Archive& ar,const unsigned int) | ||
|  |   { | ||
|  |     ar<<serialization::make_nvp("position",*node); | ||
|  |   } | ||
|  | 
 | ||
|  |   template<typename IndexIterator,class Archive> | ||
|  |   void save( | ||
|  |     IndexIterator first,IndexIterator last,Archive& ar, | ||
|  |     const unsigned int)const | ||
|  |   { | ||
|  |     /* calculate ordered positions */ | ||
|  | 
 | ||
|  |     alg.execute(first,last); | ||
|  | 
 | ||
|  |     /* Given a consecutive subsequence of displaced elements | ||
|  |      * x1,...,xn, the following information is serialized: | ||
|  |      * | ||
|  |      *   p0,p1,...,pn,0 | ||
|  |      * | ||
|  |      * where pi is a pointer to xi and p0 is a pointer to the element | ||
|  |      * preceding x1. Crealy, from this information is possible to | ||
|  |      * restore the original order on loading time. If x1 is the first | ||
|  |      * element in the sequence, the following is serialized instead: | ||
|  |      * | ||
|  |      *   p1,p1,...,pn,0 | ||
|  |      * | ||
|  |      * For each subsequence of n elements, n+2 pointers are serialized. | ||
|  |      * An optimization policy is applied: consider for instance the | ||
|  |      * sequence | ||
|  |      * | ||
|  |      *   a,B,c,D | ||
|  |      *  | ||
|  |      * where B and D are displaced, but c is in its correct position. | ||
|  |      * Applying the schema described above we would serialize 6 pointers: | ||
|  |      * | ||
|  |      *  p(a),p(B),0 | ||
|  |      *  p(c),p(D),0 | ||
|  |      *  | ||
|  |      * but this can be reduced to 5 pointers by treating c as a displaced | ||
|  |      * element: | ||
|  |      * | ||
|  |      *  p(a),p(B),p(c),p(D),0 | ||
|  |      */ | ||
|  | 
 | ||
|  |     std::size_t last_saved=3; /* distance to last pointer saved */ | ||
|  |     for(IndexIterator it=first,prev=first;it!=last;prev=it++,++last_saved){ | ||
|  |       if(!alg.is_ordered(get_node(it))){ | ||
|  |         if(last_saved>1)save_node(get_node(prev),ar); | ||
|  |         save_node(get_node(it),ar); | ||
|  |         last_saved=0; | ||
|  |       } | ||
|  |       else if(last_saved==2)save_node(null_node(),ar); | ||
|  |     } | ||
|  |     if(last_saved<=2)save_node(null_node(),ar); | ||
|  | 
 | ||
|  |     /* marks the end of the serialization info for [first,last) */ | ||
|  | 
 | ||
|  |     save_node(null_node(),ar); | ||
|  |   } | ||
|  | 
 | ||
|  | private: | ||
|  |   template<typename IndexIterator> | ||
|  |   static Node* get_node(IndexIterator it) | ||
|  |   { | ||
|  |     return it.get_node(); | ||
|  |   } | ||
|  | 
 | ||
|  |   static Node* null_node(){return 0;} | ||
|  | 
 | ||
|  |   template<typename Archive> | ||
|  |   static void save_node(Node* node,Archive& ar) | ||
|  |   { | ||
|  |     ar<<serialization::make_nvp("pointer",node); | ||
|  |   } | ||
|  | 
 | ||
|  |   index_matcher::algorithm<Node,Allocator> alg; | ||
|  | }; | ||
|  | 
 | ||
|  | } /* namespace multi_index::detail */ | ||
|  | 
 | ||
|  | } /* namespace multi_index */ | ||
|  | 
 | ||
|  | } /* namespace boost */ | ||
|  | 
 | ||
|  | #endif |