Subject: [Boost-bugs] [Boost C++ Libraries] #6250: allow sorting through an adaptor
From: Boost C++ Libraries (noreply_at_[hidden])
Date: 2011-12-10 22:15:54
#6250: allow sorting through an adaptor
-----------------------------------+----------------------------------------
Reporter: giecrilj@⦠| Owner: dave
Type: Feature Requests | Status: new
Milestone: To Be Determined | Component: iterator
Version: Boost 1.48.0 | Severity: Problem
Keywords: |
-----------------------------------+----------------------------------------
The following code does not compile because the transform adaptor offers a
proxy reference that cannot be modified:
{{{
#!c++
#include <iostream>
#include <boost/array.hpp>
#include <boost/range/algorithm/copy.hpp>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/bind.hpp>
#include <boost/range/algorithm/sort.hpp>
struct underlying { int m_; };
int main (int, char *[]) {
enum LocalParam { BASE = 073, VALUE = 030 };
typedef ::boost ::array < underlying, +BASE - 01 > mycont; mycont v;
for
(::boost ::range_iterator < mycont >:: type p ((::boost ::begin (v)));
p < ::boost ::end (v); ++p)
p -> m_ = p == ::boost ::begin (v)? +VALUE: p [-01] .m_ * VALUE %
BASE;
::boost ::copy
(v
| ::boost ::adaptors ::transformed (::boost ::bind (&underlying ::m_,
_1)),
::std ::ostream_iterator
< int, ::std ::istream ::char_type >
(::std:: cout, " ")); ::std ::cout << '\n';
::boost ::sort
(v
| ::boost ::adaptors ::transformed (::boost ::bind (&underlying ::m_,
_1)));
::boost ::copy
(v
| ::boost ::adaptors ::transformed (::boost ::bind (&underlying ::m_,
_1)),
::std ::ostream_iterator
< int, ::std ::istream ::char_type >
(::std:: cout, " "));
return (::std ::cout << '\n') .flush ()? +EXIT_SUCCESS: +EXIT_FAILURE; }
}}}
This is a deficiency because, when you have relational data packaged in a
container, you often wish to create various indices based on various
aspects of the data. This is currently unsupported by Boost, except for
Multi-Index, but Multi-Index does not allow you to create a detached
index; instead, it insists on maintaining all indices dynamically all the
time, which is not always necessary and it brings a performance penalty
compared to sorting static data.
I have implemented the missing adaptor and called it '''shufflebase''';
when applied to an adaptor, it allows the sort algorithm to rearrange the
''original container'' based on ''the ordering of the adaptor''.
Here is the adaptor code; note that it does not carry any algorithm, only
type juggling and general logistics:
{{{
#!c++
#include <boost/range/iterator_range.hpp> /* boost:: iterator_range
*/
#ifndef BOOST_RANGE_ADAPTOR_SHUFFLEBASE_DEFINED
#if 1
namespace boost {
/*
the following declarations are used in namespace adaptors;
they are here to keep the namespace in one piece */
#if 2
namespace traits { template < class P_I > struct shufflebase; }
#endif /* &boost.traits */
template < class P_I > class shufflebase_iterator;
#if 2
namespace adaptors {
/* a forward declaration for operator | */
template < class P_R > struct shufflebase_range;
#if 3
namespace detail
{ struct /* tag enabler for operator | */ shufflebase_forwarder {};
template < class P_R >
inline struct shufflebase_range < P_R const >
/* applies the shufflebase adaptor to a range */
operator | (P_R const &p_r, struct detail:: shufflebase_forwarder );
}
#endif /* &boost.adaptors.detail */
#if 3
namespace /* static */ {
detail :: shufflebase_forwarder const
/* the formal parameter for operator | */
(&shufflebase) ((detail ::shufflebase_forwarder ())); }
#endif /* &boost.adaptors.static */
#if 3
namespace traits { template < class P_T > struct shufflebase_range; }
#endif /* &boost.adaptors.traits & */
#if 3
template < class P_R >
/* applies shufflebase_iterator to the range */
struct shufflebase_range
:public traits ::shufflebase_range < P_R > ::base {
public:
inline shufflebase_range (P_R &p_r);
private: typedef traits ::shufflebase_range < P_R > traits;
private: typedef typename traits ::base base;
public: typedef typename traits ::iterator iterator; };
#endif /* #boost.adaptors.shufflebase_range */
#if 3
namespace traits {
#if 4
template < class P_R >
/* typedefs for shufflebase_range proper */ struct shufflebase_range
{ typedef
::boost :: shufflebase_iterator
< typename ::boost ::range_iterator < P_R > ::type > iterator;
typedef struct ::boost ::iterator_range < iterator > base; };
#endif /* #boost.adaptors.traits.shufflebase_range */
}
#endif /* &boost.adaptors.traits */
}
#endif /* &boost.adaptors */
#if 2
template < class P_I >
/*
Behaves transparently when applied to an adapted iterator
except that assignments are possible and apply to the underlying base */
class shufflebase_iterator
:public /* iterator faciade */ traits:: shufflebase < P_I >::
base_type
{
public:
/* constructs from an adapted iterator */
inline shufflebase_iterator (P_I const &);
public:
/* inherited */ typedef typename shufflebase_iterator ::reference
reference;
public: /* returns a proxy reference */
inline
reference
/* safety net: exclude application of default operator = to temporary */
const
operator* () const;
public:
/* inherited */ typedef typename shufflebase_iterator ::value_type
value_type;
public: /* assigns the value to the base element, bypassing the adaptor
*/
inline void assign (value_type const &p_v) const;
public:
/* bookkeeping */
typedef typename traits:: shufflebase < P_I >:: base_type inherited; };
#endif /* #boost.shufflebase_iterator */
#if 2
namespace detail { template < class P_I > class shufflebase_reference;
#if 3
template < class P_I >
/*
Stores a value of an iterator.
This class plays a double duty:
it stores the base value for assigning to a reference
and it caches the adapted value for comparisons.
This causes some memory overhead
that I believe is unavoidable
without knowing the details of the managed adaptor.
Moreover, caching the adapted value may speed things up a bit.
This class is necessary
because the sorting algorithm puts some values aside for later use. */
class shufflebase_value
{
public: /* bookkeeping */ typedef P_I base_type;
public: /* construct from a reference */
inline
shufflebase_value (class shufflebase_reference < base_type > const
&p_r);
public: /* the adapted value type */
typedef typename ::std ::iterator_traits < base_type > ::value_type
adapted;
public: /* compares as adapted */
inline operator adapted const &() const;
private: /* the adapted value */ adapted m_adapted;
public: /* the base value type */
typedef typename traits ::shufflebase < base_type > ::base_value
base_value;
private: /* the base value */ base_value m_base;
public:
/*
returns the base value for assignment
(the adapter is meant to affect the base container, remember? */
inline base_value const &base () const; };
#endif /* #boost.detail.shufflebase_value */
#if 3
template < class P_I >
/*
A proxy class serving as reference type for shufflebase_iterator.
Implicitly converts to the adapted reference for comparisons.
Assignment affects the base object instead.
*/
class shufflebase_reference
{
public: /* bookkeeping */ typedef P_I base_type;
public: /* the adapted reference type */ typedef
typename ::std ::iterator_traits < base_type > ::reference reference;
public: /* compares as adapted */
inline operator reference const () const;
public:
/* the adapted value type */
typedef class shufflebase_value < base_type > value_type;
public: /* assigned value goes to base */
inline
shufflebase_reference const
&operator= (value_type const &p_v) const;
public: /* constructor */ inline
shufflebase_reference (shufflebase_iterator < base_type > const &);
private:
/* the proxied iterator */
shufflebase_iterator < base_type > const &m_ref;
public: /* extract the base value for assigning to a value object */
inline
typename
::std ::iterator_traits < typename base_type:: base_type > ::value_type
const
&base () const;
private:
/* references are not assignable */
void operator = (shufflebase_reference const &); };
#endif /* #boost.detail.shufflebase_reference */
}
#endif /* &boost.detail */
#if 2
namespace traits {
#if 3
template < class P_I >
/* contains typedefs for shufflebase_iterator */ struct shufflebase
{
/* bookkeeping */ typedef P_I iterator;
/* the base type for shufflebase_iterator */
typedef ::boost ::iterator_adaptor
<
class shufflebase_iterator < iterator >, iterator,
class detail:: shufflebase_value < iterator >,
::boost:: use_default,
class detail:: shufflebase_reference < iterator >
> base_type;
/* the base value */ typedef
typename
::std ::iterator_traits < typename iterator ::base_type >:: value_type
base_value;
/*
The proper place to define base_value would be class shufflebase_value;
however, this type is shared by other auxiliary classes;
they depend on each other, causing the compiler to fail. */ };
#endif /* #boost.traits.shufflebase */
}
#endif /* &boost.traits */
}
#endif /* &boost */
#define BOOST_RANGE_ADAPTOR_SHUFFLEBASE_DEFINED
#endif
#ifndef BOOST_RANGE_ADAPTOR_SHUFFLEBASE_IMPLEMENTED
#if 1
namespace boost {
#if 2
namespace adaptors {
#if 3
namespace detail {
#if 4
template <class P_R >
inline struct shufflebase_range < P_R const >
operator | (P_R const &p_r, shufflebase_forwarder)
{ return shufflebase_range < P_R const > (p_r); }
#endif /* !boost.adaptors.shufflebase_range.operator| */
}
#endif /* &boost.adaptors.detail */
#if 3
template < class P_R >
inline shufflebase_range < P_R > ::shufflebase_range (P_R &p_r)
:base (iterator (::boost ::begin (p_r)), iterator (::boost ::end (p_r)))
{}
#endif /* !boost.adaptors.shufflebase_range.shufflebase_range */
}
#endif /* &boost.adaptors */
#if 2
template < class P_I >
inline typename shufflebase_iterator < P_I > ::reference const
shufflebase_iterator < P_I > ::operator * () const { return *this; }
#endif /* !boost.shufflebase_iterator.operator * */
#if 2
namespace detail {
#if 3
template < class P_I >
inline shufflebase_reference < P_I > ::operator reference const ()
const
{ return *this -> m_ref. base (); }
#endif /* !boost.detail.shufflebase_reference::reference */
#if 3
template < class P_I >
inline shufflebase_reference < P_I > const
&shufflebase_reference < P_I > ::operator = (value_type const &p_v)
const
{ this -> m_ref .assign (p_v); return *this; }
#endif /* !boost.detail.shufflebase_reference::operator = */
#if 3
template < class P_I >
inline shufflebase_reference < P_I > ::shufflebase_reference
(shufflebase_iterator < P_I > const &p_ref) :m_ref (p_ref) {}
#endif /* !boost.detail.shufflebase_reference.shufflebase_reference */
#if 3
template < class P_I >
inline shufflebase_value < P_I > ::shufflebase_value
(class shufflebase_reference < P_I > const &p_r)
:m_adapted (p_r), m_base (p_r. base ()) {}
#endif /* !boost.detail.shufflebase_value.shufflebase_value */
#if 3
template < class P_I >
inline shufflebase_value < P_I >:: operator adapted const & () const
{ return this -> m_adapted; }
#endif /* !boost.detail.shufflebase_value.adapted & */
#if 3
template < class P_I >
inline
typename ::std ::iterator_traits < typename P_I ::base_type > ::value_type
const
&shufflebase_reference < P_I > :: base () const
{ return *this -> m_ref .base () .base (); }
#endif /* !boost.detail.shufflebase_reference.base */
#if 3
template < class P_I >
typename shufflebase_value < P_I > ::base_value const
&shufflebase_value < P_I > ::base () const { return this -> m_base; }
#endif /* !boost.detail.shufflebase_value.base */
}
#endif /* &boost.detail */
#if 2
template < class P_I >
inline shufflebase_iterator < P_I >:: shufflebase_iterator (P_I const
&p_i)
:inherited (p_i) { }
#endif /* !boost.shufflebase_iterator. */
#if 2
template < class P_I >
inline void shufflebase_iterator < P_I > ::assign (value_type const &p_v)
const
{ *this -> base (). base () = p_v. base (); }
#endif /* !boost.shufflebase_iterator.assign */
}
#endif /* &boost */
#define BOOST_RANGE_ADAPTOR_SHUFFLEBASE_IMPLEMENTED
#endif
}}}
Having this, the following code becomes valid:
{{{
#!c++
#include <iostream>
#include <boost/array.hpp>
#include <boost/range/algorithm/copy.hpp>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/bind.hpp>
#include <boost/range/algorithm/sort.hpp>
struct underlying { int m_; };
int main (int, char *[]) {
enum LocalParam { BASE = 073, VALUE = 030 };
typedef ::boost ::array < underlying, +BASE - 01 > mycont; mycont v;
for
(::boost ::range_iterator < mycont >:: type p ((::boost ::begin (v)));
p < ::boost ::end (v); ++p)
p -> m_ = p == ::boost ::begin (v)? +VALUE: p [-01] .m_ * VALUE %
BASE;
::boost ::copy
(v
| ::boost ::adaptors ::transformed (::boost ::bind (&underlying ::m_,
_1)),
::std ::ostream_iterator
< int, ::std ::istream ::char_type >
(::std:: cout, " ")); ::std ::cout << '\n';
::boost ::sort
(v
| ::boost ::adaptors ::transformed (::boost ::bind (&underlying ::m_, _1))
| ::boost ::adaptors ::shufflebase);
::boost ::copy
(v
| ::boost ::adaptors ::transformed (::boost ::bind (&underlying ::m_,
_1)),
::std ::ostream_iterator
< int, ::std ::istream ::char_type >
(::std:: cout, " "));
return (::std ::cout << '\n') .flush ()? +EXIT_SUCCESS: +EXIT_FAILURE; }
}}}
and it produces the following output:
24 45 18 19 43 29 47 7 50 20 8 15 6 26 34 49 55 22 56 46 42 5 2 48 31 36
38 27 58 35 14 41 40 16 30 12 52 9 39 51 44 53 33 25 10 4 37 3 13 17 54 57
11 28 23 21 32 1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
54 55 56 57 58
-- Ticket URL: <https://svn.boost.org/trac/boost/ticket/6250> Boost C++ Libraries <http://www.boost.org/> Boost provides free peer-reviewed portable C++ source libraries.
This archive was generated by hypermail 2.1.7 : 2017-02-16 18:50:08 UTC