From 9fb791e9fad6c63fc1dac49f4d05ae63b8a3db9b Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 5 Jan 2016 11:55:15 +0200 Subject: Rename build directory/namespace to build2 --- build2/algorithm.ixx | 197 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 197 insertions(+) create mode 100644 build2/algorithm.ixx (limited to 'build2/algorithm.ixx') diff --git a/build2/algorithm.ixx b/build2/algorithm.ixx new file mode 100644 index 0000000..92cc66d --- /dev/null +++ b/build2/algorithm.ixx @@ -0,0 +1,197 @@ +// file : build2/algorithm.ixx -*- C++ -*- +// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#include // pair + +#include +#include +#include + +namespace build2 +{ + inline target& + search (prerequisite& p) + { + if (p.target == nullptr) + p.target = &search (p.key ()); + + return *p.target; + } + + inline target& + search (const target_type& t, const prerequisite_key& k) + { + return search ( + prerequisite_key + {k.proj, {&t, k.tk.dir, k.tk.name, k.tk.ext}, k.scope}); + } + + inline target& + search (const target_type& type, + const dir_path& dir, + const std::string& name, + const std::string* ext, + scope* scope) + { + return search ( + prerequisite_key {nullptr, {&type, &dir, &name, &ext}, scope}); + } + + template + inline T& + search (const dir_path& dir, + const std::string& name, + const std::string* ext, + scope* scope) + { + return static_cast (search (T::static_type, dir, name, ext, scope)); + } + + std::pair + match_impl (action, target&, bool apply); + + inline void + match (action a, target& t) + { + if (!t.recipe (a)) + match_impl (a, t, true); + + t.dependents++; + dependency_count++; + + // text << "M " << t << ": " << t.dependents << " " << dependency_count; + } + + inline void + unmatch (action, target& t) + { + // text << "U " << t << ": " << t.dependents << " " << dependency_count; + + assert (t.dependents != 0 && dependency_count != 0); + t.dependents--; + dependency_count--; + } + + inline void + match_only (action a, target& t) + { + if (!t.recipe (a)) + match_impl (a, t, false); + } + + inline std::pair + match_delegate (action a, target& t) + { + auto rp (match_impl (a, t, false)); + const match_result& mr (rp.second); + return std::make_pair (rp.first->apply (mr.recipe_action, t, mr), + mr.recipe_action); + } + + group_view + resolve_group_members_impl (action, target&); + + inline group_view + resolve_group_members (action a, target& g) + { + group_view r (g.group_members (a)); + return r.members != nullptr ? r : resolve_group_members_impl (a, g); + } + + inline void + search_and_match_prerequisites (action a, target& t) + { + search_and_match_prerequisites ( + a, + t, + a.operation () != clean_id + ? dir_path () + : t.strong_scope ().out_path ()); + } + + inline void + search_and_match_prerequisite_members (action a, target& t) + { + if (a.operation () != clean_id) + search_and_match_prerequisite_members (a, t, dir_path ()); + else + // Note that here we don't iterate over members even for see- + // through groups since the group target should clean eveything + // up. A bit of an optimization. + // + search_and_match_prerequisites (a, t, t.strong_scope ().out_path ()); + } + + target_state + execute_impl (action, target&); + + inline target_state + execute (action a, target& t) + { + // text << "E " << t << ": " << t.dependents << " " << dependency_count; + + if (dependency_count != 0) // Re-examination of a postponed target? + { + assert (t.dependents != 0); + t.dependents--; + dependency_count--; + } + + switch (target_state ts = t.state ()) + { + case target_state::unchanged: + case target_state::changed: + return ts; + default: + { + // Handle the "last" execution mode. + // + // This gets interesting when we consider interaction with + // groups. It seem to make sense to treat group members as + // dependents of the group, so, for example, if we try to + // clean the group via three of its members, only the last + // attempt will actually execute the clean. This means that + // when we match a group member, inside we should also match + // the group in order to increment the dependents count. This + // seems to be a natural requirement: if we are delegating to + // the group, we need to find a recipe for it, just like we + // would for a prerequisite. + // + // Note that below we are going to change the group state + // to postponed. This is not a mistake: until we execute + // the recipe, we want to keep returning postponed. And + // once the recipe is executed, it will reset the state + // to group (see group_action()). To put it another way, + // the execution of this member is postponed, not of the + // group. + // + // One important invariant to keep in mind: the return + // value from execute() should always be the same as what + // would get returned by a subsequent call to state(). + // + if (current_mode == execution_mode::last && t.dependents != 0) + return (t.raw_state = target_state::postponed); + + return execute_impl (a, t); + } + } + } + + inline target_state + execute_delegate (const recipe& r, action a, target& t) + { + return r (a, t); + } + + inline target_state + execute_direct (action a, target& t) + { + switch (target_state ts = t.state ()) + { + case target_state::unchanged: + case target_state::changed: return ts; + default: return execute_impl (a, t); + } + } +} -- cgit v1.1