Context
I'm looking for a way to sort multiple vectors in tandem, and finding that it's far trickier than it should be (zip_iterator doesn't work, etc...).
This seems like the most promising thing I've found so far: http://web.stanford.edu/~dgleich/notebook/2006/03/sorting_two_arrays_simultaneou.html
However, there are two additional features that I'd like over this code:
- Sorting any number of vectors, not just two.
- Custom comparators (i.e. call a function and get a result from one set of data).
The second one probably won't be an issue, but the first one is giving me trouble.
Issue
I'm adding variadic templates to allow sorting of any number of vectors, so sort_permute_iter class now contains a tuple of iterators instead of just one. I can implement increment / decrement / advance fine to cope with this, but the dereference function should return a tuple of references, and I don't know how to get it to work.
Code
#include <iterator>
#include <tuple>
#include <boost/iterator/iterator_facade.hpp>
template <class SortIter, class... PermuteIter>
struct sort_permute_iter_types
{
typedef std::tuple<
typename std::iterator_traits<SortIter>::value_type,
typename std::iterator_traits<PermuteIter>::value_type...> value_type;
typedef std::tuple<
typename std::iterator_traits<SortIter>::value_type&,
typename std::iterator_traits<PermuteIter>::value_type&...> ref_type;
};
template <class SortIter, class... PermuteIter>
class sort_permute_iter :
public boost::iterator_facade<
sort_permute_iter<SortIter, PermuteIter...>,
typename sort_permute_iter_types<SortIter, PermuteIter...>::value_type,
std::random_access_iterator_tag,
typename sort_permute_iter_types<SortIter, PermuteIter...>::ref_type,
typename std::iterator_traits<SortIter>::difference_type>
{
public:
sort_permute_iter() { }
sort_permute_iter(SortIter si, PermuteIter... pi) :
_si(si), _pi(pi...) { }
SortIter _si;
std::tuple<PermuteIter...> _pi;
private:
friend class boost::iterator_core_access;
template<class Tuple, std::size_t Size>
struct incrementer
{
static void increment(Tuple& tuple)
{
incrementer<Tuple, Size - 1>::increment(tuple);
++std::get<Size - 1>(tuple);
}
};
template<class Tuple>
struct incrementer<Tuple, 1>
{
static void increment(Tuple& tuple)
{
++std::get<0>(tuple);
}
};
void increment()
{
++_si;
incrementer<decltype(_pi), sizeof...(PermuteIter)>::increment(_pi);
}
template<class Tuple, std::size_t Size>
struct decrementer
{
static void decrement(Tuple& tuple)
{
decrementer<Tuple, Size - 1>::decrement(tuple);
--std::get<Size - 1>(tuple);
}
};
template<class Tuple>
struct decrementer<Tuple, 1>
{
static void decrement(Tuple& tuple)
{
--std::get<0>(tuple);
}
};
void decrement()
{
--_si;
decrementer<decltype(_pi), sizeof...(PermuteIter)>::decrement(_pi);
}
bool equal(sort_permute_iter const& other) const
{
return _si == other._si;
}
typename sort_permute_iter_types<SortIter, PermuteIter...>::ref_type dereference() const
{
return sort_permute_iter_types<SortIter, PermuteIter...>::ref_type(*_si, (*_pi)...); // What to do??? Help!??
}
template<class Tuple, std::size_t Size>
struct advancer
{
static void advance(Tuple& tuple, difference_type n)
{
advancer<Tuple, Size - 1>::advance(tuple, n);
std::get<Size - 1>(tuple) += n;
}
};
template<class Tuple>
struct advancer<Tuple, 1>
{
static void advance(Tuple& tuple, difference_type n)
{
std::get<0>(tuple) += n;
}
};
void advance(difference_type n)
{
_si += n;
advancer<decltype(_pi), sizeof...(PermuteIter)>::advance(_pi, n);
}
difference_type distance_to(sort_permute_iter const& other) const
{
return other._si - _si;
}
};
template <class SortIter, class... PermuteIter>
struct sort_permute_iter_compare :
public std::binary_function<
typename sort_permute_iter_types<SortIter, PermuteIter...>::value_type,
typename sort_permute_iter_types<SortIter, PermuteIter...>::value_type,
bool>
{
typedef typename sort_permute_iter_types<SortIter, PermuteIter...>::value_type T;
bool operator()(const T& t1, const T& t2)
{
return (std::get<0>(t1) < std::get<0>(t2));
}
};
template <class SortIter, class... PermuteIter>
sort_permute_iter<SortIter, PermuteIter...> make_sort_permute_iter(SortIter&& si, PermuteIter&&... pi)
{
return sort_permute_iter<SortIter, PermuteIter...>(std::forward<SortIter>(si), std::forward<PermuteIter>(pi)...);
};
#include <vector>
#include <algorithm>
#include <iostream>
int main()
{
std::vector<int> v1{ 3, 1, 0, 2 };
std::vector<int> v2{ 3, 1, 0, 2 };
std::vector<float> v3{ 3.f, 1.f, 0.f, 2.f };
std::sort(
make_sort_permute_iter(v1.data(), v2.data(), v3.data()),
make_sort_permute_iter(v1.data() + v1.size(), v2.data() + v2.size(), v3.data() + v3.size()),
sort_permute_iter_compare<decltype(v1.data()), decltype(v2.data()), decltype(v3.data())>());
for (auto i : v1)
std::cout << i << " ";
std::cout << std::endl;
for (auto i : v2)
std::cout << i << " ";
std::cout << std::endl;
for (auto i : v3)
std::cout << i << " ";
std::cout << std::endl;
}