From d66e21ffa3ac9520fb15dd3859339b178d6e6540 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 11 Oct 2022 06:29:16 +0200 Subject: Factor variable patterns out of variable_pool into separate variable_patterns We have patterns only for the public variables pool. --- libbuild2/context.cxx | 24 +++--- libbuild2/context.hxx | 3 +- libbuild2/file.cxx | 2 +- libbuild2/forward.hxx | 1 + libbuild2/variable.cxx | 34 +++++---- libbuild2/variable.hxx | 198 ++++++++++++++++++++++++++++++++----------------- 6 files changed, 168 insertions(+), 94 deletions(-) diff --git a/libbuild2/context.cxx b/libbuild2/context.cxx index e44d79f..4cbdecb 100644 --- a/libbuild2/context.cxx +++ b/libbuild2/context.cxx @@ -45,6 +45,7 @@ namespace build2 scope_map scopes; target_set targets; variable_pool var_pool; + variable_patterns var_patterns; variable_overrides var_overrides; function_map functions; @@ -55,7 +56,8 @@ namespace build2 data (context& c) : scopes (c), targets (c), - var_pool (&c /* shared */, nullptr /* outer */) {} + var_pool (&c /* shared */, nullptr /* outer */, &var_patterns), + var_patterns (&c /* shared */, &var_pool) {} }; context:: @@ -81,6 +83,7 @@ namespace build2 scopes (data_->scopes), targets (data_->targets), var_pool (data_->var_pool), + var_patterns (data_->var_patterns), var_overrides (data_->var_overrides), functions (data_->functions), global_scope (create_global_scope (data_->scopes)), @@ -99,6 +102,7 @@ namespace build2 scope_map& sm (data_->scopes); variable_pool& vp (data_->var_pool); + variable_patterns& vpats (data_->var_patterns); insert_builtin_functions (functions); @@ -330,7 +334,7 @@ namespace build2 // Note that some config.config.* variables have project visibility thus // the match argument is false. // - vp.insert_pattern ("config.**", nullopt, true, v_g, true, false); + vpats.insert ("config.**", nullopt, true, v_g, true, false); // Parse and enter the command line variables. We do it before entering // any other variables so that all the variables that are overriden are @@ -548,24 +552,26 @@ namespace build2 const auto v_t (variable_visibility::target); const auto v_q (variable_visibility::prereq); - vp.insert_pattern ("config.**.configured", false, v_p); + vpats.insert ("config.**.configured", false, v_p); - // file.cxx:import() (note: order is important; see insert_pattern()). + // file.cxx:import() + // + // Note: the order is important (see variable_patterns::insert()). // // Note that if any are overriden, they are "pre-typed" by the config.** // pattern above and we just "add" the types. // - vp.insert_pattern ("config.import.*", true, v_g, true); - vp.insert_pattern ("config.import.**", true, v_g, true); + vpats.insert ("config.import.*", true, v_g, true); + vpats.insert ("config.import.**", true, v_g, true); // module.cxx:boot/init_module(). // // Note that we also have the config..configured variable (see // above). // - vp.insert_pattern ("**.booted", false /* overridable */, v_p); - vp.insert_pattern ("**.loaded", false, v_p); - vp.insert_pattern ("**.configured", false, v_p); + vpats.insert ("**.booted", false /* overridable */, v_p); + vpats.insert ("**.loaded", false, v_p); + vpats.insert ("**.configured", false, v_p); var_src_root = &vp.insert ("src_root"); var_out_root = &vp.insert ("out_root"); diff --git a/libbuild2/context.hxx b/libbuild2/context.hxx index 0747350..9cb4fb4 100644 --- a/libbuild2/context.hxx +++ b/libbuild2/context.hxx @@ -380,7 +380,8 @@ namespace build2 // const scope_map& scopes; target_set& targets; - const variable_pool& var_pool; // Public variables. + const variable_pool& var_pool; // Public variables pool. + const variable_patterns& var_patterns; // Public variables patterns. const variable_overrides& var_overrides; // Project and relative scope. function_map& functions; diff --git a/libbuild2/file.cxx b/libbuild2/file.cxx index a2fe906..a3962d7 100644 --- a/libbuild2/file.cxx +++ b/libbuild2/file.cxx @@ -611,7 +611,7 @@ namespace build2 a ? alt_export_file : std_export_file, a ? alt_src_root_file : std_src_root_file, a ? alt_out_root_file : std_out_root_file, - {&ctx, &ctx.var_pool.rw (root)}, /* var_pool */ + {&ctx, &ctx.var_pool.rw (root), nullptr}, /* var_pool */ {}, /* meta_operations */ {}, /* operations */ {}, /* modules */ diff --git a/libbuild2/forward.hxx b/libbuild2/forward.hxx index d2b8989..057ab24 100644 --- a/libbuild2/forward.hxx +++ b/libbuild2/forward.hxx @@ -26,6 +26,7 @@ namespace build2 struct variable; class variable_pool; + class variable_patterns; class variable_map; struct variable_override; using variable_overrides = vector; diff --git a/libbuild2/variable.cxx b/libbuild2/variable.cxx index 5c32d89..54bdcf6 100644 --- a/libbuild2/variable.cxx +++ b/libbuild2/variable.cxx @@ -1659,7 +1659,7 @@ namespace build2 } static inline void - merge_pattern (const variable_pool::pattern& p, + merge_pattern (const variable_patterns::pattern& p, const build2::value_type*& t, const variable_visibility*& v, const bool*& o) @@ -1714,16 +1714,18 @@ namespace build2 // Apply pattern. // + using pattern = variable_patterns::pattern; + const pattern* pa (nullptr); auto pt (t); auto pv (v); auto po (o); - if (pat) + if (pat && patterns_ != nullptr) { if (n.find ('.') != string::npos) { // Reverse means from the "largest" (most specific). // - for (const pattern& p: reverse_iterate (patterns_)) + for (const pattern& p: reverse_iterate (patterns_->patterns_)) { if (match_pattern (n, p.prefix, p.suffix, p.multi)) { @@ -1800,13 +1802,13 @@ namespace build2 return a; } - void variable_pool:: - insert_pattern (const string& p, - optional t, - optional o, - optional v, - bool retro, - bool match) + void variable_patterns:: + insert (const string& p, + optional t, + optional o, + optional v, + bool retro, + bool match) { assert (!shared_ || shared_->phase == run_phase::load); @@ -1842,9 +1844,9 @@ namespace build2 // Apply retrospectively to existing variables. // - if (retro) + if (retro && pool_ != nullptr) { - for (auto& p: map_) + for (auto& p: pool_->map_) { variable& var (p.second); @@ -1861,10 +1863,10 @@ namespace build2 } if (j == e) - update (var, - t ? *t : nullptr, - v ? &*v : nullptr, - o ? &*o : nullptr); // Not changing the key. + pool_->update (var, + t ? *t : nullptr, + v ? &*v : nullptr, + o ? &*o : nullptr); // Not changing the key. } } } diff --git a/libbuild2/variable.hxx b/libbuild2/variable.hxx index 9f1eee6..bfe3b87 100644 --- a/libbuild2/variable.hxx +++ b/libbuild2/variable.hxx @@ -148,9 +148,9 @@ namespace build2 // A variable. // // A variable can be public, project-private, or script-private, which - // corresponds to the variable pool it belongs to. The two variables from - // the same pool are considered the same if they have the same name. The - // variable access (public/private) rules are: + // corresponds to the variable pool it belongs to (see variable_pool). The + // two variables from the same pool are considered the same if they have the + // same name. The variable access (public/private) rules are: // // - Qualified variable are by default public while unqualified -- private. // @@ -1248,7 +1248,9 @@ namespace build2 // The shared versions (as in, context or project-wide) are protected by the // phase mutex and thus can only be modified during the load phase. // - class variable_pool + class variable_patterns; + + class LIBBUILD2_SYMEXPORT variable_pool { public: // Find existing (assert exists). @@ -1352,9 +1354,10 @@ namespace build2 // Overridable aliased variables are most likely a bad idea: without a // significant effort, the overrides will only be applied along the alias // names (i.e., there would be no cross-alias overriding). So for now we - // don't allow this (use the common variable mechanism instead). + // don't allow this (manually handle multiple names by merging their + // values instead). // - LIBBUILD2_SYMEXPORT const variable& + const variable& insert_alias (const variable& var, string name); // Iteration. @@ -1368,61 +1371,39 @@ namespace build2 const_iterator begin () const {return const_iterator (map_.begin ());} const_iterator end () const {return const_iterator (map_.end ());} - // Variable patterns. + // Construction. // - public: - // Insert a variable pattern. Any variable that matches this pattern will - // have the specified type, visibility, and overridability. If match is - // true, then individual insertions of the matching variable must match - // the specified type/visibility/overridability. Otherwise, individual - // insertions can provide alternative values and the pattern values are a - // fallback (if you specify false you better be very clear about what you - // are trying to achieve). - // - // The pattern must be in the form [.](*|**)[.] where '*' - // matches single component stems (i.e., 'foo' but not 'foo.bar') and '**' - // matches single and multi-component stems. Note that only multi- - // component variables are considered for pattern matching (so just '*' - // won't match anything). + // There are three specific variable pool instances: // - // The patterns are matched in the more-specific-first order where the - // pattern is considered more specific if it has a greater sum of its - // prefix and suffix lengths. If the prefix and suffix are equal, then the - // '*' pattern is considered more specific than '**'. If neither is more - // specific, then they are matched in the reverse order of insertion. + // shared outer + // ---------------- + // true null -- public variable pool in context + // true not null -- project-private pool in scope::root_extra + // with outer pointing to context::var_pool + // false null -- script-private pool in script::environment // - // If retro is true then a newly inserted pattern is also applied - // retrospectively to all the existing variables that match but only - // if no more specific pattern already exists (which is then assumed - // to have been applied). So if you use this functionality, watch out - // for the insertion order (you probably want more specific first). + // Notice that the script-private pool doesn't rely on outer and does + // its own pool chaining. So currently we assume that if outer is not + // NULL, then this is a project-private pool. // - LIBBUILD2_SYMEXPORT void - insert_pattern (const string& pattern, - optional type, - optional overridable, - optional, - bool retro = false, - bool match = true); + private: + friend class context; + friend void setup_root_extra (scope&, optional&); - template - void - insert_pattern (const string& p, - optional overridable, - optional v, - bool retro = false, - bool match = true) - { - insert_pattern ( - p, &value_traits::value_type, overridable, v, retro, match); - } + // Shared pool (public or project-private). The shared argument is + // flag/context. + // + variable_pool (context* shared, + variable_pool* outer, + const variable_patterns* patterns) + : shared_ (shared), outer_ (outer), patterns_ (patterns) {} public: - // Create a private pool. + // Script-private pool. // explicit - variable_pool (variable_pool* outer = nullptr) - : variable_pool (nullptr /* shared */, outer) {} + variable_pool (const variable_patterns* patterns = nullptr) + : shared_ (nullptr), outer_ (nullptr), patterns_ (patterns) {} variable_pool (variable_pool&&) = delete; variable_pool& operator= (variable_pool&&) = delete; @@ -1430,6 +1411,7 @@ namespace build2 variable_pool (const variable_pool&) = delete; variable_pool& operator= (const variable_pool&) = delete; + public: // RW access (only for shared pools). // variable_pool& @@ -1451,14 +1433,14 @@ namespace build2 // Note that in insert() NULL overridable is interpreted as false unless // overridden by a pattern while in update() NULL overridable is ignored. // - LIBBUILD2_SYMEXPORT pair + pair insert (string name, const value_type*, const variable_visibility*, const bool* overridable, bool pattern = true); - LIBBUILD2_SYMEXPORT void + void update (variable&, const value_type*, const variable_visibility*, @@ -1484,10 +1466,100 @@ namespace build2 return r; } + private: + friend class variable_patterns; + + context* shared_; + variable_pool* outer_; + const variable_patterns* patterns_; map map_; + }; - // Patterns. + // Variable patterns. + // + // This mechanism is used to assign variable types/visibility/overridability + // based on the variable name pattern. This mechanism can only be used for + // qualified variables and is thus only provided for the public variable + // pool. + // + // Similar to variable_pool, the shared versions are protected by the phase + // mutex and thus can only be modified during the load phase. + // + class LIBBUILD2_SYMEXPORT variable_patterns + { + public: + // Insert a variable pattern. Any variable that matches this pattern will + // have the specified type, visibility, and overridability. If match is + // true, then individual insertions of the matching variable must match + // the specified type/visibility/overridability. Otherwise, individual + // insertions can provide alternative values and the pattern values are a + // fallback (if you specify false you better be very clear about what you + // are trying to achieve). + // + // The pattern must be in the form [.](*|**)[.] where '*' + // matches single component stems (i.e., 'foo' but not 'foo.bar') and '**' + // matches single and multi-component stems. Note that only multi- + // component variables are considered for pattern matching (so just '*' + // won't match anything). + // + // The patterns are matched in the more-specific-first order where the + // pattern is considered more specific if it has a greater sum of its + // prefix and suffix lengths. If the prefix and suffix are equal, then the + // '*' pattern is considered more specific than '**'. If neither is more + // specific, then they are matched in the reverse order of insertion. + // + // If retro is true then a newly inserted pattern is also applied + // retrospectively to all the existing variables that match but only + // if no more specific pattern already exists (which is then assumed + // to have been applied). So if you use this functionality, watch out + // for the insertion order (you probably want more specific first). + // + void + insert (const string& pattern, + optional type, + optional overridable, + optional, + bool retro = false, + bool match = true); + + template + void + insert (const string& p, + optional overridable, + optional v, + bool retro = false, + bool match = true) + { + insert (p, &value_traits::value_type, overridable, v, retro, match); + } + + public: + // The shared argument is flag/context. The pool argument is for + // retrospective pattern application. // + explicit + variable_patterns (context* shared, variable_pool* pool) + : shared_ (shared), pool_ (pool) {} + + variable_patterns (variable_patterns&&) = delete; + variable_patterns& operator= (variable_patterns&&) = delete; + + variable_patterns (const variable_patterns&) = delete; + variable_patterns& operator= (const variable_patterns&) = delete; + + public: + // RW access (only for shared pools). + // + variable_patterns& + rw () const + { + assert (shared_->phase == run_phase::load); + return const_cast (*this); + } + + variable_patterns& + rw (scope&) const {return const_cast (*this);} + public: struct pattern { @@ -1515,19 +1587,11 @@ namespace build2 }; private: - multiset patterns_; - - // Shared pool flag/context. - // - private: - friend class context; - friend void setup_root_extra (scope&, optional&); + friend class variable_pool; - variable_pool (context* shared, variable_pool* outer) - : shared_ (shared), outer_ (outer) {} - - context* shared_; - variable_pool* outer_; + context* shared_; + variable_pool* pool_; + multiset patterns_; }; } -- cgit v1.1