From cd3a77649e1c278fe5070b6eee5e5e3b55c89bce Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 4 Jan 2010 11:19:01 +0100 Subject: [PATCH] use the (new) iterable classification to mask for_each overloads --- src/lib/meta/duck-detector.hpp | 20 ++-- src/lib/meta/trait.hpp | 64 ++++++++++++- src/lib/util-foreach.hpp | 92 +++++++++---------- .../lib/meta/iterable-classification-test.cpp | 53 ----------- tests/lib/typed-counter-test.cpp | 7 +- 5 files changed, 119 insertions(+), 117 deletions(-) diff --git a/src/lib/meta/duck-detector.hpp b/src/lib/meta/duck-detector.hpp index 8c5a4656a..70bec2a18 100644 --- a/src/lib/meta/duck-detector.hpp +++ b/src/lib/meta/duck-detector.hpp @@ -74,24 +74,16 @@ #define LIB_META_DUCK_DETECTOR_H +#include "lib/meta/util.hpp" namespace lib { +namespace meta{ - - /* types for figuring out the overload resolution chosen by the compiler */ - - typedef char Yes_t; - struct No_t { char padding[8]; }; - - ////////////////////////////////////TODO: after fixing the namespace of typelist/meta programming facilities, these can be dropped. - - - - namespace meta { + ///////////////TICKET #175 sort out meta namespace + using lumiera::Yes_t; + using lumiera::No_t; - } // namespace meta - -} // namespace lib +}} // namespace lib::meta diff --git a/src/lib/meta/trait.hpp b/src/lib/meta/trait.hpp index b70310588..1852068a9 100644 --- a/src/lib/meta/trait.hpp +++ b/src/lib/meta/trait.hpp @@ -73,6 +73,68 @@ namespace meta { + /** Trait template to detect a type usable with the STL for-each loop. + * Basically we're looking for the functions to get the begin/end iterator + */ + template + class can_STL_ForEach + { + struct is_iterable + { + META_DETECT_NESTED(iterator); + META_DETECT_FUNCTION(typename X::iterator, begin,(void)); + META_DETECT_FUNCTION(typename X::iterator, end ,(void)); + + enum { value = HasNested_iterator::value + && HasFunSig_begin::value + && HasFunSig_end::value + }; + }; + + struct is_const_iterable + { + META_DETECT_NESTED(const_iterator); + META_DETECT_FUNCTION(typename X::const_iterator, begin,(void) const); + META_DETECT_FUNCTION(typename X::const_iterator, end ,(void) const); + + enum { value = HasNested_const_iterator::value + && HasFunSig_begin::value + && HasFunSig_end::value + }; + }; + + + public: + enum { value = is_iterable::value + || is_const_iterable::value + }; + }; + + + /** Trait template to detect a type usable immediately as + * "Lumiera Forward Iterator" in a specialised for-each loop + * This is just a heuristic, based on some common properties + * of such iterators; it is enough to distinguish it from an + * STL container, but can certainly be refined. + */ + template + class can_IterForEach + { + + META_DETECT_NESTED(value_type); + META_DETECT_OPERATOR_DEREF(); + META_DETECT_OPERATOR_INC(); + + public: + enum{ value = boost::is_convertible::value + && HasNested_value_type::value + && HasOperator_deref::value + && HasOperator_inc::value + }; + }; + + + /** Type definition helper for pointer and reference types. * Allows to create a member field and to get the basic type * irrespective if the given type is plain, pointer or reference @@ -103,7 +165,7 @@ namespace meta { typedef TY value_type; typedef lib::wrapper::AssignableRefWrapper member_type; }; - //////////////////////////////////////////TODO: not needed 12/09 -- obsolete? useful? keep it? + //////////////////////////////////////////TODO: member_type not needed anymore 12/09 -- obsolete? useful? keep it? }} // namespace lib::meta diff --git a/src/lib/util-foreach.hpp b/src/lib/util-foreach.hpp index c5f1e2253..b0a3f9989 100644 --- a/src/lib/util-foreach.hpp +++ b/src/lib/util-foreach.hpp @@ -25,53 +25,32 @@ #define UTIL_FOREACH_H #include "lib/util.hpp" +#include "lib/meta/trait.hpp" +#include #include namespace util { + using boost::enable_if; + using boost::disable_if; + using lib::meta::can_STL_ForEach; + using lib::meta::can_IterForEach; - /** shortcut for operating on all elements of a container. - * Isn't this already defined somewhere? It's so obvious.. - */ - template - inline Oper - for_each (Container& c, Oper doIt) - { - return std::for_each (c.begin(),c.end(), doIt); - } /** All quantification: check if all elements of a collection * satisfy the given predicate. Actually a short-circuit * evaluation is performed. */ - template + template inline bool - and_all (SEQ& coll, Oper predicate) + and_all (IT i, IT end, FUN predicate) { - typename SEQ::iterator e = coll.end(); - typename SEQ::iterator i = coll.begin(); - - for ( ; i!=e; ++i ) - if (!predicate(*i)) - return false; - - return true; - } - - - template - inline bool - and_all (SEQ const& coll, Oper predicate) - { - typename SEQ::const_iterator e = coll.end(); - typename SEQ::const_iterator i = coll.begin(); - - for ( ; i!=e; ++i ) + for ( ; i!=end; ++i ) if (!predicate(*i)) return false; @@ -83,14 +62,11 @@ namespace util { * of a collection satisfies the given predicate. * Actually, a short-circuit evaluation is performed. */ - template + template inline bool - has_any (SEQ& coll, Oper predicate) + has_any (IT i, IT end, FUN predicate) { - typename SEQ::iterator e = coll.end(); - typename SEQ::iterator i = coll.begin(); - - for ( ; i!=e; ++i ) + for ( ; i!=end; ++i ) if (predicate(*i)) return true; @@ -98,18 +74,40 @@ namespace util { } - template - inline bool - has_any (SEQ const& coll, Oper predicate) + /* === specialisations for STL containers and Lumiera Forward Iterators === */ + + /** shortcut for operating on all elements of a STL container. */ + template + inline typename disable_if< can_IterForEach, + FUN >::type + for_each (Container& c, FUN doIt) { - typename SEQ::const_iterator e = coll.end(); - typename SEQ::const_iterator i = coll.begin(); - - for ( ; i!=e; ++i ) - if (predicate(*i)) - return true; - - return false; + return std::for_each (c.begin(),c.end(), doIt); + } + + + + template + inline typename enable_if< can_STL_ForEach, + bool >::type + and_all (Container& coll, FUN predicate) + { + return and_all (coll.begin(),coll.end(), predicate); + } + + + template + inline typename enable_if< can_STL_ForEach, + bool >::type + has_any (Container& coll, FUN predicate) + { + return has_any (coll.begin(),coll.end(), predicate); } diff --git a/tests/lib/meta/iterable-classification-test.cpp b/tests/lib/meta/iterable-classification-test.cpp index 930630626..b4cc0a684 100644 --- a/tests/lib/meta/iterable-classification-test.cpp +++ b/tests/lib/meta/iterable-classification-test.cpp @@ -42,59 +42,6 @@ namespace lib { -/////////////////////////////////////////////////////////////TODO draft - - template - class can_STL_ForEach - { - struct is_iterable - { - META_DETECT_NESTED(iterator); - META_DETECT_FUNCTION(typename X::iterator, begin,(void)); - META_DETECT_FUNCTION(typename X::iterator, end ,(void)); - - enum { value = HasNested_iterator::value - && HasFunSig_begin::value - && HasFunSig_end::value - }; - }; - - struct is_const_iterable - { - META_DETECT_NESTED(const_iterator); - META_DETECT_FUNCTION(typename X::const_iterator, begin,(void) const); - META_DETECT_FUNCTION(typename X::const_iterator, end ,(void) const); - - enum { value = HasNested_const_iterator::value - && HasFunSig_begin::value - && HasFunSig_end::value - }; - }; - - - public: - enum { value = is_iterable::value - || is_const_iterable::value - }; - }; - - template - class can_IterForEach - { - - META_DETECT_NESTED(value_type); - META_DETECT_OPERATOR_DEREF(); - META_DETECT_OPERATOR_INC(); - - public: - enum{ value = boost::is_convertible::value - && HasNested_value_type::value - && HasOperator_deref::value - && HasOperator_inc::value - }; - }; - -/////////////////////////////////////////////////////////////TODO draft namespace meta{ namespace test{ diff --git a/tests/lib/typed-counter-test.cpp b/tests/lib/typed-counter-test.cpp index 02d9e26d4..68eefc988 100644 --- a/tests/lib/typed-counter-test.cpp +++ b/tests/lib/typed-counter-test.cpp @@ -216,9 +216,12 @@ namespace test{ targets_[victim].doCount (counter_to_use); } + + typedef TargetVect::iterator iterator; + /** allow Iteration over all targets in the TargetVect */ - TargetVect::iterator begin() { return targets_.begin(); } - TargetVect::iterator end() { return targets_.end(); } + iterator begin() { return targets_.begin(); } + iterator end() { return targets_.end(); } }; DummyTarget targetCollection;