143 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
		
		
			
		
	
	
			143 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
|   | /* Copyright 2003-2015 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_COPY_MAP_HPP | ||
|  | #define BOOST_MULTI_INDEX_DETAIL_COPY_MAP_HPP | ||
|  | 
 | ||
|  | #if defined(_MSC_VER) | ||
|  | #pragma once | ||
|  | #endif | ||
|  | 
 | ||
|  | #include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */ | ||
|  | #include <algorithm> | ||
|  | #include <boost/detail/no_exceptions_support.hpp> | ||
|  | #include <boost/multi_index/detail/auto_space.hpp> | ||
|  | #include <boost/multi_index/detail/raw_ptr.hpp> | ||
|  | #include <boost/noncopyable.hpp> | ||
|  | #include <cstddef> | ||
|  | #include <functional> | ||
|  | 
 | ||
|  | namespace boost{ | ||
|  | 
 | ||
|  | namespace multi_index{ | ||
|  | 
 | ||
|  | namespace detail{ | ||
|  | 
 | ||
|  | /* copy_map is used as an auxiliary structure during copy_() operations. | ||
|  |  * When a container with n nodes is replicated, node_map holds the pairings | ||
|  |  * between original and copied nodes, and provides a fast way to find a | ||
|  |  * copied node from an original one. | ||
|  |  * The semantics of the class are not simple, and no attempt has been made | ||
|  |  * to enforce it: multi_index_container handles it right. On the other hand, | ||
|  |  * the const interface, which is the one provided to index implementations, | ||
|  |  * only allows for: | ||
|  |  *   - Enumeration of pairs of (original,copied) nodes (excluding the headers), | ||
|  |  *   - fast retrieval of copied nodes (including the headers.) | ||
|  |  */ | ||
|  | 
 | ||
|  | template <typename Node> | ||
|  | struct copy_map_entry | ||
|  | { | ||
|  |   copy_map_entry(Node* f,Node* s):first(f),second(s){} | ||
|  | 
 | ||
|  |   Node* first; | ||
|  |   Node* second; | ||
|  | 
 | ||
|  |   bool operator<(const copy_map_entry<Node>& x)const | ||
|  |   { | ||
|  |     return std::less<Node*>()(first,x.first); | ||
|  |   } | ||
|  | }; | ||
|  | 
 | ||
|  | template <typename Node,typename Allocator> | ||
|  | class copy_map:private noncopyable | ||
|  | { | ||
|  | public: | ||
|  |   typedef const copy_map_entry<Node>* const_iterator; | ||
|  | 
 | ||
|  |   copy_map( | ||
|  |     const Allocator& al,std::size_t size,Node* header_org,Node* header_cpy): | ||
|  |     al_(al),size_(size),spc(al_,size_),n(0), | ||
|  |     header_org_(header_org),header_cpy_(header_cpy),released(false) | ||
|  |   {} | ||
|  | 
 | ||
|  |   ~copy_map() | ||
|  |   { | ||
|  |     if(!released){ | ||
|  |       for(std::size_t i=0;i<n;++i){ | ||
|  |         boost::detail::allocator::destroy(&(spc.data()+i)->second->value()); | ||
|  |         deallocate((spc.data()+i)->second); | ||
|  |       } | ||
|  |     } | ||
|  |   } | ||
|  | 
 | ||
|  |   const_iterator begin()const{return raw_ptr<const_iterator>(spc.data());} | ||
|  |   const_iterator end()const{return raw_ptr<const_iterator>(spc.data()+n);} | ||
|  | 
 | ||
|  |   void clone(Node* node) | ||
|  |   { | ||
|  |     (spc.data()+n)->first=node; | ||
|  |     (spc.data()+n)->second=raw_ptr<Node*>(al_.allocate(1)); | ||
|  |     BOOST_TRY{ | ||
|  |       boost::detail::allocator::construct( | ||
|  |         &(spc.data()+n)->second->value(),node->value()); | ||
|  |     } | ||
|  |     BOOST_CATCH(...){ | ||
|  |       deallocate((spc.data()+n)->second); | ||
|  |       BOOST_RETHROW; | ||
|  |     } | ||
|  |     BOOST_CATCH_END | ||
|  |     ++n; | ||
|  | 
 | ||
|  |     if(n==size_){ | ||
|  |       std::sort( | ||
|  |         raw_ptr<copy_map_entry<Node>*>(spc.data()), | ||
|  |         raw_ptr<copy_map_entry<Node>*>(spc.data())+size_); | ||
|  |     } | ||
|  |   } | ||
|  | 
 | ||
|  |   Node* find(Node* node)const | ||
|  |   { | ||
|  |     if(node==header_org_)return header_cpy_; | ||
|  |     return std::lower_bound( | ||
|  |       begin(),end(),copy_map_entry<Node>(node,0))->second; | ||
|  |   } | ||
|  | 
 | ||
|  |   void release() | ||
|  |   { | ||
|  |     released=true; | ||
|  |   } | ||
|  | 
 | ||
|  | private: | ||
|  |   typedef typename boost::detail::allocator::rebind_to< | ||
|  |     Allocator,Node | ||
|  |   >::type                                               allocator_type; | ||
|  |   typedef typename allocator_type::pointer              allocator_pointer; | ||
|  | 
 | ||
|  |   allocator_type                                        al_; | ||
|  |   std::size_t                                           size_; | ||
|  |   auto_space<copy_map_entry<Node>,Allocator>            spc; | ||
|  |   std::size_t                                           n; | ||
|  |   Node*                                                 header_org_; | ||
|  |   Node*                                                 header_cpy_; | ||
|  |   bool                                                  released; | ||
|  | 
 | ||
|  |   void deallocate(Node* node) | ||
|  |   { | ||
|  |     al_.deallocate(static_cast<allocator_pointer>(node),1); | ||
|  |   } | ||
|  | }; | ||
|  | 
 | ||
|  | } /* namespace multi_index::detail */ | ||
|  | 
 | ||
|  | } /* namespace multi_index */ | ||
|  | 
 | ||
|  | } /* namespace boost */ | ||
|  | 
 | ||
|  | #endif |