From 70af0087d8efb3f2f7dc9ffdf2568419913f16da Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 30 Jun 2015 15:07:03 +0200 Subject: Group "see through" iteration, take 1 --- build/target | 225 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 219 insertions(+), 6 deletions(-) (limited to 'build/target') diff --git a/build/target b/build/target index 8161438..b86ea94 100644 --- a/build/target +++ b/build/target @@ -8,15 +8,16 @@ #include #include #include -#include // unique_ptr -#include // size_t -#include // function, reference_wrapper +#include // unique_ptr +#include // size_t +#include // function, reference_wrapper #include #include -#include // move() +#include // move(), forward(), declval() #include +#include -#include // compare_c_string +#include // compare_c_string, reverse_iterate() #include // map_iterator_adapter #include @@ -31,6 +32,9 @@ namespace build class target; class target_group; + target& + search (prerequisite&); // From . + // Target state. // enum class target_state {unknown, postponed, unchanged, changed, failed}; @@ -359,7 +363,7 @@ namespace build private: target* t_ {nullptr}; prerequisites_type* c_ {nullptr}; - prerequisites_type::iterator i_; + base_iterator i_; }; typedef std::reverse_iterator reverse_iterator; @@ -500,6 +504,215 @@ namespace build static const target_type static_type; }; + // A member of a prerequisite. If 'target' is NULL, then this is the + // prerequisite itself. Otherwise, it is its member. In this case + // 'prerequisite' still refers to the prerequisite. + // + struct prerequisite_member + { + typedef build::target target_type; + typedef build::prerequisite prerequisite_type; + + prerequisite_ref& prerequisite; + target_type* target; + + template + bool + is_a () const + { + return target != nullptr + ? target->is_a () != nullptr + : prerequisite.get ().is_a (); + } + + prerequisite_key + key () const + { + return target != nullptr + ? prerequisite_key {target->key (), nullptr} + : prerequisite.get ().key (); + } + + const build::target_type& + type () const + { + return target != nullptr ? target->type () : prerequisite.get ().type; + } + + target_type& + search () const + { + return target != nullptr ? *target : build::search (prerequisite); + } + + prerequisite_type& + as_prerequisite (tracer&) const; + }; + + inline std::ostream& + operator<< (std::ostream& os, const prerequisite_member& pm) + { + return os << pm.key (); + } + + // A "range" that presents a sequence of prerequisites (e.g., from + // group_prerequisites()) as a sequence of prerequisite_member's. For + // each prerequisite you will first "see" the prerequisite itself + // followed by all its members, if it resolves to a target group. + // You can skip the group members with the skip_group() iterator + // function. Usage: + // + // for (prerequisite_member pm: prerequisite_members (a, ...)) + // + // Where ... can be: + // + // t.prerequisites + // reverse_iterate(t.prerequisites) + // group_prerequisites (t) + // reverse_iterate (group_prerequisites (t)) + // + // But use shortcuts instead: + // + // prerequisite_members (a, t) + // reverse_prerequisite_members (a, t) + // group_prerequisite_members (a, t) + // reverse_group_prerequisite_members (a, t) + // + template + class prerequisite_members_range; + + template + inline prerequisite_members_range + prerequisite_members (action a, T&& x) + { + return prerequisite_members_range (a, std::forward (x)); + } + + template + class prerequisite_members_range + { + public: + prerequisite_members_range (action a, T&& r) + : a_ (a), r_ (std::forward (r)) {} + + struct iterator + { + using base_iterator = decltype (std::declval ().begin ()); + + typedef prerequisite_member value_type; + typedef const value_type* pointer; + typedef const value_type& reference; + typedef typename base_iterator::difference_type difference_type; + typedef std::forward_iterator_tag iterator_category; + + iterator (): a_ (0, 0) {} + iterator (action a, base_iterator i): a_ (a), i_ (i), g_ {nullptr, 0} {} + + iterator& operator++ (); + iterator operator++ (int) {iterator r (*this); return ++r;} + + // Skip iterating over this group's members, if any. Note that + // the only valid operation after this call is to increment the + // iterator. + // + // + void + skip_group () + { + // Pretend we are on the last member of some group. + // + j_ = 0; + g_.count = 1; + } + + /* + reference operator* () const + { + m_.prerequisite = *i; + m_.target = g_.count != 0 ? g_.members[j_] : nullptr; + return m_; + } + */ + + value_type operator* () const + { + return value_type {*i_, g_.count != 0 ? g_.members[j_] : nullptr}; + } + + pointer operator-> () const + { + static_assert ( + std::is_trivially_destructible::value, + "prerequisite_member is not trivially destructible"); + + return new (&m_) + value_type {*i_, g_.count != 0 ? g_.members[j_] : nullptr}; + } + + friend bool + operator== (const iterator& x, const iterator& y) + { + return x.i_ == y.i_ && + x.g_.count == y.g_.count && + (x.g_.count == 0 || x.j_ == y.j_); + } + + friend bool + operator!= (const iterator& x, const iterator& y) {return !(x == y);} + + private: + action a_; + base_iterator i_; + group_view g_; + std::size_t j_; + mutable std::aligned_storage::type m_; + }; + + iterator + begin () const {return iterator (a_, r_.begin ());} + + iterator + end () const {return iterator (a_, r_.end ());} + + private: + action a_; + T r_; + }; + + // prerequisite_members(t.prerequisites) + // + inline auto + prerequisite_members (action a, target& t) + { + return prerequisite_members (a, t.prerequisites); + } + + // prerequisite_members(reverse_iterate(t.prerequisites)) + // + inline auto + reverse_prerequisite_members (action a, target& t) + { + return prerequisite_members (a, butl::reverse_iterate (t.prerequisites)); + } + + // prerequisite_members(group_prerequisites (t)) + // + inline auto + group_prerequisite_members (action a, target& t) + { + return prerequisite_members (a, group_prerequisites (t)); + } + + // prerequisite_members(reverse_iterate (group_prerequisites (t))) + // + inline auto + reverse_group_prerequisite_members (action a, target& t) + { + return prerequisite_members ( + a, butl::reverse_iterate (group_prerequisites (t))); + } + // Modification time-based target. // class mtime_target: public target -- cgit v1.1