From f211934d6ff53388a806c5cc06483e9d843056e4 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 27 Jan 2021 06:14:57 +0200 Subject: Make std::map prepend (=+) overriding (like insert_or_assign()) --- libbuild2/variable.cxx | 6 ++++++ libbuild2/variable.hxx | 24 +++++++++++++++++++----- libbuild2/variable.ixx | 36 ++++++++++++++++++++++++++++++++++++ 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, string>>>; template struct LIBBUILD2_DEFEXPORT + value_traits>>>; + + template struct LIBBUILD2_DEFEXPORT value_traits>; template struct LIBBUILD2_DEFEXPORT @@ -1847,5 +1850,8 @@ namespace build2 value_traits, string>>; template struct LIBBUILD2_DEFEXPORT + value_traits>>; + + template struct LIBBUILD2_DEFEXPORT value_traits>; } 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 value& operator= (T); template value& operator+= (T); + template value& prepend (T); value& operator= (names); value& operator+= (names); + //value& prepend (names); // See below. template value& operator= (T* v) { return v != nullptr ? *this = *v : *this = nullptr;} @@ -355,8 +357,12 @@ namespace build2 template value& operator+= (T* v) { return v != nullptr ? *this += *v : *this;} + template 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 making the key or value optional. // + // Note that append/+= is non-overriding (like insert()) while prepend/=+ + // is (like insert_or_assign()). + // template struct map_value_type; @@ -1125,8 +1134,7 @@ namespace build2 static void assign (value&, map&&); static void append (value&, map&&); - static void prepend (value& v, map&& x) { - return append (v, move (x));} + static void prepend (value&, map&&); static bool empty (const map& x) {return x.empty ();} static const map empty_instance; @@ -1156,6 +1164,9 @@ namespace build2 value_traits, string>>>; extern template struct LIBBUILD2_DECEXPORT + value_traits>>>; + + extern template struct LIBBUILD2_DECEXPORT value_traits>; extern template struct LIBBUILD2_DECEXPORT @@ -1165,6 +1176,9 @@ namespace build2 value_traits, string>>; extern template struct LIBBUILD2_DECEXPORT + value_traits>>; + + extern template struct LIBBUILD2_DECEXPORT value_traits>; // 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 + inline value& value:: + prepend (T v) + { + assert (type == &value_traits::value_type || (type == nullptr && null)); + + // Prepare the receiving value. + // + if (type == nullptr) + type = &value_traits::value_type; + + value_traits::prepend (*this, move (v)); + null = false; + return *this; + } + inline value& value:: operator= (names v) { @@ -867,6 +883,26 @@ namespace build2 new (&v.data_) map (move (x)); } + template + inline void value_traits>:: + prepend (value& v, map&& x) + { + if (v) + { + map& m (v.as> ()); + + 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 (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 void + map_prepend (value& v, names&& ns, const variable* var) + { + using std::map; + + map& p (v + ? v.as> () + : *new (&v.data_) map ()); + + // 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 v (value_traits>::convert ( + move (l), r, + value_traits>::value_type.name, + "element", + var)); + + // Poor man's emplace_or_assign(). + // + p.emplace (move (v.first), V ()).first->second = move (v.second); + } + } + + template + void map_assign (value& v, names&& ns, const variable* var) { using std::map; @@ -961,7 +990,7 @@ namespace build2 &default_copy_assign>, &map_assign, &map_append, - &map_append, // Prepend is the same as append. + &map_prepend, &map_reverse, nullptr, // No cast (cast data_ directly). &map_compare, -- cgit v1.1