mirror of
https://github.com/boostorg/multi_index.git
synced 2025-05-09 23:14: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