diff options
-rw-r--r-- | libbuild2/variable.cxx | 6 | ||||
-rw-r--r-- | libbuild2/variable.hxx | 24 | ||||
-rw-r--r-- | libbuild2/variable.ixx | 36 | ||||
-rw-r--r-- | libbuild2/variable.txx | 31 |
4 files changed, 91 insertions, 6 deletions
diff --git a/libbuild2/variable.cxx b/libbuild2/variable.cxx index 47703da..6f45e90 100644 --- a/libbuild2/variable.cxx +++ b/libbuild2/variable.cxx @@ -1838,6 +1838,9 @@ namespace build2 value_traits<vector<pair<optional<string>, string>>>; template struct LIBBUILD2_DEFEXPORT + value_traits<vector<pair<string, optional<bool>>>>; + + template struct LIBBUILD2_DEFEXPORT value_traits<std::map<string, string>>; template struct LIBBUILD2_DEFEXPORT @@ -1847,5 +1850,8 @@ namespace build2 value_traits<std::map<optional<string>, string>>; template struct LIBBUILD2_DEFEXPORT + value_traits<std::map<string, optional<bool>>>; + + template struct LIBBUILD2_DEFEXPORT value_traits<std::map<project_name, dir_path>>; } diff --git a/libbuild2/variable.hxx b/libbuild2/variable.hxx index a9dde7f..a04e0a9 100644 --- a/libbuild2/variable.hxx +++ b/libbuild2/variable.hxx @@ -339,15 +339,17 @@ namespace build2 // Assign/Append/Prepend. // public: - // Assign/append a typed value. For assign, LHS should be either of the - // same type or untyped. For append, LHS should be either of the same type - // or untyped and NULL. + // Assign/append/prepend a typed value. For assign, LHS should be either + // of the same type or untyped. For append, LHS should be either of the + // same type or untyped and NULL. // template <typename T> value& operator= (T); template <typename T> value& operator+= (T); + template <typename T> value& prepend (T); value& operator= (names); value& operator+= (names); + //value& prepend (names); // See below. template <typename T> value& operator= (T* v) { return v != nullptr ? *this = *v : *this = nullptr;} @@ -355,8 +357,12 @@ namespace build2 template <typename T> value& operator+= (T* v) { return v != nullptr ? *this += *v : *this;} + template <typename T> value& prepend (T* v) { + return v != nullptr ? prepend (*v) : *this;} + value& operator= (const char* v) {return *this = string (v);} value& operator+= (const char* v) {return *this += string (v);} + value& prepend (const char* v) {return prepend (string (v));} // Assign/append/prepend raw data. Variable is optional and is only used // for diagnostics. @@ -1113,6 +1119,9 @@ namespace build2 // // Either K or V can be optional<T> making the key or value optional. // + // Note that append/+= is non-overriding (like insert()) while prepend/=+ + // is (like insert_or_assign()). + // template <typename K, typename V> struct map_value_type; @@ -1125,8 +1134,7 @@ namespace build2 static void assign (value&, map<K, V>&&); static void append (value&, map<K, V>&&); - static void prepend (value& v, map<K, V>&& x) { - return append (v, move (x));} + static void prepend (value&, map<K, V>&&); static bool empty (const map<K, V>& x) {return x.empty ();} static const map<K, V> empty_instance; @@ -1156,6 +1164,9 @@ namespace build2 value_traits<vector<pair<optional<string>, string>>>; extern template struct LIBBUILD2_DECEXPORT + value_traits<vector<pair<string, optional<bool>>>>; + + extern template struct LIBBUILD2_DECEXPORT value_traits<std::map<string, string>>; extern template struct LIBBUILD2_DECEXPORT @@ -1165,6 +1176,9 @@ namespace build2 value_traits<std::map<optional<string>, string>>; extern template struct LIBBUILD2_DECEXPORT + value_traits<std::map<string, optional<bool>>>; + + extern template struct LIBBUILD2_DECEXPORT value_traits<std::map<project_name, dir_path>>; // var_subprojects // Project-wide (as opposed to global) variable overrides (see context ctor diff --git a/libbuild2/variable.ixx b/libbuild2/variable.ixx index 9b24b9d..fd78842 100644 --- a/libbuild2/variable.ixx +++ b/libbuild2/variable.ixx @@ -114,6 +114,22 @@ namespace build2 return *this; } + template <typename T> + inline value& value:: + prepend (T v) + { + assert (type == &value_traits<T>::value_type || (type == nullptr && null)); + + // Prepare the receiving value. + // + if (type == nullptr) + type = &value_traits<T>::value_type; + + value_traits<T>::prepend (*this, move (v)); + null = false; + return *this; + } + inline value& value:: operator= (names v) { @@ -867,6 +883,26 @@ namespace build2 new (&v.data_) map<K, V> (move (x)); } + template <typename K, typename V> + inline void value_traits<std::map<K, V>>:: + prepend (value& v, map<K, V>&& x) + { + if (v) + { + map<K, V>& m (v.as<map<K, V>> ()); + + m.swap (x); + + // Note that this will only move values. Keys (being const) are still + // copied. + // + m.insert (make_move_iterator (x.begin ()), + make_move_iterator (x.end ())); + } + else + new (&v.data_) map<K, V> (move (x)); + } + // variable_pool // inline const variable& variable_pool:: diff --git a/libbuild2/variable.txx b/libbuild2/variable.txx index 9c9c867..e1808fc 100644 --- a/libbuild2/variable.txx +++ b/libbuild2/variable.txx @@ -838,6 +838,35 @@ namespace build2 template <typename K, typename V> void + map_prepend (value& v, names&& ns, const variable* var) + { + using std::map; + + map<K, V>& p (v + ? v.as<map<K, V>> () + : *new (&v.data_) map<K, V> ()); + + // Verify we have a sequence of pairs and convert each lhs/rhs to K/V. + // + for (auto i (ns.begin ()); i != ns.end (); ++i) + { + name& l (*i); + name* r (l.pair ? &*++i : nullptr); + + pair<K, V> v (value_traits<pair<K, V>>::convert ( + move (l), r, + value_traits<map<K, V>>::value_type.name, + "element", + var)); + + // Poor man's emplace_or_assign(). + // + p.emplace (move (v.first), V ()).first->second = move (v.second); + } + } + + template <typename K, typename V> + void map_assign (value& v, names&& ns, const variable* var) { using std::map; @@ -961,7 +990,7 @@ namespace build2 &default_copy_assign<map<K, V>>, &map_assign<K, V>, &map_append<K, V>, - &map_append<K, V>, // Prepend is the same as append. + &map_prepend<K, V>, &map_reverse<K, V>, nullptr, // No cast (cast data_ directly). &map_compare<K, V>, |