diff options
Diffstat (limited to 'build/target')
-rw-r--r-- | build/target | 169 |
1 files changed, 146 insertions, 23 deletions
diff --git a/build/target b/build/target index 49c135f..cca8f8d 100644 --- a/build/target +++ b/build/target @@ -14,6 +14,7 @@ #include <ostream> #include <cassert> #include <utility> // move() +#include <iterator> #include <build/path> #include <build/map-key> // map_iterator_adapter @@ -69,7 +70,7 @@ namespace build extern const recipe default_recipe; target_state - noop_recipe_function (action, target&); + noop_action (action, target&); // Defined in <algorithm> // Prerequisite target. It consist of a reference to the prerequisite // plus a pointer to target to which it resolves in this context. @@ -101,6 +102,16 @@ namespace build prerequisite_target (prerequisite& p, target_type& t) : prereq (&p), target (&t) {} + + // Return true if this object belongs to the target's prerequisite + // list. Note that this test only works if you use references to + // the container elements and the container hasn't been resized + // since such a reference was obtained. Normally this function is + // used when iterating over combined prerequisites range (see + // group_prerequisites below). + // + bool + belongs (const target_type&) const; }; // Target. @@ -126,7 +137,9 @@ namespace build // if any. Note that we assume that the group // and all its members are in the same scope // (see, for example, variable lookup). - public: + // We also currently assume that there are + // no multi-level groups. + public: // Most qualified scope that contains this target. // scope& @@ -145,6 +158,16 @@ namespace build typedef std::vector<prerequisite_target> prerequisites_type; prerequisites_type prerequisites; + // Check if there are any prerequisites, taking into account + // group prerequisites. + // + bool + has_prerequisites () const + { + return !prerequisites.empty () || + (group != nullptr && !group->prerequisites.empty ()); + } + // Target-specific variables. // public: @@ -226,7 +249,7 @@ namespace build // the recipe. // recipe_function** f (recipe_.target<recipe_function*> ()); - state = (f == nullptr || *f != &noop_recipe_function) + state = (f == nullptr || *f != &noop_action) ? target_state::unknown : target_state::unchanged; @@ -255,6 +278,119 @@ namespace build std::ostream& operator<< (std::ostream&, const target&); + // A "range" that presents the prerequisites of a group and one of + // its members as one continuous sequence, or, in other words, as + // if they were in a single container. The group's prerequisites + // come first followed by the member's. If you need to see them + // in the other direction, iterate in reverse, for example: + // + // for (prerequisite_target& pe: group_prerequisites (t)) + // + // for (prerequisite_target& pe: reverse_iterate (group_prerequisites (t)) + // + // Note that in this case the individual elements of each list will + // also be traversed in reverse, but that's what you usually want, + // anyway. + // + class group_prerequisites + { + public: + typedef target::prerequisites_type prerequisites_type; + + explicit + group_prerequisites (target& t): t_ (t) {} + + struct iterator + { + typedef prerequisites_type::iterator base_iterator; + + typedef base_iterator::value_type value_type; + typedef base_iterator::pointer pointer; + typedef base_iterator::reference reference; + typedef base_iterator::difference_type difference_type; + typedef std::bidirectional_iterator_tag iterator_category; + + iterator () {} + iterator (target* t, prerequisites_type* c, base_iterator i) + : t_ (t), c_ (c), i_ (i) {} + + iterator& + operator++ () + { + if (++i_ == c_->end () && c_ != &t_->prerequisites) + { + c_ = &t_->prerequisites; + i_ = c_->begin (); + } + return *this; + } + + iterator + operator++ (int) {iterator r (*this); return ++r;} + + iterator& + operator-- () + { + if (i_ == c_->begin () && c_ == &t_->prerequisites) + { + c_ = &t_->group->prerequisites; + i_ = c_->end (); + } + + --i_; + return *this; + } + + iterator + operator-- (int) {iterator r (*this); return --r;} + + friend bool + operator== (const iterator& x, const iterator& y) + { + return x.t_ == y.t_ && x.c_ == y.c_ && x.i_ == y.i_; + } + + reference operator* () const {return *i_;} + pointer operator-> () const {return i_.operator -> ();} + + friend bool + operator!= (const iterator& x, const iterator& y) {return !(x == y);} + + private: + target* t_ {nullptr}; + prerequisites_type* c_ {nullptr}; + prerequisites_type::iterator i_; + }; + + typedef std::reverse_iterator<iterator> reverse_iterator; + + iterator + begin () const + { + auto& c ((t_.group != nullptr && !t_.group->prerequisites.empty () + ? *t_.group : t_).prerequisites); + return iterator (&t_, &c, c.begin ()); + } + + iterator + end () const + { + auto& c (t_.prerequisites); + return iterator (&t_, &c, c.end ()); + } + + reverse_iterator + rbegin () const {return reverse_iterator (end ());} + + reverse_iterator + rend () const {return reverse_iterator (begin ());} + + private: + target& t_; + }; + + // + // struct target_set { typedef std::map<target_key, std::unique_ptr<target>> map; @@ -277,14 +413,13 @@ namespace build // As above but ignore the extension and return the target or // nullptr instead of the iterator. // - target* - find (const target_type& type, - const dir_path& dir, - const std::string& name) const + template <typename T> + T* + find (const dir_path& dir, const std::string& name) const { const std::string* e (nullptr); - auto i (map_.find (target_key {&type, &dir, &name, &e})); - return i != map_.end () ? i->second.get () : nullptr; + auto i (map_.find (target_key {&T::static_type, &dir, &name, &e})); + return i != map_.end () ? static_cast<T*> (i->second.get ()) : nullptr; } iterator begin () const {return map_.begin ();} @@ -340,20 +475,6 @@ namespace build return new T (std::move (d), std::move (n), e); } - // Default implementation for a target that is a member of a - // target group. Besides creating the target as above this - // version also tries to "link up" with the group. - // - template <typename T, typename G> - target* - member_target_factory (dir_path d, std::string n, const std::string* e) - { - target* g (targets.find (G::static_type, d, n)); - target* t (new T (std::move (d), std::move (n), e)); - t->group = g; - return t; - } - // Modification time-based target. // class mtime_target: public target @@ -465,4 +586,6 @@ namespace build }; } +#include <build/target.ixx> + #endif // BUILD_TARGET |