aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2021-11-02 15:18:05 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2021-11-02 15:24:35 +0200
commitf500b3274b4c937d315a652aad3bfcdd808b49ec (patch)
tree551ced41e7912f7a4b71e77c6dc0bdef23f90b76
parentc56aa2d2e407bfffc2b62d4bad3a65051f31b80b (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.cxx70
-rw-r--r--libbuild2/functions-name.cxx2
-rw-r--r--libbuild2/functions-path.cxx33
-rw-r--r--libbuild2/functions-string.cxx46
-rw-r--r--tests/function/builtin/testscript10
-rw-r--r--tests/function/path/testscript17
-rw-r--r--tests/function/string/testscript8
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
+}