diff options
Diffstat (limited to 'libbuild2/variable.ixx')
-rw-r--r-- | libbuild2/variable.ixx | 237 |
1 files changed, 219 insertions, 18 deletions
diff --git a/libbuild2/variable.ixx b/libbuild2/variable.ixx index a84c012..ca84a33 100644 --- a/libbuild2/variable.ixx +++ b/libbuild2/variable.ixx @@ -224,7 +224,7 @@ namespace build2 template <typename T> inline const T& - cast (const lookup& l) + cast (lookup l) { return cast<T> (*l); } @@ -245,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; } @@ -259,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; } @@ -273,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; } @@ -287,7 +287,7 @@ namespace build2 template <typename T> inline T - cast_false (const lookup& l) + cast_false (lookup l) { return l && cast<T> (l); } @@ -301,7 +301,7 @@ namespace build2 template <typename T> inline T - cast_true (const lookup& l) + cast_true (lookup l) { return !l || cast<T> (l); } @@ -326,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 ()); } @@ -359,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>:: @@ -850,6 +893,44 @@ 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> @@ -903,21 +984,141 @@ namespace build2 new (&v.data_) map<K, V> (move (x)); } - // variable_pool + // 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 |