d'Arc 0.2.0
This is the benchmark code, functionally the same as the briefer filter sample.
samples/filter/filter4bench.c
/* ( (
* )\ ) ( ) d'Arc)\ ) (
* (()/( ( )\ ( /( ( ( (()/( ) ) )\ (
* /(_)) )\ ((_))\()) ))\ )( /(_))( /( ( ` ) ((_) ))\
* (_))_|((_) _ (_))/ /((_)(()\ (_)) )(_)) )\ ' /(/( _ /(( )
* | |_ (_)| || |_ (_)) ((_) / __|((_)_ _((_)) ((_)_\ | |(_)) /
* | __| | || || _|/ -_) | '_| \__ \/ _` || ' \()| '_ \)| |/ -_)
* |_| |_||_| \__|\___| |_| |___/\__,_||_|_|_| | .__/ |_|\___|
*
*
* This is a sample for d'Arc 0.2.0, a Lua sub API for Lua and LuaJIT
*
* Swearword filter: returns true when a swear is found in a value.
*
* > =filter.check("dork")
* true
*
* > =filter.check({"nice", "tender", "bitch")
* true
*
* This is not even entirely fictitious: word filters are historically
* annoyingly resource consuming. Still, this only for illustration.
*/
#include <string.h>
#include "darc.h"
/*****************************************************************************\
*** ***
*** DECLARATIONS ) ***
*** ( ) ***
\*******************************************************************( )(******/
/* nothing special in this section */
LUALIB_API int luaopen_filter (lua_State *L);
LUALIB_API int luaopen_filterjit (lua_State *L);
static int filter_check (lua_State *L);
static int filter_hello (lua_State *L);
static int filter_check_official(lua_State *L);
static int word_filter(TValue *variable, void *state);
static int word_filter_official(lua_State *L, int t);
int inspect(const char *string);
/****************************************************************************.\
*** .**
*** LUA HOOKS *)*
*** (*)
\*****************************************************************************/
/*---------------------------------------------------------------------------*\
* List of functions to register with Lua *
\*---------------------------------------------------------------------------*/
/* nothing special in this section */
static const struct luaL_Reg filter [] = {
{"hello", filter_hello }, /* bare bone test function to test the build */
{"check", filter_check }, /* main function: check strings for swearwords */
{"check_official", filter_check_official }, /* to benchmark, same via API */
{ NULL, NULL }
};
/*-------------------------------------------------------------------- ( ----*\
* Registration Function for Opening the filter Module ( \ *
\*----------------------------------------------------------------------------*/
/*
* We register a function of a different name for Lua and LuaJIT respectively.
*
* Because as a convention, we always compile two libs, once for each target,
* ie Lua and LuaJIT, at once. And want to have the name of the resulting lib
* be identical to the function registered here that opens the module. In this
* case: 'filter' for Lua, 'filterjit' for LuaJIT.
*
* Using the official API, one lib and the same works for both Lua and LuaJIT.
* Not so, by definition, when using d'Arc, which reaches below that API.
*/
#ifdef LUA_5_1
LUALIB_API int luaopen_filter4bench (lua_State *L) {
luaL_register(L, "filter4bench", filter); /* registering this module (PUC Lua) */
return 1;
}
#endif
#ifdef JIT_2
LUALIB_API int luaopen_filter4benchjit /* <<-- 'jit' */ (lua_State *L) {
luaL_register(L, "filter4bench", filter); /* registering this module (LuaJIT) */
return 1;
}
#endif
/*****************************************************************************\
*** ***
*** LUA EXPORTS ***
*** ***
*****************************************************************************
* entry point functions for calls coming from Lua scripts *
\*****************************************************************************/
/*---------------------------------------------------------------------------*\
* Main function: Test a Lua value for whether it contains swear words *
\*---------------------------------------------------------------------------*/
/* nothing special in this section */
static int filter_check(lua_State *L) {
lua_settop(L, 1); // arguments, max: 1
TValue *subject = index2addr(L, -1);
lua_pop(L, 1);
int ok = word_filter(subject, (void *)0);
/* note: for this simple sample, the boolean return value is usefull.
For more elaborate stuff, you'd use the state pointer for returns. */
lua_pushboolean(L, !ok);
return 1;
}
/*---------------------------------------------------------------------------*\
* For benchmarking: same functionality using the official API *
\*---------------------------------------------------------------------------*/
/* nothing special in this section */
static int filter_check_official(lua_State *L) {
lua_settop(L, 1); // arguments, max: 1
int ok = word_filter_official(L, 1);
lua_pop(L, 1);
/* note: for this simple sample, the boolean return value is usefull.
For more elaborate stuff, you'd use the state pointer for returns. */
lua_pushboolean(L, !ok);
return 1;
}
/*---------------------------------------------------------------------------*\
* Hello test call implementation (simple function to test the lib build) *
\*---------------------------------------------------------------------------*/
/* nothing special in this section */
static int filter_hello(lua_State *L) {
printf("Hello Jeanne!\n");
return 1;
/* that's it for this function, it is used to get plain signs of life. */
}
/*****************************************************************************\
*** ***
*** ACTUAL FUNCTIONALITY ***
*** ***
*****************************************************************************
* now to the things we are here for *
\*****************************************************************************/
/* To reiterate: this source compiles for Lua and LuaJIT. It does NOT use the
* official Lua API, but accesses Lua values directly. Thus, you get two
* different libraries as a result, one for Lua, one for LuaJIT.
*
* The relevant things here: 1) the macros and 2) the darc_traverse() function.
*
* This sample is NOT optimized to the hilt, in order to be more instructive.
*
* Anyway, in other words, this is the faster, d'Arc way of doing things:
*/
static int word_filter(TValue *variable, void *state)
{
/* if a string: screen it for bad words */
if(XLUA_IS_STRING(variable))
/* screen it */
return inspect(XLUA_STRING(variable));
/* if a table: traverse it */
else if(XLUA_IS_TABLE(variable))
/* traverse table, using this function as callback, for each element */
return darc_traverse(XLUA_TABLE(variable), word_filter, state);
return 1;
}
/* Maybe think about it for a moment. darc_traverse() is pretty powerful. */
/*****************************************************************************
* ... and for benchmarking against: the same, but using the official API *
\*****************************************************************************/
/*
* Now the plain vanilla, standard procedure as provided in the Lua manual:
*
* the conventional, slower way of doing things, for the same result as above.
*
* Objectively, this is in a different way 'hard to follow', state-heavy due to
* the use of the stack to propagate values. The callback used above may not
* be immediately transparent either. But it's arguably more straight forward.
*
*/
static int word_filter_official(lua_State *L, int t) {
int notfound = 1;
/* inspect top of stack for type */
int type = lua_type(L, -1);
/* if a string: screen it for bad words */
if(type == LUA_TSTRING) {
/* get the string via the stack */
const char *s = lua_tostring(L, -1);
/* screen it */
notfound = inspect(s);
}
/* if a table: traverse it */
else if(type == LUA_TTABLE) {
/* table is in the stack at index 't'. Push an empty 'first key': */
lua_pushnil(L);
/* lua_next provides two over the stack: the key and the value */
while (notfound && lua_next(L, t) != 0) {
/* recurse, with 'key' (at index -2) and 'value' (at index -1) */
notfound = word_filter_official(L, t+2);
/* remove 'value'; keep 'key' for next iteration */
lua_pop(L, 1);
}
}
return notfound;
}
/*****************************************************************************
* the actual work: find out foul mouthing *
\*****************************************************************************/
/* Both above functions use this, just to give some color to this sample.
*
* Then for benchmarking, the work bit is skipped entirely, to not water down
* the difference in performance between the official API and d'Arc.
*/
int inspect(const char *string)
{
#ifdef LESS_SKEW_FOR_BENCHMARK
return 1;
#else
if( strstr(string, "dork") == NULL
&& strstr(string, "damn") == NULL
&& strstr(string, "fuck") == NULL
&& strstr(string, "dick") == NULL
&& strstr(string, "f*ck") == NULL
&& strstr(string, "shit") == NULL
&& strstr(string, "sh*t") == NULL
&& strstr(string, "bitch") == NULL
&& strstr(string, "b*tch") == NULL
&& strstr(string, "biatch") == NULL
&& strstr(string, "idiot") == NULL
&& strstr(string, "sucker") == NULL
&& strstr(string, "s*cker") == NULL)
/* yeah, genius. But you get the point. */
return 1;
return 0;
#endif
}
Run it by doing: lua[jit] samples/filter/filterbench.lua.