// file : build2/variable.txx -*- C++ -*- // copyright : Copyright (c) 2014-2016 Code Synthesis Ltd // license : MIT; see accompanying LICENSE file #include 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. } diag_record dr (error); dr << "invalid " << value_traits::value_type.name << " value '" << ns << "'"; if (var != nullptr) dr << " 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. } diag_record dr (error); dr << "invalid " << value_traits::value_type.name << " value '" << ns << "'"; if (var != nullptr) dr << " 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. } diag_record dr (error); dr << "invalid " << value_traits::value_type.name << " value '" << ns << "'"; if (var != nullptr) dr << " 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_append (value& v, names&& ns, const variable* var) { vector* p (v.null () ? new (&v.data_) vector () : &v.as> ()); // Convert each element to T while merging pairs. // for (auto i (ns.begin ()); i != ns.end (); ++i) { name& n (*i); name* r (nullptr); if (n.pair) { r = &*++i; if (n.pair != '@') { diag_record dr (fail); dr << "unexpected pair style for " << value_traits::value_type.name << " value " << "'" << n << "'" << n.pair << "'" << *r << "'"; if (var != nullptr) dr << " in variable " << var->name; } } try { p->push_back (value_traits::convert (move (n), r)); } catch (const invalid_argument&) { diag_record dr (fail); dr << "invalid " << value_traits::value_type.name; if (n.pair) dr << " element pair '" << n << "'@'" << *r << "'"; else dr << " element '" << n << "'"; if (var != nullptr) dr << " in variable " << var->name; } } return !p->empty (); } template bool vector_assign (value& v, names&& ns, const variable* var) { 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 t; vector* p; if (v.null ()) p = new (&v.data_) vector (); else { 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 ()); 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 const string value_traits>::type_name = string ( value_traits::value_type.name) + 's'; template const value_type value_traits>::value_type { value_traits>::type_name.c_str (), sizeof (vector), nullptr, // No base. &default_dtor>, &default_copy_ctor>, &default_copy_assign>, &vector_assign, &vector_append, &vector_prepend, &vector_reverse, nullptr, // No cast (cast data_ directly). &vector_compare }; // map value // template bool map_append (value& v, names&& ns, const variable* var) { using std::map; map* p (v.null () ? new (&v.data_) map () : &v.as> ()); // 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 (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; } } return !p->empty (); } template bool map_assign (value& v, names&& ns, const variable* var) { using std::map; if (!v.null ()) v.as> ().clear (); return map_append (v, move (ns), var); } template static names_view map_reverse (const value& v, names& s) { using std::map; auto& vm (v.as> ()); 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)); } return s; } template static int map_compare (const value& l, const value& r) { using std::map; auto& lm (l.as> ()); auto& rm (r.as> ()); 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 0; } template const string value_traits>::type_name = string ( value_traits::value_type.name) + '_' + value_traits::value_type.name + "_map"; template const value_type value_traits>::value_type { value_traits>::type_name.c_str (), sizeof (map), nullptr, // No base. &default_dtor>, &default_copy_ctor>, &default_copy_assign>, &map_assign, &map_append, &map_append, // Prepend is the same as append. &map_reverse, nullptr, // No cast (cast data_ directly). &map_compare }; }