MINOR: lua: Add concat class

This patch adds the Concat class. This class provides a fast
way for the string concatenation.
This commit is contained in:
Thierry Fournier 2016-01-27 09:49:07 +01:00 committed by Willy Tarreau
parent 5351827560
commit 1de1659923
2 changed files with 166 additions and 0 deletions

View File

@ -533,6 +533,14 @@ Core class
:returns: A :ref:`socket_class` object.
.. js:function:: core.concat()
**context**: body, init, task, action, sample-fetch, converter
This function retruns a new concat object.
:returns: A :ref:`concat_class` object.
.. js:function:: core.done(data)
**context**: body, init, task, action, sample-fetch, converter
@ -553,6 +561,76 @@ Core class
Give back the hand at the HAProxy scheduler. It is used when the LUA
processing consumes a lot of processing time.
.. _concat_class:
Concat class
============
.. js:class:: Concat
This class provides a fast way for string concatenation. The way using native
Lua concatenation like the code below is slow for some reasons.
.. code-block:: lua
str = "string1"
str = str .. ", string2"
str = str .. ", string3"
..
For each concatenation, Lua:
* allocate memory for the result,
* catenate the two string copying the strings in the new memory bloc,
* free the old memory block containing the string whoch is no longer used.
This process does many memory move, allocation and free. In addition, the
memory is not really freed, it is just mark mark as unsused and wait for the
garbage collector.
The Concat class provide an alternative way for catenating strings. It uses
the internal Lua mechanism (it does not allocate memory), but it doesn't copy
the data more than once.
On my computer, the following loops spends 0.2s for the Concat method and
18.5s for the pure Lua implementation. So, the Concat class is about 1000x
faster than the embedded solution.
.. code-block:: lua
for j = 1, 100 do
c = core.concat()
for i = 1, 20000 do
c:add("#####")
end
end
..
.. code-block:: lua
for j = 1, 100 do
c = ""
for i = 1, 20000 do
c = c .. "#####"
end
end
..
.. js:function:: Concat.add(concat, string)
This function adds a string to the current concatenated string.
:param class_concat concat: A :ref:`concat_class` which contains the currently
builded string.
:param string string: A new string to concatenate to the current builded
string.
.. js:function:: Concat.dump(concat)
This function returns the concanated string.
:param class_concat concat: A :ref:`concat_class` which contains the currently
builded string.
:returns: the concatenated string
.. _fetches_class:
Fetches class

View File

@ -9,6 +9,9 @@
#include <common/time.h>
/* Contains the class reference of the concat object. */
static int class_concat_ref;
/* Return an object of the expected type, or throws an error. */
void *hlua_checkudata(lua_State *L, int ud, int class_ref)
{
@ -118,12 +121,97 @@ static void hlua_array_add_fcn(lua_State *L, const char *name,
lua_rawset(L, -3);
}
static luaL_Buffer *hlua_check_concat(lua_State *L, int ud)
{
return (luaL_Buffer *)(hlua_checkudata(L, ud, class_concat_ref));
}
static int hlua_concat_add(lua_State *L)
{
luaL_Buffer *b;
const char *str;
size_t l;
/* First arg must be a concat object. */
b = hlua_check_concat(L, 1);
/* Second arg must be a string. */
str = luaL_checklstring(L, 2, &l);
luaL_addlstring(b, str, l);
return 0;
}
static int hlua_concat_dump(lua_State *L)
{
luaL_Buffer *b;
/* First arg must be a concat object. */
b = hlua_check_concat(L, 1);
/* Push the soncatenated strng in the stack. */
luaL_pushresult(b);
return 1;
}
int hlua_concat_new(lua_State *L)
{
luaL_Buffer *b;
lua_newtable(L);
b = lua_newuserdata(L, sizeof(luaL_Buffer));
lua_rawseti(L, -2, 0);
lua_rawgeti(L, LUA_REGISTRYINDEX, class_concat_ref);
lua_setmetatable(L, -2);
luaL_buffinit(L, b);
return 1;
}
static int concat_tostring(lua_State *L)
{
const void *ptr = lua_topointer(L, 1);
lua_pushfstring(L, "Concat object: %p", ptr);
return 1;
}
static int hlua_concat_init(lua_State *L)
{
/* Creates the buffered concat object. */
lua_newtable(L);
lua_pushstring(L, "__tostring");
lua_pushcclosure(L, concat_tostring, 0);
lua_settable(L, -3);
lua_pushstring(L, "__index"); /* Creates the index entry. */
lua_newtable(L); /* The "__index" content. */
lua_pushstring(L, "add");
lua_pushcclosure(L, hlua_concat_add, 0);
lua_settable(L, -3);
lua_pushstring(L, "dump");
lua_pushcclosure(L, hlua_concat_dump, 0);
lua_settable(L, -3);
lua_settable(L, -3); /* Sets the __index entry. */
class_concat_ref = luaL_ref(L, LUA_REGISTRYINDEX);
return 1;
}
int hlua_fcn_reg_core_fcn(lua_State *L)
{
if (!hlua_concat_init(L))
return 0;
hlua_array_add_fcn(L, "now", hlua_now);
hlua_array_add_fcn(L, "http_date", hlua_http_date);
hlua_array_add_fcn(L, "imf_date", hlua_imf_date);
hlua_array_add_fcn(L, "rfc850_date", hlua_rfc850_date);
hlua_array_add_fcn(L, "asctime_date", hlua_asctime_date);
hlua_array_add_fcn(L, "concat", hlua_concat_new);
return 5;
}