aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2024-02-20 08:57:32 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2024-02-20 16:01:40 +0200
commitc2d2a1ac0ac41a068c4bf09f8236a61d576e74f5 (patch)
tree32fe50dc4f95772493f4242ce40fb0afd01c0bb6
parent88640e677fa0695783eac68014d7d8d5bc42d117 (diff)
Add custom subscript, iterate functions for vector and set value types
-rw-r--r--libbuild2/variable.cxx5
-rw-r--r--libbuild2/variable.txx83
-rw-r--r--tests/type/map/testscript5
-rw-r--r--tests/type/set/testscript11
-rw-r--r--tests/type/vector/buildfile4
-rw-r--r--tests/type/vector/testscript57
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