libcubescript/src/lib_list.cc

639 lines
19 KiB
C++
Raw Normal View History

2017-02-08 01:07:35 +01:00
#include <functional>
2017-06-20 21:21:39 +02:00
#include <cubescript/cubescript.hh>
#include "cs_util.hh"
namespace cscript {
2016-08-17 20:51:21 +02:00
template<typename T>
2018-04-27 23:53:55 +02:00
struct cs_arg_val;
2016-08-17 20:51:21 +02:00
template<>
2018-04-27 23:53:55 +02:00
struct cs_arg_val<cs_int> {
2017-02-13 18:10:40 +01:00
static cs_int get(cs_value &tv) {
2016-08-17 20:51:21 +02:00
return tv.get_int();
}
};
template<>
2018-04-27 23:53:55 +02:00
struct cs_arg_val<cs_float> {
2017-02-13 18:10:40 +01:00
static cs_float get(cs_value &tv) {
2016-08-17 20:51:21 +02:00
return tv.get_float();
}
};
template<>
struct cs_arg_val<std::string_view> {
static std::string_view get(cs_value &tv) {
2021-03-17 21:57:47 +01:00
return tv.get_str();
2016-08-17 20:51:21 +02:00
}
};
template<typename T, typename F>
static inline void cs_list_find(
2021-03-20 05:41:25 +01:00
cs_state &cs, std::span<cs_value> args, cs_value &res, F cmp
) {
2017-02-13 18:10:40 +01:00
cs_int n = 0, skip = args[2].get_int();
2018-04-27 23:53:55 +02:00
T val = cs_arg_val<T>::get(args[1]);
2021-03-18 23:53:16 +01:00
for (cs_list_parse_state p{args[0].get_str()}; list_parse(p, cs); ++n) {
2016-08-17 20:51:21 +02:00
if (cmp(p, val)) {
res.set_int(n);
return;
}
for (int i = 0; i < skip; ++i) {
2021-03-18 23:53:16 +01:00
if (!list_parse(p, cs)) {
2016-08-17 20:51:21 +02:00
goto notfound;
}
++n;
}
}
notfound:
res.set_int(-1);
}
template<typename T, typename F>
static inline void cs_list_assoc(
2021-03-20 05:41:25 +01:00
cs_state &cs, std::span<cs_value> args, cs_value &res, F cmp
) {
2018-04-27 23:53:55 +02:00
T val = cs_arg_val<T>::get(args[1]);
2021-03-18 23:53:16 +01:00
for (cs_list_parse_state p{args[0].get_str()}; list_parse(p, cs);) {
2016-08-17 20:51:21 +02:00
if (cmp(p, val)) {
2021-03-18 23:53:16 +01:00
if (list_parse(p, cs)) {
res.set_str(list_get_item(p, cs));
2016-08-17 20:51:21 +02:00
}
return;
}
2021-03-18 23:53:16 +01:00
if (!list_parse(p, cs)) {
2016-08-17 20:51:21 +02:00
break;
}
}
}
static void cs_loop_list_conc(
cs_state &cs, cs_value &res, cs_ident *id, std::string_view list,
2017-02-13 18:10:40 +01:00
cs_bcode *body, bool space
) {
cs_stacked_value idv{cs, id};
2016-08-31 19:49:24 +02:00
if (!idv.has_alias()) {
return;
2016-08-17 20:51:21 +02:00
}
2021-03-19 02:55:59 +01:00
cs_charbuf r{cs};
int n = 0;
2021-03-18 23:53:16 +01:00
for (cs_list_parse_state p{list}; list_parse(p, cs); ++n) {
idv.set_str(list_get_item(p, cs));
2016-08-31 19:49:24 +02:00
idv.push();
2016-08-17 20:51:21 +02:00
if (n && space) {
2021-03-19 02:55:59 +01:00
r.push_back(' ');
2016-08-17 20:51:21 +02:00
}
cs_value v{cs};
2016-09-14 23:24:13 +02:00
switch (cs.run_loop(body, v)) {
2021-03-18 20:55:14 +01:00
case cs_loop_state::BREAK:
2016-09-14 23:24:13 +02:00
goto end;
2021-03-18 20:55:14 +01:00
case cs_loop_state::CONTINUE:
2016-09-14 23:24:13 +02:00
continue;
default:
break;
}
2021-03-19 02:55:59 +01:00
r.append(v.get_str());
}
2016-09-14 23:24:13 +02:00
end:
2021-03-19 02:55:59 +01:00
res.set_str(r.str());
}
int cs_list_includes(
cs_state &cs, std::string_view list, std::string_view needle
) {
int offset = 0;
2021-03-18 23:53:16 +01:00
for (cs_list_parse_state p{list}; list_parse(p, cs);) {
if (p.item == needle) {
return offset;
2016-08-17 20:51:21 +02:00
}
++offset;
}
return -1;
}
2016-08-17 20:51:21 +02:00
template<bool PushList, bool Swap, typename F>
static inline void cs_list_merge(
2021-03-20 05:41:25 +01:00
cs_state &cs, std::span<cs_value> args, cs_value &res, F cmp
) {
std::string_view list = args[0].get_str();
std::string_view elems = args[1].get_str();
2021-03-19 02:55:59 +01:00
cs_charbuf buf{cs};
2016-08-17 20:51:21 +02:00
if (PushList) {
2021-03-19 02:55:59 +01:00
buf.append(list);
2016-08-17 20:51:21 +02:00
}
if (Swap) {
2017-01-29 15:56:38 +01:00
std::swap(list, elems);
2016-08-17 20:51:21 +02:00
}
2021-03-18 23:53:16 +01:00
for (cs_list_parse_state p{list}; list_parse(p, cs);) {
if (cmp(cs_list_includes(cs, elems, p.item), 0)) {
2016-08-17 20:52:18 +02:00
if (!buf.empty()) {
2021-03-19 02:55:59 +01:00
buf.push_back(' ');
2016-08-17 20:52:18 +02:00
}
2021-03-19 02:55:59 +01:00
buf.append(p.quoted_item);
2016-08-17 20:51:21 +02:00
}
}
2021-03-19 02:55:59 +01:00
res.set_str(buf.str());
2016-08-17 20:51:21 +02:00
}
2017-02-13 18:10:40 +01:00
static void cs_init_lib_list_sort(cs_state &cs);
2017-02-13 18:10:40 +01:00
void cs_init_lib_list(cs_state &gcs) {
gcs.new_command("listlen", "s", [](auto &cs, auto args, auto &res) {
2021-03-18 23:53:16 +01:00
cs_list_parse_state p{args[0].get_str()};
res.set_int(cs_int(list_count(p, cs)));
});
gcs.new_command("at", "si1V", [](auto &cs, auto args, auto &res) {
2016-08-17 20:51:21 +02:00
if (args.empty()) {
return;
2016-08-17 20:51:21 +02:00
}
cs_strref str = args[0].get_str();
2021-03-18 23:53:16 +01:00
cs_list_parse_state p{str};
p.item = str;
2017-01-25 02:09:50 +01:00
for (size_t i = 1; i < args.size(); ++i) {
p.set_input(str);
2017-02-13 18:10:40 +01:00
cs_int pos = args[i].get_int();
2016-08-17 20:51:21 +02:00
for (; pos > 0; --pos) {
2021-03-18 23:53:16 +01:00
if (!list_parse(p, cs)) {
2016-08-17 20:51:21 +02:00
break;
}
}
2021-03-18 23:53:16 +01:00
if (pos > 0 || !list_parse(p, cs)) {
p.item = p.quoted_item = std::string_view{};
2016-08-17 20:51:21 +02:00
}
}
2021-03-18 23:53:16 +01:00
res.set_str(list_get_item(p, cs));
});
gcs.new_command("sublist", "siiN", [](auto &cs, auto args, auto &res) {
2021-03-18 23:53:16 +01:00
cs_int skip = args[1].get_int(),
2016-08-14 18:35:38 +02:00
count = args[2].get_int(),
2016-10-24 02:38:52 +02:00
numargs = args[3].get_int();
2017-02-18 17:49:01 +01:00
cs_int offset = std::max(skip, cs_int(0)),
len = (numargs >= 3) ? std::max(count, cs_int(0)) : -1;
2021-03-18 23:53:16 +01:00
cs_list_parse_state p{args[0].get_str()};
2017-02-13 18:10:40 +01:00
for (cs_int i = 0; i < offset; ++i) {
2021-03-18 23:53:16 +01:00
if (!list_parse(p, cs)) break;
2016-08-17 20:51:21 +02:00
}
if (len < 0) {
2016-08-17 20:51:21 +02:00
if (offset > 0) {
2021-03-18 23:53:16 +01:00
list_find_item(p);
2016-08-17 20:51:21 +02:00
}
res.set_str(p.get_input());
return;
}
char const *list = p.get_input().data();
p.quoted_item = std::string_view{};
2021-03-18 23:53:16 +01:00
if (len > 0 && list_parse(p, cs)) {
while (--len > 0 && list_parse(p, cs));
2016-08-17 20:51:21 +02:00
}
std::string_view quote = p.quoted_item;
2016-11-07 23:33:53 +01:00
char const *qend = !quote.empty() ? &quote[quote.size()] : list;
res.set_str(std::string_view{list, std::size_t(qend - list)});
});
gcs.new_command("listfind", "rse", [](auto &cs, auto args, auto &res) {
cs_stacked_value idv{cs, args[0].get_ident()};
2016-08-31 19:49:24 +02:00
if (!idv.has_alias()) {
res.set_int(-1);
return;
}
2016-08-31 19:49:24 +02:00
auto body = args[2].get_code();
int n = -1;
2021-03-18 23:53:16 +01:00
for (cs_list_parse_state p{args[1].get_str()}; list_parse(p, cs);) {
++n;
idv.set_str(p.item);
2016-08-31 19:49:24 +02:00
idv.push();
if (cs.run(body).get_bool()) {
2017-02-13 18:10:40 +01:00
res.set_int(cs_int(n));
2016-08-31 19:49:24 +02:00
return;
}
}
res.set_int(-1);
});
gcs.new_command("listassoc", "rse", [](auto &cs, auto args, auto &res) {
cs_stacked_value idv{cs, args[0].get_ident()};
2016-08-31 19:49:24 +02:00
if (!idv.has_alias()) {
return;
2016-08-17 20:51:21 +02:00
}
2016-08-31 19:49:24 +02:00
auto body = args[2].get_code();
int n = -1;
2021-03-18 23:53:16 +01:00
for (cs_list_parse_state p{args[1].get_str()}; list_parse(p, cs);) {
++n;
idv.set_str(p.item);
2016-08-31 19:49:24 +02:00
idv.push();
if (cs.run(body).get_bool()) {
2021-03-18 23:53:16 +01:00
if (list_parse(p, cs)) {
res.set_str(list_get_item(p, cs));
}
break;
}
2021-03-18 23:53:16 +01:00
if (!list_parse(p, cs)) {
break;
2016-08-17 20:51:21 +02:00
}
}
});
gcs.new_command("listfind=", "i", [](auto &cs, auto args, auto &res) {
2017-02-13 18:10:40 +01:00
cs_list_find<cs_int>(
2021-03-18 23:53:16 +01:00
cs, args, res, [](cs_list_parse_state const &p, cs_int val) {
return cs_parse_int(p.item) == val;
2016-08-17 20:51:21 +02:00
}
);
});
gcs.new_command("listfind=f", "f", [](auto &cs, auto args, auto &res) {
2017-02-13 18:10:40 +01:00
cs_list_find<cs_float>(
2021-03-18 23:53:16 +01:00
cs, args, res, [](cs_list_parse_state const &p, cs_float val) {
return cs_parse_float(p.item) == val;
2016-08-17 20:51:21 +02:00
}
);
});
gcs.new_command("listfind=s", "s", [](auto &cs, auto args, auto &res) {
cs_list_find<std::string_view>(
cs, args, res, [](cs_list_parse_state const &p, std::string_view val) {
2021-03-18 23:53:16 +01:00
return p.item == val;
2016-08-17 20:51:21 +02:00
}
);
});
gcs.new_command("listassoc=", "i", [](auto &cs, auto args, auto &res) {
2017-02-13 18:10:40 +01:00
cs_list_assoc<cs_int>(
2021-03-18 23:53:16 +01:00
cs, args, res, [](cs_list_parse_state const &p, cs_int val) {
return cs_parse_int(p.item) == val;
2016-08-17 20:51:21 +02:00
}
);
});
gcs.new_command("listassoc=f", "f", [](auto &cs, auto args, auto &res) {
2017-02-13 18:10:40 +01:00
cs_list_assoc<cs_float>(
2021-03-18 23:53:16 +01:00
cs, args, res, [](cs_list_parse_state const &p, cs_float val) {
return cs_parse_float(p.item) == val;
2016-08-17 20:51:21 +02:00
}
);
});
gcs.new_command("listassoc=s", "s", [](auto &cs, auto args, auto &res) {
cs_list_assoc<std::string_view>(
cs, args, res, [](cs_list_parse_state const &p, std::string_view val) {
2021-03-18 23:53:16 +01:00
return p.item == val;
2016-08-17 20:51:21 +02:00
}
);
});
gcs.new_command("looplist", "rse", [](auto &cs, auto args, auto &) {
cs_stacked_value idv{cs, args[0].get_ident()};
2016-08-31 19:49:24 +02:00
if (!idv.has_alias()) {
return;
2016-08-17 20:51:21 +02:00
}
2016-08-31 19:49:24 +02:00
auto body = args[2].get_code();
int n = 0;
2021-03-18 23:53:16 +01:00
for (cs_list_parse_state p{args[1].get_str()}; list_parse(p, cs); ++n) {
idv.set_str(list_get_item(p, cs));
2016-08-31 19:49:24 +02:00
idv.push();
2016-09-14 23:24:13 +02:00
switch (cs.run_loop(body)) {
2021-03-18 20:55:14 +01:00
case cs_loop_state::BREAK:
2016-09-14 23:24:13 +02:00
goto end;
default: /* continue and normal */
break;
}
}
2016-09-14 23:24:13 +02:00
end:
return;
});
gcs.new_command("looplist2", "rrse", [](auto &cs, auto args, auto &) {
cs_stacked_value idv1{cs, args[0].get_ident()};
cs_stacked_value idv2{cs, args[1].get_ident()};
2016-08-31 19:49:24 +02:00
if (!idv1.has_alias() || !idv2.has_alias()) {
return;
2016-08-17 20:51:21 +02:00
}
2016-08-31 19:49:24 +02:00
auto body = args[3].get_code();
int n = 0;
2021-03-18 23:53:16 +01:00
for (cs_list_parse_state p{args[2].get_str()}; list_parse(p, cs); n += 2) {
idv1.set_str(list_get_item(p, cs));
if (list_parse(p, cs)) {
idv2.set_str(list_get_item(p, cs));
2016-09-15 22:34:52 +02:00
} else {
idv2.set_str("");
}
2016-08-31 19:49:24 +02:00
idv1.push();
idv2.push();
2016-09-14 23:24:13 +02:00
switch (cs.run_loop(body)) {
2021-03-18 20:55:14 +01:00
case cs_loop_state::BREAK:
2016-09-14 23:24:13 +02:00
goto end;
default: /* continue and normal */
break;
}
}
2016-09-14 23:24:13 +02:00
end:
return;
});
gcs.new_command("looplist3", "rrrse", [](auto &cs, auto args, auto &) {
cs_stacked_value idv1{cs, args[0].get_ident()};
cs_stacked_value idv2{cs, args[1].get_ident()};
cs_stacked_value idv3{cs, args[2].get_ident()};
2016-08-31 19:49:24 +02:00
if (!idv1.has_alias() || !idv2.has_alias() || !idv3.has_alias()) {
return;
2016-08-17 20:51:21 +02:00
}
2016-08-31 19:49:24 +02:00
auto body = args[4].get_code();
int n = 0;
2021-03-18 23:53:16 +01:00
for (cs_list_parse_state p{args[3].get_str()}; list_parse(p, cs); n += 3) {
idv1.set_str(list_get_item(p, cs));
if (list_parse(p, cs)) {
idv2.set_str(list_get_item(p, cs));
2016-09-15 22:34:52 +02:00
} else {
idv2.set_str("");
}
2021-03-18 23:53:16 +01:00
if (list_parse(p, cs)) {
idv3.set_str(list_get_item(p, cs));
2016-09-15 22:34:52 +02:00
} else {
idv3.set_str("");
}
2016-08-31 19:49:24 +02:00
idv1.push();
idv2.push();
idv3.push();
2016-09-14 23:24:13 +02:00
switch (cs.run_loop(body)) {
2021-03-18 20:55:14 +01:00
case cs_loop_state::BREAK:
2016-09-14 23:24:13 +02:00
goto end;
default: /* continue and normal */
break;
}
}
2016-09-14 23:24:13 +02:00
end:
return;
});
gcs.new_command("looplistconcat", "rse", [](auto &cs, auto args, auto &res) {
cs_loop_list_conc(
2021-03-17 21:57:47 +01:00
cs, res, args[0].get_ident(), args[1].get_str(),
args[2].get_code(), true
);
});
gcs.new_command("looplistconcatword", "rse", [](
auto &cs, auto args, auto &res
2016-08-17 20:51:21 +02:00
) {
cs_loop_list_conc(
2021-03-17 21:57:47 +01:00
cs, res, args[0].get_ident(), args[1].get_str(),
args[2].get_code(), false
);
});
gcs.new_command("listfilter", "rse", [](auto &cs, auto args, auto &res) {
cs_stacked_value idv{cs, args[0].get_ident()};
2016-08-31 19:49:24 +02:00
if (!idv.has_alias()) {
return;
2016-08-17 20:51:21 +02:00
}
2016-08-31 19:49:24 +02:00
auto body = args[2].get_code();
2021-03-19 02:55:59 +01:00
cs_charbuf r{cs};
int n = 0;
2021-03-18 23:53:16 +01:00
for (cs_list_parse_state p{args[1].get_str()}; list_parse(p, cs); ++n) {
idv.set_str(p.item);
2016-08-31 19:49:24 +02:00
idv.push();
if (cs.run(body).get_bool()) {
2016-08-17 20:51:21 +02:00
if (r.size()) {
2021-03-19 02:55:59 +01:00
r.push_back(' ');
2016-08-17 20:51:21 +02:00
}
2021-03-19 02:55:59 +01:00
r.append(p.quoted_item);
}
}
2021-03-19 02:55:59 +01:00
res.set_str(r.str());
});
gcs.new_command("listcount", "rse", [](auto &cs, auto args, auto &res) {
cs_stacked_value idv{cs, args[0].get_ident()};
2016-08-31 19:49:24 +02:00
if (!idv.has_alias()) {
return;
2016-08-17 20:51:21 +02:00
}
2016-08-31 19:49:24 +02:00
auto body = args[2].get_code();
int n = 0, r = 0;
2021-03-18 23:53:16 +01:00
for (cs_list_parse_state p{args[1].get_str()}; list_parse(p, cs); ++n) {
idv.set_str(p.item);
2016-08-31 19:49:24 +02:00
idv.push();
if (cs.run(body).get_bool()) {
r++;
2016-08-17 20:51:21 +02:00
}
}
res.set_int(r);
});
gcs.new_command("prettylist", "ss", [](auto &cs, auto args, auto &res) {
2021-03-19 02:55:59 +01:00
auto buf = ostd::appender<cs_charbuf>(cs);
std::string_view s = args[0].get_str();
std::string_view conj = args[1].get_str();
2021-03-18 23:53:16 +01:00
cs_list_parse_state p{s};
size_t len = list_count(p, cs);
2017-01-25 02:09:50 +01:00
size_t n = 0;
for (p.set_input(s); list_parse(p, cs); ++n) {
2021-03-18 23:53:16 +01:00
if (!p.quoted_item.empty() && (p.quoted_item.front() == '"')) {
util::unescape_string(buf, p.item);
} else {
buf.get().append(p.item);
}
if ((n + 1) < len) {
2016-08-17 20:51:21 +02:00
if ((len > 2) || conj.empty()) {
2016-09-15 22:34:52 +02:00
buf.put(',');
2016-08-17 20:51:21 +02:00
}
if ((n + 2 == len) && !conj.empty()) {
2016-09-15 22:34:52 +02:00
buf.put(' ');
buf.get().append(conj);
}
2016-09-15 22:34:52 +02:00
buf.put(' ');
}
}
2021-03-19 02:55:59 +01:00
res.set_str(buf.get().str());
});
gcs.new_command("indexof", "ss", [](auto &cs, auto args, auto &res) {
res.set_int(
2021-03-17 21:57:47 +01:00
cs_list_includes(cs, args[0].get_str(), args[1].get_str())
);
});
gcs.new_command("listdel", "ss", [](auto &cs, auto args, auto &res) {
2017-02-08 01:07:35 +01:00
cs_list_merge<false, false>(cs, args, res, std::less<int>());
2016-08-17 20:51:21 +02:00
});
gcs.new_command("listintersect", "ss", [](auto &cs, auto args, auto &res) {
2017-02-08 01:07:35 +01:00
cs_list_merge<false, false>(cs, args, res, std::greater_equal<int>());
2016-08-17 20:51:21 +02:00
});
gcs.new_command("listunion", "ss", [](auto &cs, auto args, auto &res) {
2017-02-08 01:07:35 +01:00
cs_list_merge<true, true>(cs, args, res, std::less<int>());
});
gcs.new_command("listsplice", "ssii", [](auto &cs, auto args, auto &res) {
2017-02-18 17:49:01 +01:00
cs_int offset = std::max(args[2].get_int(), cs_int(0));
cs_int len = std::max(args[3].get_int(), cs_int(0));
std::string_view s = args[0].get_str();
std::string_view vals = args[1].get_str();
char const *list = s.data();
2021-03-18 23:53:16 +01:00
cs_list_parse_state p{s};
2017-02-13 18:10:40 +01:00
for (cs_int i = 0; i < offset; ++i) {
2021-03-18 23:53:16 +01:00
if (!list_parse(p, cs)) {
break;
2016-08-17 20:51:21 +02:00
}
}
std::string_view quote = p.quoted_item;
2016-11-07 23:33:53 +01:00
char const *qend = !quote.empty() ? &quote[quote.size()] : list;
2021-03-19 02:55:59 +01:00
cs_charbuf buf{cs};
2016-08-17 20:51:21 +02:00
if (qend > list) {
2021-03-19 02:55:59 +01:00
buf.append(list, qend);
2016-08-17 20:51:21 +02:00
}
if (!vals.empty()) {
2016-08-17 20:51:21 +02:00
if (!buf.empty()) {
2021-03-19 02:55:59 +01:00
buf.push_back(' ');
2016-08-17 20:51:21 +02:00
}
2021-03-19 02:55:59 +01:00
buf.append(vals);
}
2017-02-13 18:10:40 +01:00
for (cs_int i = 0; i < len; ++i) {
2021-03-18 23:53:16 +01:00
if (!list_parse(p, cs)) {
break;
2016-08-17 20:51:21 +02:00
}
}
2021-03-18 23:53:16 +01:00
list_find_item(p);
if (!p.get_input().empty()) {
switch (p.get_input().front()) {
2016-08-17 20:51:21 +02:00
case ')':
case ']':
break;
default:
if (!buf.empty()) {
2021-03-19 02:55:59 +01:00
buf.push_back(' ');
2016-08-17 20:51:21 +02:00
}
buf.append(p.get_input());
2016-08-17 20:51:21 +02:00
break;
}
}
2021-03-19 02:55:59 +01:00
res.set_str(buf.str());
});
cs_init_lib_list_sort(gcs);
}
struct ListSortItem {
std::string_view str;
std::string_view quote;
};
struct ListSortFun {
2017-02-13 18:10:40 +01:00
cs_state &cs;
cs_stacked_value &xv, &yv;
cs_bcode *body;
bool operator()(ListSortItem const &xval, ListSortItem const &yval) {
xv.set_str(xval.str);
yv.set_str(yval.str);
2016-08-31 19:49:24 +02:00
xv.push();
yv.push();
return cs.run(body).get_bool();
}
};
static void cs_list_sort(
cs_state &cs, cs_value &res, std::string_view list,
2017-02-13 18:10:40 +01:00
cs_ident *x, cs_ident *y, cs_bcode *body, cs_bcode *unique
) {
2016-08-17 20:51:21 +02:00
if (x == y || !x->is_alias() || !y->is_alias()) {
return;
2016-08-17 20:51:21 +02:00
}
2017-02-13 18:10:40 +01:00
cs_alias *xa = static_cast<cs_alias *>(x), *ya = static_cast<cs_alias *>(y);
2016-08-18 00:06:39 +02:00
2021-03-19 22:49:29 +01:00
cs_valbuf<ListSortItem> items{cs};
2017-01-25 02:09:50 +01:00
size_t total = 0;
2021-03-18 23:53:16 +01:00
for (cs_list_parse_state p{list}; list_parse(p, cs);) {
ListSortItem item = { p.item, p.quoted_item };
2017-01-25 01:18:29 +01:00
items.push_back(item);
total += item.quote.size();
}
if (items.empty()) {
2021-03-18 23:53:16 +01:00
res.set_str(list);
return;
}
cs_stacked_value xval{cs, xa}, yval{cs, ya};
2021-03-18 20:55:14 +01:00
xval.set_none();
yval.set_none();
2016-08-31 19:49:24 +02:00
xval.push();
yval.push();
2017-01-25 02:09:50 +01:00
size_t totaluniq = total;
size_t nuniq = items.size();
if (body) {
2016-08-31 19:49:24 +02:00
ListSortFun f = { cs, xval, yval, body };
2021-03-19 22:49:29 +01:00
ostd::sort_cmp(ostd::iter(items.buf), f);
2016-08-29 19:17:11 +02:00
if (!cs_code_is_empty(unique)) {
f.body = unique;
totaluniq = items[0].quote.size();
nuniq = 1;
2017-01-25 02:09:50 +01:00
for (size_t i = 1; i < items.size(); i++) {
ListSortItem &item = items[i];
2016-08-17 20:51:21 +02:00
if (f(items[i - 1], item)) {
item.quote = std::string_view{};
2016-08-17 20:51:21 +02:00
} else {
totaluniq += item.quote.size();
++nuniq;
}
}
}
} else {
2016-08-31 19:49:24 +02:00
ListSortFun f = { cs, xval, yval, unique };
totaluniq = items[0].quote.size();
nuniq = 1;
2017-01-25 02:09:50 +01:00
for (size_t i = 1; i < items.size(); i++) {
ListSortItem &item = items[i];
2017-01-25 02:09:50 +01:00
for (size_t j = 0; j < i; ++j) {
ListSortItem &prev = items[j];
if (!prev.quote.empty() && f(item, prev)) {
item.quote = std::string_view{};
break;
}
}
if (!item.quote.empty()) {
totaluniq += item.quote.size();
++nuniq;
}
}
}
2016-08-31 19:49:24 +02:00
xval.pop();
yval.pop();
2021-03-19 02:55:59 +01:00
cs_charbuf sorted{cs};
2017-02-18 17:49:01 +01:00
sorted.reserve(totaluniq + std::max(nuniq - 1, size_t(0)));
2017-01-25 02:09:50 +01:00
for (size_t i = 0; i < items.size(); ++i) {
ListSortItem &item = items[i];
2016-08-17 20:51:21 +02:00
if (item.quote.empty()) {
continue;
2016-08-17 20:51:21 +02:00
}
if (i) {
2021-03-19 02:55:59 +01:00
sorted.push_back(' ');
2016-08-17 20:51:21 +02:00
}
2021-03-19 02:55:59 +01:00
sorted.append(item.quote);
}
2021-03-19 02:55:59 +01:00
res.set_str(sorted.str());
}
2017-02-13 18:10:40 +01:00
static void cs_init_lib_list_sort(cs_state &gcs) {
gcs.new_command("sortlist", "srree", [](auto &cs, auto args, auto &res) {
cs_list_sort(
2021-03-17 21:57:47 +01:00
cs, res, args[0].get_str(), args[1].get_ident(),
args[2].get_ident(), args[3].get_code(), args[4].get_code()
);
});
gcs.new_command("uniquelist", "srre", [](auto &cs, auto args, auto &res) {
cs_list_sort(
2021-03-17 21:57:47 +01:00
cs, res, args[0].get_str(), args[1].get_ident(),
args[2].get_ident(), nullptr, args[3].get_code()
);
});
}
} /* namespace cscript */