From 6e91cb7cdb0c4f000a79d20d8578890d56bcdc84 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 22 Jan 2021 08:39:10 +0200 Subject: Add support for optional pair halves in variable values --- libbuild2/variable.txx | 513 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 358 insertions(+), 155 deletions(-) (limited to 'libbuild2/variable.txx') diff --git a/libbuild2/variable.txx b/libbuild2/variable.txx index 8fa1d7c..9c9c867 100644 --- a/libbuild2/variable.txx +++ b/libbuild2/variable.txx @@ -241,9 +241,228 @@ namespace build2 return value_traits::compare (l.as (), r.as ()); } - // vector value + // pair value // + template + pair pair_value_traits:: + convert (name&& l, name* r, + const char* type, const char* what, const variable* var) + { + if (!l.pair) + { + diag_record dr (fail); + + dr << type << ' ' << what << (*what != '\0' ? " " : "") + << "pair expected instead of '" << l << "'"; + + if (var != nullptr) + dr << " in variable " << var->name; + } + + if (l.pair != '@') + { + diag_record dr (fail); + + dr << "unexpected pair style for " + << type << ' ' << what << (*what != '\0' ? " " : "") + << "key-value pair '" + << l << "'" << l.pair << "'" << *r << "'"; + + if (var != nullptr) + dr << " in variable " << var->name; + } + + try + { + F f (value_traits::convert (move (l), nullptr)); + + try + { + S s (value_traits::convert (move (*r), nullptr)); + + return pair (move (f), move (s)); + } + catch (const invalid_argument&) + { + diag_record dr (fail); + + dr << "invalid " << value_traits::value_type.name + << " second have of pair '" << *r << "'"; + + if (var != nullptr) + dr << " in variable " << var->name; + + dr << endf; + } + } + catch (const invalid_argument&) + { + diag_record dr (fail); + + dr << "invalid " << value_traits::value_type.name + << " first have of pair '" << l << "'"; + + if (var != nullptr) + dr << " in variable " << var->name; + + dr << endf; + } + } + + template + pair> pair_value_traits>:: + convert (name&& l, name* r, + const char* type, const char* what, const variable* var) + { + if (l.pair && l.pair != '@') + { + diag_record dr (fail); + + dr << "unexpected pair style for " + << type << ' ' << what << (*what != '\0' ? " " : "") + << "key-value pair '" + << l << "'" << l.pair << "'" << *r << "'"; + + if (var != nullptr) + dr << " in variable " << var->name; + } + + try + { + F f (value_traits::convert (move (l), nullptr)); + + try + { + optional s; + + if (l.pair) + s = value_traits::convert (move (*r), nullptr); + + return pair> (move (f), move (s)); + } + catch (const invalid_argument&) + { + diag_record dr (fail); + + dr << "invalid " << value_traits::value_type.name + << " second have of pair '" << *r << "'"; + + if (var != nullptr) + dr << " in variable " << var->name; + + dr << endf; + } + } + catch (const invalid_argument&) + { + diag_record dr (fail); + + dr << "invalid " << value_traits::value_type.name + << " first have of pair '" << l << "'"; + if (var != nullptr) + dr << " in variable " << var->name; + + dr << endf; + } + } + + template + pair, S> pair_value_traits, S>:: + convert (name&& l, name* r, + const char* type, const char* what, const variable* var) + { + if (l.pair && l.pair != '@') + { + diag_record dr (fail); + + dr << "unexpected pair style for " + << type << ' ' << what << (*what != '\0' ? " " : "") + << "key-value pair '" + << l << "'" << l.pair << "'" << *r << "'"; + + if (var != nullptr) + dr << " in variable " << var->name; + } + + try + { + optional f; + + if (l.pair) + { + f = value_traits::convert (move (l), nullptr); + l = move (*r); // Shift. + } + + try + { + S s (value_traits::convert (move (l), nullptr)); + + return pair, S> (move (f), move (s)); + } + catch (const invalid_argument&) + { + diag_record dr (fail); + + dr << "invalid " << value_traits::value_type.name + << " second have of pair '" << l << "'"; + + if (var != nullptr) + dr << " in variable " << var->name; + + dr << endf; + } + } + catch (const invalid_argument&) + { + diag_record dr (fail); + + dr << "invalid " << value_traits::value_type.name + << " first have of pair '" << l << "'"; + + if (var != nullptr) + dr << " in variable " << var->name; + + dr << endf; + } + } + + template + void pair_value_traits:: + reverse (const F& f, const S& s, names& ns) + { + ns.push_back (value_traits::reverse (f)); + ns.back ().pair = '@'; + ns.push_back (value_traits::reverse (s)); + } + + template + void pair_value_traits>:: + reverse (const F& f, const optional& s, names& ns) + { + ns.push_back (value_traits::reverse (f)); + if (s) + { + ns.back ().pair = '@'; + ns.push_back (value_traits::reverse (*s)); + } + } + + template + void pair_value_traits, S>:: + reverse (const optional& f, const S& s, names& ns) + { + if (f) + { + ns.push_back (value_traits::reverse (*f)); + ns.back ().pair = '@'; + } + ns.push_back (value_traits::reverse (s)); + } + + // vector value + // template vector value_traits>:: convert (names&& ns) @@ -396,21 +615,28 @@ namespace build2 return 0; } + // Make sure these are static-initialized together. Failed that VC will make + // sure it's done in the wrong order. + // template - value_traits>::value_type_ex:: - value_type_ex (value_type&& v) - : value_type (move (v)) + struct vector_value_type: value_type { - type_name = value_traits::type_name; - type_name += 's'; - name = type_name.c_str (); - } + string type_name; + + vector_value_type (value_type&& v) + : value_type (move (v)) + { + type_name = value_traits::type_name; + type_name += 's'; + name = type_name.c_str (); + } + }; template const vector value_traits>::empty_instance; template - const typename value_traits>::value_type_ex + const vector_value_type value_traits>::value_type = build2::value_type // VC14 wants =. { nullptr, // Patched above. @@ -444,63 +670,14 @@ namespace build2 for (auto i (ns.begin ()); i != ns.end (); ++i) { name& l (*i); + name* r (l.pair ? &*++i : nullptr); - if (!l.pair) - { - diag_record dr (fail); - - dr << value_traits>>::value_type.name - << " key-value pair expected instead of '" << l << "'"; + p.push_back (value_traits>::convert ( + move (l), r, + value_traits>>::value_type.name, + "element", + var)); - 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; - } } } @@ -522,11 +699,7 @@ namespace build2 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)); - } + value_traits>::reverse (p.first, p.second, s); return s; } @@ -543,9 +716,7 @@ namespace build2 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) + if (int r = value_traits>::compare (*li, *ri)) return r; } @@ -558,23 +729,66 @@ namespace build2 return 0; } + // Make sure these are static-initialized together. Failed that VC will make + // sure it's done in the wrong order. + // template - value_traits>>::value_type_ex:: - value_type_ex (value_type&& v) - : value_type (move (v)) + struct pair_vector_value_type: value_type { - type_name = value_traits::type_name; - type_name += '_'; - type_name += value_traits::type_name; - type_name += "_pair_vector"; - name = type_name.c_str (); - } + string type_name; + + pair_vector_value_type (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 (); + } + }; + + // This is beyond our static initialization order control skills, so we hack + // it up for now. + // + template + struct pair_vector_value_type>: value_type + { + string type_name; + + pair_vector_value_type (value_type&& v) + : value_type (move (v)) + { + type_name = value_traits::type_name; + type_name += "_optional_"; + type_name += value_traits::type_name; + type_name += "_pair_vector"; + name = type_name.c_str (); + } + }; + + template + struct pair_vector_value_type, V>: value_type + { + string type_name; + + pair_vector_value_type (value_type&& v) + : value_type (move (v)) + { + type_name = "optional_"; + 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 + const pair_vector_value_type value_traits>>::value_type = build2::value_type // VC14 wants = { nullptr, // Patched above. @@ -610,63 +824,15 @@ namespace build2 for (auto i (ns.begin ()); i != ns.end (); ++i) { name& l (*i); + name* r (l.pair ? &*++i : nullptr); - if (!l.pair) - { - diag_record dr (fail); + pair v (value_traits>::convert ( + move (l), r, + value_traits>::value_type.name, + "element", + var)); - 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 (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; - } + p.emplace (move (v.first), move (v.second)); } } @@ -692,11 +858,7 @@ namespace build2 s.reserve (2 * vm.size ()); for (const auto& p: vm) - { - s.push_back (value_traits::reverse (p.first)); - s.back ().pair = '@'; - s.push_back (value_traits::reverse (p.second)); - } + value_traits>::reverse (p.first, p.second, s); return s; } @@ -715,9 +877,7 @@ namespace build2 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) + if (int r = value_traits>::compare (*li, *ri)) return r; } @@ -730,23 +890,66 @@ namespace build2 return 0; } + // Make sure these are static-initialized together. Failed that VC will make + // sure it's done in the wrong order. + // template - value_traits>::value_type_ex:: - value_type_ex (value_type&& v) - : value_type (move (v)) + struct map_value_type: value_type { - type_name = value_traits::type_name; - type_name += '_'; - type_name += value_traits::type_name; - type_name += "_map"; - name = type_name.c_str (); - } + string type_name; + + map_value_type (value_type&& v) + : value_type (move (v)) + { + type_name = value_traits::type_name; + type_name += '_'; + type_name += value_traits::type_name; + type_name += "_map"; + name = type_name.c_str (); + } + }; + + // This is beyond our static initialization order control skills, so we hack + // it up for now. + // + template + struct map_value_type>: value_type + { + string type_name; + + map_value_type (value_type&& v) + : value_type (move (v)) + { + type_name = value_traits::type_name; + type_name += "_optional_"; + type_name += value_traits::type_name; + type_name += "_map"; + name = type_name.c_str (); + } + }; + + template + struct map_value_type, V>: value_type + { + string type_name; + + map_value_type (value_type&& v) + : value_type (move (v)) + { + type_name = "optional_"; + type_name += value_traits::type_name; + type_name += '_'; + type_name += value_traits::type_name; + type_name += "_map"; + name = type_name.c_str (); + } + }; template const std::map value_traits>::empty_instance; template - const typename value_traits>::value_type_ex + const map_value_type value_traits>::value_type = build2::value_type // VC14 wants = { nullptr, // Patched above. -- cgit v1.1