From 785087aa43cf962855724b8fa5da393022204a14 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Thu, 29 Sep 2022 13:12:19 +0200 Subject: Add $find(, ), $find_index(, ) functions The $find() function returns true if the sequence contains the specified value. The $find_index() function returns the index of the first element in the sequence that is equal to the specified value or $size() if none is found. For string sequences, it's possible to request case- insensitive comparison with a flag. --- libbuild2/functions-builtin.cxx | 33 +++++++++++++++++++++++ libbuild2/functions-name.cxx | 25 +++++++++++++++++ libbuild2/functions-path.cxx | 43 ++++++++++++++++++++++++++++-- libbuild2/functions-string.cxx | 56 +++++++++++++++++++++++++++++++++++++++ tests/function/builtin/testscript | 14 ++++++++++ tests/function/name/testscript | 18 +++++++++++-- tests/function/path/testscript | 14 ++++++++++ tests/function/string/testscript | 16 +++++++++++ 8 files changed, 215 insertions(+), 4 deletions(-) diff --git a/libbuild2/functions-builtin.cxx b/libbuild2/functions-builtin.cxx index 7000f16..de79538 100644 --- a/libbuild2/functions-builtin.cxx +++ b/libbuild2/functions-builtin.cxx @@ -219,6 +219,39 @@ namespace build2 return v; }; + // $find(, ) + // + // Return true if the integer sequence contains the specified integer. + // + f["find"] += [](int64s vs, value v) + { + return find (vs.begin (), vs.end (), + convert (move (v))) != vs.end (); + }; + + f["find"] += [](uint64s vs, value v) + { + return find (vs.begin (), vs.end (), + convert (move (v))) != vs.end (); + }; + + // $find_index(, ) + // + // Return the index of the first element in the integer sequence that is + // equal to the specified integer or $size() if none is found. + // + f["find_index"] += [](int64s vs, value v) + { + auto i (find (vs.begin (), vs.end (), convert (move (v)))); + return i != vs.end () ? i - vs.begin () : vs.size (); + }; + + f["find_index"] += [](uint64s vs, value v) + { + auto i (find (vs.begin (), vs.end (), convert (move (v)))); + return i != vs.end () ? i - vs.begin () : vs.size (); + }; + // getenv // // Return NULL if the environment variable is not set, untyped value diff --git a/libbuild2/functions-name.cxx b/libbuild2/functions-name.cxx index 43de039..9011cc0 100644 --- a/libbuild2/functions-name.cxx +++ b/libbuild2/functions-name.cxx @@ -330,6 +330,31 @@ namespace build2 return ns; }; + // $find(, ) + // + // Return true if the name sequence contains the specified name. + // + fn["find"] += [](names vs, names v) + { + //@@ TODO: shouldn't we do this in a pair-aware manner? + + return find (vs.begin (), vs.end (), + convert (move (v))) != vs.end (); + }; + + // $find_index(, ) + // + // Return the index of the first element in the name sequence that is + // equal to the specified name or $size() if none is found. + // + fn["find_index"] += [](names vs, names v) + { + //@@ TODO: shouldn't we do this in a pair-aware manner? + + auto i (find (vs.begin (), vs.end (), convert (move (v)))); + return i != vs.end () ? i - vs.begin () : vs.size (); + }; + // Functions that can be called only on real targets. // function_family ft (m, "target"); diff --git a/libbuild2/functions-path.cxx b/libbuild2/functions-path.cxx index b79585d..0c9b57f 100644 --- a/libbuild2/functions-path.cxx +++ b/libbuild2/functions-path.cxx @@ -541,8 +541,8 @@ namespace build2 // $sort( [, ]) // $sort( [, ]) // - // Sort paths in ascending order. Note that on case-insensitive filesystem - // the order is case-insensitive. + // Sort paths in ascending order. Note that on hosts with a case- + // insensitive filesystem the order is case-insensitive. // // The following flags are supported: // @@ -568,6 +568,45 @@ namespace build2 return v; }; + // $find(, ) + // $find(, ) + // + // Return true if the path sequence contains the specified path. Note that + // on hosts with a case-insensitive filesystem the comparison is + // case-insensitive. + // + f["find"] += [](paths vs, value v) + { + return find (vs.begin (), vs.end (), + convert (move (v))) != vs.end (); + }; + + f["find"] += [](dir_paths vs, value v) + { + return find (vs.begin (), vs.end (), + convert (move (v))) != vs.end (); + }; + + // $find_index(, ) + // $find_index(, ) + // + // Return the index of the first element in the path sequence that is + // equal to the specified path or $size() if none is found. Note + // that on hosts with a case-insensitive filesystem the comparison is + // case-insensitive. + // + f["find_index"] += [](paths vs, value v) + { + auto i (find (vs.begin (), vs.end (), convert (move (v)))); + return i != vs.end () ? i - vs.begin () : vs.size (); + }; + + f["find_index"] += [](dir_paths vs, value v) + { + auto i (find (vs.begin (), vs.end (), convert (move (v)))); + return i != vs.end () ? i - vs.begin () : vs.size (); + }; + // $path.match(, [, ]) // // Match a filesystem entry name against a name pattern (both are strings), diff --git a/libbuild2/functions-string.cxx b/libbuild2/functions-string.cxx index 4a03a5e..a41449a 100644 --- a/libbuild2/functions-string.cxx +++ b/libbuild2/functions-string.cxx @@ -8,6 +8,32 @@ using namespace std; namespace build2 { + static size_t + find_index (const strings& vs, value&& v, optional&& fs) + { + bool ic (false); + if (fs) + { + for (name& f: *fs) + { + string s (convert (move (f))); + + if (s == "icase") + ic = true; + else + throw invalid_argument ("invalid flag '" + s + "'"); + } + } + + auto i (find_if (vs.begin (), vs.end (), + [ic, y = convert (move (v))] (const string& x) + { + return (ic ? icasecmp (x, y) : x.compare (y)) == 0; + })); + + return i != vs.end () ? i - vs.begin () : vs.size (); + }; + void string_functions (function_map& m) { @@ -135,6 +161,36 @@ namespace build2 return v; }; + // $find(, [, ]) + // + // Return true if the string sequence contains the specified string. + // + // The following flags are supported: + // + // icase - compare ignoring case + // + // See also $regex.find_{match,search}(). + // + f["find"] += [](strings vs, value v, optional fs) + { + return find_index (vs, move (v), move (fs)) != vs.size (); + }; + + // $find_index(, [, ]) + // + // Return the index of the first element in the string sequence that + // is equal to the specified string or $size() if none is + // found. + // + // The following flags are supported: + // + // icase - compare ignoring case + // + f["find_index"] += [](strings vs, value v, optional fs) + { + return find_index (vs, move (v), move (fs)); + }; + // String-specific overloads from builtins. // function_family b (m, "builtin"); diff --git a/tests/function/builtin/testscript b/tests/function/builtin/testscript index bbfd4e5..3c430d7 100644 --- a/tests/function/builtin/testscript +++ b/tests/function/builtin/testscript @@ -100,6 +100,20 @@ $* <'print $sort([uint64s] 0 2 1 000, dedup)' >'0 1 2' : dedup } +: find +: +{ + $* <'print $find([uint64s] 1 2 3, 2)' >'true' : basics-true + $* <'print $find([uint64s] 1 2 3, 0)' >'false' : basics-false +} + +: find_index +: +{ + $* <'print $find_index([int64s] -1 -2 -3, -2)' >'1' : basics-true + $* <'print $find_index([int64s] -1 -2 -3, 0)' >'3' : basics-false +} + : getenv : { diff --git a/tests/function/name/testscript b/tests/function/name/testscript index 6222167..4588e1d 100644 --- a/tests/function/name/testscript +++ b/tests/function/name/testscript @@ -49,6 +49,20 @@ : sort : { - $* <'print $sort( d/t{a} t{c b} d/t{a})' >'t{b} t{c} d/t{a} d/t{a}' : basics - $* <'print $sort( d/t{a} t{c b} d/t{a}, dedup)' >'t{b} t{c} d/t{a}' : dedup + $* <'print $sort(d/t{a} t{c b} d/t{a})' >'t{b} t{c} d/t{a} d/t{a}' : basics + $* <'print $sort(d/t{a} t{c b} d/t{a}, dedup)' >'t{b} t{c} d/t{a}' : dedup +} + +: find +: +{ + $* <'print $find([names] d/t{a} t{a b}, t{a})' >'true' : basics-true + $* <'print $find([names] d/t{a} t{a b}, d/t{b})' >'false' : basics-false +} + +: find_index +: +{ + $* <'print $find_index([names] d/t{a} t{a b}, t{a})' >'1' : basics-true + $* <'print $find_index([names] d/t{a} t{a b}, d/t{b})' >'3' : basics-false } diff --git a/tests/function/path/testscript b/tests/function/path/testscript index 6219f3c..c58bbf8 100644 --- a/tests/function/path/testscript +++ b/tests/function/path/testscript @@ -158,6 +158,20 @@ if! $posix $* <'print $size([dir_path] )' >'0' : dir-zero } +: find +: +{ + $* <'print $find([paths] x y z, y)' >'true' : basics-true + $* <'print $find([paths] x y z, a)' >'false' : basics-false +} + +: find_index +: +{ + $* <'print $find_index([dir_paths] x y z, y)' >'1' : basics-true + $* <'print $find_index([dir_paths] x y z, a)' >'3' : basics-false +} + : invalid-path : p = ($posix ? /../foo : 'c:/../foo'); diff --git a/tests/function/string/testscript b/tests/function/string/testscript index 00835ce..364ce42 100644 --- a/tests/function/string/testscript +++ b/tests/function/string/testscript @@ -46,3 +46,19 @@ $* <'print $size([string] abc)' >'3' : basics $* <'print $size([string] )' >'0' : zero } + +: find +: +{ + $* <'print $find([strings] x y z, y)' >'true' : basics-true + $* <'print $find([strings] x y z, Y)' >'false' : basics-false + $* <'print $find([strings] x y z, Y, icase)' >'true' : icase +} + +: find_index +: +{ + $* <'print $find_index([strings] x y z, y)' >'1' : basics-true + $* <'print $find_index([strings] x y z, Y)' >'3' : basics-false + $* <'print $find_index([strings] x y z, Y, icase)' >'1' : icase +} -- cgit v1.1