mirror of
https://github.com/boostorg/multi_index.git
synced 2025-05-09 23:14:04 +00:00
added serialization support
[SVN r26504]
This commit is contained in:
parent
f595384267
commit
ac2fad60b1
144
example/serialization.cpp
Normal file
144
example/serialization.cpp
Normal file
@ -0,0 +1,144 @@
|
||||
/* Boost.MultiIndex example of serialization.
|
||||
*
|
||||
* Copyright 2003-2004 Joaquín M López Muñoz.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
#define BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING
|
||||
#define BOOST_MULTI_INDEX_ENABLE_SAFE_MODE
|
||||
#endif
|
||||
|
||||
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
|
||||
#include <algorithm>
|
||||
#include <boost/archive/text_oarchive.hpp>
|
||||
#include <boost/archive/text_iarchive.hpp>
|
||||
#include <boost/multi_index_container.hpp>
|
||||
#include <boost/multi_index/identity.hpp>
|
||||
#include <boost/multi_index/ordered_index.hpp>
|
||||
#include <boost/multi_index/sequenced_index.hpp>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
using namespace boost::multi_index;
|
||||
|
||||
/* An MRU (most recently used) list keeps record of the last n
|
||||
* inserted items, listing first the newer ones. Care has to be
|
||||
* taken when a duplicate item is inserted: instead of letting it
|
||||
* appear twice, the MRU list relocates it to the first position.
|
||||
*/
|
||||
|
||||
template <typename Item>
|
||||
class mru_list
|
||||
{
|
||||
typedef multi_index_container<
|
||||
Item,
|
||||
indexed_by<
|
||||
sequenced<>,
|
||||
ordered_unique<identity<Item> >
|
||||
>
|
||||
> item_list;
|
||||
|
||||
public:
|
||||
typedef Item item_type;
|
||||
typedef typename item_list::iterator iterator;
|
||||
|
||||
mru_list(std::size_t max_num_items):max_num_items(max_num_items){}
|
||||
|
||||
void insert(const item_type& item)
|
||||
{
|
||||
std::pair<iterator,bool> p=il.push_front(item);
|
||||
|
||||
if(!p.second){ /* duplicate item */
|
||||
il.relocate(il.begin(),p.first); /* put in front */
|
||||
}
|
||||
else if(il.size()>max_num_items){ /* keep the length <= max_num_items */
|
||||
il.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
iterator begin(){return il.begin();}
|
||||
iterator end(){return il.end();}
|
||||
|
||||
/* Utilities to save and load the MRU list, internally
|
||||
* based on Boost.Serialization.
|
||||
*/
|
||||
|
||||
void save_to_file(const char* file_name)const
|
||||
{
|
||||
std::ofstream ofs(file_name);
|
||||
boost::archive::text_oarchive oa(ofs);
|
||||
oa<<boost::serialization::make_nvp("mru",*this);
|
||||
}
|
||||
|
||||
void load_from_file(const char* file_name)
|
||||
{
|
||||
std::ifstream ifs(file_name);
|
||||
if(ifs){
|
||||
boost::archive::text_iarchive ia(ifs);
|
||||
ia>>boost::serialization::make_nvp("mru",*this);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
item_list il;
|
||||
std::size_t max_num_items;
|
||||
|
||||
/* serialization support */
|
||||
|
||||
friend class boost::serialization::access;
|
||||
|
||||
template<class Archive>
|
||||
void serialize(Archive& ar,const unsigned int)
|
||||
{
|
||||
ar&BOOST_SERIALIZATION_NVP(il);
|
||||
ar&BOOST_SERIALIZATION_NVP(max_num_items);
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
const char* mru_store="mru_store";
|
||||
|
||||
/* Construct a MRU limited to 10 items and retrieve its
|
||||
* previous contents.
|
||||
*/
|
||||
|
||||
mru_list<std::string> mru(10);
|
||||
mru.load_from_file(mru_store);
|
||||
|
||||
/* main loop */
|
||||
|
||||
for(;;){
|
||||
std::cout<<"enter a term: ";
|
||||
|
||||
std::string line;
|
||||
std::getline(std::cin,line);
|
||||
if(line.empty())break;
|
||||
|
||||
std::string term;
|
||||
std::istringstream iss(line);
|
||||
iss>>term;
|
||||
if(term.empty())break;
|
||||
|
||||
mru.insert(term);
|
||||
|
||||
std::cout<<"most recently entered terms:"<<std::endl;
|
||||
std::copy(
|
||||
mru.begin(),mru.end(),
|
||||
std::ostream_iterator<std::string>(std::cout,"\n"));
|
||||
}
|
||||
|
||||
/* persist the MRU list */
|
||||
|
||||
mru.save_to_file(mru_store);
|
||||
|
||||
return 0;
|
||||
}
|
75
include/boost/multi_index/detail/archive_constructed.hpp
Normal file
75
include/boost/multi_index/detail/archive_constructed.hpp
Normal file
@ -0,0 +1,75 @@
|
||||
/* Copyright 2003-2004 Joaquín M López Muñoz.
|
||||
* 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_ARCHIVE_CONSTRUCTED_HPP
|
||||
#define BOOST_MULTI_INDEX_DETAIL_ARCHIVE_CONSTRUCTED_HPP
|
||||
|
||||
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
|
||||
#include <boost/aligned_storage.hpp>
|
||||
#include <boost/detail/no_exceptions_support.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/serialization/access.hpp>
|
||||
#include <boost/serialization/nvp.hpp>
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace multi_index{
|
||||
|
||||
namespace detail{
|
||||
|
||||
/* constructs a stack-based object from a serialization archive */
|
||||
|
||||
template<typename T>
|
||||
struct archive_constructed:private noncopyable
|
||||
{
|
||||
template<class Archive>
|
||||
archive_constructed(Archive& ar,const unsigned int version)
|
||||
{
|
||||
serialization::load_construct_data(ar,&get(),version);
|
||||
BOOST_TRY{
|
||||
ar>>get();
|
||||
}
|
||||
BOOST_CATCH(...){
|
||||
(&get())->~T();
|
||||
BOOST_RETHROW;
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
}
|
||||
|
||||
template<class Archive>
|
||||
archive_constructed(const char* name,Archive& ar,const unsigned int version)
|
||||
{
|
||||
serialization::load_construct_data(ar,&get(),version);
|
||||
BOOST_TRY{
|
||||
ar>>serialization::make_nvp(name,get());
|
||||
}
|
||||
BOOST_CATCH(...){
|
||||
(&get())->~T();
|
||||
BOOST_RETHROW;
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
}
|
||||
|
||||
~archive_constructed()
|
||||
{
|
||||
(&get())->~T();
|
||||
}
|
||||
|
||||
T& get(){return *static_cast<T*>(space.address());}
|
||||
|
||||
private:
|
||||
aligned_storage<sizeof(T)> space;
|
||||
};
|
||||
|
||||
} /* namespace multi_index::detail */
|
||||
|
||||
} /* namespace multi_index */
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
117
include/boost/multi_index/detail/duplicates_iterator.hpp
Normal file
117
include/boost/multi_index/detail/duplicates_iterator.hpp
Normal file
@ -0,0 +1,117 @@
|
||||
/* Copyright 2003-2004 Joaquín M López Muñoz.
|
||||
* 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_DUPLICATES_ITERATOR_HPP
|
||||
#define BOOST_MULTI_INDEX_DETAIL_DUPLICATES_ITERATOR_HPP
|
||||
|
||||
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace multi_index{
|
||||
|
||||
namespace detail{
|
||||
|
||||
/* duplicates_operator is given a range of ordered elements and
|
||||
* passes only over those which are duplicated.
|
||||
*/
|
||||
|
||||
template<typename Node,typename Predicate>
|
||||
class duplicates_iterator
|
||||
{
|
||||
public:
|
||||
typedef typename Node::value_type value_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef const typename Node::value_type* pointer;
|
||||
typedef const typename Node::value_type& reference;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
|
||||
duplicates_iterator(Node* node,Node* end,Predicate pred):
|
||||
node(node),begin_chunk(0),end(end),pred(pred)
|
||||
{
|
||||
advance();
|
||||
}
|
||||
|
||||
duplicates_iterator(Node* end,Predicate pred):
|
||||
node(end),begin_chunk(end),end(end),pred(pred)
|
||||
{
|
||||
}
|
||||
|
||||
reference operator*()const
|
||||
{
|
||||
return node->value;
|
||||
}
|
||||
|
||||
pointer operator->()const
|
||||
{
|
||||
return node->value;
|
||||
}
|
||||
|
||||
duplicates_iterator& operator++()
|
||||
{
|
||||
Node::increment(node);
|
||||
sync();
|
||||
return *this;
|
||||
}
|
||||
|
||||
duplicates_iterator operator++(int)
|
||||
{
|
||||
duplicates_iterator tmp(*this);
|
||||
++(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
Node* get_node()const{return node;}
|
||||
|
||||
private:
|
||||
void sync()
|
||||
{
|
||||
if(pred(begin_chunk->value,node->value))advance();
|
||||
}
|
||||
|
||||
void advance()
|
||||
{
|
||||
for(Node* node2=node;node!=end;node=node2){
|
||||
Node::increment(node2);
|
||||
if(node2!=end&&!pred(node->value,node2->value))break;
|
||||
node=node2;
|
||||
}
|
||||
begin_chunk=node;
|
||||
}
|
||||
|
||||
Node* node;
|
||||
Node* begin_chunk;
|
||||
Node* end;
|
||||
Predicate pred;
|
||||
};
|
||||
|
||||
template<typename Node,typename Predicate>
|
||||
bool operator==(
|
||||
const duplicates_iterator<Node,Predicate>& x,
|
||||
const duplicates_iterator<Node,Predicate>& y)
|
||||
{
|
||||
return x.get_node()==y.get_node();
|
||||
}
|
||||
|
||||
template<typename Node,typename Predicate>
|
||||
bool operator!=(
|
||||
const duplicates_iterator<Node,Predicate>& x,
|
||||
const duplicates_iterator<Node,Predicate>& y)
|
||||
{
|
||||
return !(x==y);
|
||||
}
|
||||
|
||||
} /* namespace multi_index::detail */
|
||||
|
||||
} /* namespace multi_index */
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
128
include/boost/multi_index/detail/index_loader.hpp
Normal file
128
include/boost/multi_index/detail/index_loader.hpp
Normal file
@ -0,0 +1,128 @@
|
||||
/* Copyright 2003-2004 Joaquín M López Muñoz.
|
||||
* 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_LOADER_HPP
|
||||
#define BOOST_MULTI_INDEX_DETAIL_INDEX_LOADER_HPP
|
||||
|
||||
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
|
||||
#include <algorithm>
|
||||
#include <boost/archive/archive_exception.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/multi_index/detail/auto_space.hpp>
|
||||
#include <boost/serialization/nvp.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <cstddef>
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace multi_index{
|
||||
|
||||
namespace detail{
|
||||
|
||||
/* Counterpart of index_saver (check index_saver.hpp for serialization
|
||||
* details.)* multi_index_container is in charge of supplying the info about
|
||||
* the base sequence, and each index can subsequently load itself using the
|
||||
* const interface of index_loader.
|
||||
*/
|
||||
|
||||
template<typename Node,typename FinalNode,typename Allocator>
|
||||
class index_loader:private noncopyable
|
||||
{
|
||||
public:
|
||||
index_loader(const Allocator& al,std::size_t size):
|
||||
spc(al,size),size_(size),n(0),sorted(false)
|
||||
{
|
||||
}
|
||||
|
||||
template<class Archive>
|
||||
void add(Node* node,Archive& ar,const unsigned int)
|
||||
{
|
||||
ar>>serialization::make_nvp("position",*node);
|
||||
entries()[n++]=node;
|
||||
}
|
||||
|
||||
/* A rearranger is passed two nodes, and is expected to
|
||||
* reposition the second after the first.
|
||||
* If the first node is 0, then the second should be moved
|
||||
* to the beginning of the sequence.
|
||||
*/
|
||||
|
||||
template<typename Rearranger,class Archive>
|
||||
void load(Rearranger r,Archive& ar,const unsigned int)const
|
||||
{
|
||||
FinalNode* prev=unchecked_load_node(ar);
|
||||
if(!prev)return;
|
||||
|
||||
if(!sorted){
|
||||
std::sort(entries(),entries()+size_);
|
||||
sorted=true;
|
||||
}
|
||||
|
||||
check_node(prev);
|
||||
|
||||
for(;;){
|
||||
for(;;){
|
||||
FinalNode* node=load_node(ar);
|
||||
if(!node)break;
|
||||
|
||||
if(node==prev)prev=0;
|
||||
r(prev,node);
|
||||
|
||||
prev=node;
|
||||
}
|
||||
prev=load_node(ar);
|
||||
if(!prev)break;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Node** entries()const{return spc.data();}
|
||||
|
||||
/* We try to delay sorting as much as possible just in case it
|
||||
* is not necessary, hence this version of load_node.
|
||||
*/
|
||||
|
||||
template<class Archive>
|
||||
FinalNode* unchecked_load_node(Archive& ar)const
|
||||
{
|
||||
Node* node=0;
|
||||
ar>>serialization::make_nvp("pointer",node);
|
||||
return static_cast<FinalNode*>(node);
|
||||
}
|
||||
|
||||
template<class Archive>
|
||||
FinalNode* load_node(Archive& ar)const
|
||||
{
|
||||
Node* node=0;
|
||||
ar>>serialization::make_nvp("pointer",node);
|
||||
check_node(node);
|
||||
return static_cast<FinalNode*>(node);
|
||||
}
|
||||
|
||||
void check_node(Node* node)const
|
||||
{
|
||||
if(node!=0&&!std::binary_search(entries(),entries()+size_,node)){
|
||||
throw_exception(
|
||||
archive::archive_exception(
|
||||
archive::archive_exception::other_exception));
|
||||
}
|
||||
}
|
||||
|
||||
auto_space<Node*,Allocator> spc;
|
||||
std::size_t size_;
|
||||
std::size_t n;
|
||||
mutable bool sorted;
|
||||
};
|
||||
|
||||
} /* namespace multi_index::detail */
|
||||
|
||||
} /* namespace multi_index */
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
244
include/boost/multi_index/detail/index_matcher.hpp
Normal file
244
include/boost/multi_index/detail/index_matcher.hpp
Normal file
@ -0,0 +1,244 @@
|
||||
/* Copyright 2003-2004 Joaquín M López Muñoz.
|
||||
* 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_MATCHER_HPP
|
||||
#define BOOST_MULTI_INDEX_DETAIL_INDEX_MATCHER_HPP
|
||||
|
||||
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
|
||||
#include <algorithm>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/multi_index/detail/auto_space.hpp>
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace multi_index{
|
||||
|
||||
namespace detail{
|
||||
|
||||
/* index_matcher compares a sequence of elements against a
|
||||
* base sequence, identifying those elements that belong to the
|
||||
* longest subsequence which is ordered with respect to the base.
|
||||
* For instance, if the base sequence is:
|
||||
*
|
||||
* 0 1 2 3 4 5 6 7 8 9
|
||||
*
|
||||
* and the compared sequence (not necesarilly the same length):
|
||||
*
|
||||
* 1 4 2 3 0 7 8 9
|
||||
*
|
||||
* the elements of the longest ordered subsequence are:
|
||||
*
|
||||
* 1 2 3 7 8 9
|
||||
*
|
||||
* The algorithm for obtaining such a subsequence is called
|
||||
* Patience Sorting, described in ch. 1 of:
|
||||
* Aldous, D., Diaconis, P.: "Longest increasing subsequences: from
|
||||
* patience sorting to the Baik-Deift-Johansson Theorem", Bulletin
|
||||
* of the American Mathematical Society, vol. 36, no 4, pp. 413-432,
|
||||
* July 1999.
|
||||
* http://www.ams.org/bull/1999-36-04/S0273-0979-99-00796-X/
|
||||
* S0273-0979-99-00796-X.pdf
|
||||
*
|
||||
* This implementation is not fully generic since it assumes that
|
||||
* the sequences given are pointed to by index iterators (having a
|
||||
* get_node() memfun.)
|
||||
*/
|
||||
|
||||
namespace index_matcher{
|
||||
|
||||
/* The algorithm stores the nodes of the base sequence and a number
|
||||
* of "piles" that are dynamically updated during the calculation
|
||||
* stage. From a logical point of view, nodes form an independent
|
||||
* sequence from piles. They are stored together so as to minimize
|
||||
* allocated memory.
|
||||
*/
|
||||
|
||||
struct entry
|
||||
{
|
||||
entry(void* node_,std::size_t pos_=0):node(node_),pos(pos_){}
|
||||
|
||||
/* node stuff */
|
||||
|
||||
void* node;
|
||||
std::size_t pos;
|
||||
entry* previous;
|
||||
bool ordered;
|
||||
|
||||
struct less_by_node
|
||||
{
|
||||
bool operator()(
|
||||
const entry& x,const entry& y)const
|
||||
{
|
||||
return std::less<void*>()(x.node,y.node);
|
||||
}
|
||||
};
|
||||
|
||||
/* pile stuff */
|
||||
|
||||
std::size_t pile_top;
|
||||
entry* pile_top_entry;
|
||||
|
||||
struct less_by_pile_top
|
||||
{
|
||||
bool operator()(
|
||||
const entry& x,const entry& y)const
|
||||
{
|
||||
return x.pile_top<y.pile_top;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/* common code operating on void *'s */
|
||||
|
||||
template<typename Allocator>
|
||||
class algorithm_base:private noncopyable
|
||||
{
|
||||
protected:
|
||||
algorithm_base(const Allocator& al,std::size_t size):
|
||||
spc(al,size),size_(size),n(0),sorted(false)
|
||||
{
|
||||
}
|
||||
|
||||
void add(void* node)
|
||||
{
|
||||
entries()[n]=entry(node,n);
|
||||
++n;
|
||||
}
|
||||
|
||||
void begin_algorithm()const
|
||||
{
|
||||
if(!sorted){
|
||||
std::sort(entries(),entries()+size_,entry::less_by_node());
|
||||
sorted=true;
|
||||
}
|
||||
num_piles=0;
|
||||
}
|
||||
|
||||
void add_node_to_algorithm(void* node)const
|
||||
{
|
||||
entry* ent=
|
||||
std::lower_bound(
|
||||
entries(),entries()+size_,
|
||||
entry(node),entry::less_by_node()); /* localize entry */
|
||||
ent->ordered=false;
|
||||
std::size_t n=ent->pos; /* get its position */
|
||||
|
||||
entry dummy(0);
|
||||
dummy.pile_top=n;
|
||||
|
||||
entry* pile_ent= /* find the first available pile */
|
||||
std::lower_bound( /* to stack the entry */
|
||||
entries(),entries()+num_piles,
|
||||
dummy,entry::less_by_pile_top());
|
||||
|
||||
pile_ent->pile_top=n; /* stack the entry */
|
||||
pile_ent->pile_top_entry=ent;
|
||||
|
||||
/* if not the first pile, link entry to top of the preceding pile */
|
||||
if(pile_ent>&entries()[0]){
|
||||
ent->previous=(pile_ent-1)->pile_top_entry;
|
||||
}
|
||||
|
||||
if(pile_ent==&entries()[num_piles]){ /* new pile? */
|
||||
++num_piles;
|
||||
}
|
||||
}
|
||||
|
||||
void finish_algorithm()const
|
||||
{
|
||||
if(num_piles>0){
|
||||
/* Mark those elements which are in their correct position, i.e. those
|
||||
* belonging to the longest increasing subsequence. These are those
|
||||
* elements linked from the top of the last pile.
|
||||
*/
|
||||
|
||||
entry* ent=entries()[num_piles-1].pile_top_entry;
|
||||
for(std::size_t n=num_piles;n--;){
|
||||
ent->ordered=true;
|
||||
ent=ent->previous;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool is_ordered(void * node)const
|
||||
{
|
||||
return std::lower_bound(
|
||||
entries(),entries()+size_,
|
||||
entry(node),entry::less_by_node())->ordered;
|
||||
}
|
||||
|
||||
private:
|
||||
entry* entries()const{return spc.data();}
|
||||
|
||||
auto_space<entry,Allocator> spc;
|
||||
std::size_t size_;
|
||||
std::size_t n;
|
||||
mutable bool sorted;
|
||||
mutable std::size_t num_piles;
|
||||
};
|
||||
|
||||
/* The algorithm has three phases:
|
||||
* - Initialization, during which the nodes of the base sequence are added.
|
||||
* - Execution.
|
||||
* - Results querying, through the is_ordered memfun.
|
||||
*/
|
||||
|
||||
template<typename Node,typename Allocator>
|
||||
class algorithm:private algorithm_base<Allocator>
|
||||
{
|
||||
typedef algorithm_base<Allocator> super;
|
||||
|
||||
public:
|
||||
algorithm(const Allocator& al,std::size_t size):super(al,size){}
|
||||
|
||||
void add(Node* node)
|
||||
{
|
||||
super::add(node);
|
||||
}
|
||||
|
||||
template<typename IndexIterator>
|
||||
void execute(IndexIterator first,IndexIterator last)const
|
||||
{
|
||||
begin_algorithm();
|
||||
|
||||
for(IndexIterator it=first;it!=last;++it){
|
||||
add_node_to_algorithm(get_node(it));
|
||||
}
|
||||
|
||||
finish_algorithm();
|
||||
}
|
||||
|
||||
bool is_ordered(Node* node)const
|
||||
{
|
||||
return super::is_ordered(node);
|
||||
}
|
||||
|
||||
private:
|
||||
void add_node_to_algorithm(Node* node)const
|
||||
{
|
||||
super::add_node_to_algorithm(node);
|
||||
}
|
||||
|
||||
template<typename IndexIterator>
|
||||
static Node* get_node(IndexIterator it)
|
||||
{
|
||||
return static_cast<Node*>(it.get_node());
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace multi_index::detail::index_matcher */
|
||||
|
||||
} /* namespace multi_index::detail */
|
||||
|
||||
} /* namespace multi_index */
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
125
include/boost/multi_index/detail/index_saver.hpp
Normal file
125
include/boost/multi_index/detail/index_saver.hpp
Normal file
@ -0,0 +1,125 @@
|
||||
/* Copyright 2003-2004 Joaquín M López Muñoz.
|
||||
* 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
|
||||
|
||||
#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<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
|
225
test/test_serialization.cpp
Normal file
225
test/test_serialization.cpp
Normal file
@ -0,0 +1,225 @@
|
||||
/* Boost.MultiIndex test for serialization.
|
||||
*
|
||||
* Copyright 2003-2004 Joaquín M López Muñoz.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "test_serialization.hpp"
|
||||
|
||||
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
|
||||
#include <boost/archive/text_oarchive.hpp>
|
||||
#include <boost/archive/text_iarchive.hpp>
|
||||
#include "pre_multi_index.hpp"
|
||||
#include <boost/multi_index_container.hpp>
|
||||
#include <boost/multi_index/ordered_index.hpp>
|
||||
#include <boost/multi_index/sequenced_index.hpp>
|
||||
#include <boost/multi_index/key_extractors.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/test/test_tools.hpp>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include "pair_of_ints.hpp"
|
||||
|
||||
using namespace boost::multi_index;
|
||||
|
||||
template<int N>
|
||||
struct all_indices_equal_helper
|
||||
{
|
||||
template<class MultiIndexContainer>
|
||||
static bool compare(
|
||||
const MultiIndexContainer& m1,const MultiIndexContainer& m2)
|
||||
{
|
||||
if(!(get<N>(m1)==get<N>(m2))){
|
||||
return false;
|
||||
}
|
||||
return all_indices_equal_helper<N-1>::compare(m1,m2);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct all_indices_equal_helper<0>
|
||||
{
|
||||
template<class MultiIndexContainer>
|
||||
static bool compare(
|
||||
const MultiIndexContainer& m1,const MultiIndexContainer& m2)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<class MultiIndexContainer>
|
||||
bool all_indices_equal(
|
||||
const MultiIndexContainer& m1,const MultiIndexContainer& m2)
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(int,
|
||||
N=boost::mpl::size<
|
||||
BOOST_DEDUCED_TYPENAME MultiIndexContainer::index_type_list>::type::value);
|
||||
|
||||
return all_indices_equal_helper<N-1>::compare(m1,m2);
|
||||
}
|
||||
|
||||
template<class MultiIndexContainer>
|
||||
void test_serialization(const MultiIndexContainer& m)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
{
|
||||
boost::archive::text_oarchive oa(oss);
|
||||
oa<<boost::serialization::make_nvp("container",m);
|
||||
}
|
||||
|
||||
std::istringstream iss(oss.str());
|
||||
MultiIndexContainer m2;
|
||||
{
|
||||
boost::archive::text_iarchive ia(iss);
|
||||
ia>>boost::serialization::make_nvp("container",m2);
|
||||
}
|
||||
|
||||
BOOST_CHECK(all_indices_equal(m,m2));
|
||||
}
|
||||
|
||||
struct container_holder
|
||||
{
|
||||
typedef multi_index_container<
|
||||
int,
|
||||
indexed_by<
|
||||
sequenced<>
|
||||
>
|
||||
> multi_index_t;
|
||||
|
||||
container_holder(const multi_index_t& m_):m(m_){}
|
||||
|
||||
bool operator==(const container_holder& x)const
|
||||
{
|
||||
return m==x.m;
|
||||
}
|
||||
|
||||
multi_index_t m;
|
||||
|
||||
private:
|
||||
friend class boost::serialization::access;
|
||||
|
||||
template<class Archive>
|
||||
void serialize(Archive& ar,const unsigned int)
|
||||
{
|
||||
ar&boost::serialization::make_nvp("container",m);
|
||||
}
|
||||
};
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace serialization{
|
||||
|
||||
template<class Archive>
|
||||
inline void load_construct_data(
|
||||
Archive& ar,container_holder* p, const unsigned int)
|
||||
{
|
||||
::new(p)container_holder(container_holder::multi_index_t());
|
||||
}
|
||||
|
||||
} /* namespace serialization */
|
||||
|
||||
} /* namespace boost*/
|
||||
|
||||
void test_serialization()
|
||||
{
|
||||
{
|
||||
typedef multi_index_container<
|
||||
int,
|
||||
indexed_by<
|
||||
sequenced<>,
|
||||
sequenced<>
|
||||
>
|
||||
> multi_index_t;
|
||||
|
||||
multi_index_t m;
|
||||
for(int i=0;i<100;++i)m.push_back(i);
|
||||
m.reverse();
|
||||
test_serialization(m);
|
||||
|
||||
m.clear();
|
||||
for(int j=50;j<100;++j)m.push_back(j);
|
||||
for(int k=0;k<50;++k)m.push_back(k);
|
||||
m.sort();
|
||||
test_serialization(m);
|
||||
}
|
||||
{
|
||||
typedef multi_index_container<
|
||||
int,
|
||||
indexed_by<
|
||||
sequenced<>,
|
||||
ordered_non_unique<identity<int> >
|
||||
>
|
||||
> multi_index_t;
|
||||
|
||||
multi_index_t m;
|
||||
for(int i=0;i<100;++i){
|
||||
m.push_back(i);
|
||||
m.push_back(i);
|
||||
m.push_back(i);
|
||||
}
|
||||
m.reverse();
|
||||
test_serialization(m);
|
||||
}
|
||||
{
|
||||
typedef multi_index_container<
|
||||
pair_of_ints,
|
||||
indexed_by<
|
||||
ordered_unique<
|
||||
BOOST_MULTI_INDEX_MEMBER(pair_of_ints,int,first)
|
||||
>,
|
||||
ordered_non_unique<
|
||||
BOOST_MULTI_INDEX_MEMBER(pair_of_ints,int,second)
|
||||
>,
|
||||
sequenced<>
|
||||
>
|
||||
> multi_index_t;
|
||||
|
||||
multi_index_t m;
|
||||
test_serialization(m);
|
||||
|
||||
m.insert(pair_of_ints(4,0));
|
||||
test_serialization(m);
|
||||
|
||||
m.insert(pair_of_ints(3,1));
|
||||
m.insert(pair_of_ints(2,1));
|
||||
test_serialization(m);
|
||||
|
||||
m.insert(pair_of_ints(1,1));
|
||||
test_serialization(m);
|
||||
|
||||
m.insert(pair_of_ints(0,0));
|
||||
test_serialization(m);
|
||||
|
||||
m.insert(pair_of_ints(5,1));
|
||||
m.insert(pair_of_ints(7,1));
|
||||
m.insert(pair_of_ints(6,1));
|
||||
test_serialization(m);
|
||||
|
||||
m.insert(pair_of_ints(8,1));
|
||||
m.insert(pair_of_ints(9,1));
|
||||
m.insert(pair_of_ints(12,1));
|
||||
m.insert(pair_of_ints(11,1));
|
||||
m.insert(pair_of_ints(10,1));
|
||||
test_serialization(m);
|
||||
}
|
||||
{
|
||||
typedef multi_index_container<
|
||||
container_holder,
|
||||
indexed_by<
|
||||
sequenced<>
|
||||
>
|
||||
> multi_index_t;
|
||||
|
||||
multi_index_t m;
|
||||
container_holder::multi_index_t c1,c2;
|
||||
for(int i=0;i<100;++i)c1.push_back(i);
|
||||
for(int j=100;j<200;++j)c2.push_back(j);
|
||||
m.push_back(container_holder(c1));
|
||||
m.push_back(container_holder(c2));
|
||||
test_serialization(m);
|
||||
}
|
||||
}
|
11
test/test_serialization.hpp
Normal file
11
test/test_serialization.hpp
Normal file
@ -0,0 +1,11 @@
|
||||
/* Boost.MultiIndex test test for serialization.
|
||||
*
|
||||
* Copyright 2003-2004 Joaquín M López Muñoz.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
void test_serialization();
|
18
test/test_serialization_main.cpp
Normal file
18
test/test_serialization_main.cpp
Normal file
@ -0,0 +1,18 @@
|
||||
/* Boost.MultiIndex test for serialization.
|
||||
*
|
||||
* Copyright 2003-2004 Joaquín M López Muñoz.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <boost/test/included/test_exec_monitor.hpp>
|
||||
#include "test_serialization.hpp"
|
||||
|
||||
int test_main(int,char *[])
|
||||
{
|
||||
test_serialization();
|
||||
return 0;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user