From 3ce44330cca9dbc4314feebb27403ebc3175b6c2 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 28 Mar 2016 09:14:31 +0200 Subject: New variable architecture --- build2/variable.txx | 401 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 303 insertions(+), 98 deletions(-) (limited to 'build2/variable.txx') diff --git a/build2/variable.txx b/build2/variable.txx index 7a0d53a..721e3c0 100644 --- a/build2/variable.txx +++ b/build2/variable.txx @@ -6,57 +6,232 @@ namespace build2 { + // value + // + template + void + default_dtor (value& v) + { + v.as ().~T (); + } + + template + void + default_copy_ctor (value& l, const value& r, bool m) + { + if (m) + new (&l.data_) T (move (const_cast (r).as ())); + else + new (&l.data_) T (r.as ()); + } + + template + void + default_copy_assign (value& l, const value& r, bool m) + { + if (m) + l.as () = move (const_cast (r).as ()); + else + l.as () = r.as (); + } + + template + bool + simple_assign (value& v, names&& ns, const variable& var) + { + size_t n (ns.size ()); + + if (empty ? n <= 1 : n == 1) + { + try + { + return value_traits::assign ( + v, + (n == 0 + ? T () + : value_traits::convert (move (ns.front ()), nullptr))); + } + catch (const invalid_argument&) {} // Fall through. + } + + error << "invalid " << value_traits::value_type.name + << " value '" << ns << "' in variable " << var.name; + throw failed (); + } + + template + bool + simple_append (value& v, names&& ns, const variable& var) + { + size_t n (ns.size ()); + + if (empty ? n <= 1 : n == 1) + { + try + { + return value_traits::append ( + v, + (n == 0 + ? T () + : value_traits::convert (move (ns.front ()), nullptr))); + } + catch (const invalid_argument&) {} // Fall through. + } + + error << "invalid " << value_traits::value_type.name + << " value '" << ns << "' in variable " << var.name; + throw failed (); + } + + template + bool + simple_prepend (value& v, names&& ns, const variable& var) + { + size_t n (ns.size ()); + + if (empty ? n <= 1 : n == 1) + { + try + { + return value_traits::prepend ( + v, + (n == 0 + ? T () + : value_traits::convert (move (ns.front ()), nullptr))); + } + catch (const invalid_argument&) {} // Fall through. + } + + error << "invalid " << value_traits::value_type.name + << " value '" << ns << "' in variable " << var.name; + throw failed (); + } + + template + names_view + simple_reverse (const value& v, names& s) + { + s.emplace_back (value_traits::reverse (v.as ())); + return s; + } + + template + int + simple_compare (const value& l, const value& r) + { + return value_traits::compare (l.as (), r.as ()); + } + // vector value // + template bool - vector_assign (names& v, const variable& var) + vector_append (value& v, names&& ns, const variable& var) { - // Verify each element has valid value of T. Merge pairs. + vector* p (v.null () + ? new (&v.data_) vector () + : &v.as> ()); + + // Convert each element to T while merging pairs. // - for (auto i (v.begin ()); i != v.end (); ) + for (auto i (ns.begin ()); i != ns.end (); ++i) { name& n (*i); + name* r (n.pair ? &*++i : nullptr); - if (n.pair) + try { - name& r (*++i); - - if (!assign (n, r)) - fail << "invalid " << value_traits::value_type.name - << " pair '" << n << "'@'" << r << "'" - << " in variable '" << var.name << "'"; - - i = v.erase (i); + p->push_back (value_traits::convert (move (n), r)); } - else + catch (const invalid_argument&) { - if (!assign (n)) - fail << "invalid " << value_traits::value_type.name - << " element '" << n << "' in variable '" << var.name << "'"; - ++i; + diag_record dr (fail); + + dr << "invalid " << value_traits::value_type.name; + + if (n.pair) + dr << " element pair '" << n << "'@'" << *r << "'"; + else + dr << " element '" << n << "'"; + + dr << " in variable " << var.name; } } - return !v.empty (); + return !p->empty (); } template bool - vector_append (names& v, names a, const variable& var) + vector_assign (value& v, names&& ns, const variable& var) { - // Verify that what we are appending is valid. + if (!v.null ()) + v.as> ().clear (); + + return vector_append (v, move (ns), var); + } + + template + bool + vector_prepend (value& v, names&& ns, const variable& var) + { + // Reduce to append. // - vector_assign (a, var); + vector t; + vector* p; - if (v.empty ()) - v = move (a); + if (v.null ()) + p = new (&v.data_) vector (); else - v.insert (v.end (), - make_move_iterator (a.begin ()), - make_move_iterator (a.end ())); + { + p = &v.as> (); + p->swap (t); + } + + vector_append (v, move (ns), var); + + p->insert (p->end (), + make_move_iterator (t.begin ()), + make_move_iterator (t.end ())); + + return !p->empty (); + } + + template + static names_view + vector_reverse (const value& v, names& s) + { + auto& vv (v.as> ()); + s.reserve (vv.size ()); - return !v.empty (); + for (const T& x: vv) + s.push_back (value_traits::reverse (x)); + + return s; + } + + template + static int + 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) + if (int r = value_traits::compare (*li, *ri)) + 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 @@ -67,105 +242,127 @@ namespace build2 const value_type value_traits>::value_type { value_traits>::type_name.c_str (), + sizeof (vector), + &default_dtor>, + &default_copy_ctor>, + &default_copy_assign>, &vector_assign, - &vector_append + &vector_append, + &vector_prepend, + &vector_reverse, + nullptr, // No cast (cast data_ directly). + &vector_compare }; // map value // - template - map_value& map_value:: - assign (std::map m) + template + bool + map_append (value& v, names&& ns, const variable& var) { - d->clear (); - for (auto& p: m) - { - d->emplace_back (p.first); // Const, can't move. - d->back ().pair = true; - d->emplace_back (move (p.second)); - } + using std::map; - return *this; - } + map* p (v.null () + ? new (&v.data_) map () + : &v.as> ()); - template - auto map_value:: - find (const K& k) -> iterator - { - // @@ Scan backwards to handle duplicates. + // Verify we have a sequence of pairs and convert each lhs/rhs to K/V. // - for (auto i (d->rbegin ()); i != d->rend (); ++i) - if (as (*++i) == k) - return iterator (--(i.base ())); + for (auto i (ns.begin ()); i != ns.end (); ++i) + { + name& l (*i); - return end (); - } + if (!l.pair) + fail << value_traits>::value_type.name << " key-value " + << "pair expected instead of '" << l << "' " + << "in variable " << var.name; - template - auto map_value:: - find (const K& k) const -> const_iterator - { - // @@ Scan backwards to handle duplicates. - // - for (auto i (d->rbegin ()); i != d->rend (); ++i) - if (as (*++i) == k) - return const_iterator (--(i.base ())); + name& r (*++i); // Got to have the second half of the pair. + + try + { + K k (value_traits::convert (move (l), nullptr)); + + try + { + V v (value_traits::convert (move (r), nullptr)); - return end (); + p->emplace (move (k), move (v)); + } + catch (const invalid_argument&) + { + fail << "invalid " << value_traits::value_type.name + << " element value '" << r << "' in variable " << var.name; + } + } + catch (const invalid_argument&) + { + fail << "invalid " << value_traits::value_type.name + << " element key '" << l << "' in variable " << var.name; + } + } + + return !p->empty (); } template bool - map_assign (names& v, const variable& var) + map_assign (value& v, names&& ns, const variable& var) { - // Verify we have a sequence of pairs and each lhs/rhs is a valid - // value of K/V. - // - for (auto i (v.begin ()); i != v.end (); ++i) - { - if (!i->pair) - fail << value_traits>::value_type.name << " key-value " - << "pair expected instead of '" << *i << "' " - << "in variable '" << var.name << "'"; + using std::map; - if (!assign (*i)) - fail << "invalid " << value_traits::value_type.name << " key " - << "'" << *i << "' in variable '" << var.name << "'"; + if (!v.null ()) + v.as> ().clear (); - ++i; // Got to have the second half of the pair. + return map_append (v, move (ns), var); + } - if (!assign (*i)) - fail << "invalid " << value_traits::value_type.name << " value " - << "'" << *i << "' in variable '" << var.name << "'"; - } + template + static names_view + map_reverse (const value& v, names& s) + { + using std::map; - //@@ When doing sorting, note that assign() can convert the - // value. + auto& vm (v.as> ()); + s.reserve (2 * vm.size ()); - //@@ Is sorting really the right trade-off (i.e., insertion - // vs search)? Perhaps linear search is ok? + for (const auto& p: vm) + { + s.push_back (value_traits::reverse (p.first)); + s.back ().pair = true; + s.push_back (value_traits::reverse (p.second)); + } - return !v.empty (); + return s; } template - bool - map_append (names& v, names a, const variable& var) + static int + map_compare (const value& l, const value& r) { - //@@ Not weeding out duplicates. + using std::map; - // Verify that what we are appending is valid. - // - map_assign (a, var); + auto& lm (l.as> ()); + auto& rm (r.as> ()); - if (v.empty ()) - v = move (a); - else - v.insert (v.end (), - make_move_iterator (a.begin ()), - make_move_iterator (a.end ())); + auto li (lm.begin ()), le (lm.end ()); + auto ri (rm.begin ()), re (rm.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 !v.empty (); + return 0; } template @@ -176,8 +373,16 @@ namespace build2 template const value_type value_traits>::value_type { - value_traits>::type_name.c_str (), + value_traits>::type_name.c_str (), + sizeof (map), + &default_dtor>, + &default_copy_ctor>, + &default_copy_assign>, &map_assign, - &map_append + &map_append, + &map_append, // Prepend is the same as append. + &map_reverse, + nullptr, // No cast (cast data_ directly). + &map_compare }; } -- cgit v1.1