diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2019-11-12 12:20:34 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2019-11-12 12:20:34 +0200 |
commit | c0743592bfae808b61a8146fd97af94b50156f0e (patch) | |
tree | a1d0b98f24391ec1350be23eefe5ef492fa3c387 | |
parent | 87d871e77649d439b4d62208576239d1341eedef (diff) |
Add support for vector<pair<K, V>> variable values
-rw-r--r-- | libbuild2/variable.cxx | 6 | ||||
-rw-r--r-- | libbuild2/variable.hxx | 30 | ||||
-rw-r--r-- | libbuild2/variable.ixx | 31 | ||||
-rw-r--r-- | libbuild2/variable.txx | 166 |
4 files changed, 231 insertions, 2 deletions
diff --git a/libbuild2/variable.cxx b/libbuild2/variable.cxx index 643a061..546eb91 100644 --- a/libbuild2/variable.cxx +++ b/libbuild2/variable.cxx @@ -1523,7 +1523,11 @@ namespace build2 template struct LIBBUILD2_DEFEXPORT value_traits<dir_paths>; template struct LIBBUILD2_DEFEXPORT value_traits<uint64s>; - template struct LIBBUILD2_DEFEXPORT value_traits<std::map<string, string>>; + template struct LIBBUILD2_DEFEXPORT + value_traits<vector<pair<string, string>>>; + + template struct LIBBUILD2_DEFEXPORT + value_traits<std::map<string, string>>; template struct LIBBUILD2_DEFEXPORT value_traits<std::map<project_name, dir_path>>; diff --git a/libbuild2/variable.hxx b/libbuild2/variable.hxx index 6a2c681..3389a8e 100644 --- a/libbuild2/variable.hxx +++ b/libbuild2/variable.hxx @@ -954,6 +954,33 @@ namespace build2 static const value_type_ex value_type; }; + // vector<pair<K, V>> + // + template <typename K, typename V> + struct value_traits<vector<pair<K, V>>> + { + static_assert (sizeof (vector<pair<K, V>>) <= value::size_, + "insufficient space"); + + static void assign (value&, vector<pair<K, V>>&&); + static void append (value&, vector<pair<K, V>>&&); + static void prepend (value& v, vector<pair<K, V>>&& x) { + return append (v, move (x));} + static bool empty (const vector<pair<K, V>>& x) {return x.empty ();} + + static const vector<pair<K, V>> empty_instance; + + // Make sure these are static-initialized together. Failed that VC will + // make sure it's done in the wrong order. + // + struct value_type_ex: build2::value_type + { + string type_name; + value_type_ex (value_type&&); + }; + static const value_type_ex value_type; + }; + // map<K, V> // template <typename K, typename V> @@ -995,6 +1022,9 @@ namespace build2 extern template struct LIBBUILD2_DECEXPORT value_traits<uint64s>; extern template struct LIBBUILD2_DECEXPORT + value_traits<vector<pair<string, string>>>; + + extern template struct LIBBUILD2_DECEXPORT value_traits<std::map<string, string>>; extern template struct LIBBUILD2_DECEXPORT diff --git a/libbuild2/variable.ixx b/libbuild2/variable.ixx index d341c26..d6bf119 100644 --- a/libbuild2/variable.ixx +++ b/libbuild2/variable.ixx @@ -707,6 +707,37 @@ namespace build2 new (&v.data_) vector<T> (move (x)); } + // vector<pair<K, V>> value + // + template <typename K, typename V> + inline void value_traits<vector<pair<K, V>>>:: + assign (value& v, vector<pair<K, V>>&& x) + { + if (v) + v.as<vector<pair<K, V>>> () = move (x); + else + new (&v.data_) vector<pair<K, V>> (move (x)); + } + + template <typename K, typename V> + inline void value_traits<vector<pair<K, V>>>:: + append (value& v, vector<pair<K, V>>&& x) + { + if (v) + { + vector<pair<K, V>>& y (v.as<vector<pair<K, V>>> ()); + + if (y.empty ()) + y.swap (x); + else + y.insert (y.end (), + make_move_iterator (x.begin ()), + make_move_iterator (x.end ())); + } + else + new (&v.data_) vector<pair<K, V>> (move (x)); + } + // map<K, V> value // template <typename K, typename V> diff --git a/libbuild2/variable.txx b/libbuild2/variable.txx index 041dc94..5029edf 100644 --- a/libbuild2/variable.txx +++ b/libbuild2/variable.txx @@ -424,6 +424,170 @@ namespace build2 &default_empty<vector<T>> }; + // vector<pair<K, V>> value + // + template <typename K, typename V> + void + pair_vector_append (value& v, names&& ns, const variable* var) + { + vector<pair<K, V>>& p (v + ? v.as<vector<pair<K, V>>> () + : *new (&v.data_) vector<pair<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); + + if (!l.pair) + { + diag_record dr (fail); + + dr << value_traits<vector<pair<K, V>>>::value_type.name + << " key-value pair expected instead of '" << l << "'"; + + if (var != nullptr) + dr << " in variable " << var->name; + } + + name& r (*++i); // Got to have the second half of the pair. + + if (l.pair != '@') + { + diag_record dr (fail); + + dr << "unexpected pair style for " + << value_traits<vector<pair<K, V>>>::value_type.name + << " key-value '" << l << "'" << l.pair << "'" << r << "'"; + + if (var != nullptr) + dr << " in variable " << var->name; + } + + try + { + K k (value_traits<K>::convert (move (l), nullptr)); + + try + { + V v (value_traits<V>::convert (move (r), nullptr)); + + p.emplace_back (move (k), move (v)); + } + catch (const invalid_argument&) + { + diag_record dr (fail); + + dr << "invalid " << value_traits<V>::value_type.name + << " element value '" << r << "'"; + + if (var != nullptr) + dr << " in variable " << var->name; + } + } + catch (const invalid_argument&) + { + diag_record dr (fail); + + dr << "invalid " << value_traits<K>::value_type.name + << " element key '" << l << "'"; + + if (var != nullptr) + dr << " in variable " << var->name; + } + } + } + + template <typename K, typename V> + void + pair_vector_assign (value& v, names&& ns, const variable* var) + { + if (v) + v.as<vector<pair<K, V>>> ().clear (); + + pair_vector_append<K, V> (v, move (ns), var); + } + + template <typename K, typename V> + static names_view + pair_vector_reverse (const value& v, names& s) + { + auto& vv (v.as<vector<pair<K, V>>> ()); + s.reserve (2 * vv.size ()); + + for (const auto& p: vv) + { + s.push_back (value_traits<K>::reverse (p.first)); + s.back ().pair = '@'; + s.push_back (value_traits<V>::reverse (p.second)); + } + + return s; + } + + template <typename K, typename V> + static int + pair_vector_compare (const value& l, const value& r) + { + auto& lv (l.as<vector<pair<K, V>>> ()); + auto& rv (r.as<vector<pair<K, V>>> ()); + + auto li (lv.begin ()), le (lv.end ()); + auto ri (rv.begin ()), re (rv.end ()); + + for (; li != le && ri != re; ++li, ++ri) + { + int r; + if ((r = value_traits<K>::compare (li->first, ri->first)) != 0 || + (r = value_traits<V>::compare (li->second, ri->second)) != 0) + return r; + } + + if (li == le && ri != re) // l shorter than r. + return -1; + + if (ri == re && li != le) // r shorter than l. + return 1; + + return 0; + } + + template <typename K, typename V> + value_traits<vector<pair<K, V>>>::value_type_ex:: + value_type_ex (value_type&& v) + : value_type (move (v)) + { + type_name = value_traits<K>::type_name; + type_name += '_'; + type_name += value_traits<V>::type_name; + type_name += "_pair_vector"; + name = type_name.c_str (); + } + + template <typename K, typename V> + const vector<pair<K, V>> value_traits<vector<pair<K, V>>>::empty_instance; + + template <typename K, typename V> + const typename value_traits<std::vector<pair<K, V>>>::value_type_ex + value_traits<vector<pair<K, V>>>::value_type = build2::value_type // VC14 wants = + { + nullptr, // Patched above. + sizeof (vector<pair<K, V>>), + nullptr, // No base. + nullptr, // No element. + &default_dtor<vector<pair<K, V>>>, + &default_copy_ctor<vector<pair<K, V>>>, + &default_copy_assign<vector<pair<K, V>>>, + &pair_vector_assign<K, V>, + &pair_vector_append<K, V>, + &pair_vector_append<K, V>, // Prepend is the same as append. + &pair_vector_reverse<K, V>, + nullptr, // No cast (cast data_ directly). + &pair_vector_compare<K, V>, + &default_empty<vector<pair<K, V>>> + }; + // map<K, V> value // template <typename K, typename V> @@ -574,7 +738,7 @@ namespace build2 } template <typename K, typename V> - const std::map<K,V> value_traits<std::map<K, V>>::empty_instance; + const std::map<K, V> value_traits<std::map<K, V>>::empty_instance; template <typename K, typename V> const typename value_traits<std::map<K, V>>::value_type_ex |