aboutsummaryrefslogtreecommitdiff
path: root/build/target
diff options
context:
space:
mode:
Diffstat (limited to 'build/target')
-rw-r--r--build/target169
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