Related
I am searching for template library with set-like container allowing searching by different key. I don't want map (key duplication) and want C++11 compliant code (C++14 added template<class K> iterator std::set::find(const K& x) which could be used in std::set<T*,my_transparent_deref_less<T*> > with custom compare functor).
Do you know such? Will boost add such or does it have already?
The signature should look like this: the_set<T, GetKey, Compare> and I want structure optimized for both size / memory usage (thus flat_set / btree_set) and speed of searching (insert/remove speed is not that critical). Example:
class User {
public:
User(const char *name);
const char *name();
... };
the_set<User*,const char*> USERS([](User* u) { u->name(); },
[](const char* lhs, const char* rhs) { strcmp(lhs, rhs) < 0; });
I have found red-black-tree in boost::detail that looks like what I want - the signature is template <class Key, class Value, class KeyOfValue, class KeyCompare, class A> class rbtree. Do we have something like that with flat_set and btree_set that I could use (without the fear of using something that is not to be used publicly but purposedly hidden as detail)?
Reason: I do plan to use such sets for many objects and many keys (possibly different keys/sets for same objects).
USERS, UNITS, ... - global using btree_set, possibly something like boost::multi_index
User::units, ... - sets in objects using flat_set
My code so far: (The problem is that I have to use StringWrapper now)
#include <set>
#include <iostream>
#include <type_traits>
#include "btree_set.h"
#include "boost/container/flat_set.hpp"
// dereferencing comparator
template <class T>
class less: public std::less<T> {
public:
typename std::enable_if<std::is_pointer<T>::value,
bool>::type operator() (T lhs, T rhs) const {
return *lhs < *rhs; }};
// here I can change underlying structure to btree_set or std::set
template <class T,
class C = less<T>,
class A = std::allocator<T> >
using default_set = boost::container::flat_set<T, C, A>;
// this works fine for classes derived from their primary key
template <class T, class K = T,
class B = default_set<K*> >
class object_set {
private:
typename std::enable_if<std::is_base_of<K, T>::value,
B>::type impl;
public:
template<class... Args>
T* add(K* key, Args&& ...args) {
auto it = impl.insert(key);
if (!it.second) return nullptr;
T* value = new T(*key, std::forward<Args>(args)...);
*it.first = value;
return value; }
T* operator[](K* key) {
auto it = impl.find(key);
if (it == impl.end()) return nullptr;
return (T*)*it; }
T* remove(K* key) {
auto it = impl.find(key);
if (it == impl.end()) return nullptr;
T* value = (T*)*it;
impl.erase(it);
return value; }
public:
template<class... Args>
T* add(K key, Args&& ...args) {
return add(&key, std::forward<Args>(args)...); }
T* operator[](K key) {
return (*this)[&key]; }
T* remove(K key) {
return remove(&key); }};
// workaround for above std::is_base_of constraint
class StringWrapper {
const char *data;
public:
StringWrapper(const char *data) {
this->data = data; }
operator const char *() const {
return data; }};
// example of class I want to use the container on
class User: public StringWrapper {
public:
User(const char *name): StringWrapper(name) {}};
// testing
object_set<User,StringWrapper> USERS;
int main() {
USERS.add("firda"); USERS.add("firda2");
User* firda = USERS["firda"];
delete USERS.remove(firda);
delete USERS.remove("firda2"); }
Sounds like a job for boost::multi_index
http://www.boost.org/doc/libs/1_55_0/libs/multi_index/doc/index.html
This is what I came with:
#include "boost/container/flat_set.hpp"
template<class T, class K, class GetKey, class CmpKey>
class fset {
private:
boost::container::container_detail::flat_tree<
K, T*, GetKey, CmpKey, std::allocator<T*> >
impl;
public:
template<class... Args>
T* add(K key, Args&& ...args) {
auto it = impl.lower_bound(key);
if (it != impl.end() && impl.key_comp()(key, GetKey()(*it))) {
return nullptr; }
T* value = new T(key, std::forward<Args>(args)...);
impl.insert_unique(it, value);
return value; }
T* operator[](K key) {
auto it = impl.find(key);
if (it == impl.end()) return nullptr;
return *it; }
T* remove(K key) {
auto it = impl.find(key);
if (it == impl.end()) return nullptr;
T* value = *it;
impl.erase(it);
return value; }};
class User {
private:
const char *name_;
public:
User(const char *name) {
std::size_t size = std::strlen(name) + 1;
char *buf = new char[size];
std::memcpy(buf, name, size);
name_ = buf; }
~User() {
delete[] name_; }
const char *name() const {
return name_; }
public:
struct get_name {
const char *operator()(User* u) const {
return u->name(); }};
struct cmp_name {
bool operator()(const char* lhs, const char* rhs) const {
return std::strcmp(lhs, rhs) < 0; }};};
fset<User,const char*,User::get_name,User::cmp_name>
USERS;
int main() {
USERS.add("firda");
User* firda = USERS["firda"];
delete USERS.remove("firda"); }
Should I close or delete this question now?
This is what I use now (look at struct vset_adaptor)
#ifndef HEADER___VECTSET___BE8EB41D7B3971E1
#define HEADER___VECTSET___BE8EB41D7B3971E1
#include <vector>
//############################################################### ptrvect
template <class T, class base = std::vector<T*> >
class ptrvect: public base {
public:
class iterator: public base::iterator {
friend class ptrvect;
private:
iterator(const typename base::const_iterator& it):
base::iterator(const_cast<T**>(&*it)) {
return; }
public:
iterator(const typename base::iterator& it):
base::iterator(it) {
return; }
T* operator->() const {
return **this; }};
class const_iterator: public base::const_iterator {
public:
const_iterator(const typename base::const_iterator& it):
base::const_iterator(it) {
return; }
const_iterator(const typename base::iterator& it):
base::const_iterator(it) {
return; }
T* operator->() const {
return **this; }};
template <class It = iterator>
class condpair: public std::pair<It,bool> {
public:
condpair(It it, bool second):
std::pair<It,bool>(it, second) {
return; }
T* operator->() const {
return *std::pair<It,bool>::first; }};
public:
iterator begin() {
return iterator(base::begin()); }
iterator end() {
return iterator(base::end()); }
const_iterator begin() const {
return const_iterator(base::begin()); }
const_iterator end() const {
return const_iterator(base::end()); }
public: // workarounds for pre-C++11 / bad C++11 implementation (should allow const_iterator)
iterator insert(const_iterator pos, T* value) {
return base::insert(iterator(pos), value); }
iterator erase(const_iterator pos) {
return base::erase(iterator(pos)); }
public: // addons
iterator find (T* key) {
return std::find(begin(), end(), key); }
const_iterator find (T* key) const {
return std::find(begin(), end(), key); }
bool contains (T* key) const {
return find(key) != end(); }
T* remove(T* key) {
auto it = find(key);
if (it == end()) return null;
T* val = *it;
base::erase(it);
return val; }
T* add(T* val) {
base::push_back(val);
return val; }
void release() {
for (T* it : *this) delete it;
base::clear(); }};
//########################################################## vset adaptor
template <class T, class K>
struct vset_adaptor {
K operator()(T* it) const {
return (K)(*it); }
bool operator()(K lhs, K rhs) const {
return lhs < rhs; }};
template <class T>
struct vset_adaptor<T,T*> {
T* operator()(T* it) const {
return it; }
bool operator()(T* lhs, T* rhs) const {
return lhs < rhs; }};
//================================================================== vset
template <class T, class K=T*, class F = vset_adaptor<T,K> >
class vset {
private:
ptrvect<T> impl;
struct Comp {
F f;
K operator()(T* it) const {
return f(it); }
bool operator()(K lhs, K rhs) const {
return f(lhs, rhs); }
bool operator()(T* lhs, K rhs) const {
return f(f(lhs), rhs); }
bool operator()(K lhs, T* rhs) const {
return f(lhs, f(rhs)); }
bool operator()(T* lhs, T* rhs) const {
return f(f(lhs), f(rhs)); }};
Comp comp;
public:
typedef typename ptrvect<T>::const_iterator iterator, const_iterator;
typedef unsigned size_type;
typedef T *value_type;
typedef K key_type;
typedef typename ptrvect<T>::template condpair<iterator> condpair;
public:
iterator begin() const {
return iterator(impl.begin()); }
iterator end() const {
return iterator(impl.end()); }
size_type size() const {
return impl.size(); }
bool empty() const {
return impl.empty(); }
public:
iterator lower_bound(K key) const {
return std::lower_bound(impl.begin(), impl.end(), key, comp); }
iterator upper_bound(K key) const {
return std::upper_bound(impl.begin(), impl.end(), key, comp); }
std::pair<iterator, iterator> equal_range(K key) const {
return std::equal_range(impl.begin(), impl.end(), key, comp); }
iterator find(K key) const {
iterator it = lower_bound(key);
return it == end() || comp(key, *it) ? end() : it; }
bool contains(K key) const {
iterator it = lower_bound(key);
return it != end() && !comp(key, *it); }
public:
typename std::enable_if<!std::is_same<T*,K>::value,
iterator>::type lower_bound(T* key) const {
return std::lower_bound(impl.begin(), impl.end(), comp(key), comp); }
typename std::enable_if<!std::is_same<T*,K>::value,
iterator>::type upper_bound(T* key) const {
return std::upper_bound(impl.begin(), impl.end(), comp(key), comp); }
typename std::enable_if<!std::is_same<T*,K>::value,
std::pair<iterator, iterator> >::type equal_range(T* key) const {
return std::equal_range(impl.begin(), impl.end(), comp(key), comp); }
typename std::enable_if<!std::is_same<T*,K>::value,
iterator>::type find(T* key) const {
iterator it = lower_bound(comp(key));
return it == end() || comp(key, *it) ? end() : it; }
public:
template<class... Args>
condpair emplace(K key, Args&& ...args) {
iterator it = lower_bound(key);
if (it == end() || comp(key, *it)) {
return condpair(impl.insert(it,
new T(key, std::forward<Args>(args)...)), true); }
return condpair(it, false); }
iterator erase(iterator at) {
return impl.erase(at); }
public:
T* add(T* value) {
iterator it = lower_bound(value);
if (it == end() || comp(comp(value), *it)) {
impl.insert(it, value);
return value; }
return nullptr; }
template<class... Args>
T* add(K key, Args&& ...args) {
iterator it = lower_bound(key);
if (it == end() || comp(key, *it)) {
T* value = new T(key, std::forward<Args>(args)...);
impl.insert(it, value);
return value; }
return nullptr; }
T* get(K key) const {
iterator it = find(key);
return it == impl.end() ? nullptr : *it; }
T* operator[](K key) const {
return *emplace(key).first; }
T* remove(K key) {
iterator it = find(key);
if (it == impl.end()) return nullptr;
T* value = *it;
impl.erase(it);
return value; }
typename std::enable_if<!std::is_same<T*,K>::value,
T*>::type remove(T* key) {
return remove(comp(key)); }
void release() {
for (T* it : *this) {
delete it; }
impl.clear(); }
void clear() {
impl.clear(); }};
#endif
....if you wonder about the codestyling, it is output of my own preprocessor. This is the real code:
#include <vector>
//############################################################### ptrvect
template <class T, class base = std::vector<T*> >
class ptrvect: public base
public:
class iterator: public base::iterator
friend class ptrvect
private:
iterator(const typename base::const_iterator& it):
base::iterator(const_cast<T**>(&*it))
return
public:
iterator(const typename base::iterator& it):
base::iterator(it)
return
T* operator->() const
return **this
class const_iterator: public base::const_iterator
public:
const_iterator(const typename base::const_iterator& it):
base::const_iterator(it)
return
const_iterator(const typename base::iterator& it):
base::const_iterator(it)
return
T* operator->() const
return **this
template <class It = iterator>
class condpair: public std::pair<It,bool>
public:
condpair(It it, bool second):
std::pair<It,bool>(it, second)
return
T* operator->() const
return *std::pair<It,bool>::first
public:
iterator begin()
return iterator(base::begin())
iterator end()
return iterator(base::end())
const_iterator begin() const
return const_iterator(base::begin())
const_iterator end() const
return const_iterator(base::end())
public: // workarounds for pre-C++11 / bad C++11 implementation (should allow const_iterator)
iterator insert(const_iterator pos, T* value)
return base::insert(iterator(pos), value)
iterator erase(const_iterator pos)
return base::erase(iterator(pos))
public: // addons
iterator find (T* key)
return std::find(begin(), end(), key)
const_iterator find (T* key) const
return std::find(begin(), end(), key)
bool contains (T* key) const
return find(key) != end()
T* remove(T* key)
auto it = find(key)
if it == end(); return null
T* val = *it
base::erase(it)
return val
T* add(T* val)
base::push_back(val)
return val
void release()
for T* it : *this; delete it
base::clear()
//########################################################## vset adaptor
template <class T, class K>
struct vset_adaptor
K operator()(T* it) const
return (K)(*it)
bool operator()(K lhs, K rhs) const
return lhs < rhs
template <class T>
struct vset_adaptor<T,T*>
T* operator()(T* it) const
return it
bool operator()(T* lhs, T* rhs) const
return lhs < rhs
//================================================================== vset
template <class T, class K=T*, class F = vset_adaptor<T,K> >
class vset
private:
ptrvect<T> impl
struct Comp
F f
K operator()(T* it) const
return f(it)
bool operator()(K lhs, K rhs) const
return f(lhs, rhs)
bool operator()(T* lhs, K rhs) const
return f(f(lhs), rhs)
bool operator()(K lhs, T* rhs) const
return f(lhs, f(rhs))
bool operator()(T* lhs, T* rhs) const
return f(f(lhs), f(rhs))
Comp comp
public:
typedef typename ptrvect<T>::const_iterator iterator, const_iterator
typedef unsigned size_type
typedef T *value_type
typedef K key_type
typedef typename ptrvect<T>::template condpair<iterator> condpair
public:
iterator begin() const
return iterator(impl.begin())
iterator end() const
return iterator(impl.end())
size_type size() const
return impl.size()
bool empty() const
return impl.empty()
public:
iterator lower_bound(K key) const
return std::lower_bound(impl.begin(), impl.end(), key, comp)
iterator upper_bound(K key) const
return std::upper_bound(impl.begin(), impl.end(), key, comp)
std::pair<iterator, iterator> equal_range(K key) const
return std::equal_range(impl.begin(), impl.end(), key, comp)
iterator find(K key) const
iterator it = lower_bound(key)
return it == end() || comp(key, *it) ? end() : it
bool contains(K key) const
iterator it = lower_bound(key)
return it != end() && !comp(key, *it)
public:
typename std::enable_if<!std::is_same<T*,K>::value,
iterator>::type lower_bound(T* key) const
return std::lower_bound(impl.begin(), impl.end(), comp(key), comp)
typename std::enable_if<!std::is_same<T*,K>::value,
iterator>::type upper_bound(T* key) const
return std::upper_bound(impl.begin(), impl.end(), comp(key), comp)
typename std::enable_if<!std::is_same<T*,K>::value,
std::pair<iterator, iterator> >::type equal_range(T* key) const
return std::equal_range(impl.begin(), impl.end(), comp(key), comp)
typename std::enable_if<!std::is_same<T*,K>::value,
iterator>::type find(T* key) const
iterator it = lower_bound(comp(key))
return it == end() || comp(key, *it) ? end() : it
public:
template<class... Args>
condpair emplace(K key, Args&& ...args)
iterator it = lower_bound(key)
if it == end() || comp(key, *it)
return condpair(impl.insert(it,
new T(key, std::forward<Args>(args)...)), true)
return condpair(it, false)
iterator erase(iterator at)
return impl.erase(at)
public:
T* add(T* value)
iterator it = lower_bound(value)
if it == end() || comp(comp(value), *it)
impl.insert(it, value)
return value
return nullptr
template<class... Args>
T* add(K key, Args&& ...args)
iterator it = lower_bound(key)
if it == end() || comp(key, *it)
T* value = new T(key, std::forward<Args>(args)...)
impl.insert(it, value)
return value
return nullptr
T* get(K key) const
iterator it = find(key)
return it == impl.end() ? nullptr : *it
T* operator[](K key) const
return *emplace(key).first
T* remove(K key)
iterator it = find(key)
if it == impl.end(); return nullptr
T* value = *it
impl.erase(it)
return value
typename std::enable_if<!std::is_same<T*,K>::value,
T*>::type remove(T* key)
return remove(comp(key))
void release()
for T* it : *this
delete it
impl.clear()
void clear()
impl.clear()
You already mentioned c++14 and the template find function. Here is a simple example for who is interested in it:
#include <iostream>
#include <set>
#include <vector>
using namespace std;
class Info
{
int num_;
public:
explicit Info(int n) : num_(n) {}
bool operator<(const Info &other) const { return num_ < other.num_; }
friend inline bool operator<(const Info& lhs, const int& rhs);
friend bool operator<(const int& lhs, const Info& rhs);
};
inline bool operator<(const Info& lhs, const int& rhs) { return lhs.num_ < rhs; }
inline bool operator<(const int& lhs, const Info& rhs) { return lhs < rhs.num_; }
int main()
{
// less<> is a is_transparent comparer
set<Info, less<> > s;
// insert two items
s.insert(Info(2));
s.insert(Info(4));
// search
for (auto n : {1,2,3,4,5}) {
cout << "Searching " << n << (s.find(n) == s.end()?" not found":" found") << endl;
}
return 0;
}
Result:
Searching 1 not found
Searching 2 found
Searching 3 not found
Searching 4 found
Searching 5 not found
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).
I am designing a container that is a grid, represented as a 1D array (templated). I am posting here an extract of the code, there is actually more to it. It is used as a rolling occupancy grid in a robotic application, where each cell represents a small area of the world.
One operation I do frequently with that grid is to go through all the cells and also retrieve their world coordinates:
for( unsigned r=0; r<mygrid.rows_; ++r ) {
for( unsigned c=0; c<mygrid.cols_; ++c ) {
cell = mygrid.getRC(r,c);
mygrid.rcToXY(r,c,&x,&y);
}
}
I would like to have an iterator than stores all of these: the cell, its rc coordinates and its xy coordinates.
for( Grid<CellType>::const_iterator it=mygrid.begin(); it!=mygrid.end(); ++it ) {
cell = *it;
printf("%d %d %f %f\n", it.r(), it.c(), it.x(), it.y());
}
Following numerous answers and tutorials online I came up with the following implementation, which works. However it seems a bit clumsy to me, and for academic sake I'd like to make it look better. Also STL compatibility would be great.
template <class G, typename C>
class base_iterator
{
private:
G* grid_;
C* cell_;
unsigned r_, c_; // local
double x_, y_;
// this should be private with access for friends (Grid) only
// but I can't make it work
public:
base_iterator(G* grid, unsigned r, unsigned c) : grid_(grid), r_(r), c_(c)
{
cell_ = ( r<grid->rows_ && c<grid->cols_ ) ? &grid_->getRC(r,c) : 0;
grid_->rcToXY(r,c,&x_,&y_);
}
public:
base_iterator() : grid_(0) { }
// used to cast an iterator to a const_iterator
template <class G2, typename C2>
base_iterator(const base_iterator<G2,C2>& other)
{
grid_ = other.grid();
cell_ = & other.cell();
r_ = other.r();
c_ = other.c();
x_ = other.x();
y_ = other.y();
}
// this should be private with access for friends only
G* grid() const { return grid_; }
C& cell() { return *cell_; }
const C& cell() const { return *cell_; }
unsigned r() const { return r_; }
unsigned c() const { return c_; }
double x() const { return x_; }
double y() const { return y_; }
C* operator->() { return cell_; }
const C* operator->() const { return cell_; }
C& operator*() { return *cell_; }
const C& operator*() const { return *cell_; }
//prefix
base_iterator & operator++()
{
// my iteration logic here which needs access to grid
// in order to find the number of rows, etc.
return *this;
}
//postfix
base_iterator operator++(int)
{
base_iterator it(*this); // make a copy for result
++(*this); // Now use the prefix version to do the work
return it; // return the copy (the old) value.
}
template <class G2, typename C2>
bool operator==(const base_iterator<G2,C2> & other) const
{
return cell_ == &other.cell();
}
template <class G2, typename C2>
bool operator!=(const base_iterator<G2,C2>& other) const
{ return cell_!=other.cell(); }
};
And then in my grid class:
typedef base_iterator<Grid<T>,T> iterator;
typedef base_iterator<Grid<T> const, T const> const_iterator;
iterator begin() { return iterator(this,0,0); }
iterator end() { return iterator(this,rows_,cols_); }
const_iterator begin() const { return const_iterator(this,0,0); }
const_iterator end() const { return const_iterator(this,rows_,cols_); }
Again, this works, but I feel that it's a bit clumsy (see the comments in the iterator code), and I'd like to know how I can improve it. I saw numerous posts about using boost iterator facade or adaptor, but I could not figure out how to adapt it to my case.
Well I found one solution, that I am quite satisfied with. Here is the full listing for reference. There are some tricky parts that took me some time, in particular in order to be able to take the implementation outside of the class declarations. I haven't managed to make class base_iterator a non-nested class of Grid, according to what I read here and there, I think it's not possible.
#include <cstdio>
#include <cassert>
#include <stdexcept>
#include <algorithm>
template <class T>
class Grid
{
public:
// these should be private, with public getters...
double resolution_;
unsigned rows_, cols_;
int map_r0_, map_c0_; // grid coordinates of origin of map
private:
T* cell_;
public:
Grid(double resolution, unsigned rows, unsigned cols);
~Grid() { delete[] cell_; }
T & getRC(unsigned r, unsigned c);
const T & getRC(unsigned r, unsigned c) const;
void rcToXY(unsigned r, unsigned c, double* x, double* y) const;
public:
template <class GridType, class CellType>
class base_iterator : std::iterator<std::forward_iterator_tag, CellType>
{
private:
friend class Grid;
GridType* grid_;
CellType* cell_;
unsigned r_, c_; // local
double x_, y_;
base_iterator(GridType* grid, unsigned r, unsigned c);
public:
base_iterator() : grid_(0) { }
template <class G2, class C2>
base_iterator(const base_iterator<G2,C2>& other);
CellType& cell() { return *cell_; }
const CellType& cell() const { return *cell_; }
unsigned r() const { return r_; }
unsigned c() const { return c_; }
double x() const { return x_; }
double y() const { return y_; }
CellType* operator->() { return cell_; }
const CellType* operator->() const { return cell_; }
CellType& operator*() { return *cell_; }
const CellType& operator*() const { return *cell_; }
//prefix
base_iterator & operator++();
//postfix
base_iterator operator++(int);
template <class G2, class C2>
bool operator==(const base_iterator<G2,C2> & other) const
{ return cell_ == other.cell_; }
template <class G2, class C2>
bool operator!=(const base_iterator<G2,C2>& other) const
{ return cell_ != other.cell_; }
};
typedef base_iterator<Grid<T>,T> iterator;
typedef base_iterator<Grid<T> const, T const> const_iterator;
iterator begin() { return iterator(this,0,0); }
iterator end() { return iterator(this,rows_,0); }
const_iterator begin() const { return const_iterator(this,0,0); }
const_iterator end() const { return const_iterator(this,rows_,0); }
};
template <class T>
Grid<T>::Grid(double resolution, unsigned rows, unsigned cols)
: resolution_(resolution), rows_(rows), cols_(cols), map_r0_(0), map_c0_(0)
{
cell_ = new T[rows_*cols_];
}
template <class T>
T & Grid<T>::getRC(unsigned r, unsigned c)
{
if (r >= rows_ || c >= cols_)
throw std::runtime_error("Out of bounds");
return cell_[r * cols_ + c];
}
template <class T>
const T & Grid<T>::getRC(unsigned r, unsigned c) const
{
if (r >= rows_ || c >= cols_)
throw std::runtime_error("Out of bounds");
return cell_[r * cols_ + c];
}
template <class T>
void Grid<T>::rcToXY(unsigned r, unsigned c, double* x, double* y) const
{
*x = (map_c0_ + c + 0.5) * resolution_;
*y = (map_r0_ + r + 0.5) * resolution_;
}
template <class T>
template <class GridType, class CellType>
Grid<T>::base_iterator<GridType,CellType>::base_iterator(GridType* grid, unsigned r, unsigned c)
: grid_(grid), r_(r), c_(c)
{
if( r<grid->rows_ && c<grid->cols_ ) {
cell_ = &grid_->getRC(r,c);
grid_->rcToXY(r,c,&x_,&y_);
}
else
cell_ = &grid_->getRC(grid->rows_-1,grid->cols_-1) + 1;
}
// beautiful triple template declaration !
template <class T>
template <class GridType, class CellType>
template <class G2, class C2>
Grid<T>::base_iterator<GridType,CellType>::base_iterator(const Grid<T>::base_iterator<G2,C2>& other)
{
grid_ = other.grid_;
cell_ = other.cell_;
r_ = other.r();
c_ = other.c();
x_ = other.x();
y_ = other.y();
}
template <class T>
template <class GridType, class CellType>
Grid<T>::base_iterator<GridType,CellType> & Grid<T>::base_iterator<GridType,CellType>::operator++()
{
assert( grid_!=0 );
if( c_==grid_->cols_-1 )
{
c_ = 0;
x_ = (grid_->map_c0_ + 0.5) * grid_->resolution_;
++r_;
y_ += grid_->resolution_;
}
else
{
++c_;
x_ += grid_->resolution_;
}
++cell_;
return *this;
}
template <class T>
template <class GridType, class CellType>
Grid<T>::base_iterator<GridType,CellType> Grid<T>::base_iterator<GridType,CellType>::operator++(int)
{
base_iterator it(*this); // make a copy for result
++(*this); // Now use the prefix version to do the work
return it; // return the copy (the old) value.
}
void print(unsigned i)
{
printf("%d ", i);
}
int main()
{
Grid<unsigned> mygrid(.1,2,3);
unsigned ctr=0;
for( Grid<unsigned>::iterator it=mygrid.begin(); it!=mygrid.end(); ++it )
*it = ctr++;
ctr = 0;
printf("All elements: r, c, x, y, value\n");
for( Grid<unsigned>::const_iterator it=mygrid.begin(); it!=mygrid.end(); ++it ) {
assert( *it == ctr++ );
printf("%d %d %f %f %d\n", it.r(), it.c(), it.x(), it.y(), *it);
}
printf("All elements values: ");
std::for_each(mygrid.begin(), mygrid.end(), print);
printf("\n");
return 0;
}
I'm trying to write a C++ version of Python's itertools.tee for Boost::Range (as seen here). Here is my first attempt:
template<typename R>
class tee_iterator : std::iterator<std::forward_iterator_tag, typename boost::range_value<R>::type>
{
public:
typedef typename boost::range_value<R>::type T;
typedef std::list<T> tee_queue;
typedef std::vector<tee_queue> tee_queue_collection;
tee_iterator(const R& r, tee_queue* q, tee_queue_collection* qs) :
it_(r.begin()), queue_(q), queues_(qs) {}
tee_iterator(const R& r) : it_(r.end()), queue_(NULL), queues_(NULL) {}
T& operator*() const { return current_; }
tee_iterator& operator++()
{
if (queue_->empty()) {
++it_;
for (auto q : queues_) {
q->push_back(*it_);
}
}
current_ = queue_->front();
queue_->pop_front();
return *this;
}
bool operator==(tee_iterator const& o) const { return it_ == o.it_; }
bool operator!=(tee_iterator const& o) const { return !(*this == o); }
private:
typedef typename boost::range_iterator<const R>::type const_iterator;
const_iterator it_;
tee_queue* queue_;
tee_queue_collection* queues_;
T current_;
};
template<typename R>
using tee_range = boost::iterator_range<tee_iterator<R> >;
template<typename R>
std::list<tee_range<R> > tee(const R& r, int n)
{
typedef typename boost::range_value<R>::type T;
typedef std::list<T> tee_queue;
typedef std::vector<tee_queue> tee_queue_collection;
tee_queue_collection queues(n);
std::list<tee_range<R> > ranges;
for (int i = 0; i < n; ++i) {
tee_range<R> t = { tee_iterator<R>(r, &queues[i], &queues), tee_iterator<R>(r) };
ranges.push_back(t);
}
return ranges;
}
but as soon as I try to use it:
int main(int argc, char* argv[])
{
std::list<int> l;
for (int i = 0; i < 10; ++i) {
l.push_back(i);
}
auto t = tee(l, 3);
}
it blows in my face, complaining about a missing value_type in boost::detail::iterator_traits<tee_iterator<std::list<int, std::allocator<int> > > > (and others). What am I missing? Isn't tee_iterator being a child of std::iterator enough?
You forgot to add public:
class tee_iterator : public std::iterator...