From 5f7c3f923de106f9d204a8f3500274731ae84fd9 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Sat, 9 Apr 2016 11:38:42 +0200 Subject: Tweak override logic WRT location of overridden value --- build2/scope | 18 +++++++-------- build2/scope.cxx | 66 +++++++++++++++++++++++++++++++++++------------------ build2/variable | 10 +++++--- build2/variable.cxx | 3 ++- 4 files changed, 62 insertions(+), 35 deletions(-) (limited to 'build2') diff --git a/build2/scope b/build2/scope index 566466a..09914a9 100644 --- a/build2/scope +++ b/build2/scope @@ -92,7 +92,7 @@ namespace build2 lookup operator[] (const variable& var) const { - return find (var, nullptr, nullptr); + return find (var).first; } lookup @@ -106,7 +106,7 @@ namespace build2 lookup find (const variable& var, const target_key& tk) const { - return find (var, tk.type, tk.name); + return find (var, tk.type, tk.name).first; } lookup @@ -118,7 +118,7 @@ namespace build2 lookup find (const variable& var, const target_type& tt, const string& tn) const { - return find (var, &tt, &tn); + return find (var, &tt, &tn).first; } lookup @@ -127,13 +127,13 @@ namespace build2 return find (var_pool.find (var), tt, tn); } - lookup - find (const variable& var, const target_type* tt, const string* tn) const + pair + find (const variable& var, + const target_type* tt = nullptr, + const string* tn = nullptr) const { auto p (find_original (var, tt, tn)); - return var.override == nullptr - ? p.first - : find_override (var, move (p), false).first; + return var.override == nullptr ? p : find_override (var, move (p)); } // Implementation details (used by scope target lookup). @@ -147,7 +147,7 @@ namespace build2 pair find_override (const variable&, pair&& original, - bool target) const; + bool target = false) const; // Return a value suitable for assignment (or append if you only // want to append to the value from this scope). If the variable diff --git a/build2/scope.cxx b/build2/scope.cxx index 3fd3c95..75652a2 100644 --- a/build2/scope.cxx +++ b/build2/scope.cxx @@ -66,6 +66,11 @@ namespace build2 // be a few of them. As a result, here we concentrate on keeping the logic // as straightforward as possible without trying to optimize anything. // + // Note also that we rely (e.g., in the config module) on the fact that if + // no overrides apply, then we return the original value and not its copy + // in the cache (this can be used to detect if the value was overriden). + // + // assert (var.override != nullptr); lookup& origl (original.first); @@ -73,9 +78,9 @@ namespace build2 // The first step is to find out where our cache will reside. After some // meditation it becomes clear it should be next to the innermost (scope- - // wise) value (override or original) that contributes to the end result. + // wise) value (override or original) that could contribute to the end + // result. // - size_t depth (0); const variable_map* vars (nullptr); // Root scope of a project from which our initial value comes. See below. @@ -92,12 +97,9 @@ namespace build2 if (targetspec) { - depth = origd; vars = origl.vars; proj = root_scope (); } - else - depth = 2; // For implied target-specific lookup. } const scope* s; @@ -172,16 +174,11 @@ namespace build2 // if (vars == nullptr && origl.defined () && belongs (origl)) { - depth = origd; vars = origl.vars; - proj = s->root_scope (); + proj = s->root_scope (); // This is so we skip non-recursive overrides + // that would not apply. We reset it later. } - if (vars == nullptr) - // Extra 2 for implied target type/pattern-specific lookup. - // - depth += target ? 3 : 1; - for (const variable* o (var.override.get ()); o != nullptr; o = o->override.get ()) @@ -218,17 +215,20 @@ namespace build2 // versioning (incremented on every update) to detect stem value changes. // We also need to watch out for the change of the stem itself in addition // to its value (think of a new variable set since last lookup which is - // now a new stem). + // now a new stem). Thus stem_vars in variable_override_value. // // @@ MT // - variable_override_value& cache (variable_override_cache[vars]); + variable_override_value& cache ( + variable_override_cache[make_pair (vars, &var)]); // Now find our "stem", that is the value to which we will be appending // suffixes and prepending prefixes. This is either the original or the // __override provided it applies. We may also not have either. // lookup stem (targetspec ? origl : lookup ()); + size_t depth (targetspec ? origd : 0); + size_t ovrd (target ? 2 : 0); // For implied target-specific lookup. for (s = this; s != nullptr; s = s->parent_scope ()) { @@ -239,10 +239,13 @@ namespace build2 if (origl.defined () && belongs (origl)) { stem = origl; + depth = origd; proj = s->root_scope (); // Keep searching. } + ++ovrd; + // Then look for an __override that applies. // for (const variable* o (var.override.get ()); @@ -259,6 +262,7 @@ namespace build2 if (l.defined ()) { + depth = ovrd; stem = move (l); proj = s->root_scope (); done = true; @@ -301,8 +305,13 @@ namespace build2 // Now apply override prefixes and suffixes. // + ovrd = target ? 2 : 0; + const variable_map* ovrv (cache.stem_vars); + for (s = this; s != nullptr; s = s->parent_scope ()) { + ++ovrd; + for (const variable* o (var.override.get ()); o != nullptr; o = o->override.get ()) @@ -331,18 +340,31 @@ namespace build2 cache.value.append (names (cast (l)), var); } - // If we had no stem, use the scope of the first override that applies - // as the project. - // - if (proj == nullptr && l.defined ()) - proj = s; + if (l.defined ()) + { + // If we had no stem, use the scope of the first override that + // applies as the project. For vars/depth we need to pick the + // innermost. + // + if (proj == nullptr) + { + proj = s->root_scope (); + depth = ovrd; + ovrv = &s->vars; + } + else if (ovrd < depth) + { + depth = ovrd; + ovrv = &s->vars; + } + } } } - // Use the location of the cache (innermost value that contributes) as - // the location of the result. + // Use the location of the innermost value that contributed as the + // location of the result. // - return make_pair (lookup (&cache.value, vars), depth); + return make_pair (lookup (&cache.value, ovrv), depth); } value& scope:: diff --git a/build2/variable b/build2/variable index 5a33037..77e9db2 100644 --- a/build2/variable +++ b/build2/variable @@ -277,11 +277,15 @@ namespace build2 belongs (const T& x) const {return vars == &x.vars;} lookup (): value (nullptr), vars (nullptr) {} - lookup (const value_type* v, const variable_map* vs) - : value (v), vars (v != nullptr ? vs : nullptr) {} template lookup (const value_type& v, const T& x): lookup (&v, &x.vars) {} + + lookup (const value_type& v, const variable_map& vs) + : value (&v), vars (&vs) {} + + lookup (const value_type* v, const variable_map* vs) + : value (v), vars (v != nullptr ? vs : nullptr) {} }; // Two lookups are equal if they point to the same variable. @@ -735,7 +739,7 @@ namespace build2 const variable_map* stem_vars = nullptr; // NULL means there is no stem. }; - extern std::map, variable_override_value> variable_override_cache; } diff --git a/build2/variable.cxx b/build2/variable.cxx index 61f5975..4a2ffa9 100644 --- a/build2/variable.cxx +++ b/build2/variable.cxx @@ -742,5 +742,6 @@ namespace build2 // variable_override // - map variable_override_cache; + map, variable_override_value> + variable_override_cache; } -- cgit v1.1