Skip to content

Instantly share code, notes, and snippets.

@2bbb
Last active December 18, 2015 01:28
Show Gist options
  • Select an option

  • Save 2bbb/c9467adc2849a265e764 to your computer and use it in GitHub Desktop.

Select an option

Save 2bbb/c9467adc2849a265e764 to your computer and use it in GitHub Desktop.
iterator_delegation
#include <type_traits>
#include <iterator>
namespace bbb {
template <typename container>
struct iteratable_class_traits {
#pragma mark iterator
struct forward_iterator_check {
template <typename testee, typename _ = typename testee::iterator> struct tester {};
template <typename testee> static std::true_type test(tester<testee> *);
template <typename> static std::false_type test(...);
};
static constexpr bool has_iterator = decltype(forward_iterator_check::template test<container>(nullptr))::value;
struct const_forward_iterator_check {
template <typename testee, typename _ = typename testee::const_iterator> struct tester {};
template <typename testee> static std::true_type test(tester<testee> *);
template <typename> static std::false_type test(...);
};
static constexpr bool has_const_iterator = decltype(const_forward_iterator_check::template test<container>(nullptr))::value;
struct reverse_iterator_check {
template <typename testee, typename _ = typename testee::reverse_iterator> struct tester {};
template <typename testee> static std::true_type test(tester<testee> *);
template <typename> static std::false_type test(...);
};
static constexpr bool has_reverse_iterator = decltype(reverse_iterator_check::template test<container>(nullptr))::value;
struct const_reverse_iterator_check {
template <typename testee, typename _ = typename testee::const_reverse_iterator> struct tester {};
template <typename testee> static std::true_type test(tester<testee> *);
template <typename> static std::false_type test(...);
};
static constexpr bool has_const_reverse_iterator = decltype(const_reverse_iterator_check::template test<container>(nullptr))::value;
#pragma mark inserter
template <typename testee, typename testee::iterator (testee::*)(typename testee::const_iterator, const typename testee::value_type &) = &testee::insert> struct insert_tester {};
template <typename testee> static std::true_type insert_test(insert_tester<testee> *);
template <typename> static std::false_type insert_test(...);
static constexpr bool has_insert = decltype(insert_test<container>(nullptr))::value;
template <typename testee, void (testee::*)(const typename testee::value_type &) = &testee::push_front> struct front_insert_tester {};
template <typename testee> static std::true_type push_front_test(front_insert_tester<testee> *);
template <typename> static std::false_type push_front_test(...);
static constexpr bool has_push_front = decltype(push_front_test<container>(nullptr))::value;
template <typename testee, void (testee::*)(const typename testee::value_type &) = &testee::push_back> struct back_insert_tester {};
template <typename testee> static std::true_type push_back_test(back_insert_tester<testee> *);
template <typename> static std::false_type push_back_test(...);
static constexpr bool has_push_back = decltype(push_back_test<container>(nullptr))::value;
};
template <typename container>
struct iterator_providers {
using traits = iteratable_class_traits<container>;
struct forward_iterator_provider_not_impl {
protected:
forward_iterator_provider_not_impl(container &) {}
};
struct mutable_forward_iterator_provider_impl {
using iterator = typename container::iterator;
iterator begin() { return body.begin(); }
iterator end() { return body.end(); }
protected:
mutable_forward_iterator_provider_impl(container &body) : body(body) {};
private:
container &body;
};
struct const_forward_iterator_provider_impl {
using const_iterator = typename container::const_iterator;
const_iterator begin() const { return body.begin(); }
const_iterator end() const { return body.end(); }
const_iterator cbegin() const { return body.cbegin(); }
const_iterator cend() const { return body.cend(); }
protected:
const_forward_iterator_provider_impl(container &body) : body(body) {};
private:
container &body;
};
struct forward_iterator_provider_impl
: mutable_forward_iterator_provider_impl
, const_forward_iterator_provider_impl {
using typename mutable_forward_iterator_provider_impl::iterator;
using mutable_forward_iterator_provider_impl::begin;
using mutable_forward_iterator_provider_impl::end;
using typename const_forward_iterator_provider_impl::const_iterator;
using const_forward_iterator_provider_impl::begin;
using const_forward_iterator_provider_impl::end;
using const_forward_iterator_provider_impl::cbegin;
using const_forward_iterator_provider_impl::cend;
protected:
forward_iterator_provider_impl(container &body)
: mutable_forward_iterator_provider_impl(body)
, const_forward_iterator_provider_impl(body) {}
};
struct reverse_iterator_provider_not_impl {
protected:
reverse_iterator_provider_not_impl(container &) {}
};
struct mutable_reverse_iterator_provider_impl {
using reverse_iterator = typename container::reverse_iterator;
reverse_iterator rbegin() { return body.rbegin(); }
reverse_iterator rend() { return body.rend(); }
protected:
mutable_reverse_iterator_provider_impl(container &body) : body(body) {}
private:
container &body;
};
struct const_reverse_iterator_provider_impl {
using const_reverse_iterator = typename container::const_reverse_iterator;
const_reverse_iterator rbegin() const { return body.rbegin(); }
const_reverse_iterator rend() const { return body.rend(); }
const_reverse_iterator crbegin() const { return body.crbegin(); }
const_reverse_iterator crend() const { return body.crend(); }
protected:
const_reverse_iterator_provider_impl(container &body) : body(body) {}
private:
container &body;
};
struct reverse_iterator_provider_impl
: mutable_reverse_iterator_provider_impl
, const_reverse_iterator_provider_impl {
using typename mutable_reverse_iterator_provider_impl::reverse_iterator;
using mutable_reverse_iterator_provider_impl::rbegin;
using mutable_reverse_iterator_provider_impl::rend;
using typename const_reverse_iterator_provider_impl::const_reverse_iterator;
using const_reverse_iterator_provider_impl::rbegin;
using const_reverse_iterator_provider_impl::rend;
using const_reverse_iterator_provider_impl::crbegin;
using const_reverse_iterator_provider_impl::crend;
protected:
reverse_iterator_provider_impl(container &body)
: mutable_reverse_iterator_provider_impl(body)
, const_reverse_iterator_provider_impl(body) {}
};
template <bool has, typename impl, typename not_impl>
using type_if = typename std::conditional<has, impl, not_impl>::type;
template <bool has_mutable, bool has_const, typename mutable_impl, typename const_impl, typename impl, typename not_impl>
using quad_if = type_if<
has_mutable,
type_if<has_const, impl, mutable_impl>,
type_if<has_const, const_impl, not_impl>
>;
using forward_iterator_provider = quad_if<
traits::has_iterator, traits::has_const_iterator,
mutable_forward_iterator_provider_impl, const_forward_iterator_provider_impl,
forward_iterator_provider_impl, forward_iterator_provider_not_impl
>;
using reverse_iterator_provider = quad_if<
traits::has_reverse_iterator, traits::has_const_reverse_iterator,
mutable_reverse_iterator_provider_impl, const_reverse_iterator_provider_impl,
reverse_iterator_provider_impl, reverse_iterator_provider_not_impl
>;
};
#pragma mark value_type provider
template <typename container, bool has_iterator = iteratable_class_traits<container>::has_iterator>
struct value_type_provider {};
template <typename container>
struct value_type_provider<container, true> {
using value_type = typename std::iterator_traits<typename container::iterator>::value_type;
};
#pragma mark inserter provider
template <bool condition, template <typename ...> class t, template <typename ...> class f>
struct template_conditional {
template <typename ... arguments>
using type = typename std::conditional<condition, t<arguments ...>, f<arguments ...>>::type;
};
template <typename container>
struct inserter_provider_impl {
private:
container &body;
public:
inserter_provider_impl(container &body) : body(body) {};
template <typename ... arguments>
auto insert(arguments ... args)
-> decltype(body.insert(args ...)) { return body.insert(args ...); }
template <typename ... arguments>
auto emplace(arguments ... args)
-> decltype(body.emplace(args ...)) { return body.emplace(args ...); }
};
template <typename container>
struct inserter_provider_not_impl {
inserter_provider_not_impl(container &) {};
};
template <typename container>
using inserter_provider = typename template_conditional<
iteratable_class_traits<container>::has_insert,
inserter_provider_impl,
inserter_provider_not_impl
>::template type<container>;
template <typename container>
struct front_inserter_provider_impl {
front_inserter_provider_impl(container &body) : body(body) {};
inline void push_front(const typename container::value_type &v) { body.push_front(v); }
inline void push_front(typename container::value_type &&v) { body.push_front(v); }
template <typename ... arguments>
void emplace_front(arguments && ... args) { body.emplace_front(args ...); }
private:
container &body;
};
template <typename container>
struct front_inserter_provider_not_impl {
front_inserter_provider_not_impl(container &) {};
};
template <typename container>
using front_inserter_provider = typename template_conditional<
iteratable_class_traits<container>::has_push_front,
front_inserter_provider_impl,
front_inserter_provider_not_impl
>::template type<container>;
template <typename container>
struct back_inserter_provider_impl {
back_inserter_provider_impl(container &body) : body(body) {};
inline void push_back(const typename container::value_type &v) { body.push_back(v); }
inline void push_back(typename container::value_type &&v) { body.push_back(v); }
template <typename ... arguments>
void emplace_back(arguments && ... args) { body.emplace_back(args ...); }
private:
container &body;
};
template <typename container>
struct back_inserter_provider_not_impl {
back_inserter_provider_not_impl(container &) {};
};
template <typename container>
using back_inserter_provider = typename template_conditional<
iteratable_class_traits<container>::has_push_back,
back_inserter_provider_impl,
back_inserter_provider_not_impl
>::template type<container>;
#pragma mark iterator delegation
template <typename container>
struct iterator_delegation
: iterator_providers<container>::forward_iterator_provider
, iterator_providers<container>::reverse_iterator_provider
, inserter_provider<container>
, front_inserter_provider<container>
, back_inserter_provider<container>
, value_type_provider<container> {
protected:
using delegation = iterator_delegation<container>;
iterator_delegation(container &body)
: iterator_providers<container>::forward_iterator_provider(body)
, iterator_providers<container>::reverse_iterator_provider(body)
, inserter_provider<container>(body)
, front_inserter_provider<container>(body)
, back_inserter_provider<container>(body) {}
};
};
#include <iostream>
#include <vector>
#include <deque>
#include <queue>
#include <list>
#include <map>
#include <string>
struct vectroid
: bbb::iterator_delegation<std::vector<int>> {
std::vector<int> body;
vectroid() : delegation(body) {};
};
struct mappoid : bbb::iterator_delegation<std::map<int, int>> {
std::map<int, int> body;
mappoid() : delegation(body) {};
};
struct introid : bbb::iterator_delegation<int> {
int body;
introid() : delegation(body) {};
};
int main(int argc, char *argv[]) {
std::cout << "std::vector<int>::iterator " << bbb::iteratable_class_traits<std::vector<int>>::has_iterator << std::endl;
std::cout << "std::vector<int>::reverse_iterator " << bbb::iteratable_class_traits<std::vector<int>>::has_reverse_iterator << std::endl;
std::cout << "std::map<int, int>::iterator " << bbb::iteratable_class_traits<std::map<int, int>>::has_iterator << std::endl;
std::cout << "std::string::iterator " << bbb::iteratable_class_traits<std::string>::has_iterator << std::endl;
std::cout << "int::iterator " << bbb::iteratable_class_traits<int>::has_iterator << std::endl;
std::cout << "bbb::iterator_delegation<std::vector<int>>::iterator " << bbb::iteratable_class_traits<bbb::iterator_delegation<std::vector<int>>>::has_iterator << std::endl;
std::cout << std::endl;
std::cout << "vector has_insert " << bbb::iteratable_class_traits<std::vector<int>>::has_insert << std::endl;
std::cout << "vector has_push_back " << bbb::iteratable_class_traits<std::vector<int>>::has_push_back << std::endl;
std::cout << "vector has_push_front " << bbb::iteratable_class_traits<std::vector<int>>::has_push_front << std::endl;
std::cout << "deque has_insert " << bbb::iteratable_class_traits<std::deque<int>>::has_insert << std::endl;
std::cout << "deque has_push_back " << bbb::iteratable_class_traits<std::deque<int>>::has_push_back << std::endl;
std::cout << "deque has_push_front " << bbb::iteratable_class_traits<std::deque<int>>::has_push_front << std::endl;
std::cout << "list has_insert " << bbb::iteratable_class_traits<std::list<int>>::has_insert << std::endl;
std::cout << "list has_push_back " << bbb::iteratable_class_traits<std::list<int>>::has_push_back << std::endl;
std::cout << "list has_push_front " << bbb::iteratable_class_traits<std::list<int>>::has_push_front << std::endl;
std::cout << "queue has_insert " << bbb::iteratable_class_traits<std::queue<int>>::has_insert << std::endl;
std::cout << "queue has_push_back " << bbb::iteratable_class_traits<std::queue<int>>::has_push_back << std::endl;
std::cout << "queue has_push_front " << bbb::iteratable_class_traits<std::queue<int>>::has_push_front << std::endl;
std::cout << "int has_insert " << bbb::iteratable_class_traits<int>::has_insert << std::endl;
std::cout << "int has_push_back " << bbb::iteratable_class_traits<int>::has_push_back << std::endl;
std::cout << "int has_push_front " << bbb::iteratable_class_traits<int>::has_push_front << std::endl;
vectroid v;
v.body.push_back(-1);
v.body.push_back(-2);
v.body.push_back(-3);
std::vector<int> src{1, 2, 3, 4};
std::copy(src.begin(), src.end(), std::back_inserter(v));
std::copy(src.begin(), src.end(), std::inserter(v, v.begin()));
for(const auto &i : v) {
std::cout << i << std::endl;
}
mappoid m;
m.body.insert(std::make_pair(2, 3));
m.body.insert(std::make_pair(6, 7));
m.body.insert(std::make_pair(4, 5));
m.body.insert(std::make_pair(8, 9));
for(const auto &p : m) {
std::cout << p.first << ", " << p.second << std::endl;
}
introid i;
// for(auto &it : i) {} // Error: delegated type doesn't provide iterator
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment