diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2016-03-28 09:14:31 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2016-03-28 16:03:35 +0200 |
commit | 3ce44330cca9dbc4314feebb27403ebc3175b6c2 (patch) | |
tree | 8c1f27442f3b2dafaec3ba50baaca3d5fd63dca7 /build2/variable.ixx | |
parent | 9d0d078ff297138622cd2f3f1076f5984395e42b (diff) |
New variable architecture
Diffstat (limited to 'build2/variable.ixx')
-rw-r--r-- | build2/variable.ixx | 525 |
1 files changed, 303 insertions, 222 deletions
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 <type_traits> // is_same + namespace build2 { // value // - template <typename T> - inline void - assign (value& v, const variable& var) + inline value& value:: + operator= (reference_wrapper<value> v) { - auto t (&value_traits<T>::value_type); + return *this = v.get (); + } - if (v.type != t) - assign (v, t, var); + inline value& value:: + operator= (reference_wrapper<const value> v) + { + return *this = v.get (); } template <typename T> - inline typename value_traits<T>::type - as (value& v) + inline value& value:: + operator= (T v) { - return value_traits<T>::as (v); + assert (type == &value_traits<T>::value_type || type == nullptr); + + // Prepare the receiving value. + // + if (type == nullptr) + { + if (!null ()) + *this = nullptr; + + type = &value_traits<T>::value_type; + } + + state = value_traits<T>::assign (*this, move (v)) + ? value_state::filled + : value_state::empty; + + return *this; } template <typename T> - inline typename value_traits<T>::const_type - as (const value& v) + inline value& value:: + operator+= (T v) { - return value_traits<T>::as (v); + assert (type == &value_traits<T>::value_type || + (type == nullptr && null ())); + + // Prepare the receiving value. + // + if (type == nullptr) + type = &value_traits<T>::value_type; + + state = value_traits<T>::append (*this, move (v)) + ? value_state::filled + : value_state::empty; + + return *this; } - template <typename T> inline bool - assign (name& n) + operator!= (const value& x, const value& y) { - return value_traits<T>::assign (n, nullptr); + return !(x == y); } - template <typename T> - inline bool - assign (name& l, name& r) + template <> + inline const names& + cast (const value& v) { - return value_traits<T>::assign (l, &r); + // Note that it can still be a typed vector<names>. + // + assert (!v.null () && + (v.type == nullptr || v.type == &value_traits<names>::value_type)); + return v.as<names> (); } template <typename T> - inline typename value_traits<T>::type - as (name& n) + inline const T& + cast (const value& v) { - return value_traits<T>::as (n); + assert (!v.null () && v.type == &value_traits<T>::value_type); + return *static_cast<const T*> (v.type->cast == nullptr + ? static_cast<const void*> (&v.data_) + : v.type->cast (v)); } template <typename T> - inline typename value_traits<T>::const_type - as (const name& n) + inline T& + cast (value& v) { - return value_traits<T>::as (n); + return const_cast<T&> (cast<T> (static_cast<const value&> (v))); } template <typename T> - inline value& value:: - operator= (T v) + inline T&& + cast (value&& v) { - value_traits<T>::assign (*this, move (v)); - return *this; + return move (cast<T> (v)); // Forward to T&. } template <typename T> - inline value& value:: - operator+= (T v) + inline void + typify (value& v, const variable& var) { - value_traits<T>::append (*this, move (v)); - return *this; + value_type& t (value_traits<T>::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<names> () : v.type->reverse (v, storage); } - // bool value + // value_traits // - inline bool_value<name> value_traits<bool>:: - as (value& v) + template <typename T> + inline T + convert (name&& n) { - assert (v.type == bool_type); - return bool_value<name> (v.data_.front ()); + return value_traits<T>::convert (move (n), nullptr); } - inline bool_value<const name> value_traits<bool>:: - as (const value& v) + template <typename T> + inline T + convert (name&& l, name&& r) { - assert (v.type == bool_type); - return bool_value<const name> (v.data_.front ()); + return value_traits<T>::convert (move (l), &r); } - inline void value_traits<bool>:: + // bool value + // + inline bool value_traits<bool>:: 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<bool> () = x; - as (v) = x; - v.state_ = value::state_type::filled; + return true; } - inline void value_traits<bool>:: + inline bool value_traits<bool>:: 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<bool> () = v.as<bool> () || x; + + return true; } - // string value - // - inline string& value_traits<string>:: - as (value& v) + inline int value_traits<bool>:: + 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<string>:: - as (const value& v) + // string value + // + inline bool value_traits<string>:: + 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<string> () = move (x)); + + return !p->empty (); } - inline void value_traits<string>:: - assign (value& v, string x) + inline bool value_traits<string>:: + 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<string> (); + + 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<string>:: - append (value& v, string x) + inline bool value_traits<string>:: + 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<string> (); - // dir_path value - // - inline dir_path& value_traits<dir_path>:: - 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<dir_path>:: - as (const value& v) + inline int value_traits<string>:: + 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<dir_path>:: - assign (value& v, dir_path x) + // dir_path value + // + inline bool value_traits<dir_path>:: + 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<dir_path> () = move (x)); - v.state_ = (as (v) = move (x)).empty () - ? value::state_type::empty - : value::state_type::filled; + return !p->empty (); } - inline void value_traits<dir_path>:: - append (value& v, dir_path x) + inline bool value_traits<dir_path>:: + 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<dir_path> (); - // name value - // - inline name& value_traits<name>:: - 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<name>:: - as (const value& v) - { - assert (v.type == name_type); - return v.data_.front (); + return !p->empty (); } - inline void value_traits<name>:: - assign (value& v, name x) + inline bool value_traits<dir_path>:: + 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<dir_path> (); - v.state_ = (as (v) = move (x)).empty () - ? value::state_type::empty - : value::state_type::filled; - } + if (!p->empty ()) + x /= *p; - // vector<T> value - // - template <typename T, typename D> - inline vector_value<T, D>& vector_value<T, D>:: - assign (vector<T> 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 <typename T, typename D> - template <typename D1> - inline vector_value<T, D>& vector_value<T, D>:: - assign (const vector_value<T, D1>& v) + inline int value_traits<dir_path>:: + 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 <typename T, typename D> - template <typename D1> - inline vector_value<T, D>& vector_value<T, D>:: - append (const vector_value<T, D1>& v) + // name value + // + inline bool value_traits<name>:: + 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<name> () = move (x)); + + return !p->empty (); } - template <typename T> - inline vector_value<T, names> value_traits<vector<T>>:: - as (value& v) + inline int value_traits<name>:: + compare (const name& l, const name& r) { - assert (v.type == &value_traits<vector<T>>::value_type); - return vector_value<T, names> (v.data_); + return l.compare (r); } + // vector<T> value + // template <typename T> - inline vector_value<T, const names> value_traits<vector<T>>:: - as (const value& v) + inline bool value_traits<vector<T>>:: + assign (value& v, vector<T>&& x) { - assert (v.type == &value_traits<vector<T>>::value_type); - return vector_value<T, const names> (v.data_); + vector<T>* p; + + if (v.null ()) + p = new (&v.data_) vector<T> (move (x)); + else + p = &(v.as<vector<T>> () = move (x)); + + return !p->empty (); } template <typename T> - template <typename V> - inline void value_traits<vector<T>>:: - assign (value& v, V x) + inline bool value_traits<vector<T>>:: + append (value& v, vector<T>&& x) { + vector<T>* p; + if (v.null ()) + p = new (&v.data_) vector<T> (move (x)); + else { - if (v.type == nullptr) - v.type = &value_traits<vector<T>>::value_type; - v.state_ = value::state_type::empty; + p = &v.as<vector<T>> (); + + 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 <typename T> - template <typename V> - inline void value_traits<vector<T>>:: - append (value& v, V x) + inline bool value_traits<vector<T>>:: + prepend (value& v, vector<T>&& x) { + vector<T>* p; + if (v.null ()) - assign (v, move (x)); + new (&v.data_) vector<T> (move (x)); else - v.state_ = (as (v).append (move (x))).empty () - ? value::state_type::empty - : value::state_type::filled; + { + p = &v.as<vector<T>> (); + + if (!p->empty ()) + x.insert (x.end (), + make_move_iterator (p->begin ()), + make_move_iterator (p->end ())); + + p->swap (x); + } + + return !p->empty (); } // map<K, V> value // template <typename K, typename V> - inline map_value<K, V, names> value_traits<std::map<K, V>>:: - as (value& v) + inline bool value_traits<std::map<K, V>>:: + assign (value& v, map<K, V>&& x) { - assert ((v.type == &value_traits<std::map<K, V>>::value_type)); - return map_value<K, V, names> (v.data_); - } + map<K, V>* p; - template <typename K, typename V> - inline map_value<K, V, const names> value_traits<std::map<K, V>>:: - as (const value& v) - { - assert ((v.type == &value_traits<std::map<K, V>>::value_type)); - return map_value<K, V, const names> (v.data_); + if (v.null ()) + p = new (&v.data_) map<K, V> (move (x)); + else + p = &(v.as<map<K, V>> () = move (x)); + + return !p->empty (); } template <typename K, typename V> - template <typename M> - inline void value_traits<std::map<K, V>>:: - assign (value& v, M x) + inline bool value_traits<std::map<K, V>>:: + append (value& v, map<K, V>&& x) { + map<K, V>* p; + if (v.null ()) + p = new (&v.data_) map<K, V> (move (x)); + else { - if (v.type == nullptr) - v.type = &value_traits<std::map<K, V>>::value_type; - v.state_ = value::state_type::empty; + p = &v.as<map<K, V>> (); + + 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 <typename K, typename V> - template <typename M> - inline void value_traits<std::map<K, V>>:: - 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<variable&> (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<variable&> (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<value&> (val), var.type, var); + typify (const_cast<value&> (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<value&> (val), var.type, var); + typify (const_cast<value&> (val), *var.type, var); return p; } |