Related
I'm writing my own container class that also provides iterators. These iterators can be dereferenced and reveal then a sub-range of the original container, for which again an iterator can be obtained.
Currently, I've a template iterator class (using boost::iterator_facade) that dereferences to an Collection ("range") if L!=0 or to a T& (stored elements) if L==0. Is it possible combine both in one class, such that less duplicate code is needed?
template<typename T, int L>
class CollectionIter : public boost::iterator_facade<
CollectionIter<T,L>, // type it selfe
Collection<T,L-1>, // value type
boost::random_access_traversal_tag,
Collection<T,L-1> > // deref. type
{
public:
CollectionIter(T* ptr, const std::vector<int>& collectionSize_)
: pointer(ptr), collectionSize(collectionSize_) { }
T* element() { return pointer; }
private:
friend class boost::iterator_core_access;
bool equal(const CollectionIter<T,L>& other) const { return pointer==other.pointer; }
auto dereference() const { return Collection<T,L-1>(pointer, collectionSize); }
void increment() { pointer = pointer + stepsize(); }
void decrement() { pointer = pointer - stepsize(); }
void advance(size_t i) { pointer = pointer + i*stepsize(); }
auto distance_to(const CollectionIter<T,L>& other) { return (other.pointer - pointer)/stepsize(); }
int stepsize() { return collectionSize.at(L); }
T* pointer;
const std::vector<int>& collectionSize;
};
/* Groundlevel Collection: deref returns T& */
template<typename T>
class CollectionIter<T,0> : public boost::iterator_facade<
CollectionIter<T,0>,
T,
boost::random_access_traversal_tag >
{
public:
CollectionIter(T* ptr, const std::vector<int>& collectionSize_)
: pointer(ptr), collectionSize(collectionSize_) { assert(stepsize()==1); }
T* element() { return pointer; }
private:
friend class boost::iterator_core_access;
bool equal(const CollectionIter<T,0>& other) const { return pointer==other.pointer; }
T& dereference() const { return *pointer; }
void increment() { pointer = pointer + stepsize(); }
void decrement() { pointer = pointer - stepsize(); }
void advance(size_t i) { pointer = pointer + i*stepsize(); }
auto distance_to(const CollectionIter<T,0>& other) { return (other.pointer - pointer)/stepsize(); }
int stepsize() { return collectionSize.at(0); }
T* pointer;
const std::vector<int>& collectionSize;
};
I see only three differences in the two version of CollectionIter:
(1) the boost::iterator_facade() inherited class receive different arguments. You can solve this with std::conditional as suggested by Johannes Schaub; something like
public std::conditional< (L > 0U),
boost::iterator_facade<
CollectionIter<T, L>,
Collection<T, L-1U>,
boost::random_access_traversal_tag,
Collection<T, L-1U> >,
boost::iterator_facade<
CollectionIter<T, 0U>,
T,
boost::random_access_traversal_tag > >
(2) the assert(stepsize()==1); in the constructor is present only in the ground (L == 0U) version. You can modify it as
assert( (L > 0U) || (stepsize() == 1) );
(3) the recursive dereference() method is really different in the ground version. I'm not an expert of SFINAE but, if I'm not wrong, you can insert both as follows
template <int M = L, typename = std::enable_if_t<(M > 0U)>>
auto dereference () const
{ return Collection<T, L-1U>(pointer, collectionSize); }
template <int M = L, typename = std::enable_if_t<(M == 0U)>>
T & dereference () const
{ return *pointer; }
So the full class become (sorry: I've changed L in a std::size_t)
template <typename T, std::size_t L>
class CollectionIter :
public std::conditional< (L > 0U),
boost::iterator_facade<
CollectionIter<T, L>,
Collection<T, L-1U>,
boost::random_access_traversal_tag,
Collection<T, L-1U> >,
boost::iterator_facade<
CollectionIter<T, 0U>,
T,
boost::random_access_traversal_tag > >
{
public:
CollectionIter (T * ptr, const std::vector<int> & collectionSize_)
: pointer(ptr), collectionSize(collectionSize_)
{ assert( (L > 0U) || (stepsize() == 1) ); }
T* element() { return pointer; }
private:
friend class boost::iterator_core_access;
bool equal (const CollectionIter<T, L> & other) const
{ return pointer==other.pointer; }
template <int M = L, typename = std::enable_if_t<(M > 0U)>>
auto dereference () const
{ return Collection<T, L-1U>(pointer, collectionSize); }
template <int M = L, typename = std::enable_if_t<(M == 0U)>>
T & dereference () const
{ return *pointer; }
void increment ()
{ pointer = pointer + stepsize(); }
void decrement()
{ pointer = pointer - stepsize(); }
void advance (size_t i)
{ pointer = pointer + i*stepsize(); }
auto distance_to (const CollectionIter<T, L> & other)
{ return (other.pointer - pointer)/stepsize(); }
int stepsize()
{ return collectionSize.at(L); }
T * pointer;
const std::vector<int> & collectionSize;
};
Is it possible to rewrite this raw loop:
vector<double> v { ... };
for (size_t i = 1; i<v.size(); ++i) {
v[i]*=v[i-1];
}
or the even more cryptic:
for (auto i = v.begin()+1; i<v.end(); ++i) {
(*i) *= *(i-1);
}
(and similar, maybe accessing also v[i-2], ...) in a more STLish way?
Are there other forms which are equal or better (both in style and performances) than the ones above?
The most STLish way I can imagine:
std::partial_sum(std::begin(v), std::end(v),
std::begin(v), std::multiplies<double>());
Example:
#include <iostream>
#include <vector>
#include <iterator>
#include <numeric>
#include <functional>
int main()
{
std::vector<double> v{ 1.0, 2.0, 3.0, 4.0 };
std::partial_sum(std::begin(v), std::end(v),
std::begin(v), std::multiplies<double>());
std::copy(std::begin(v), std::end(v),
std::ostream_iterator<double>(std::cout, " "));
}
Output:
1 2 6 24
Live demo link.
You can do that with std::transform, the overload that takes two input sequences:
int container[] = {1,2,3};
std::transform(
std::begin(container), std::end(container) - 1,
std::begin(container) + 1, std::begin(container) + 1,
[](auto a, auto b) { return a * b; }
);
But the hand-coded loop is much more readable.
If you want a generic way to do sliding windows rather than a non-transferable STL-ish way to answer your particular problem, you could consider the following ridiculous nonsense:
#include <array>
#include <cstddef>
#include <memory>
#include <tuple>
namespace detail {
template<std::size_t, typename>
class slide_iterator;
}
template<std::size_t N, typename I>
detail::slide_iterator<N, I> slide_begin(const I&);
template<std::size_t N, typename I>
detail::slide_iterator<N, I> slide_end(const I&);
namespace detail {
template<std::size_t N, typename T, typename... Args>
struct repeat {
typedef typename repeat<N - 1, T, T, Args...>::type type;
template<typename I>
type operator()(const I& it, Args&... args) const {
auto jt = it;
return repeat<N - 1, T, T, Args...>()(++jt, args..., *it);
}
};
template<typename T, typename... Args>
struct repeat<0, T, Args...> {
typedef std::tuple<Args&...> type;
template<typename I>
type operator()(const I&, Args&... args) const {
return type(args...);
}
};
template<std::size_t N, typename I /* forward iterator */>
class slide_iterator {
public:
typedef slide_iterator iterator;
typedef decltype(*I{}) reference;
typedef typename repeat<N, reference>::type window_tuple;
slide_iterator() = default;
~slide_iterator() = default;
slide_iterator(const iterator& it) = default;
iterator& operator=(const iterator& it) = default;
window_tuple operator*() const {
return repeat<N, reference>()(first_);
}
iterator& operator++() { // prefix
++first_;
++last_;
return *this;
}
iterator operator++(int) { // postfix
auto tmp{*this};
operator++();
return tmp;
}
friend void swap(iterator& lhs, iterator& rhs) {
swap(lhs.first_, rhs.first_);
swap(lhs.last_, rhs.last_);
swap(lhs.dirty_, rhs.dirty_);
swap(lhs.window_, rhs.window_);
}
friend bool operator==(const iterator& lhs, const iterator& rhs) {
return lhs.last_ == rhs.last_;
}
friend bool operator!=(const iterator& lhs, const iterator& rhs) {
return !operator==(lhs, rhs);
}
friend iterator slide_begin<N, I>(const I& it);
friend iterator slide_end<N, I>(const I& it);
private:
I first_;
I last_; // for equality only
};
template<typename T, std::size_t N>
struct slide_helper {
T& t;
auto begin() -> decltype(slide_begin<N>(t.begin())) {
return slide_begin<N>(t.begin());
}
auto end() -> decltype(slide_end<N>(t.end())) {
return slide_end<N>(t.end());
}
};
} // ::detail
// note it is undefined to call slide_begin<N>() on an iterator which cannot
// be incremented at least N - 1 times
template<std::size_t N, typename I>
detail::slide_iterator<N, I> slide_begin(const I& it) {
detail::slide_iterator<N, I> r;
r.first_ = r.last_ = it;
std::advance(r.last_, N - 1);
return r;
}
template<std::size_t N, typename I>
detail::slide_iterator<N, I> slide_end(const I& it) {
detail::slide_iterator<N, I> r;
r.last_ = it;
return r;
}
template<std::size_t N, typename T>
detail::slide_helper<T, N> slide(T& t) {
return {t};
}
Example usage:
#include <iostream>
#include <vector>
int main() {
std::vector<int> v{1, 2, 3, 4};
/* helper for
for (auto it = slide_begin<2>(v.begin()),
et = slide_end<2>(v.end()); it != et ... BLAH BLAH BLAH */
for (const auto& t : slide<2>(v)) {
std::get<1>(t) *= std::get<0>(t);
}
for (const auto& i : v) {
std::cout << i << std::endl;
}
}
This is an implementation that keeps an array of iterators of size N under the hood to produce a sliding window:
namespace details {
template<unsigned...>struct indexes { using type=indexes; };
template<unsigned max, unsigned... is>struct make_indexes:make_indexes<max-1, max-1, is...>{};
template<unsigned... is>struct make_indexes<0,is...>:indexes<is...>{};
template<unsigned max>using make_indexes_t=typename make_indexes<max>::type;
template<bool b, class T=void>
using enable_if_t=typename std::enable_if<b,T>::type;
struct list_tag {};
struct from_iterator_tag {};
template<unsigned N, class Iterator>
struct iterator_array {
private:
std::array<Iterator,N> raw;
size_t index = 0;
static Iterator to_elem(Iterator& it, Iterator end, bool advance=true) {
if (it == end) return end;
if (advance) return ++it;
return it;
}
template< unsigned...Is>
iterator_array( indexes<Is...>, from_iterator_tag, Iterator& it, Iterator end ):
raw( {to_elem(it, end, false), (void(Is), to_elem(it,end))...} )
{}
public:
Iterator begin() const { return raw[index]; }
Iterator end() const { return std::next(raw[(index+N-1)%N]); }
void push_back( Iterator it ) {
raw[index] = it;
index = (index+1)%N;
}
iterator_array( from_iterator_tag, Iterator& it, Iterator end ):iterator_array( make_indexes<N-1>{}, from_iterator_tag{}, it, end ) {}
iterator_array( iterator_array const& o )=default;
iterator_array() = default; // invalid!
iterator_array& operator=( iterator_array const& o )=delete;
typedef decltype(*std::declval<Iterator>()) reference_type;
reference_type operator[](std::size_t i)const{return *(raw[ (i+index)%N ]);}
};
struct sentinal_tag {};
template<class I>using value_type_t=typename std::iterator_traits<I>::value_type;
template<class I, unsigned N>
class slide_iterator:public std::iterator<
std::forward_iterator_tag,
iterator_array<N,I>,
iterator_array<N,I>*,
iterator_array<N,I> const&
> {
I current;
mutable bool bread = false;
typedef iterator_array<N,I> value_type;
mutable value_type data;
void ensure_read() const {
if (!bread) {
data.push_back(current);
}
bread = true;
}
public:
slide_iterator& operator++() { ensure_read(); ++current; bread=false; return *this; }
slide_iterator operator++(int) { slide_iterator retval=*this; ++*this; return retval; }
value_type const& operator*() const { ensure_read(); return data; }
bool operator==(slide_iterator const& o){return current==o.current;}
bool operator!=(slide_iterator const& o){return current!=o.current;}
bool operator<(slide_iterator const& o){return current<o.current;}
bool operator>(slide_iterator const& o){return current>o.current;}
bool operator<=(slide_iterator const& o){return current<=o.current;}
bool operator>=(slide_iterator const& o){return current>=o.current;}
explicit slide_iterator( I start, I end ):current(start), bread(true), data(from_iterator_tag{}, current, end) {}
explicit slide_iterator( sentinal_tag, I end ):current(end) {}
};
}
template<class Iterator, unsigned N>
struct slide_range_t {
using iterator=details::slide_iterator<Iterator, N>;
iterator b;
iterator e;
slide_range_t( Iterator start, Iterator end ):
b( start, end ),
e( details::sentinal_tag{}, end )
{}
slide_range_t( slide_range_t const& o )=default;
slide_range_t() = delete;
iterator begin() const { return b; }
iterator end() const { return e; }
};
template<unsigned N, class Iterator>
slide_range_t< Iterator, N > slide_range( Iterator b, Iterator e ) {
return {b,e};
}
live example
Note that the elements of your slide range are themselves iterable. A further improvement would be to specialize for random-access iterators and only store the begin/end pair in that case.
Sample use:
int main() {
std::vector<int> foo(33);
for (int i = 0; i < foo.size(); ++i)
foo[i]=i;
for( auto&& r:slide_range<3>(foo.begin(), foo.end()) ) {
for (int x : r) {
std::cout << x << ",";
}
std::cout << "\n";
}
// your code goes here
return 0;
}
I'm writing a library that uses expression templates with CRTP. The source files can be found here: https://github.com/mspraggs/pyQCD/tree/master/lib/include/base
The expression templates are based on the example given in the Wikipedia article on the subject. I list the code here in case the Wiki article changes in future:
#include <vector>
#include <cassert>
template <typename E>
// A CRTP base class for Vecs with a size and indexing:
class VecExpression {
public:
typedef std::vector<double> container_type;
typedef container_type::size_type size_type;
typedef container_type::value_type value_type;
typedef container_type::reference reference;
size_type size() const { return static_cast<E const&>(*this).size(); }
value_type operator[](size_type i) const { return static_cast<E const&>(*this)[i]; }
operator E&() { return static_cast< E&>(*this); }
operator E const&() const { return static_cast<const E&>(*this); }
};
// The actual Vec class:
class Vec : public VecExpression<Vec> {
container_type _data;
public:
reference operator[](size_type i) { return _data[i]; }
value_type operator[](size_type i) const { return _data[i]; }
size_type size() const { return _data.size(); }
Vec(size_type n) : _data(n) {} // Construct a given size:
// Construct from any VecExpression:
template <typename E>
Vec(VecExpression<E> const& vec) {
E const& v = vec;
_data.resize(v.size());
for (size_type i = 0; i != v.size(); ++i) {
_data[i] = v[i];
}
}
};
template <typename E1, typename E2>
class VecDifference : public VecExpression<VecDifference<E1, E2> > {
E1 const& _u;
E2 const& _v;
public:
typedef Vec::size_type size_type;
typedef Vec::value_type value_type;
VecDifference(VecExpression<E1> const& u, VecExpression<E2> const& v) : _u(u), _v(v) {
assert(u.size() == v.size());
}
size_type size() const { return _v.size(); }
value_type operator[](Vec::size_type i) const { return _u[i] - _v[i]; }
};
template <typename E>
class VecScaled : public VecExpression<VecScaled<E> > {
double _alpha;
E const& _v;
public:
VecScaled(double alpha, VecExpression<E> const& v) : _alpha(alpha), _v(v) {}
Vec::size_type size() const { return _v.size(); }
Vec::value_type operator[](Vec::size_type i) const { return _alpha * _v[i]; }
};
// Now we can overload operators:
template <typename E1, typename E2>
VecDifference<E1,E2> const
operator-(VecExpression<E1> const& u, VecExpression<E2> const& v) {
return VecDifference<E1,E2>(u,v);
}
template <typename E>
VecScaled<E> const
operator*(double alpha, VecExpression<E> const& v) {
return VecScaled<E>(alpha,v);
}
What I want to do is add another expression template that allows assignment to part of the original template object (the Vec class in the code above, and the LatticeBase class in the code I've linked to). Possible usage:
Vec myvector(10);
Vec another_vector(5);
myvector.head(5) = another_vector; // Assign first 5 elements on myvector
myvector.head(2) = another_vector.head(2); // EDIT
So I'd create a new function Vec::head that would a return an expression template for a portion of the Vec object. I don't know how this would fit into the framework I currently have. In particular I have the following questions/comments:
I've seen examples of what I want to achieve in expression templates that don't use CRTP. What do I gain by using CRTP in this case? Is there any point? Should I ditch it and follow the other examples I've found?
In the current framework, the assignment to the _data member in the Vec class is handled by a copy constructor in the Vec class. This won't work if I want to use the expression template returned by Vec::head, since the assignment happens within the class that holds the data, not the expression template.
I've tried creating an assignment operator within the new expression template, but that won't work with the code above as all the expression template members are const references, and so the assignment operator is deleted at compile time. Can I just switch the members to being values instead of references? Will this impact on performance if additional storage is needed? Will this even work (if I change a stored copy of the expression rather than the expression itself)?
Overall I'm confused about how to go about adding an expression template that can be used as an lvalue in the code above. Any guidance on this would be greatly appreciated.
Try this:
#include <vector>
#include <cassert>
template <typename E>
// A CRTP base class for Vecs with a size and indexing:
class VecExpression {
public:
typedef std::vector<double> container_type;
typedef container_type::size_type size_type;
typedef container_type::value_type value_type;
typedef container_type::reference reference;
size_type size() const { return static_cast<E const&>(*this).size(); }
value_type operator[](size_type i) const { return static_cast<E const&>(*this)[i]; }
operator E&() { return static_cast<E&>(*this); }
operator E const&() const { return static_cast<const E&>(*this); }
};
class VecHead;
// The actual Vec class:
class Vec : public VecExpression<Vec> {
container_type _data;
public:
reference operator[](size_type i) { return _data[i]; }
value_type operator[](size_type i) const { return _data[i]; }
size_type size() const { return _data.size(); }
Vec(size_type n) : _data(n) {} // Construct a given size:
// Construct from any VecExpression:
template <typename E>
Vec(VecExpression<E> const& vec) {
E const& v = vec;
_data.resize(v.size());
for (size_type i = 0; i != v.size(); ++i) {
_data[i] = v[i];
}
}
VecHead head(size_type s);
};
class VecHead : public VecExpression< VecHead >
{
Vec::size_type _s;
Vec& _e;
public:
typedef Vec::size_type size_type;
typedef Vec::value_type value_type;
VecHead(std::size_t s, Vec& e)
: _s(s)
, _e(e)
{
assert(_e.size() >= _s);
}
size_type size() const { return _s; }
value_type operator[](Vec::size_type i) const { assert(i < _s); return _e[i]; }
VecHead& operator = (const VecHead& rhs)
{
return operator=(static_cast<const VecExpression<VecHead>&>(rhs));
}
template <typename E>
VecHead& operator = (const VecExpression<E>& rhs)
{
assert(rhs.size() >= _s);
for (size_type i = 0; i < _s && i < rhs.size(); ++i)
_e[i] = rhs[i];
return *this;
}
};
VecHead Vec::head(size_type s)
{
VecHead aHead(s, *this);
return aHead;
}
template <typename E1, typename E2>
class VecDifference : public VecExpression<VecDifference<E1, E2> > {
E1 const& _u;
E2 const& _v;
public:
typedef Vec::size_type size_type;
typedef Vec::value_type value_type;
VecDifference(VecExpression<E1> const& u, VecExpression<E2> const& v) : _u(u), _v(v) {
assert(u.size() == v.size());
}
size_type size() const { return _v.size(); }
value_type operator[](Vec::size_type i) const { return _u[i] - _v[i]; }
};
template <typename E>
class VecScaled : public VecExpression<VecScaled<E> > {
double _alpha;
E const& _v;
public:
VecScaled(double alpha, VecExpression<E> const& v) : _alpha(alpha), _v(v) {}
Vec::size_type size() const { return _v.size(); }
Vec::value_type operator[](Vec::size_type i) const { return _alpha * _v[i]; }
};
// Now we can overload operators:
template <typename E1, typename E2>
VecDifference<E1, E2> const
operator-(VecExpression<E1> const& u, VecExpression<E2> const& v) {
return VecDifference<E1, E2>(u, v);
}
template <typename E>
VecScaled<E> const
operator*(double alpha, VecExpression<E> const& v) {
return VecScaled<E>(alpha, v);
}
int main()
{
Vec myvector(10);
Vec another_vector(5);
for (int i = 0; i < 5; ++i)
another_vector[i] = i;
myvector.head(5) = another_vector; // Assign first 5 elements on myvector
assert(myvector.head(5).size() == 5);
for (int i = 0; i < 10; ++i)
{
assert(myvector[i] == (i < 5 ? static_cast<double>(i) : 0.));
}
//! Added test due to comment vec1.head(2) = vec2.head(2) doesn't work.
Vec vec1(10), vec2(10);
for (int i = 0; i < 10; ++i)
vec2[i] = 2 * (vec1[i] = i);
vec1.head(2) = vec2.head(2);
for (int i = 0; i < 10; ++i)
{
if (i < 2)
{
assert(vec1[i] == vec2[i]);
}
else
{
assert(vec1[i] != vec2[i]);
}
}
return 0;
}
For supercomputing simulation purpose, I have a structure that contains two big (billions of elements) std::vector: one std::vector of "keys" (64 bits integers) and one std::vector of "values". I cannot use a std::map because in the simulations I consider, vectors are far more optimal than std::map. Moreover, I cannot use a vector of pairs because of some optimization and cache efficiency provided by separate vectors. Moreover I cannot use any extra memory.
So, considering these constaints, what is the most optimized way to sort the two vectors by increasing values of the keys ? (template metaprogramming and crazy compile-time tricks are welcome)
Two ideas off the top of my head:
Take a quicksort implementation and apply it to the "key" vector; but modify the code so that every time it does a swap on the key vector, it also performs the same swap on the value vector.
Or, perhaps more in keeping with the spirit of C++, write a custom "wrapper" iterator which iterates over both vectors at once (returning a std::pair when dereferenced). Perhaps Boost has one? You could then combine this with std::sort and a custom comparison function which considers only the "key".
EDIT:
I've used the first suggestion here for a similar problem back in a past life as a C programmer. It's far from ideal for obvious reasons, but it's possibly the quickest way to get something going.
I haven't tried a wrapper iterator like this with std::sort, but TemplateRex in the comments says it won't work, and I'm happy to defer to him on that one.
I think problem may be splitted into 2 independent parts:
How to make effective iterator for virtual map
Which sorting alorithm to use
Iterator
Implementing iterator the main problem how to return pair of key/value not creating
unnecessary copies. We can achieve it by using different types for value_type & reference. My implementation is here.
template <typename _Keys, typename _Values>
class virtual_map
{
public:
typedef typename _Keys::value_type key_type;
typedef typename _Values::value_type mapped_type;
typedef std::pair<key_type, mapped_type> value_type;
typedef std::pair<key_type&, mapped_type&> proxy;
typedef std::pair<const key_type&, const mapped_type&> const_proxy;
class iterator :
public boost::iterator_facade < iterator, value_type, boost::random_access_traversal_tag, proxy >
{
friend class boost::iterator_core_access;
public:
iterator(virtual_map *map_, size_t offset_) :
map(map_),
offset(offset_)
{}
iterator(const iterator &other_)
{
this->map = other_.map;
this->offset = other_.offset;
}
private:
bool equal(const iterator &other) const
{
assert(this->map == other.map);
return this->offset == other.offset;
}
void increment() { ++offset; }
void decrement() { --offset; }
void advance(difference_type n) { offset += n; }
reference dereference() const { return reference(map->keys[offset], map->values[offset]); }
difference_type distance_to(const iterator &other_) const { return other_.offset - this->offset; }
private:
size_t offset;
virtual_map *map;
};
public:
virtual_map(_Keys &keys_, _Values &values_) :
keys(keys_),
values(values_)
{
if(keys_.size() != values_.size())
throw std::runtime_error("different size");
}
public:
iterator begin() { return iterator(this, 0); }
iterator end() { return iterator(this, keys.size()); }
protected:
_Keys &keys;
_Values &values;
};
usage sample:
int main(int argc, char* const argv[])
{
std::vector<int> keys_ = { 17, 2, 13, 4, 51, 78, 49, 37, 1 };
std::vector<std::string> values_ = { "17", "2", "13", "4", "51", "78", "49", "37", "1" };
typedef virtual_map<std::vector<int>, std::vector<std::string>> map;
map map_(keys_, values_);
std::sort(std::begin(map_), std::end(map_), [](map::const_proxy left_, map::const_proxy right_)
{
return left_.first < right_.first;
});
return 0;
}
Sorting algorithm
Its very hard to reason which method better without additional details. What memory restriction do you have? Is it possible to use concurrency?
There are some issues:
Iterating both sequences together requires a pair representing
references to the sequence elements - that pair, itself, is no
reference. Hence, algorithms working on references will not work.
Performance will degenerate (the sequences are loosely coupled) -
An implementation using a pair of references and std::sort:
// Copyright (c) 2014 Dieter Lucking. 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)
#include <algorithm>
#include <chrono>
#include <memory>
#include <iostream>
// None
// ============================================================================
/// A void type
struct None {
None()
{}
/// Explicit conversion to None.
template <typename T>
explicit None(const T&)
{}
template <typename T>
None& operator = (const T&) {
return *this;
}
/// Never null.
None* operator & () const;
};
extern None& none();
inline None* None::operator & () const { return &none(); }
None& none() {
static None result;
return result;
}
// IteratorAdaptorTraits
// ============================================================================
namespace Detail {
// IteratorAdaptorTraits
// =====================
template <typename Iterator, typename ReturnType, bool IsReference>
struct IteratorAdaptorTraits;
// No reference
// ============
template <typename Iterator, typename ReturnType>
struct IteratorAdaptorTraits<Iterator, ReturnType, false>
{
typedef Iterator iterator_type;
typedef ReturnType return_type;
typedef ReturnType value_type;
typedef None reference;
typedef None pointer;
static_assert(
! std::is_base_of<None, return_type>::value,
"None as return type.");
template <typename Accessor>
static return_type iterator_value(const Accessor& accessor, const Iterator& iterator) {
return accessor.value(iterator);
}
template <typename Accessor>
static pointer iterator_pointer(const Accessor& accessor, const Iterator& iterator) {
return &none();
}
};
// Reference
// =========
template <typename Iterator, typename ReturnType>
struct IteratorAdaptorTraits<Iterator, ReturnType, true>
{
typedef Iterator iterator_type;
typedef ReturnType return_type;
typedef typename std::remove_reference<ReturnType>::type value_type;
typedef ReturnType reference;
typedef value_type* pointer;
static_assert(
! std::is_base_of<None, return_type>::value,
"None as return type.");
template <typename Accessor>
static return_type iterator_value(const Accessor& accessor, const Iterator& iterator) {
return accessor.value(iterator);
}
template <typename Accessor>
static pointer iterator_pointer(const Accessor& accessor, const Iterator& iterator) {
return &accessor.value(iterator);
}
};
} // namespace Detail
// RandomAccessIteratorAdaptor
// ============================================================================
/// An adaptor around a random access iterator.
/// \ATTENTION The adaptor will not fulfill the standard iterator requierments,
/// if the accessor does not support references: In that case, the
/// reference and pointer type are None.
template <typename Iterator, typename Accessor>
class RandomAccessIteratorAdaptor
{
// Types
// =====
private:
static_assert(
! std::is_base_of<None, Accessor>::value,
"None as accessor.");
static_assert(
! std::is_base_of<None, typename Accessor::return_type>::value,
"None as return type.");
typedef typename Detail::IteratorAdaptorTraits<
Iterator,
typename Accessor::return_type,
std::is_reference<typename Accessor::return_type>::value
> Traits;
public:
typedef typename Traits::iterator_type iterator_type;
typedef Accessor accessor_type;
typedef typename std::random_access_iterator_tag iterator_category;
typedef typename std::ptrdiff_t difference_type;
typedef typename Traits::return_type return_type;
typedef typename Traits::value_type value_type;
typedef typename Traits::reference reference;
typedef typename Traits::pointer pointer;
typedef typename accessor_type::base_type accessor_base_type;
typedef RandomAccessIteratorAdaptor<iterator_type, accessor_base_type> base_type;
// Tag
// ===
public:
struct RandomAccessIteratorAdaptorTag {};
// Construction
// ============
public:
explicit RandomAccessIteratorAdaptor(
iterator_type iterator, const accessor_type& accessor = accessor_type())
: m_iterator(iterator), m_accessor(accessor)
{}
template <typename IteratorType, typename AccessorType>
explicit RandomAccessIteratorAdaptor(const RandomAccessIteratorAdaptor<
IteratorType, AccessorType>& other)
: m_iterator(other.iterator()), m_accessor(other.accessor())
{}
// Element Access
// ==============
public:
/// The underlaying accessor.
const accessor_type& accessor() const { return m_accessor; }
/// The underlaying iterator.
const iterator_type& iterator() const { return m_iterator; }
/// The underlaying iterator.
iterator_type& iterator() { return m_iterator; }
/// The underlaying iterator.
operator iterator_type () const { return m_iterator; }
/// The base adaptor.
base_type base() const {
return base_type(m_iterator, m_accessor.base());
}
// Iterator
// ========
public:
return_type operator * () const {
return Traits::iterator_value(m_accessor, m_iterator);
}
pointer operator -> () const {
return Traits::iterator_pointer(m_accessor, m_iterator);
}
RandomAccessIteratorAdaptor increment() const {
return ++RandomAccessIteratorAdaptor(*this);
}
RandomAccessIteratorAdaptor increment_n(difference_type n) const {
RandomAccessIteratorAdaptor tmp(*this);
tmp.m_iterator += n;
return tmp;
}
RandomAccessIteratorAdaptor decrement() const {
return --RandomAccessIteratorAdaptor(*this);
}
RandomAccessIteratorAdaptor decrement_n(difference_type n) const {
RandomAccessIteratorAdaptor tmp(*this);
tmp.m_iterator -= n;
return tmp;
}
RandomAccessIteratorAdaptor& operator ++ () {
++m_iterator;
return *this;
}
RandomAccessIteratorAdaptor operator ++ (int) {
RandomAccessIteratorAdaptor tmp(*this);
++m_iterator;
return tmp;
}
RandomAccessIteratorAdaptor& operator += (difference_type n) {
m_iterator += n;
return *this;
}
RandomAccessIteratorAdaptor& operator -- () {
--m_iterator;
return *this;
}
RandomAccessIteratorAdaptor operator -- (int) {
RandomAccessIteratorAdaptor tmp(*this);
--m_iterator;
return tmp;
}
RandomAccessIteratorAdaptor& operator -= (difference_type n) {
m_iterator -= n;
return *this;
}
bool equal(const RandomAccessIteratorAdaptor& other) const {
return this->m_iterator == other.m_iterator;
}
bool less(const RandomAccessIteratorAdaptor& other) const {
return this->m_iterator < other.m_iterator;
}
bool less_equal(const RandomAccessIteratorAdaptor& other) const {
return this->m_iterator <= other.m_iterator;
}
bool greater(const RandomAccessIteratorAdaptor& other) const {
return this->m_iterator > other.m_iterator;
}
bool greater_equal(const RandomAccessIteratorAdaptor& other) const {
return this->m_iterator >= other.m_iterator;
}
private:
iterator_type m_iterator;
accessor_type m_accessor;
};
template <typename Iterator, typename Accessor>
inline RandomAccessIteratorAdaptor<Iterator, Accessor> operator + (
const RandomAccessIteratorAdaptor<Iterator, Accessor>& i,
typename RandomAccessIteratorAdaptor<Iterator, Accessor>::difference_type n) {
return i.increment_n(n);
}
template <typename Iterator, typename Accessor>
inline RandomAccessIteratorAdaptor<Iterator, Accessor> operator - (
const RandomAccessIteratorAdaptor<Iterator, Accessor>& i,
typename RandomAccessIteratorAdaptor<Iterator, Accessor>::difference_type n) {
return i.decrement_n(n);
}
template <typename Iterator, typename Accessor>
inline typename RandomAccessIteratorAdaptor<Iterator, Accessor>::difference_type
operator - (
const RandomAccessIteratorAdaptor<Iterator, Accessor>& a,
const RandomAccessIteratorAdaptor<Iterator, Accessor>& b) {
return a.iterator() - b.iterator();
}
template <typename Iterator, typename Accessor>
inline bool operator == (
const RandomAccessIteratorAdaptor<Iterator, Accessor>& a,
const RandomAccessIteratorAdaptor<Iterator, Accessor>& b) {
return a.equal(b);
}
template <typename Iterator, typename Accessor>
inline bool operator != (
const RandomAccessIteratorAdaptor<Iterator, Accessor>& a,
const RandomAccessIteratorAdaptor<Iterator, Accessor>& b) {
return ! a.equal(b);
}
template <typename Iterator, typename Accessor>
inline bool operator < (
const RandomAccessIteratorAdaptor<Iterator, Accessor>& a,
const RandomAccessIteratorAdaptor<Iterator, Accessor>& b) {
return a.less(b);
}
template <typename Iterator, typename Accessor>
inline bool operator <= (
const RandomAccessIteratorAdaptor<Iterator, Accessor>& a,
const RandomAccessIteratorAdaptor<Iterator, Accessor>& b) {
return a.less_equal(b);
}
template <typename Iterator, typename Accessor>
inline bool operator > (
const RandomAccessIteratorAdaptor<Iterator, Accessor>& a,
const RandomAccessIteratorAdaptor<Iterator, Accessor>& b) {
return a.greater(b);
}
template <typename Iterator, typename Accessor>
inline bool operator >= (
const RandomAccessIteratorAdaptor<Iterator, Accessor>& a,
const RandomAccessIteratorAdaptor<Iterator, Accessor>& b) {
return a.greater_equal(b);
}
// ElementPair
// ============================================================================
/// A pair of references which can mutate to a pair of values.
/// \NOTE If the key is one or two the pair is less comparable
/// regarding the first or second element.
template <typename First, typename Second, unsigned Key = 0>
class ElementPair
{
// Types
// =====
public:
typedef First first_type;
typedef Second second_type;
// Construction
// ============
public:
/// Reference
/// \POSTCONDITION reference() returns true
ElementPair(first_type& first, second_type& second)
: m_first(&first), m_second(&second)
{}
/// Copy construction
/// \POSTCONDITION reference() returns false
ElementPair(const ElementPair& other)
: m_first(new(m_first_storage) first_type(*other.m_first)),
m_second(new(&m_second_storage) second_type(*other.m_second))
{}
/// Move construction
/// \POSTCONDITION reference() returns false
ElementPair(ElementPair&& other)
: m_first(new(m_first_storage) first_type(std::move(*other.m_first))),
m_second(new(m_second_storage) second_type(std::move(*other.m_second)))
{}
~ElementPair() {
if( ! reference()) {
reinterpret_cast<first_type*>(m_first_storage)->~first_type();
reinterpret_cast<second_type*>(m_second_storage)->~second_type();
}
}
// Assignment
// ==========
public:
/// Swap content.
void swap(ElementPair& other) {
std::swap(*m_first, *other.m_first);
std::swap(*m_second, *other.m_second);
}
/// Assign content.
ElementPair& operator = (const ElementPair& other) {
if(&other != this) {
*m_first = *other.m_first;
*m_second = *other.m_second;
}
return *this;
}
/// Assign content.
ElementPair& operator = (ElementPair&& other) {
if(&other != this) {
*m_first = std::move(*other.m_first);
*m_second = std::move(*other.m_second);
}
return *this;
}
// Element Access
// ==============
public:
/// True if the pair holds references to external elements.
bool reference() {
return (m_first != reinterpret_cast<first_type*>(m_first_storage));
}
const first_type& first() const { return *m_first; }
first_type& first() { return *m_first; }
const second_type& second() const { return *m_second; }
second_type& second() { return *m_second; }
private:
first_type* m_first;
typename std::aligned_storage<
sizeof(first_type),
std::alignment_of<first_type>::value>::type
m_first_storage[1];
second_type* m_second;
typename std::aligned_storage<
sizeof(second_type),
std::alignment_of<second_type>::value>::type
m_second_storage[1];
};
// Compare
// =======
template <typename First, typename Second>
inline bool operator < (
const ElementPair<First, Second, 1>& a,
const ElementPair<First, Second, 1>& b)
{
return (a.first() < b.first());
}
template <typename First, typename Second>
inline bool operator < (
const ElementPair<First, Second, 2>& a,
const ElementPair<First, Second, 2>& b)
{
return (a.second() < b.second());
}
// Swap
// ====
namespace std {
template <typename First, typename Second, unsigned Key>
inline void swap(
ElementPair<First, Second, Key>& a,
ElementPair<First, Second, Key>& b)
{
a.swap(b);
}
}
// SequencePairAccessor
// ============================================================================
template <typename FirstSequence, typename SecondSequence, unsigned Keys = 0>
class SequencePairAccessor
{
// Types
// =====
public:
typedef FirstSequence first_sequence_type;
typedef SecondSequence second_sequence_type;
typedef typename first_sequence_type::size_type size_type;
typedef typename first_sequence_type::value_type first_type;
typedef typename second_sequence_type::value_type second_type;
typedef typename first_sequence_type::iterator iterator;
typedef None base_type;
typedef ElementPair<first_type, second_type, Keys> return_type;
// Construction
// ============
public:
SequencePairAccessor(first_sequence_type& first, second_sequence_type& second)
: m_first_sequence(&first), m_second_sequence(&second)
{}
// Element Access
// ==============
public:
base_type base() const { return base_type(); }
return_type value(iterator pos) const {
return return_type(*pos, (*m_second_sequence)[pos - m_first_sequence->begin()]);
}
// Data
// ====
private:
first_sequence_type* m_first_sequence;
second_sequence_type* m_second_sequence;
};
This test shows a degenaration of performance (on my system) by a factor of 1.5 for const char* and a factor of 3.4 for a std::string (compared to a single vector holding std::pair(s)).
// Test
// ============================================================================
#define SAMPLE_SIZE 1e1
#define VALUE_TYPE const char*
int main() {
const unsigned samples = SAMPLE_SIZE;
typedef int key_type;
typedef VALUE_TYPE value_type;
typedef std::vector<key_type> key_sequence_type;
typedef std::vector<value_type> value_sequence_type;
typedef SequencePairAccessor<key_sequence_type, value_sequence_type, 1> accessor_type;
typedef RandomAccessIteratorAdaptor<
key_sequence_type::iterator,
accessor_type>
iterator_adaptor_type;
key_sequence_type keys;
value_sequence_type values;
keys.reserve(samples);
values.reserve(samples);
const char* words[] = { "Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine" };
for(unsigned i = 0; i < samples; ++i) {
key_type k = i % 10;
keys.push_back(k);
values.push_back(words[k]);
}
accessor_type accessor(keys, values);
std::random_shuffle(
iterator_adaptor_type(keys.begin(), accessor),
iterator_adaptor_type(keys.end(), accessor)
);
if(samples <= 10) {
std::cout << "\nRandom:\n"
<< "======\n";
for(unsigned i = 0; i < keys.size(); ++i)
std::cout << keys[i] << ": " << values[i] << '\n';
}
typedef std::pair<key_type, value_type> pair_type;
std::vector<pair_type> ref;
for(const auto& k: keys) {
ref.push_back(pair_type(k, words[k]));
}
struct Less {
bool operator () (const pair_type& a, const pair_type& b) const {
return a.first < b.first;
}
};
auto ref_start = std::chrono::system_clock::now();
std::sort(ref.begin(), ref.end(), Less());
auto ref_end = std::chrono::system_clock::now();
auto ref_elapsed = double((ref_end - ref_start).count())
/ std::chrono::system_clock::period::den;
auto start = std::chrono::system_clock::now();
std::sort(
iterator_adaptor_type(keys.begin(), accessor),
iterator_adaptor_type(keys.end(), accessor)
);
auto end = std::chrono::system_clock::now();
auto elapsed = double((end - start).count())
/ std::chrono::system_clock::period::den;;
if(samples <= 10) {
std::cout << "\nSorted:\n"
<< "======\n";
for(unsigned i = 0; i < keys.size(); ++i)
std::cout << keys[i] << ": " << values[i] << '\n';
}
std::cout << "\nDuration sorting " << double(samples) << " samples:\n"
<< "========\n"
<< " One Vector: " << ref_elapsed << '\n'
<< "Two Vectors: " << elapsed << '\n'
<< " Factor: " << elapsed/ref_elapsed << '\n'
<< '\n';
}
(Please adjust SAMPLE_SIZE and VALUE_TYPE)
My conclusion is a sorted view into a sequence of unsorted data might be more aprropiate (but that violates the requirement of the question).
Is there an implementation of a "for each" macro like BOOST_FOREACH that doesn't need Boost?
I've made one.
It should work with C++11 r-value references in GCC and MSVC, but I haven't tested it well so if there's any errors please let me know.
Edit: I added support for strings.
#include <iterator>
#include <utility>
#define foreach(v, r) \
if (fe_detail::any const &fe_r_ = \
fe_detail::make_range(r)) { } else \
if (fe_detail::any const &fe_b_ = \
fe_detail::begin(fe_r_, ((void)0, 1) ? NULL : fe_detail::twrap(r))) { } else \
if (fe_detail::equal( \
fe_b_, \
fe_detail::end(fe_r_, ((void)0, 1) ? NULL : fe_detail::twrap(r)), \
((void)0, 1) ? NULL : fe_detail::twrap(r))) { } else \
for (bool fe_c_ = false; \
!fe_c_ && !fe_detail::equal( \
fe_b_, \
fe_detail::end(fe_r_, ((void)0, 1) ? NULL : fe_detail::twrap(r)), \
((void)0, 1) ? NULL : fe_detail::twrap(r)); \
fe_detail::advance(fe_b_, 1, ((void)0, 1) ? NULL : fe_detail::twrap(r))) \
for (v = (fe_detail::move(*fe_detail::iter(fe_b_, ((void)0, 1) ? NULL : fe_detail::twrap(r)))); \
fe_c_ = !fe_c_; )
namespace fe_detail
{
// Container traits
template<class C, class It> struct CT
{
typedef It It;
static It begin(C &c) { return c.begin(); }
static It end(C &c) { return c.end(); }
};
// Range traits
template<class R> struct RT : public CT<R, typename R::iterator> { };
template<class R> struct RT<R const> : public CT<R const, typename R::const_iterator> { };
template<class R> struct RT<R &> : public RT<R> { };
template<class T, bool B = T::value> struct enable_if;
template<class T> struct enable_if<T, true> { typedef T type; };
template<class T> struct is_char { static bool const value = false; };
template<class T> struct is_char<T const> : public is_char<T> { };
template<class T> struct is_char<T volatile> : public is_char<T> { };
template<> struct is_char<char> { static bool const value = true; };
template<> struct is_char<wchar_t> { static bool const value = true; };
template<class Ch> struct RT<Ch *> : enable_if<is_char<Ch> >
{
typedef Ch *It;
static It begin(It a) { return &a[0]; }
static It end(It a) { return &a[std::char_traits<Ch>::length(a)]; }
};
template<class R, size_t N> struct RT<R[N]>
{
typedef R *It;
static It begin(It a) { return &a[0]; }
static It end(It a) { return &a[N - (((void)0, is_char<R>::value) ? 1 : 0)]; }
};
template<class It> struct RT<std::pair<It, It> >
{
typedef It It;
static It begin(std::pair<It, It> const a) { return a.first; }
static It end(std::pair<It, It> const a) { return a.second; }
};
struct any { operator bool() const { return false; } };
template<class T> struct type_wrap { type_wrap(bool = false) { } };
template<class T> class wrap : public any
{ wrap &operator =(wrap const &); public: mutable T v; wrap(T v) : any(), v(v) { } };
template<class T> class wrap<T const> : public any
{ wrap &operator =(wrap const &); public: T const v; wrap(T const v) : any(), v(v) { } };
template<class T, size_t N> class wrap<T[N]> : public any
{ wrap &operator =(wrap const &); public: T (&v)[N]; wrap(T (&v)[N]) : any(), v(v) { } };
template<class T> class wrap<T const &> : public wrap<T const>
{ wrap &operator =(wrap const &); public: wrap(T const &v) : wrap<T const>(v) { } };
template<class T, size_t N> wrap<T[N]> make_range(T (&r)[N]) { return r; }
template<class T, size_t N> type_wrap<T[N]> twrap(T (&r)[N]) { throw 0; }
template<class It> type_wrap<std::pair<It, It> > twrap(std::pair<It, It> const &p) { throw 0; }
#if defined(_MSC_VER) && _MSC_VER >= 1600 || defined(__RVALUE_REFERENCE) || defined(__GXX_EXPERIMENTAL_CXX0X__)
template<class R> struct RT<R &&> : public RT<R> { };
template<class T> class wrap<T &&> : public wrap<T> { public: wrap(T &&v) : wrap<T>(std::move(v)) { } };
template<class R> wrap<R &&> make_range(R &&r) { return wrap<R &&>(std::forward<R>(r)); }
template<class R> type_wrap<R> twrap(R &&) { throw 0; }
using std::move;
#else
template<class R> wrap<R> make_range(R &r) { return r; }
template<class R> wrap<R const &> make_range(R const &r) { return r; }
template<class R> type_wrap<R> twrap(R &) { throw 0; }
template<class R> type_wrap<R const &> twrap(R const &) { throw 0; }
template<class T> T &move(T &v) { return v; }
template<class T> T const &move(T const &v) { return v; }
#endif
template<class R> wrap<typename RT<R>::It> begin(any const &r, type_wrap<R>)
{ return RT<R>::begin(static_cast<wrap<R> const &>(r).v); }
template<class R> wrap<typename RT<R>::It> end(any const &r, type_wrap<R>)
{ return RT<R>::end (static_cast<wrap<R> const &>(r).v); }
template<class R> bool equal(any const &i, any const &j, type_wrap<R>)
{ return static_cast<wrap<typename RT<R>::It> const &>(i).v == static_cast<wrap<typename RT<R>::It> const &>(j).v; }
template<class R> void advance(any const &i, typename std::iterator_traits<typename RT<R>::It>::difference_type const d, type_wrap<R>)
{ return std::advance(static_cast<wrap<typename RT<R>::It> const &>(i).v, d); }
template<class R> typename RT<R>::It &iter(any const &i, type_wrap<R>)
{ return static_cast<wrap<typename RT<R>::It> const &>(i).v; }
}
You can use it like:
#include <vector>
#include <iostream>
std::vector<int> make_vect()
{
std::vector<int> v;
v.push_back(5);
v.push_back(8);
v.push_back(10);
return v;
}
int main()
{
foreach (int c, make_vect())
{
std::cout << c << std::endl;
}
}