Last active
December 18, 2015 01:28
-
-
Save 2bbb/c9467adc2849a265e764 to your computer and use it in GitHub Desktop.
iterator_delegation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #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