aboutsummaryrefslogtreecommitdiff
path: root/build2/variable.txx
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2016-03-28 09:14:31 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2016-03-28 16:03:35 +0200
commit3ce44330cca9dbc4314feebb27403ebc3175b6c2 (patch)
tree8c1f27442f3b2dafaec3ba50baaca3d5fd63dca7 /build2/variable.txx
parent9d0d078ff297138622cd2f3f1076f5984395e42b (diff)
New variable architecture
Diffstat (limited to 'build2/variable.txx')
-rw-r--r--build2/variable.txx401
1 files changed, 303 insertions, 98 deletions
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 <typename T>
+ void
+ default_dtor (value& v)
+ {
+ v.as<T> ().~T ();
+ }
+
+ template <typename T>
+ void
+ default_copy_ctor (value& l, const value& r, bool m)
+ {
+ if (m)
+ new (&l.data_) T (move (const_cast<value&> (r).as<T> ()));
+ else
+ new (&l.data_) T (r.as<T> ());
+ }
+
+ template <typename T>
+ void
+ default_copy_assign (value& l, const value& r, bool m)
+ {
+ if (m)
+ l.as<T> () = move (const_cast<value&> (r).as<T> ());
+ else
+ l.as<T> () = r.as<T> ();
+ }
+
+ template <typename T, bool empty>
+ 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<T>::assign (
+ v,
+ (n == 0
+ ? T ()
+ : value_traits<T>::convert (move (ns.front ()), nullptr)));
+ }
+ catch (const invalid_argument&) {} // Fall through.
+ }
+
+ error << "invalid " << value_traits<T>::value_type.name
+ << " value '" << ns << "' in variable " << var.name;
+ throw failed ();
+ }
+
+ template <typename T, bool empty>
+ 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<T>::append (
+ v,
+ (n == 0
+ ? T ()
+ : value_traits<T>::convert (move (ns.front ()), nullptr)));
+ }
+ catch (const invalid_argument&) {} // Fall through.
+ }
+
+ error << "invalid " << value_traits<T>::value_type.name
+ << " value '" << ns << "' in variable " << var.name;
+ throw failed ();
+ }
+
+ template <typename T, bool empty>
+ 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<T>::prepend (
+ v,
+ (n == 0
+ ? T ()
+ : value_traits<T>::convert (move (ns.front ()), nullptr)));
+ }
+ catch (const invalid_argument&) {} // Fall through.
+ }
+
+ error << "invalid " << value_traits<T>::value_type.name
+ << " value '" << ns << "' in variable " << var.name;
+ throw failed ();
+ }
+
+ template <typename T>
+ names_view
+ simple_reverse (const value& v, names& s)
+ {
+ s.emplace_back (value_traits<T>::reverse (v.as<T> ()));
+ return s;
+ }
+
+ template <typename T>
+ int
+ simple_compare (const value& l, const value& r)
+ {
+ return value_traits<T>::compare (l.as<T> (), r.as<T> ());
+ }
+
// vector<T> value
//
+
template <typename T>
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<T>* p (v.null ()
+ ? new (&v.data_) vector<T> ()
+ : &v.as<vector<T>> ());
+
+ // 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<T> (n, r))
- fail << "invalid " << value_traits<T>::value_type.name
- << " pair '" << n << "'@'" << r << "'"
- << " in variable '" << var.name << "'";
-
- i = v.erase (i);
+ p->push_back (value_traits<T>::convert (move (n), r));
}
- else
+ catch (const invalid_argument&)
{
- if (!assign<T> (n))
- fail << "invalid " << value_traits<T>::value_type.name
- << " element '" << n << "' in variable '" << var.name << "'";
- ++i;
+ diag_record dr (fail);
+
+ dr << "invalid " << value_traits<T>::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 <typename T>
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<vector<T>> ().clear ();
+
+ return vector_append<T> (v, move (ns), var);
+ }
+
+ template <typename T>
+ bool
+ vector_prepend (value& v, names&& ns, const variable& var)
+ {
+ // Reduce to append.
//
- vector_assign<T> (a, var);
+ vector<T> t;
+ vector<T>* p;
- if (v.empty ())
- v = move (a);
+ if (v.null ())
+ p = new (&v.data_) vector<T> ();
else
- v.insert (v.end (),
- make_move_iterator (a.begin ()),
- make_move_iterator (a.end ()));
+ {
+ p = &v.as<vector<T>> ();
+ p->swap (t);
+ }
+
+ vector_append<T> (v, move (ns), var);
+
+ p->insert (p->end (),
+ make_move_iterator (t.begin ()),
+ make_move_iterator (t.end ()));
+
+ return !p->empty ();
+ }
+
+ template <typename T>
+ static names_view
+ vector_reverse (const value& v, names& s)
+ {
+ auto& vv (v.as<vector<T>> ());
+ s.reserve (vv.size ());
- return !v.empty ();
+ for (const T& x: vv)
+ s.push_back (value_traits<T>::reverse (x));
+
+ return s;
+ }
+
+ template <typename T>
+ static int
+ vector_compare (const value& l, const value& r)
+ {
+ auto& lv (l.as<vector<T>> ());
+ auto& rv (r.as<vector<T>> ());
+
+ 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<T>::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 <typename T>
@@ -67,105 +242,127 @@ namespace build2
const value_type value_traits<vector<T>>::value_type
{
value_traits<vector<T>>::type_name.c_str (),
+ sizeof (vector<T>),
+ &default_dtor<vector<T>>,
+ &default_copy_ctor<vector<T>>,
+ &default_copy_assign<vector<T>>,
&vector_assign<T>,
- &vector_append<T>
+ &vector_append<T>,
+ &vector_prepend<T>,
+ &vector_reverse<T>,
+ nullptr, // No cast (cast data_ directly).
+ &vector_compare<T>
};
// map<K, V> value
//
- template <typename K, typename V, typename D>
- map_value<K, V, D>& map_value<K, V, D>::
- assign (std::map<K, V> m)
+ template <typename K, typename V>
+ 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<K, V>* p (v.null ()
+ ? new (&v.data_) map<K, V> ()
+ : &v.as<map<K, V>> ());
- template <typename K, typename V, typename D>
- auto map_value<K, V, D>::
- 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<K> (*++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<map<K, V>>::value_type.name << " key-value "
+ << "pair expected instead of '" << l << "' "
+ << "in variable " << var.name;
- template <typename K, typename V, typename D>
- auto map_value<K, V, D>::
- find (const K& k) const -> const_iterator
- {
- // @@ Scan backwards to handle duplicates.
- //
- for (auto i (d->rbegin ()); i != d->rend (); ++i)
- if (as<K> (*++i) == k)
- return const_iterator (--(i.base ()));
+ name& r (*++i); // Got to have the second half of the pair.
+
+ try
+ {
+ K k (value_traits<K>::convert (move (l), nullptr));
+
+ try
+ {
+ V v (value_traits<V>::convert (move (r), nullptr));
- return end ();
+ p->emplace (move (k), move (v));
+ }
+ catch (const invalid_argument&)
+ {
+ fail << "invalid " << value_traits<V>::value_type.name
+ << " element value '" << r << "' in variable " << var.name;
+ }
+ }
+ catch (const invalid_argument&)
+ {
+ fail << "invalid " << value_traits<K>::value_type.name
+ << " element key '" << l << "' in variable " << var.name;
+ }
+ }
+
+ return !p->empty ();
}
template <typename K, typename V>
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<std::map<K, V>>::value_type.name << " key-value "
- << "pair expected instead of '" << *i << "' "
- << "in variable '" << var.name << "'";
+ using std::map;
- if (!assign<K> (*i))
- fail << "invalid " << value_traits<K>::value_type.name << " key "
- << "'" << *i << "' in variable '" << var.name << "'";
+ if (!v.null ())
+ v.as<map<K, V>> ().clear ();
- ++i; // Got to have the second half of the pair.
+ return map_append<K, V> (v, move (ns), var);
+ }
- if (!assign<V> (*i))
- fail << "invalid " << value_traits<V>::value_type.name << " value "
- << "'" << *i << "' in variable '" << var.name << "'";
- }
+ template <typename K, typename V>
+ 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<map<K, V>> ());
+ 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<K>::reverse (p.first));
+ s.back ().pair = true;
+ s.push_back (value_traits<V>::reverse (p.second));
+ }
- return !v.empty ();
+ return s;
}
template <typename K, typename V>
- 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<K, V> (a, var);
+ auto& lm (l.as<map<K, V>> ());
+ auto& rm (r.as<map<K, V>> ());
- 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<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 !v.empty ();
+ return 0;
}
template <typename K, typename V>
@@ -176,8 +373,16 @@ namespace build2
template <typename K, typename V>
const value_type value_traits<std::map<K, V>>::value_type
{
- value_traits<std::map<K, V>>::type_name.c_str (),
+ value_traits<map<K, V>>::type_name.c_str (),
+ sizeof (map<K, V>),
+ &default_dtor<map<K, V>>,
+ &default_copy_ctor<map<K, V>>,
+ &default_copy_assign<map<K, V>>,
&map_assign<K, V>,
- &map_append<K, V>
+ &map_append<K, V>,
+ &map_append<K, V>, // Prepend is the same as append.
+ &map_reverse<K, V>,
+ nullptr, // No cast (cast data_ directly).
+ &map_compare<K, V>
};
}