diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2021-11-02 15:18:05 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2021-11-02 15:24:35 +0200 |
commit | f500b3274b4c937d315a652aad3bfcdd808b49ec (patch) | |
tree | 551ced41e7912f7a4b71e77c6dc0bdef23f90b76 | |
parent | c56aa2d2e407bfffc2b62d4bad3a65051f31b80b (diff) |
Add $sort() function
Available overloads:
$sort(<names> [, <flags>])
$sort(<ints> [, <flags>])
$sort(<strings> [, <flags>])
$sort(<paths> [, <flags>])
$sort(<dir_paths> [, <flags>])
The following flag is supported by the all overloads:
dedup - in addition to sorting also remove duplicates
Additionally, the strings overload also support the following flag:
icase - sort ignoring case
Note that on case-insensitive filesystem the paths and dir_paths overload's
order is case-insensitive.
-rw-r--r-- | libbuild2/functions-builtin.cxx | 70 | ||||
-rw-r--r-- | libbuild2/functions-name.cxx | 2 | ||||
-rw-r--r-- | libbuild2/functions-path.cxx | 33 | ||||
-rw-r--r-- | libbuild2/functions-string.cxx | 46 | ||||
-rw-r--r-- | tests/function/builtin/testscript | 10 | ||||
-rw-r--r-- | tests/function/path/testscript | 17 | ||||
-rw-r--r-- | tests/function/string/testscript | 8 |
7 files changed, 184 insertions, 2 deletions
diff --git a/libbuild2/functions-builtin.cxx b/libbuild2/functions-builtin.cxx index 2adff38..d040ba8 100644 --- a/libbuild2/functions-builtin.cxx +++ b/libbuild2/functions-builtin.cxx @@ -11,6 +11,27 @@ using namespace std; namespace build2 { + // Note: not static since used by type-specific sort() implementations. + // + bool + functions_sort_flags (optional<names> fs) + { + bool r (false); + if (fs) + { + for (name& f: *fs) + { + string s (convert<string> (move (f))); + + if (s == "dedup") + r = true; + else + throw invalid_argument ("invalid flag '" + s + "'"); + } + } + return r; + }; + void builtin_functions (function_map& m) { @@ -57,7 +78,6 @@ namespace build2 f["string"] += [](bool b) {return b ? "true" : "false";}; f["string"] += [](int64_t i) {return to_string (i);}; f["string"] += [](uint64_t i) {return to_string (i);}; - f["string"] += [](name n) {return to_string (n);}; // Quote a value returning its string representation. If escape is true, // then also escape (with a backslash) the quote characters being added @@ -80,6 +100,54 @@ namespace build2 return os.str (); }; + // $sort(<names> [, <flags>]) + // + // Sort names in ascending order. + // + // See also type-specific overloads. + // + // The following flags are supported: + // + // dedup - in addition to sorting also remove duplicates + // + f["sort"] += [] (names v, optional<names> fs) + { + sort (v.begin (), v.end ()); + + if (functions_sort_flags (move (fs))) + v.erase (unique (v.begin(), v.end()), v.end ()); + + return v; + }; + + // $sort(<ints> [, <flags>]) + // + // Sort integers in ascending order. + // + // The following flags are supported: + // + // dedup - in addition to sorting also remove duplicates + // + f["sort"] += [](int64s v, optional<names> fs) + { + sort (v.begin (), v.end ()); + + if (functions_sort_flags (move (fs))) + v.erase (unique (v.begin(), v.end()), v.end ()); + + return v; + }; + + f["sort"] += [](uint64s v, optional<names> fs) + { + sort (v.begin (), v.end ()); + + if (functions_sort_flags (move (fs))) + v.erase (unique (v.begin(), v.end()), v.end ()); + + return v; + }; + // 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 43bd8cb..9ba20a8 100644 --- a/libbuild2/functions-name.cxx +++ b/libbuild2/functions-name.cxx @@ -63,6 +63,8 @@ namespace build2 // function_family fn (m, "name"); + fn["string"] += [](name n) {return to_string (n);}; + fn["name"] += [](const scope* s, name n) { return to_target_name (s, move (n)).first.value; diff --git a/libbuild2/functions-path.cxx b/libbuild2/functions-path.cxx index b7c9a8d..d6ff83f 100644 --- a/libbuild2/functions-path.cxx +++ b/libbuild2/functions-path.cxx @@ -10,6 +10,9 @@ using namespace std; namespace build2 { + extern bool + functions_sort_flags (optional<names>); // functions-builtin.cxx + static value path_thunk (const scope* base, vector_view<value> args, @@ -411,6 +414,36 @@ namespace build2 return extension (convert<path> (move (ns))); }; + // $sort(<paths> [, <flags>]) + // $sort(<dir_paths> [, <flags>]) + // + // Sort paths in ascending order. Note that on case-insensitive filesystem + // the order is case-insensitive. + // + // The following flags are supported: + // + // dedup - in addition to sorting also remove duplicates + // + f["sort"] += [](paths v, optional<names> fs) + { + sort (v.begin (), v.end ()); + + if (functions_sort_flags (move (fs))) + v.erase (unique (v.begin(), v.end()), v.end ()); + + return v; + }; + + f["sort"] += [](dir_paths v, optional<names> fs) + { + sort (v.begin (), v.end ()); + + if (functions_sort_flags (move (fs))) + v.erase (unique (v.begin(), v.end()), v.end ()); + + return v; + }; + // $path.match(<val>, <pat> [, <start>]) // // 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 b430ebf..6e39c44 100644 --- a/libbuild2/functions-string.cxx +++ b/libbuild2/functions-string.cxx @@ -77,6 +77,52 @@ namespace build2 return names {name (ucase (convert<string> (move (s))))}; }; + // $sort(<strings> [, <flags>]) + // + // Sort strings in ascending order. + // + // The following flags are supported: + // + // icase - sort ignoring case + // + // dedup - in addition to sorting also remove duplicates + // + f["sort"] += [](strings v, optional<names> fs) + { + bool ic (false); + bool dd (false); + if (fs) + { + for (name& f: *fs) + { + string s (convert<string> (move (f))); + + if (s == "icase") + ic = true; + else if (s == "dedup") + dd = true; + else + throw invalid_argument ("invalid flag '" + s + "'"); + } + } + + sort (v.begin (), v.end (), + [ic] (const string& x, const string& y) + { + return (ic ? icasecmp (x, y) : x.compare (y)) < 0; + }); + + if (dd) + v.erase (unique (v.begin(), v.end(), + [ic] (const string& x, const string& y) + { + return (ic ? icasecmp (x, y) : x.compare (y)) == 0; + }), + v.end ()); + + return v; + }; + // String-specific overloads from builtins. // function_family b (m, "builtin"); diff --git a/tests/function/builtin/testscript b/tests/function/builtin/testscript index 3d31ca2..3853ec2 100644 --- a/tests/function/builtin/testscript +++ b/tests/function/builtin/testscript @@ -77,6 +77,16 @@ $* <'print $type($identity(abc))' >'' : untyped } +: sort +: +{ + $* <'print $sort( d/t{a} t{c b} d/t{a})' >'t{b} t{c} d/t{a} d/t{a}' : name-basics + $* <'print $sort( d/t{a} t{c b} d/t{a}, dedup)' >'t{b} t{c} d/t{a}' : name-dedup + + $* <'print $sort([uint64s] 0 2 1 000)' >'0 0 1 2' : int-basics + $* <'print $sort([uint64s] 0 2 1 000, dedup)' >'0 1 2' : int-dedup +} + : getenv : { diff --git a/tests/function/path/testscript b/tests/function/path/testscript index ad76513..a408ba4 100644 --- a/tests/function/path/testscript +++ b/tests/function/path/testscript @@ -3,7 +3,8 @@ .include ../../common.testscript -posix = ($cxx.target.class != 'windows') +windows = ($cxx.target.class == 'windows') +posix = (!$windows) s = ($posix ? '/' : '\') @@ -104,6 +105,20 @@ if! $posix EOO } +: sort +: +{ + $* <'print $sort([paths] a c b a)' >'a a b c' : basics + $* <'print $sort([paths] a c b a, dedup)' >'a b c' : dedup + + : icase + : + if $windows + { + $* <'print $sort([paths] a C B a)' >'a a B c' + } +} + : invalid-path : p = ($posix ? /../foo : 'c:/../foo'); diff --git a/tests/function/string/testscript b/tests/function/string/testscript index 9275fe5..5f80bfe 100644 --- a/tests/function/string/testscript +++ b/tests/function/string/testscript @@ -31,3 +31,11 @@ $* <'print $trim([string] " a ")' >'a' : string $* <'print $string.trim( " a ")' >'a' : untyped } + +: sort +: +{ + $* <'print $sort([strings] a c b a)' >'a a b c' : basics + $* <'print $sort([strings] a c b a, dedup)' >'a b c' : dedup + $* <'print $sort([strings] a C B a, icase)' >'a a B C' : icase +} |