mirror of
https://github.com/boostorg/multi_index.git
synced 2025-05-11 13:24:04 +00:00
added rearrange facilities
[SVN r32645]
This commit is contained in:
parent
c1f8fc6348
commit
1e39e5f9af
245
example/rearrange.cpp
Normal file
245
example/rearrange.cpp
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
/* Boost.MultiIndex example of use of rearrange facilities.
|
||||||
|
*
|
||||||
|
* Copyright 2003-2006 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>
|
||||||
|
#include <boost/detail/iterator.hpp>
|
||||||
|
#include <boost/multi_index_container.hpp>
|
||||||
|
#include <boost/multi_index/random_access_index.hpp>
|
||||||
|
#include <boost/random/binomial_distribution.hpp>
|
||||||
|
#include <boost/random/uniform_real.hpp>
|
||||||
|
#include <boost/random/mersenne_twister.hpp>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iostream>
|
||||||
|
#include <iterator>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
using boost::multi_index_container;
|
||||||
|
using namespace boost::multi_index;
|
||||||
|
|
||||||
|
/* We model a card deck with a random access array containing
|
||||||
|
* card numbers (from 0 to 51), supplemented with an additional
|
||||||
|
* index which retains the start ordering.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class deck
|
||||||
|
{
|
||||||
|
BOOST_STATIC_CONSTANT(std::size_t,num_cards=52);
|
||||||
|
|
||||||
|
typedef multi_index_container<
|
||||||
|
int,
|
||||||
|
indexed_by<
|
||||||
|
random_access<>, /* base index */
|
||||||
|
random_access<> /* "start" index */
|
||||||
|
>
|
||||||
|
> container_type;
|
||||||
|
container_type cont;
|
||||||
|
|
||||||
|
public:
|
||||||
|
deck()
|
||||||
|
{
|
||||||
|
cont.reserve(num_cards);
|
||||||
|
get<1>(cont).reserve(num_cards);
|
||||||
|
for(std::size_t i=0;i<num_cards;++i)cont.push_back(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef container_type::iterator iterator;
|
||||||
|
typedef container_type::size_type size_type;
|
||||||
|
|
||||||
|
iterator begin()const{return cont.begin();}
|
||||||
|
iterator end()const{return cont.end();}
|
||||||
|
size_type size()const{return cont.size();}
|
||||||
|
|
||||||
|
template<typename InputIterator>
|
||||||
|
void rearrange(InputIterator it)
|
||||||
|
{
|
||||||
|
cont.rearrange(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset()
|
||||||
|
{
|
||||||
|
/* simply rearrange the base index like the start index */
|
||||||
|
|
||||||
|
cont.rearrange(get<1>(cont).begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t position(int i)const
|
||||||
|
{
|
||||||
|
/* The position of a card in the deck is calculated by locating
|
||||||
|
* the card through the start index (which is ordered), projecting
|
||||||
|
* to the base index and diffing with the begin position.
|
||||||
|
* Resulting complexity: constant.
|
||||||
|
*/
|
||||||
|
|
||||||
|
return project<0>(cont,get<1>(cont).begin()+i)-cont.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t rising_sequences()const
|
||||||
|
{
|
||||||
|
/* Iterate through all cards and increment the sequence count
|
||||||
|
* when the current position is left to the previous.
|
||||||
|
* Resulting complexity: O(n), n=num_cards.
|
||||||
|
*/
|
||||||
|
|
||||||
|
std::size_t s=1;
|
||||||
|
std::size_t last_pos=0;
|
||||||
|
|
||||||
|
for(std::size_t i=0;i<num_cards;++i){
|
||||||
|
std::size_t pos=position(i);
|
||||||
|
if(pos<last_pos)++s;
|
||||||
|
last_pos=pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* A vector of reference_wrappers to deck elements can be used
|
||||||
|
* as a view to the deck container.
|
||||||
|
* We use a special implicit_reference_wrapper having implicit
|
||||||
|
* ctor from its base type, as this simplifies the use of generic
|
||||||
|
* techniques on the resulting data structures.
|
||||||
|
*/
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class implicit_reference_wrapper:public boost::reference_wrapper<T>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
typedef boost::reference_wrapper<T> super;
|
||||||
|
public:
|
||||||
|
implicit_reference_wrapper(T& t):super(t){}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::vector<implicit_reference_wrapper<const int> > deck_view;
|
||||||
|
|
||||||
|
/* Riffle shuffle is modeled like this: A cut is selected in the deck
|
||||||
|
* following a binomial distribution. Then, cards are randomly selected
|
||||||
|
* from one packet or the other with probability proportional to
|
||||||
|
* packet size.
|
||||||
|
*/
|
||||||
|
|
||||||
|
template<typename RandomAccessIterator,typename OutputIterator>
|
||||||
|
void riffle_shuffle(
|
||||||
|
RandomAccessIterator first,RandomAccessIterator last,
|
||||||
|
OutputIterator out)
|
||||||
|
{
|
||||||
|
static boost::mt19937 rnd_gen;
|
||||||
|
|
||||||
|
typedef typename boost::detail::iterator_traits<
|
||||||
|
RandomAccessIterator>::difference_type difference_type;
|
||||||
|
typedef boost::binomial_distribution<
|
||||||
|
difference_type> rnd_cut_select_type;
|
||||||
|
typedef boost::uniform_real<> rnd_deck_select_type;
|
||||||
|
|
||||||
|
rnd_cut_select_type cut_select(last-first);
|
||||||
|
RandomAccessIterator middle=first+cut_select(rnd_gen);
|
||||||
|
difference_type s0=middle-first;
|
||||||
|
difference_type s1=last-middle;
|
||||||
|
rnd_deck_select_type deck_select;
|
||||||
|
|
||||||
|
while(s0!=0&&s1!=0){
|
||||||
|
if(deck_select(rnd_gen)<(double)s0/(s0+s1)){
|
||||||
|
*out++=*first++;
|
||||||
|
--s0;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
*out++=*middle++;
|
||||||
|
--s1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::copy(first,first+s0,out);
|
||||||
|
std::copy(middle,middle+s1,out);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct riffle_shuffler
|
||||||
|
{
|
||||||
|
void operator()(deck& d)const
|
||||||
|
{
|
||||||
|
dv.clear();
|
||||||
|
dv.reserve(d.size());
|
||||||
|
riffle_shuffle(
|
||||||
|
d.begin(),d.end(),std::back_inserter(dv)); /* do the shuffling */
|
||||||
|
d.rearrange(dv.begin()); /* apply to the deck */
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
mutable deck_view dv;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* A truly random shuffle (up to stdlib implementation quality) using
|
||||||
|
* std::random_shuffle.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct random_shuffler
|
||||||
|
{
|
||||||
|
void operator()(deck& d)const
|
||||||
|
{
|
||||||
|
dv.clear();
|
||||||
|
dv.reserve(d.size());
|
||||||
|
std::copy(d.begin(),d.end(),std::back_inserter(dv));
|
||||||
|
std::random_shuffle(dv.begin(),dv.end()); /* do the shuffling */
|
||||||
|
d.rearrange(dv.begin()); /* apply to the deck */
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
mutable deck_view dv;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Repeat a given shuffling algorithm repeats_num times
|
||||||
|
* and obtain the resulting rising sequences number. Average
|
||||||
|
* for tests_num trials.
|
||||||
|
*/
|
||||||
|
|
||||||
|
template<typename Shuffler>
|
||||||
|
double shuffle_test(
|
||||||
|
unsigned int repeats_num,unsigned int tests_num
|
||||||
|
BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(Shuffler))
|
||||||
|
{
|
||||||
|
deck d;
|
||||||
|
Shuffler sh;
|
||||||
|
unsigned long total=0;
|
||||||
|
|
||||||
|
for(unsigned int n=0;n<tests_num;++n){
|
||||||
|
for(unsigned m=0;m<repeats_num;++m)sh(d);
|
||||||
|
total+=d.rising_sequences();
|
||||||
|
d.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (double)total/tests_num;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
unsigned rifs_num=0;
|
||||||
|
unsigned tests_num=0;
|
||||||
|
|
||||||
|
std::cout<<"number of riffle shuffles (vg 5):";
|
||||||
|
std::cin>>rifs_num;
|
||||||
|
std::cout<<"number of tests (vg 1000):";
|
||||||
|
std::cin>>tests_num;
|
||||||
|
|
||||||
|
std::cout<<"shuffling..."<<std::endl;
|
||||||
|
|
||||||
|
std::cout<<"riffle shuffling\n"
|
||||||
|
" avg number of rising sequences: "
|
||||||
|
<<shuffle_test<riffle_shuffler>(rifs_num,tests_num)
|
||||||
|
<<std::endl;
|
||||||
|
|
||||||
|
std::cout<<"random shuffling\n"
|
||||||
|
" avg number of rising sequences: "
|
||||||
|
<<shuffle_test<random_shuffler>(1,tests_num)
|
||||||
|
<<std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
125
test/test_rearrange.cpp
Normal file
125
test/test_rearrange.cpp
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
/* Boost.MultiIndex test for rearrange operations.
|
||||||
|
*
|
||||||
|
* Copyright 2003-2006 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_rearrange.hpp"
|
||||||
|
|
||||||
|
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iterator>
|
||||||
|
#include "pre_multi_index.hpp"
|
||||||
|
#include <boost/multi_index_container.hpp>
|
||||||
|
#include <boost/multi_index/sequenced_index.hpp>
|
||||||
|
#include <boost/multi_index/random_access_index.hpp>
|
||||||
|
#include <boost/ref.hpp>
|
||||||
|
#include <boost/test/test_tools.hpp>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
using namespace boost::multi_index;
|
||||||
|
|
||||||
|
#undef _
|
||||||
|
#define _ ,
|
||||||
|
|
||||||
|
#undef CHECK_EQUAL
|
||||||
|
#define CHECK_EQUAL(p,check_range) \
|
||||||
|
{\
|
||||||
|
int v[]=check_range;\
|
||||||
|
std::size_t size_v=sizeof(v)/sizeof(int);\
|
||||||
|
BOOST_CHECK(std::size_t(std::distance((p).begin(),(p).end()))==size_v);\
|
||||||
|
BOOST_CHECK(std::equal((p).begin(),(p).end(),v));\
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef CHECK_VOID_RANGE
|
||||||
|
#define CHECK_VOID_RANGE(p) BOOST_CHECK((p).first==(p).second)
|
||||||
|
|
||||||
|
template<typename Sequence>
|
||||||
|
static void local_test_rearrange(BOOST_EXPLICIT_TEMPLATE_TYPE(Sequence))
|
||||||
|
{
|
||||||
|
typedef typename Sequence::iterator iterator;
|
||||||
|
typedef typename Sequence::value_type value_type;
|
||||||
|
|
||||||
|
Sequence sc;
|
||||||
|
sc.push_back(0);
|
||||||
|
sc.push_back(1);
|
||||||
|
sc.push_back(2);
|
||||||
|
sc.push_back(3);
|
||||||
|
sc.push_back(4);
|
||||||
|
sc.push_back(5);
|
||||||
|
|
||||||
|
iterator it;
|
||||||
|
|
||||||
|
it=sc.begin();
|
||||||
|
std::advance(it,3);
|
||||||
|
sc.relocate(sc.begin(),it);
|
||||||
|
CHECK_EQUAL(sc,{3 _ 0 _ 1 _ 2 _ 4 _ 5});
|
||||||
|
BOOST_CHECK(it==sc.begin());
|
||||||
|
|
||||||
|
sc.relocate(it,it);
|
||||||
|
CHECK_EQUAL(sc,{3 _ 0 _ 1 _ 2 _ 4 _ 5});
|
||||||
|
|
||||||
|
std::advance(it,3);
|
||||||
|
sc.relocate(sc.end(),it,sc.end());
|
||||||
|
CHECK_EQUAL(sc,{3 _ 0 _ 1 _ 2 _ 4 _ 5});
|
||||||
|
|
||||||
|
sc.relocate(sc.begin(),it,it);
|
||||||
|
CHECK_EQUAL(sc,{3 _ 0 _ 1 _ 2 _ 4 _ 5});
|
||||||
|
|
||||||
|
iterator it2;
|
||||||
|
|
||||||
|
it2=sc.begin();
|
||||||
|
++it2;
|
||||||
|
sc.relocate(it2,it,sc.end());
|
||||||
|
CHECK_EQUAL(sc,{3 _ 2 _ 4 _ 5 _ 0 _ 1});
|
||||||
|
BOOST_CHECK(std::distance(it,it2)==3);
|
||||||
|
|
||||||
|
sc.relocate(--(sc.end()),it,it2);
|
||||||
|
CHECK_EQUAL(sc,{3 _ 0 _ 2 _ 4 _ 5 _ 1});
|
||||||
|
|
||||||
|
std::vector<boost::reference_wrapper<const value_type> > v;
|
||||||
|
for(iterator it3=sc.begin();it3!=sc.end();++it3){
|
||||||
|
v.push_back(boost::cref(*it3));
|
||||||
|
}
|
||||||
|
|
||||||
|
sc.rearrange(v.begin());
|
||||||
|
BOOST_CHECK(std::equal(sc.begin(),sc.end(),v.begin()));
|
||||||
|
|
||||||
|
std::reverse(v.begin(),v.end());
|
||||||
|
sc.rearrange(v.begin());
|
||||||
|
BOOST_CHECK(std::equal(sc.begin(),sc.end(),v.begin()));
|
||||||
|
|
||||||
|
std::sort(v.begin(),v.end());
|
||||||
|
sc.rearrange(v.begin());
|
||||||
|
BOOST_CHECK(std::equal(sc.begin(),sc.end(),v.begin()));
|
||||||
|
|
||||||
|
std::reverse(v.begin(),v.begin()+v.size()/2);
|
||||||
|
sc.rearrange(v.begin());
|
||||||
|
BOOST_CHECK(std::equal(sc.begin(),sc.end(),v.begin()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_rearrange()
|
||||||
|
{
|
||||||
|
typedef multi_index_container<
|
||||||
|
int,
|
||||||
|
indexed_by<sequenced<> >
|
||||||
|
> int_list;
|
||||||
|
|
||||||
|
/* MSVC++ 6.0 chokes on local_test_rearrange without this
|
||||||
|
* explicit instantiation
|
||||||
|
*/
|
||||||
|
int_list il;
|
||||||
|
local_test_rearrange<int_list>();
|
||||||
|
|
||||||
|
typedef multi_index_container<
|
||||||
|
int,
|
||||||
|
indexed_by<random_access<> >
|
||||||
|
> int_vector;
|
||||||
|
|
||||||
|
int_vector iv;
|
||||||
|
local_test_rearrange<int_vector>();
|
||||||
|
}
|
11
test/test_rearrange.hpp
Normal file
11
test/test_rearrange.hpp
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
/* Boost.MultiIndex test for rearrange operations.
|
||||||
|
*
|
||||||
|
* Copyright 2003-2005 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_rearrange();
|
18
test/test_rearrange_main.cpp
Normal file
18
test/test_rearrange_main.cpp
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
/* Boost.MultiIndex test for rearrange operations.
|
||||||
|
*
|
||||||
|
* Copyright 2003-2005 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_rearrange.hpp"
|
||||||
|
|
||||||
|
int test_main(int,char *[])
|
||||||
|
{
|
||||||
|
test_rearrange();
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user