summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2020-03-01 22:48:48 +0800
committerruki <[email protected]>2020-03-01 22:48:48 +0800
commit2b41fac5b92bc0e5e3c4a848dfd7d9a1435fd20f (patch)
tree58dabccfd6158af8a83d19f56517c40c415f5405
parentfc36d8022fed422d34498bc111cd69bff5b08c60 (diff)
improve string.split
-rw-r--r--core/src/xmake/machine.c2
-rw-r--r--core/src/xmake/makefile1
-rw-r--r--core/src/xmake/string/split.c132
-rw-r--r--core/src/xmake/string/trim.c6
-rw-r--r--tests/modules/string/split_perf.lua6
-rw-r--r--xmake/core/base/string.lua6
6 files changed, 145 insertions, 8 deletions
diff --git a/core/src/xmake/machine.c b/core/src/xmake/machine.c
index e3a584f49..5cd6c1bd5 100644
--- a/core/src/xmake/machine.c
+++ b/core/src/xmake/machine.c
@@ -166,6 +166,7 @@ tb_int_t xm_winos_registry_query(lua_State* lua);
// the string functions
tb_int_t xm_string_trim(lua_State* lua);
+tb_int_t xm_string_split(lua_State* lua);
tb_int_t xm_string_convert(lua_State* lua);
tb_int_t xm_string_endswith(lua_State* lua);
tb_int_t xm_string_startswith(lua_State* lua);
@@ -327,6 +328,7 @@ static luaL_Reg const g_hash_functions[] =
static luaL_Reg const g_string_functions[] =
{
{ "trim", xm_string_trim }
+, { "split", xm_string_split }
, { "convert", xm_string_convert }
, { "endswith", xm_string_endswith }
, { "startswith", xm_string_startswith }
diff --git a/core/src/xmake/makefile b/core/src/xmake/makefile
index caa8f3150..1292adea3 100644
--- a/core/src/xmake/makefile
+++ b/core/src/xmake/makefile
@@ -95,6 +95,7 @@ xmake_C_FILES += \
hash/uuid4 \
hash/sha256 \
string/trim \
+ string/split \
string/convert \
string/endswith \
string/startswith \
diff --git a/core/src/xmake/string/split.c b/core/src/xmake/string/split.c
new file mode 100644
index 000000000..7954caab3
--- /dev/null
+++ b/core/src/xmake/string/split.c
@@ -0,0 +1,132 @@
+/*!A cross-platform build utility based on Lua
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Copyright (C) 2015-2020, TBOOX Open Source Group.
+ *
+ * @author ruki
+ * @file split.c
+ *
+ */
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * trace
+ */
+#define TB_TRACE_MODULE_NAME "string_split"
+#define TB_TRACE_MODULE_DEBUG (0)
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * includes
+ */
+#include "prefix.h"
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * private implementation
+ */
+static tb_void_t xm_string_split_str(lua_State* lua, tb_char_t const* cstr, tb_size_t nstr, tb_char_t const* cdls, tb_size_t ndls, tb_bool_t strict, tb_int_t limit)
+{
+ tb_int_t num = 0;
+ tb_char_t const* end = cstr + nstr;
+ tb_char_t const* pos = tb_strstr(cstr, cdls); // faster than tb_strnstr()
+ while (pos && pos < end)
+ {
+ if (pos > cstr || strict)
+ {
+ if (limit > 0 && num + 1 >= limit)
+ break;
+
+ lua_pushlstring(lua, cstr, pos - cstr);
+ lua_rawseti(lua, -2, ++num);
+ }
+
+ cstr = pos + ndls;
+ pos = tb_strstr(cstr, cdls);
+ }
+ if (cstr < end)
+ {
+ lua_pushlstring(lua, cstr, end - cstr);
+ lua_rawseti(lua, -2, ++num);
+ }
+ else if (strict && (limit < 0 || num < limit) && cstr == end)
+ {
+ lua_pushliteral(lua, "");
+ lua_rawseti(lua, -2, ++num);
+ }
+}
+static tb_void_t xm_string_split_chr(lua_State* lua, tb_char_t const* cstr, tb_size_t nstr, tb_char_t ch, tb_bool_t strict, tb_int_t limit)
+{
+ tb_int_t num = 0;
+ tb_char_t const* end = cstr + nstr;
+ tb_char_t const* pos = tb_strchr(cstr, ch); // faster than tb_strnchr()
+ while (pos && pos < end)
+ {
+ if (pos > cstr || strict)
+ {
+ if (limit > 0 && num + 1 >= limit)
+ break;
+
+ lua_pushlstring(lua, cstr, pos - cstr);
+ lua_rawseti(lua, -2, ++num);
+ }
+
+ cstr = pos + 1;
+ pos = tb_strchr(cstr, ch);
+ }
+ if (cstr < end)
+ {
+ lua_pushlstring(lua, cstr, end - cstr);
+ lua_rawseti(lua, -2, ++num);
+ }
+ else if (strict && (limit < 0 || num < limit) && cstr == end)
+ {
+ lua_pushliteral(lua, "");
+ lua_rawseti(lua, -2, ++num);
+ }
+}
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * implementation
+ */
+
+/* split string (only support plain text)
+ *
+ * @param str the string
+ * @param delimiter the delimiter
+ * @param strict is strict?
+ * @param limit the limit count
+ */
+tb_int_t xm_string_split(lua_State* lua)
+{
+ // check
+ tb_assert_and_check_return_val(lua, 0);
+
+ // get string
+ size_t nstr = 0;
+ tb_char_t const* cstr = luaL_checklstring(lua, 1, &nstr);
+
+ // get delimiter
+ size_t ndls = 0;
+ tb_char_t const* cdls = luaL_checklstring(lua, 2, &ndls);
+
+ // is strict?
+ tb_bool_t const strict = (tb_bool_t)lua_toboolean(lua, 3);
+
+ // get limit count
+ tb_int_t const limit = (tb_int_t)luaL_optinteger(lua, 4, -1);
+
+ // split it
+ lua_newtable(lua);
+ if (ndls == 1) xm_string_split_chr(lua, cstr, (tb_size_t)nstr, cdls[0], strict, limit);
+ else xm_string_split_str(lua, cstr, (tb_size_t)nstr, cdls, ndls, strict, limit);
+ return 1;
+}
diff --git a/core/src/xmake/string/trim.c b/core/src/xmake/string/trim.c
index 57ab727ac..04a0c3b08 100644
--- a/core/src/xmake/string/trim.c
+++ b/core/src/xmake/string/trim.c
@@ -22,7 +22,7 @@
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
-#define TB_TRACE_MODULE_NAME "trim"
+#define TB_TRACE_MODULE_NAME "string_trim"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
@@ -31,9 +31,8 @@
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
- * privates
+ * private implementation
*/
-
static tb_void_t xm_string_trim_space(tb_char_t const** psstr, tb_char_t const** pestr, tb_int_t mode)
{
// check
@@ -115,7 +114,6 @@ tb_int_t xm_string_trim(lua_State* lua)
do
{
tb_assert_and_check_break(sstr && trimchars);
- // empty string
tb_check_break(lstr != 0);
tb_char_t const* const rsstr = sstr;
diff --git a/tests/modules/string/split_perf.lua b/tests/modules/string/split_perf.lua
index 2b9328663..d9ac1c462 100644
--- a/tests/modules/string/split_perf.lua
+++ b/tests/modules/string/split_perf.lua
@@ -1,11 +1,11 @@
-function _split_perf(str, pattern, opt)
+function _split_perf(str, delimiter, opt)
local dt = os.mclock()
for i = 0, 1000000 do
- str:split(pattern, opt)
+ str:split(delimiter, opt)
end
dt = os.mclock() - dt
- print("split(%s .., %s, %s): %d ms", str:sub(1, 16), pattern, string.serialize(opt or {}, {strip = true, indent = false}), dt)
+ print("split(%s .., %s, %s): %d ms", str:sub(1, 16), delimiter, string.serialize(opt or {}, {strip = true, indent = false}), dt)
end
function main()
diff --git a/xmake/core/base/string.lua b/xmake/core/base/string.lua
index 97a950bb8..e188596ce 100644
--- a/xmake/core/base/string.lua
+++ b/xmake/core/base/string.lua
@@ -28,6 +28,7 @@ local serialize = require("base/serialize")
-- save original interfaces
string._dump = string._dump or string.dump
string._trim = string._trim or string.trim
+string._split = string._split or string.split
-- find the last substring with the given pattern
function string:find_last(pattern, plain)
@@ -78,13 +79,16 @@ function string:split(delimiter, opt)
plain = opt.plain
strict = opt.strict
end
+ if plain then
+ return string._split(self, delimiter, strict, limit)
+ end
local start = 1
local result = {}
local pos, epos = self:find(delimiter, start, plain)
while pos do
local substr = self:sub(start, pos - 1)
if (#substr > 0) or strict then
- if limit and limit > 0 and #result + 1 >= imit then
+ if limit and limit > 0 and #result + 1 >= limit then
break
end
table.insert(result, substr)