From 3ce44330cca9dbc4314feebb27403ebc3175b6c2 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 28 Mar 2016 09:14:31 +0200 Subject: New variable architecture --- build2/variable.ixx | 525 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 303 insertions(+), 222 deletions(-) (limited to 'build2/variable.ixx') diff --git a/build2/variable.ixx b/build2/variable.ixx index df3f0c5..a129835 100644 --- a/build2/variable.ixx +++ b/build2/variable.ixx @@ -2,371 +2,452 @@ // copyright : Copyright (c) 2014-2016 Code Synthesis Ltd // license : MIT; see accompanying LICENSE file +#include // is_same + namespace build2 { // value // - template - inline void - assign (value& v, const variable& var) + inline value& value:: + operator= (reference_wrapper v) { - auto t (&value_traits::value_type); + return *this = v.get (); + } - if (v.type != t) - assign (v, t, var); + inline value& value:: + operator= (reference_wrapper v) + { + return *this = v.get (); } template - inline typename value_traits::type - as (value& v) + inline value& value:: + operator= (T v) { - return value_traits::as (v); + assert (type == &value_traits::value_type || type == nullptr); + + // Prepare the receiving value. + // + if (type == nullptr) + { + if (!null ()) + *this = nullptr; + + type = &value_traits::value_type; + } + + state = value_traits::assign (*this, move (v)) + ? value_state::filled + : value_state::empty; + + return *this; } template - inline typename value_traits::const_type - as (const value& v) + inline value& value:: + operator+= (T v) { - return value_traits::as (v); + assert (type == &value_traits::value_type || + (type == nullptr && null ())); + + // Prepare the receiving value. + // + if (type == nullptr) + type = &value_traits::value_type; + + state = value_traits::append (*this, move (v)) + ? value_state::filled + : value_state::empty; + + return *this; } - template inline bool - assign (name& n) + operator!= (const value& x, const value& y) { - return value_traits::assign (n, nullptr); + return !(x == y); } - template - inline bool - assign (name& l, name& r) + template <> + inline const names& + cast (const value& v) { - return value_traits::assign (l, &r); + // Note that it can still be a typed vector. + // + assert (!v.null () && + (v.type == nullptr || v.type == &value_traits::value_type)); + return v.as (); } template - inline typename value_traits::type - as (name& n) + inline const T& + cast (const value& v) { - return value_traits::as (n); + assert (!v.null () && v.type == &value_traits::value_type); + return *static_cast (v.type->cast == nullptr + ? static_cast (&v.data_) + : v.type->cast (v)); } template - inline typename value_traits::const_type - as (const name& n) + inline T& + cast (value& v) { - return value_traits::as (n); + return const_cast (cast (static_cast (v))); } template - inline value& value:: - operator= (T v) + inline T&& + cast (value&& v) { - value_traits::assign (*this, move (v)); - return *this; + return move (cast (v)); // Forward to T&. } template - inline value& value:: - operator+= (T v) + inline void + typify (value& v, const variable& var) { - value_traits::append (*this, move (v)); - return *this; + value_type& t (value_traits::value_type); + + if (v.type != &t) + typify (v, t, var); } - inline void value:: - assign (names v, const variable& var) + inline names_view + reverse (const value& v, names& storage) { - data_ = move (v); - state_ = (type != nullptr && type->assign != nullptr - ? type->assign (data_, var) - : !data_.empty ()) - ? state_type::filled - : state_type::empty; + assert (!v.null () && + storage.empty () && + (v.type == nullptr || v.type->reverse != nullptr)); + return v.type == nullptr ? v.as () : v.type->reverse (v, storage); } - // bool value + // value_traits // - inline bool_value value_traits:: - as (value& v) + template + inline T + convert (name&& n) { - assert (v.type == bool_type); - return bool_value (v.data_.front ()); + return value_traits::convert (move (n), nullptr); } - inline bool_value value_traits:: - as (const value& v) + template + inline T + convert (name&& l, name&& r) { - assert (v.type == bool_type); - return bool_value (v.data_.front ()); + return value_traits::convert (move (l), &r); } - inline void value_traits:: + // bool value + // + inline bool value_traits:: assign (value& v, bool x) { if (v.null ()) - { - if (v.type == nullptr) - v.type = bool_type; - v.data_.emplace_back (name ()); - v.state_ = value::state_type::empty; - } + new (&v.data_) bool (x); + else + v.as () = x; - as (v) = x; - v.state_ = value::state_type::filled; + return true; } - inline void value_traits:: + inline bool value_traits:: append (value& v, bool x) { + // Logical OR. + // if (v.null ()) - assign (v, x); + new (&v.data_) bool (x); else - as (v) += x; // Cannot be empty. + v.as () = v.as () || x; + + return true; } - // string value - // - inline string& value_traits:: - as (value& v) + inline int value_traits:: + compare (bool l, bool r) { - assert (v.type == string_type); - return v.data_.front ().value; + return l < r ? -1 : (l > r ? 1 : 0); } - inline const string& value_traits:: - as (const value& v) + // string value + // + inline bool value_traits:: + assign (value& v, string&& x) { - assert (v.type == string_type); - return v.data_.front ().value; + string* p; + + if (v.null ()) + p = new (&v.data_) string (move (x)); + else + p = &(v.as () = move (x)); + + return !p->empty (); } - inline void value_traits:: - assign (value& v, string x) + inline bool value_traits:: + append (value& v, string&& x) { + string* p; + if (v.null ()) + p = new (&v.data_) string (move (x)); + else { - if (v.type == nullptr) - v.type = string_type; - v.data_.emplace_back (name ()); - v.state_ = value::state_type::empty; + p = &v.as (); + + if (p->empty ()) + p->swap (x); + else + *p += x; } - v.state_ = (as (v) = move (x)).empty () - ? value::state_type::empty - : value::state_type::filled; + return !p->empty (); } - inline void value_traits:: - append (value& v, string x) + inline bool value_traits:: + prepend (value& v, string&& x) { + string* p; + if (v.null ()) - assign (v, move (x)); + new (&v.data_) string (move (x)); else - v.state_ = (as (v) += move (x)).empty () - ? value::state_type::empty - : value::state_type::filled; - } + { + p = &v.as (); - // dir_path value - // - inline dir_path& value_traits:: - as (value& v) - { - assert (v.type == dir_path_type); - return v.data_.front ().dir; + if (!p->empty ()) + x += *p; + + p->swap (x); + } + + return !p->empty (); } - inline const dir_path& value_traits:: - as (const value& v) + inline int value_traits:: + compare (const string& l, const string& r) { - assert (v.type == dir_path_type); - return v.data_.front ().dir; + return l.compare (r); } - inline void value_traits:: - assign (value& v, dir_path x) + // dir_path value + // + inline bool value_traits:: + assign (value& v, dir_path&& x) { + dir_path* p; + if (v.null ()) - { - if (v.type == nullptr) - v.type = dir_path_type; - v.data_.emplace_back (name ()); - v.state_ = value::state_type::empty; - } + p = new (&v.data_) dir_path (move (x)); + else + p = &(v.as () = move (x)); - v.state_ = (as (v) = move (x)).empty () - ? value::state_type::empty - : value::state_type::filled; + return !p->empty (); } - inline void value_traits:: - append (value& v, dir_path x) + inline bool value_traits:: + append (value& v, dir_path&& x) { + dir_path* p; + if (v.null ()) - assign (v, move (x)); + p = new (&v.data_) dir_path (move (x)); else - v.state_ = (as (v) /= move (x)).empty () - ? value::state_type::empty - : value::state_type::filled; - } + { + p = &v.as (); - // name value - // - inline name& value_traits:: - as (value& v) - { - assert (v.type == name_type); - return v.data_.front (); - } + if (p->empty ()) + p->swap (x); + else + *p /= x; + } - inline const name& value_traits:: - as (const value& v) - { - assert (v.type == name_type); - return v.data_.front (); + return !p->empty (); } - inline void value_traits:: - assign (value& v, name x) + inline bool value_traits:: + prepend (value& v, dir_path&& x) { + dir_path* p; + if (v.null ()) + new (&v.data_) dir_path (move (x)); + else { - if (v.type == nullptr) - v.type = name_type; - v.data_.emplace_back (name ()); - v.state_ = value::state_type::empty; - } + p = &v.as (); - v.state_ = (as (v) = move (x)).empty () - ? value::state_type::empty - : value::state_type::filled; - } + if (!p->empty ()) + x /= *p; - // vector value - // - template - inline vector_value& vector_value:: - assign (vector v) - { - d->clear (); - d->insert (d->end (), - make_move_iterator (v.begin ()), - make_move_iterator (v.end ())); - return *this; + p->swap (x); + } + + return !p->empty (); } - template - template - inline vector_value& vector_value:: - assign (const vector_value& v) + inline int value_traits:: + compare (const dir_path& l, const dir_path& r) { - d->clear (); - d->insert (d->end (), v.begin (), v.end ()); - return *this; + return l.compare (r); } - template - template - inline vector_value& vector_value:: - append (const vector_value& v) + // name value + // + inline bool value_traits:: + assign (value& v, name&& x) { - d->insert (d->end (), v.begin (), v.end ()); - return *this; + name* p; + + if (v.null ()) + p = new (&v.data_) name (move (x)); + else + p = &(v.as () = move (x)); + + return !p->empty (); } - template - inline vector_value value_traits>:: - as (value& v) + inline int value_traits:: + compare (const name& l, const name& r) { - assert (v.type == &value_traits>::value_type); - return vector_value (v.data_); + return l.compare (r); } + // vector value + // template - inline vector_value value_traits>:: - as (const value& v) + inline bool value_traits>:: + assign (value& v, vector&& x) { - assert (v.type == &value_traits>::value_type); - return vector_value (v.data_); + vector* p; + + if (v.null ()) + p = new (&v.data_) vector (move (x)); + else + p = &(v.as> () = move (x)); + + return !p->empty (); } template - template - inline void value_traits>:: - assign (value& v, V x) + inline bool value_traits>:: + append (value& v, vector&& x) { + vector* p; + if (v.null ()) + p = new (&v.data_) vector (move (x)); + else { - if (v.type == nullptr) - v.type = &value_traits>::value_type; - v.state_ = value::state_type::empty; + p = &v.as> (); + + if (p->empty ()) + p->swap (x); + else + p->insert (p->end (), + make_move_iterator (x.begin ()), + make_move_iterator (x.end ())); } - v.state_ = (as (v).assign (move (x))).empty () - ? value::state_type::empty - : value::state_type::filled; + return !p->empty (); } template - template - inline void value_traits>:: - append (value& v, V x) + inline bool value_traits>:: + prepend (value& v, vector&& x) { + vector* p; + if (v.null ()) - assign (v, move (x)); + new (&v.data_) vector (move (x)); else - v.state_ = (as (v).append (move (x))).empty () - ? value::state_type::empty - : value::state_type::filled; + { + p = &v.as> (); + + if (!p->empty ()) + x.insert (x.end (), + make_move_iterator (p->begin ()), + make_move_iterator (p->end ())); + + p->swap (x); + } + + return !p->empty (); } // map value // template - inline map_value value_traits>:: - as (value& v) + inline bool value_traits>:: + assign (value& v, map&& x) { - assert ((v.type == &value_traits>::value_type)); - return map_value (v.data_); - } + map* p; - template - inline map_value value_traits>:: - as (const value& v) - { - assert ((v.type == &value_traits>::value_type)); - return map_value (v.data_); + if (v.null ()) + p = new (&v.data_) map (move (x)); + else + p = &(v.as> () = move (x)); + + return !p->empty (); } template - template - inline void value_traits>:: - assign (value& v, M x) + inline bool value_traits>:: + append (value& v, map&& x) { + map* p; + if (v.null ()) + p = new (&v.data_) map (move (x)); + else { - if (v.type == nullptr) - v.type = &value_traits>::value_type; - v.state_ = value::state_type::empty; + p = &v.as> (); + + if (p->empty ()) + p->swap (x); + else + // Note that this will only move values. Keys (being const) are still + // copied. + // + p->insert (p->end (), + make_move_iterator (x.begin ()), + make_move_iterator (x.end ())); } - v.state_ = (as (v).assign (move (x))).empty () - ? value::state_type::empty - : value::state_type::filled; + return !p->empty (); } - template - template - inline void value_traits>:: - append (value& v, M x) + inline const variable& variable_pool:: + find (string n, const variable_visibility* vv, const build2::value_type* t) { - if (v.null ()) - assign (v, move (x)); - else - v.state_ = (as (v).append (move (x))).empty () - ? value::state_type::empty - : value::state_type::filled; + auto r ( + insert ( + variable { + move (n), + t, + vv != nullptr ? *vv : variable_visibility::normal})); + const variable& v (*r.first); + + // Update type? + // + if (!r.second && t != nullptr && v.type != t) + { + assert (v.type == nullptr); + const_cast (v).type = t; // Not changing the key. + } + + // Change visibility? While this might at first seem like a bad idea, + // it can happen that the variable lookup happens before any values + // were set, in which case the variable will be entered with the + // default visibility. + // + if (!r.second && vv != nullptr && v.visibility != *vv) + { + assert (v.visibility == variable_visibility::normal); // Default. + const_cast (v).visibility = *vv; // Not changing the key. + } + + return v; } // variable_map::iterator_adapter @@ -382,7 +463,7 @@ namespace build2 // First access after being assigned a type? // if (var.type != nullptr && val.type != var.type) - build2::assign (const_cast (val), var.type, var); + typify (const_cast (val), *var.type, var); return r; } @@ -398,7 +479,7 @@ namespace build2 // First access after being assigned a type? // if (var.type != nullptr && val.type != var.type) - build2::assign (const_cast (val), var.type, var); + typify (const_cast (val), *var.type, var); return p; } -- cgit v1.1