aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/variable.ixx
diff options
context:
space:
mode:
Diffstat (limited to 'libbuild2/variable.ixx')
-rw-r--r--libbuild2/variable.ixx302
1 files changed, 282 insertions, 20 deletions
diff --git a/libbuild2/variable.ixx b/libbuild2/variable.ixx
index c8f9541..ca84a33 100644
--- a/libbuild2/variable.ixx
+++ b/libbuild2/variable.ixx
@@ -114,6 +114,22 @@ namespace build2
return *this;
}
+ template <typename T>
+ inline value& value::
+ prepend (T v)
+ {
+ assert (type == &value_traits<T>::value_type || (type == nullptr && null));
+
+ // Prepare the receiving value.
+ //
+ if (type == nullptr)
+ type = &value_traits<T>::value_type;
+
+ value_traits<T>::prepend (*this, move (v));
+ null = false;
+ return *this;
+ }
+
inline value& value::
operator= (names v)
{
@@ -208,7 +224,7 @@ namespace build2
template <typename T>
inline const T&
- cast (const lookup& l)
+ cast (lookup l)
{
return cast<T> (*l);
}
@@ -229,7 +245,7 @@ namespace build2
template <typename T>
inline const T*
- cast_null (const lookup& l)
+ cast_null (lookup l)
{
return l ? &cast<T> (*l) : nullptr;
}
@@ -243,7 +259,7 @@ namespace build2
template <typename T>
inline const T&
- cast_empty (const lookup& l)
+ cast_empty (lookup l)
{
return l ? cast<T> (l) : value_traits<T>::empty_instance;
}
@@ -257,7 +273,7 @@ namespace build2
template <typename T>
inline T
- cast_default (const lookup& l, const T& d)
+ cast_default (lookup l, const T& d)
{
return l ? cast<T> (l) : d;
}
@@ -271,7 +287,7 @@ namespace build2
template <typename T>
inline T
- cast_false (const lookup& l)
+ cast_false (lookup l)
{
return l && cast<T> (l);
}
@@ -285,7 +301,7 @@ namespace build2
template <typename T>
inline T
- cast_true (const lookup& l)
+ cast_true (lookup l)
{
return !l || cast<T> (l);
}
@@ -310,18 +326,21 @@ namespace build2
}
inline vector_view<const name>
- reverse (const value& v, names& storage)
+ reverse (const value& v, names& storage, bool reduce)
{
assert (v &&
storage.empty () &&
(v.type == nullptr || v.type->reverse != nullptr));
- return v.type == nullptr ? v.as<names> () : v.type->reverse (v, storage);
+
+ return v.type == nullptr
+ ? v.as<names> ()
+ : v.type->reverse (v, storage, reduce);
}
inline vector_view<name>
- reverse (value& v, names& storage)
+ reverse (value& v, names& storage, bool reduce)
{
- names_view cv (reverse (static_cast<const value&> (v), storage));
+ names_view cv (reverse (static_cast<const value&> (v), storage, reduce));
return vector_view<name> (const_cast<name*> (cv.data ()), cv.size ());
}
@@ -343,13 +362,53 @@ namespace build2
// This one will be SFINAE'd out unless T is a container.
//
+ // If T is both (e.g., json_value), then make this version preferable.
+ //
template <typename T>
inline auto
- convert (names&& ns) -> decltype (value_traits<T>::convert (move (ns)))
+ convert_impl (names&& ns, int)
+ -> decltype (value_traits<T>::convert (move (ns)))
{
return value_traits<T>::convert (move (ns));
}
+ // This one will be SFINAE'd out unless T is a simple value.
+ //
+ // If T is both (e.g., json_value), then make this version less preferable.
+ //
+ template <typename T>
+ auto // NOTE: not inline!
+ convert_impl (names&& ns, ...) ->
+ decltype (value_traits<T>::convert (move (ns[0]), nullptr))
+ {
+ size_t n (ns.size ());
+
+ if (n == 0)
+ {
+ if (value_traits<T>::empty_value)
+ return T ();
+ }
+ else if (n == 1)
+ {
+ return convert<T> (move (ns[0]));
+ }
+ else if (n == 2 && ns[0].pair != '\0')
+ {
+ return convert<T> (move (ns[0]), move (ns[1]));
+ }
+
+ throw invalid_argument (
+ string ("invalid ") + value_traits<T>::type_name +
+ (n == 0 ? " value: empty" : " value: multiple names"));
+ }
+
+ template <typename T>
+ inline T
+ convert (names&& ns)
+ {
+ return convert_impl<T> (move (ns), 0);
+ }
+
// bool value
//
inline void value_traits<bool>::
@@ -728,6 +787,31 @@ namespace build2
: s);
}
+ // optional<T>
+ //
+ template <typename T>
+ inline int value_traits<optional<T>>::
+ compare (const optional<T>& l, const optional<T>& r)
+ {
+ return l
+ ? (r ? value_traits<T>::compare (*l, *r) : 1)
+ : (r ? -1 : 0);
+ }
+
+ // pair<F, S> value
+ //
+ template <typename F, typename S>
+ inline int value_traits<pair<F, S>>::
+ compare (const pair<F, S>& l, const pair<F, S>& r)
+ {
+ int i (value_traits<F>::compare (l.first, r.first));
+
+ if (i == 0)
+ i = value_traits<S>::compare (l.second, r.second);
+
+ return i;
+ }
+
// vector<T> value
//
template <typename T>
@@ -809,10 +893,48 @@ namespace build2
new (&v.data_) vector<pair<K, V>> (move (x));
}
+ // set<T> value
+ //
+ template <typename T>
+ inline void value_traits<set<T>>::
+ assign (value& v, set<T>&& x)
+ {
+ if (v)
+ v.as<set<T>> () = move (x);
+ else
+ new (&v.data_) set<T> (move (x));
+ }
+
+ template <typename T>
+ inline void value_traits<set<T>>::
+ append (value& v, set<T>&& x)
+ {
+ if (v)
+ {
+ set<T>& p (v.as<set<T>> ());
+
+ if (p.empty ())
+ p.swap (x);
+ else
+ // Keys (being const) can only be copied.
+ //
+ p.insert (x.begin (), x.end ());
+ }
+ else
+ new (&v.data_) set<T> (move (x));
+ }
+
+ template <typename T>
+ inline void value_traits<set<T>>::
+ prepend (value& v, set<T>&& x)
+ {
+ append (v, move (x));
+ }
+
// map<K, V> value
//
template <typename K, typename V>
- inline void value_traits<std::map<K, V>>::
+ inline void value_traits<map<K, V>>::
assign (value& v, map<K, V>&& x)
{
if (v)
@@ -822,7 +944,7 @@ namespace build2
}
template <typename K, typename V>
- inline void value_traits<std::map<K, V>>::
+ inline void value_traits<map<K, V>>::
append (value& v, map<K, V>&& x)
{
if (v)
@@ -842,21 +964,161 @@ namespace build2
new (&v.data_) map<K, V> (move (x));
}
- // variable_pool
+ template <typename K, typename V>
+ inline void value_traits<map<K, V>>::
+ prepend (value& v, map<K, V>&& x)
+ {
+ if (v)
+ {
+ map<K, V>& m (v.as<map<K, V>> ());
+
+ m.swap (x);
+
+ // Note that this will only move values. Keys (being const) are still
+ // copied.
+ //
+ m.insert (make_move_iterator (x.begin ()),
+ make_move_iterator (x.end ()));
+ }
+ else
+ new (&v.data_) map<K, V> (move (x));
+ }
+
+ // json
//
- inline const variable& variable_pool::
- operator[] (const string& n) const
+ inline bool value_traits<json_value>::
+ empty (const json_value& v)
{
- const variable* r (find (n));
- assert (r != nullptr);
- return *r;
+ // Note: should be consistent with $json.size().
+ //
+ switch (v.type)
+ {
+ case json_type::null: return true;
+ case json_type::boolean:
+ case json_type::signed_number:
+ case json_type::unsigned_number:
+ case json_type::hexadecimal_number:
+ case json_type::string: break;
+ case json_type::array: return v.array.empty ();
+ case json_type::object: return v.object.empty ();
+ }
+
+ return false;
+ }
+
+ inline void value_traits<json_value>::
+ assign (value& v, json_value&& x)
+ {
+ if (v)
+ v.as<json_value> () = move (x);
+ else
+ new (&v.data_) json_value (move (x));
+ }
+
+ inline void value_traits<json_value>::
+ append (value& v, json_value&& x)
+ {
+ if (v)
+ v.as<json_value> ().append (move (x));
+ else
+ new (&v.data_) json_value (move (x));
+ }
+
+ inline void value_traits<json_value>::
+ prepend (value& v, json_value&& x)
+ {
+ if (v)
+ v.as<json_value> ().prepend (move (x));
+ else
+ new (&v.data_) json_value (move (x));
+ }
+
+ // json_array
+ //
+ inline void value_traits<json_array>::
+ assign (value& v, json_array&& x)
+ {
+ if (v)
+ v.as<json_array> () = move (x);
+ else
+ new (&v.data_) json_array (move (x));
}
+ inline void value_traits<json_array>::
+ append (value& v, json_value&& x)
+ {
+ if (!v)
+ new (&v.data_) json_array ();
+
+ v.as<json_array> ().append (move (x));
+ }
+
+ inline void value_traits<json_array>::
+ prepend (value& v, json_value&& x)
+ {
+ if (!v)
+ new (&v.data_) json_array ();
+
+ v.as<json_array> ().prepend (move (x));
+ }
+
+ // json_object
+ //
+ inline void value_traits<json_object>::
+ assign (value& v, json_object&& x)
+ {
+ if (v)
+ v.as<json_object> () = move (x);
+ else
+ new (&v.data_) json_object (move (x));
+ }
+
+ inline void value_traits<json_object>::
+ append (value& v, json_value&& x)
+ {
+ if (!v)
+ new (&v.data_) json_object ();
+
+ v.as<json_object> ().append (move (x));
+ }
+
+ inline void value_traits<json_object>::
+ prepend (value& v, json_value&& x)
+ {
+ if (!v)
+ new (&v.data_) json_object ();
+
+ v.as<json_object> ().prepend (move (x));
+ }
+
+ // variable_pool
+ //
inline const variable* variable_pool::
find (const string& n) const
{
+ // The pool chaining semantics for lookup: first check own pool then, if
+ // not found, check the outer pool.
+ //
auto i (map_.find (&n));
- return i != map_.end () ? &i->second : nullptr;
+ if (i != map_.end ())
+ return &i->second;
+
+ if (outer_ != nullptr)
+ {
+ i = outer_->map_.find (&n);
+ if (i != outer_->map_.end ())
+ return &i->second;
+ }
+
+ return nullptr;
+ }
+
+ inline const variable& variable_pool::
+ operator[] (const string& n) const
+ {
+ const variable* r (find (n));
+ assert (r != nullptr);
+ return *r;
}
// variable_map