diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2024-02-20 08:57:32 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2024-02-20 16:01:40 +0200 |
commit | c2d2a1ac0ac41a068c4bf09f8236a61d576e74f5 (patch) | |
tree | 32fe50dc4f95772493f4242ce40fb0afd01c0bb6 | |
parent | 88640e677fa0695783eac68014d7d8d5bc42d117 (diff) |
Add custom subscript, iterate functions for vector and set value types
-rw-r--r-- | libbuild2/variable.cxx | 5 | ||||
-rw-r--r-- | libbuild2/variable.txx | 83 | ||||
-rw-r--r-- | tests/type/map/testscript | 5 | ||||
-rw-r--r-- | tests/type/set/testscript | 11 | ||||
-rw-r--r-- | tests/type/vector/buildfile | 4 | ||||
-rw-r--r-- | tests/type/vector/testscript | 57 |
6 files changed, 156 insertions, 9 deletions
diff --git a/libbuild2/variable.cxx b/libbuild2/variable.cxx index 6f9f0fb..4a08b4d 100644 --- a/libbuild2/variable.cxx +++ b/libbuild2/variable.cxx @@ -2093,8 +2093,9 @@ namespace build2 return r; } - void json_iterate (const value& val, - const function<void (value&&, bool first)>& f) + static void + json_iterate (const value& val, + const function<void (value&&, bool first)>& f) { // Implement in terms of subscript for consistency (in particular, // iterating over simple values like number, string). diff --git a/libbuild2/variable.txx b/libbuild2/variable.txx index 501e103..9d39ed7 100644 --- a/libbuild2/variable.txx +++ b/libbuild2/variable.txx @@ -629,6 +629,68 @@ namespace build2 return 0; } + // Provide subscript for vector<T> for efficiency. + // + template <typename T> + value + vector_subscript (const value& val, value* val_data, + value&& sub, + const location& sloc, + const location& bloc) + { + // Process subscript even if the value is null to make sure it is valid. + // + size_t i; + try + { + i = static_cast<size_t> (convert<uint64_t> (move (sub))); + } + catch (const invalid_argument& e) + { + fail (sloc) << "invalid " << value_traits<vector<T>>::value_type.name + << " value subscript: " << e << + info (bloc) << "use the '\\[' escape sequence if this is a " + << "wildcard pattern"; + } + + value r; + if (!val.null) + { + const auto& v (val.as<vector<T>> ()); + if (i < v.size ()) + { + const T& e (v[i]); + + // Steal the value if possible. + // + r = &val == val_data ? T (move (const_cast<T&> (e))) : T (e); + } + } + + // Typify null values so that type-specific subscript (e.g., for + // json_value) gets called for chained subscripts. + // + if (r.null) + r.type = &value_traits<T>::value_type; + + return r; + } + + // Provide iterate for vector<T> for efficiency. + // + template <typename T> + void + vector_iterate (const value& val, + const function<void (value&&, bool first)>& f) + { + const auto& v (val.as<vector<T>> ()); // Never NULL. + + for (auto b (v.begin ()), i (b), e (v.end ()); i != e; ++i) + { + f (value (*i), i == b); + } + } + // Make sure these are static-initialized together. Failed that VC will make // sure it's done in the wrong order. // @@ -670,8 +732,8 @@ namespace build2 nullptr, // No cast (cast data_ directly). &vector_compare<T>, &default_empty<vector<T>>, - nullptr, // Subscript. - nullptr // Iterate. + &vector_subscript<T>, + &vector_iterate<T> }; // vector<pair<K, V>> value @@ -999,6 +1061,21 @@ namespace build2 return value (r); } + // Provide iterate for set<T> for efficiency. + // + template <typename T> + void + set_iterate (const value& val, + const function<void (value&&, bool first)>& f) + { + const auto& v (val.as<set<T>> ()); // Never NULL. + + for (auto b (v.begin ()), i (b), e (v.end ()); i != e; ++i) + { + f (value (*i), i == b); + } + } + // Make sure these are static-initialized together. Failed that VC will make // sure it's done in the wrong order. // @@ -1054,7 +1131,7 @@ namespace build2 &set_compare<T>, &default_empty<set<T>>, &set_subscript<T>, - nullptr // Iterate. + &set_iterate<T> }; // map<K, V> value diff --git a/tests/type/map/testscript b/tests/type/map/testscript index 7b90ddd..1c6224a 100644 --- a/tests/type/map/testscript +++ b/tests/type/map/testscript @@ -34,9 +34,11 @@ EOO $* <<EOI >>EOO m = [string_map] a@1 b@2 c@3 print ($m[b]) +print $type($m[b]) print ($m[z]) EOI 2 +string [null] EOO @@ -45,6 +47,9 @@ EOO $* <<EOI >>EOO for p: [string_map] a@1 b@2 c@3 print $first($p) $second($p) + +for p: [string_map, null] + fail bad EOI a 1 b 2 diff --git a/tests/type/set/testscript b/tests/type/set/testscript index 3897220..da5e181 100644 --- a/tests/type/set/testscript +++ b/tests/type/set/testscript @@ -44,9 +44,12 @@ EOO : $* <<EOI >>EOO for s: [string_set] a b c - print $s + print $type($s) $s + +for s: [string_set, null] + fail bad EOI -a -b -c +string a +string b +string c EOO diff --git a/tests/type/vector/buildfile b/tests/type/vector/buildfile new file mode 100644 index 0000000..5b2aa0e --- /dev/null +++ b/tests/type/vector/buildfile @@ -0,0 +1,4 @@ +# file : tests/type/vector/buildfile +# license : MIT; see accompanying LICENSE file + +./: testscript $b diff --git a/tests/type/vector/testscript b/tests/type/vector/testscript new file mode 100644 index 0000000..9b3aaba --- /dev/null +++ b/tests/type/vector/testscript @@ -0,0 +1,57 @@ +# file : tests/type/vector/testscript +# license : MIT; see accompanying LICENSE file + +# See also tests in function/*/ (size(), find(), etc). + +.include ../../common.testscript + +: basics +: +$* <<EOI >>EOO +v = [strings] b c +print $v +v += d +print $v +v =+ a +print $v +EOI +b c +b c d +a b c d +EOO + +: type +: +$* <<EOI >>EOO +v = [strings] +print $type($v) +EOI +strings +EOO + +: subscript +: +$* <<EOI >>EOO +v = [strings] a b c +print ($v[1]) +print $type($v[1]) +print ($v[3]) +EOI +b +string +[null] +EOO + +: iteration +: +$* <<EOI >>EOO +for s: [strings] a b c + print $type($s) $s + +for s: [strings, null] + fail bad +EOI +string a +string b +string c +EOO |