aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libbuild2/variable.cxx6
-rw-r--r--libbuild2/variable.hxx24
-rw-r--r--libbuild2/variable.ixx36
-rw-r--r--libbuild2/variable.txx31
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>,