From c0743592bfae808b61a8146fd97af94b50156f0e Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 12 Nov 2019 12:20:34 +0200 Subject: Add support for vector> variable values --- libbuild2/variable.cxx | 6 +- libbuild2/variable.hxx | 30 +++++++++ libbuild2/variable.ixx | 31 +++++++++ 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; template struct LIBBUILD2_DEFEXPORT value_traits; - template struct LIBBUILD2_DEFEXPORT value_traits>; + template struct LIBBUILD2_DEFEXPORT + value_traits>>; + + template struct LIBBUILD2_DEFEXPORT + value_traits>; template struct LIBBUILD2_DEFEXPORT value_traits>; 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> + // + template + struct value_traits>> + { + static_assert (sizeof (vector>) <= value::size_, + "insufficient space"); + + static void assign (value&, vector>&&); + static void append (value&, vector>&&); + static void prepend (value& v, vector>&& x) { + return append (v, move (x));} + static bool empty (const vector>& x) {return x.empty ();} + + static const vector> 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 // template @@ -995,6 +1022,9 @@ namespace build2 extern template struct LIBBUILD2_DECEXPORT value_traits; extern template struct LIBBUILD2_DECEXPORT + value_traits>>; + + extern template struct LIBBUILD2_DECEXPORT value_traits>; 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 (move (x)); } + // vector> value + // + template + inline void value_traits>>:: + assign (value& v, vector>&& x) + { + if (v) + v.as>> () = move (x); + else + new (&v.data_) vector> (move (x)); + } + + template + inline void value_traits>>:: + append (value& v, vector>&& x) + { + if (v) + { + vector>& y (v.as>> ()); + + 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> (move (x)); + } + // map value // template 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> value + // + template + void + pair_vector_append (value& v, names&& ns, const variable* var) + { + vector>& p (v + ? v.as>> () + : *new (&v.data_) vector> ()); + + // 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>>::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>>::value_type.name + << " key-value '" << l << "'" << l.pair << "'" << r << "'"; + + if (var != nullptr) + dr << " in variable " << var->name; + } + + try + { + K k (value_traits::convert (move (l), nullptr)); + + try + { + V v (value_traits::convert (move (r), nullptr)); + + p.emplace_back (move (k), move (v)); + } + catch (const invalid_argument&) + { + diag_record dr (fail); + + dr << "invalid " << value_traits::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::value_type.name + << " element key '" << l << "'"; + + if (var != nullptr) + dr << " in variable " << var->name; + } + } + } + + template + void + pair_vector_assign (value& v, names&& ns, const variable* var) + { + if (v) + v.as>> ().clear (); + + pair_vector_append (v, move (ns), var); + } + + template + static names_view + pair_vector_reverse (const value& v, names& s) + { + auto& vv (v.as>> ()); + s.reserve (2 * vv.size ()); + + for (const auto& p: vv) + { + s.push_back (value_traits::reverse (p.first)); + s.back ().pair = '@'; + s.push_back (value_traits::reverse (p.second)); + } + + return s; + } + + template + static int + pair_vector_compare (const value& l, const value& r) + { + auto& lv (l.as>> ()); + auto& rv (r.as>> ()); + + 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::compare (li->first, ri->first)) != 0 || + (r = value_traits::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 + value_traits>>::value_type_ex:: + value_type_ex (value_type&& v) + : value_type (move (v)) + { + type_name = value_traits::type_name; + type_name += '_'; + type_name += value_traits::type_name; + type_name += "_pair_vector"; + name = type_name.c_str (); + } + + template + const vector> value_traits>>::empty_instance; + + template + const typename value_traits>>::value_type_ex + value_traits>>::value_type = build2::value_type // VC14 wants = + { + nullptr, // Patched above. + sizeof (vector>), + nullptr, // No base. + nullptr, // No element. + &default_dtor>>, + &default_copy_ctor>>, + &default_copy_assign>>, + &pair_vector_assign, + &pair_vector_append, + &pair_vector_append, // Prepend is the same as append. + &pair_vector_reverse, + nullptr, // No cast (cast data_ directly). + &pair_vector_compare, + &default_empty>> + }; + // map value // template @@ -574,7 +738,7 @@ namespace build2 } template - const std::map value_traits>::empty_instance; + const std::map value_traits>::empty_instance; template const typename value_traits>::value_type_ex -- cgit v1.1