From f519c44792429ce52cfab09898701bff9c202770 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 31 Jan 2017 09:53:25 +0200 Subject: Add load generation to global variable_map values --- build2/context | 2 +- build2/parser.cxx | 18 ++++++++----- build2/target | 2 +- build2/types | 4 +++ build2/variable | 38 +++++++++++++++++++------- build2/variable.cxx | 77 +++++++++++++++++++++++++++++++++++++++-------------- build2/variable.ixx | 20 +++++++++++--- 7 files changed, 118 insertions(+), 43 deletions(-) diff --git a/build2/context b/build2/context index 2f0a76f..c443a7a 100644 --- a/build2/context +++ b/build2/context @@ -24,7 +24,7 @@ namespace build2 // The phase can only be changed during serial or exclusive execution // (see below). // - extern enum class run_phase {load, search_match, execute} phase; + extern run_phase phase; // The build system model (internal state) is protected at the top level by // the model mutex. During serial execution the model mutex is unlocked. diff --git a/build2/parser.cxx b/build2/parser.cxx index af6a6f5..7f6b940 100644 --- a/build2/parser.cxx +++ b/build2/parser.cxx @@ -1658,13 +1658,17 @@ namespace build2 // be the same. Also check that the requested value type doesn't conflict // with the variable type. // - if (type != nullptr && - var != nullptr && - var->type != nullptr && - var->type != type) + if (var != nullptr && var->type != nullptr) { - fail (l) << "conflicting variable " << var->name << " type " - << var->type->name << " and value type " << type->name; + if (type == nullptr) + { + type = var->type; + } + else if (var->type != type) + { + fail (l) << "conflicting variable " << var->name << " type " + << var->type->name << " and value type " << type->name; + } } // What if both LHS and RHS are typed? For now we do lexical conversion: @@ -1682,7 +1686,7 @@ namespace build2 { // Only consider RHS type if there is no explicit or variable type. // - if (type == nullptr && (var == nullptr || var->type == nullptr)) + if (type == nullptr) { type = rhs.type; rhs_type = true; diff --git a/build2/target b/build2/target index 8733a59..30dffab 100644 --- a/build2/target +++ b/build2/target @@ -550,7 +550,7 @@ namespace build2 public: target (dir_path d, dir_path o, string n, optional e) : dir (move (d)), out (move (o)), name (move (n)), ext (move (e)), - vars (true) // Global. + vars (false) // Note: not global. {} }; diff --git a/build2/types b/build2/types index daf10d3..7f39274 100644 --- a/build2/types +++ b/build2/types @@ -159,6 +159,10 @@ namespace build2 // // using butl::target_triplet; + + // See context. + // + enum class run_phase {load, search_match, execute}; } // In order to be found (via ADL) these have to be either in std:: or in diff --git a/build2/variable b/build2/variable index 0df28d8..6e20a9c 100644 --- a/build2/variable +++ b/build2/variable @@ -1011,26 +1011,37 @@ namespace build2 class variable_map { public: + struct value_data: value + { + using value::value; + + size_t generation; // load_generation of this value (global only). + }; + using map_type = butl::prefix_map, - value, + value_data, '.'>; using size_type = map_type::size_type; template - struct iterator_adapter: I + class iterator_adapter: public I { + public: iterator_adapter () = default; - iterator_adapter (const I& i): I (i) {} + iterator_adapter (const I& i, const variable_map& m): I (i), m_ (&m) {} // Automatically type a newly typed value on access. // typename I::reference operator* () const; - typename I::pointer operator-> () const; + typename I::pointer operator-> () const; // Untyped access. // uint16_t extra () const {return I::operator* ().second.extra;} typename I::reference untyped () const {return I::operator* ();} + + private: + const variable_map* m_; }; using const_iterator = iterator_adapter; @@ -1060,10 +1071,10 @@ namespace build2 // If typed is false, leave the value untyped even if the variable is. // - const value* + const value_data* find (const variable&, bool typed = true) const; - value* + value_data* find (const variable&, bool typed = true); // Return a value suitable for assignment. See scope for details. @@ -1087,14 +1098,15 @@ namespace build2 find_namespace (const variable& ns) const { auto r (m_.find_prefix (ns)); - return make_pair (const_iterator (r.first), const_iterator (r.second)); + return make_pair (const_iterator (r.first, *this), + const_iterator (r.second, *this)); } const_iterator - begin () const {return m_.begin ();} + begin () const {return const_iterator (m_.begin (), *this);} const_iterator - end () const {return m_.end ();} + end () const {return const_iterator (m_.end (), *this);} bool empty () const {return m_.empty ();} @@ -1104,12 +1116,18 @@ namespace build2 public: // Global should be true if this map is part of the global (model) state - // (e.g., scope, target, etc). + // (e.g., scopes, etc). // explicit variable_map (bool global = false): global_ (global) {} private: + friend class variable_type_map; + + void + typify (value_data&, const variable&) const; + + private: bool global_; map_type m_; }; diff --git a/build2/variable.cxx b/build2/variable.cxx index 1cdde5e..963eb0e 100644 --- a/build2/variable.cxx +++ b/build2/variable.cxx @@ -1016,7 +1016,7 @@ namespace build2 t, nullptr, v != nullptr ? *v : variable_visibility::normal, - load_generation})); + global_ ? load_generation : 0})); variable& r (p.first->second); @@ -1085,30 +1085,53 @@ namespace build2 // variable_map // - const value* variable_map:: - find (const variable& var, bool typed) const + void variable_map:: + typify (value_data& v, const variable& var) const + { + // In the global state existing value can only be typified during + // the same load generation or during serial execution. + // + assert (!global_ || + load_generation == 0 || + v.generation == load_generation); + + build2::typify (v, *var.type, &var); + } + + auto variable_map:: + find (const variable& var, bool typed) const -> const value_data* { auto i (m_.find (var)); - const value* r (i != m_.end () ? &i->second : nullptr); + const value_data* r (i != m_.end () ? &i->second : nullptr); // First access after being assigned a type? // if (r != nullptr && typed && var.type != nullptr && r->type != var.type) - typify (const_cast (*r), *var.type, &var); + { + // All values shall be typed during load. + // + assert (!global_ || phase == run_phase::load); + typify (const_cast (*r), var); + } return r; } - value* variable_map:: - find (const variable& var, bool typed) + auto variable_map:: + find (const variable& var, bool typed) -> value_data* { auto i (m_.find (var)); - value* r (i != m_.end () ? &i->second : nullptr); + value_data* r (i != m_.end () ? &i->second : nullptr); // First access after being assigned a type? // if (r != nullptr && typed && var.type != nullptr && r->type != var.type) - typify (*r, *var.type, &var); + { + // All values shall be typed during load. + // + assert (!global_ || phase == run_phase::load); + typify (*r, var); + } return r; } @@ -1116,15 +1139,22 @@ namespace build2 pair, bool> variable_map:: insert (const variable& var, bool typed) { - auto r (m_.emplace (var, value (typed ? var.type : nullptr))); - value& v (r.first->second); + assert (!global_ || phase == run_phase::load); - // First access after being assigned a type? - // - if (typed && !r.second && var.type != nullptr && v.type != var.type) - typify (v, *var.type, &var); + auto p (m_.emplace (var, value_data (typed ? var.type : nullptr))); + value_data& r (p.first->second); + + if (p.second) + r.generation = global_ ? load_generation : 0; + else + { + // First access after being assigned a type? + // + if (typed && var.type != nullptr && r.type != var.type) + typify (r, var); + } - return make_pair (reference_wrapper (v), r.second); + return make_pair (reference_wrapper (r), p.second); } // variable_type_map @@ -1187,12 +1217,19 @@ namespace build2 // to automatically type it. And if it is assignment, then typify it // ourselves. // - if (const value* v = j->second.find (var, false)) + const variable_map& vm (j->second); + + if (const variable_map::value_data* v = vm.find (var, false)) { if (v->extra == 0 && var.type != nullptr && v->type != var.type) - typify (const_cast (*v), *var.type, &var); - - return lookup (v, &j->second); + { + // All values shall be typed during load. + // + assert (!global_ || phase == run_phase::load); + vm.typify (const_cast (*v), var); + } + + return lookup (v, &vm); } } } diff --git a/build2/variable.ixx b/build2/variable.ixx index 816f4bf..8d5d710 100644 --- a/build2/variable.ixx +++ b/build2/variable.ixx @@ -639,18 +639,25 @@ namespace build2 // variable_map::iterator_adapter // + extern run_phase phase; // context + template inline typename I::reference variable_map::iterator_adapter:: operator* () const { auto& r (I::operator* ()); const variable& var (r.first); - auto& val (r.second); + const value_data& val (r.second); // First access after being assigned a type? // if (var.type != nullptr && val.type != var.type) - typify (const_cast (val), *var.type, &var); + { + // All values shall be typed during load. + // + assert (!m_->global_ || phase == run_phase::load); + m_->typify (const_cast (val), var); + } return r; } @@ -661,12 +668,17 @@ namespace build2 { auto p (I::operator-> ()); const variable& var (p->first); - auto& val (p->second); + const value_data& val (p->second); // First access after being assigned a type? // if (var.type != nullptr && val.type != var.type) - typify (const_cast (val), *var.type, &var); + { + // All values shall be typed during load. + // + assert (!m_->global_ || phase == run_phase::load); + m_->typify (const_cast (val), var); + } return p; } -- cgit v1.1