-
Notifications
You must be signed in to change notification settings - Fork 0
/
README.html
executable file
·285 lines (204 loc) · 13.8 KB
/
README.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>d'Arc 0.2.0</title>
<style type="text/css"><!--
body { font-family: "Century Gothic", Verdana, Helvetica, Arial, sans-serif;
text-align: justify;
margin: 0;
background-color: #fffce0; }
a { color: #c25036;
text-decoration: none; }
a:visited { color: brown; }
a:hover { color: orange; }
img.head { margin: 0px 10px 10px 0px; }
div.body { padding: 4em 5em 1em 5em;
text-align: justify;
}
div.panel { background-color: white;
border-radius: 2em;
-moz-border-radius: 2em;
border: 2px solid navy;
margin: 2em;
padding: 2em;
}
pre.code-index,
pre.code,
pre
{ background-color: #f4eca8; /* #e2d090; */ /* #fff8d2; */
border: 2px solid #fcb000; /* #f4eac8; */
padding: 1em;
border-bottom-left-radius: 1em;
-moz-border-radius-bottomleft: 1em;
border-top-right-radius: 1em;
-moz-border-radius-topright: 1em;
overflow: hidden; scrollbar: auto;
}
pre.codelast-index,
pre.codelast
{ background-color: #f4eca8; /* #e2d090; */ /* #fff8d2; */
border: 2px solid #fcb000; /* #f4eac8; */
padding: 1em;
border-bottom-left-radius: 1em;
-moz-border-radius-bottomleft: 1em;
border-bottom-right-radius: 1.2em;
-moz-border-radius-bottomright: 1.2em;
}
pre.code,
pre { background-color: white;
border: 2px solid #f0d8c0; }
pre.codelast
{ background-color: #f0e4c4;
border: 2px solid white; }
div.head { border: 0;
border-top-left-radius: 20px 7px;
-moz-border-radius-topleft: 20px 7px;
border-bottom-right-radius: 35px 30px;
-moz-border-radius-bottomright: 50px 15px;
background: url(etc/images/darc-head-background.png) no-repeat top right;
padding: 0; margin: 0;
}
div.foot { border: 0;
border-top-left-radius: 15px;
-moz-border-radius-topleft: 15px;
border-bottom-right-radius: 15px;
-moz-border-radius-bottomright: 15px;
background: url(etc/images/darc-head-background.png) no-repeat bottom left;
height:31px; padding: 0; margin: 0;
}
div.rightinset
{ border: 2px solid white;
margin-left: 1em;
padding: 2.5em;
background-color: #c25036;
color: #f4eca8;
float: right;
width: 40;
border-radius: 1em;
-moz-border-radius: 1em;
font-size: 1em;
text-align: justify; }
--></style>
</head>
<body>
<div class=head>
<img class=head src=etc/images/darc-head.png>
</div>
<div class=body>
<h1>d'Arc 0.2.0</h1>
<p><strong>d'Arc is a small, fast, straight forward, you better read-only, sub-API interface to Lua data for both Lua 5.1.4 and LuaJIT 2 beta 7. It's not for the faint of heart but really sweet. Using it may get you fired. Or promoted. Or both, just like <a href="http://hdiedrich.github.com/darc/doc/NAME.html">Jeanne</a>.</strong></p>
<p>d'Arc lets you read out Lua variables and tables as <a href="http://hdiedrich.github.com/darc/doc/BENCHMARKS.html">fast</a> as possible, for both Lua and LuaJIT. Done right, i.e. using the official Lua API, you will always be wasting quite a bit of time when traversing a table, or reading out a variable. Which - life can be so confusing - implies that under some circumstance doing it right may not be right after all. Like, if performance matters. It's complicated. Jeanne to the rescue. </p>
<p>Using d'Arc allows you to avoid the repeat look ups, hash calculations and stack writes that bog down table traversion and variable access when using the official API for Lua or LuaJIT. And once you have accessed a variable, you keep a direct C pointer to its value, rather than going via a look up and the stack again. When traversing a table, d'Arc uses the existing, implicit pointers to the next elements rather than doing separate look ups for each and every individual key, as the official API does.</p>
<p>As an example, here is the <a href="http://hdiedrich.github.com/darc/doc/IMPLEMENTATION.html">implementation</a> of d'Arc vs. the official API, at the C level. On the face of it, d'Arc looks like this:</p>
<pre><code>const char *s = XLUA_STRING(tval);
</code></pre>
<p>... instead of going via the Lua state and stack, like this:</p>
<pre><code>const char *s = lua_tostring (lua_State *L, int index);
</code></pre>
<div class=rightinset style='width:40%; color:#fff0f0;'>
With Jeanne, in the end, it didn't really matter were the voices came from that she heard. She was highly effective for them and kicked some butt. They so hated her for it, just killing her wouldn't do. Same for your projects: in the face of world history, maybe it matters less that inevitably some people will feel you are cheating when using something as dirty as d'Arc to be faster than a nice, clean API call. To wit, playing by the rules will safe them re-doing 50 lines of code in case Lua publishes a next version but will waste gazillions of cpu cycles that translate into millions of wasted Megawatts, wasted life time and dead trees! Right. So do the right thing, revel in their frantic screams and do something nice. And dirty. And even green, too!
</div>
<p>The calls are not only different in form but as the different parameters suggest, they are used in different places. Which is what provides for the performance gain. With d'Arc you use pointers to variable structures (e.g. 'tval'), not the Lua state and stack index (L, and index).</p>
<p>Watch out when you get all enthusiastic and start feeling like writing to the variables. That can have all sorts of consequences that you will not have plumbed until you thought about string interning, garbage collection, longjumping, yielding and parallel processes. Stay with reading unless you know what you are doing. Which, anyway, happens to be the requirement for using d'Arc in the first place. In case that hadn't transpired yet. </p>
<p>Maybe memorize it like this: Jeanne listened to God and that worked great for a while. But it didn't necessarily work the other way around when she got in trouble. The quintessential read-only: God is listening. But he likes you to take care of the action.</p>
<h2>Usage</h2>
<p>See <a href="http://hdiedrich.github.com/darc/doc/sample.html">sample/filter/filter.c</a></p>
<p>Basically you get a bunch of oyster shucker macros for direct access of the actual contents of the VM value structures, and to test for the content types (string, number, table etc).</p>
<p>Plus, one function to traverse a table in low-level flight.</p>
<p>The macros and that fold function do not alter the Lua stack and no values are copied. You could write to and change the variable contents, but that's not the intention at this point. There are side effects, e.g. strings are <a href="http://en.wikipedia.org/wiki/String_interning">interned</a> so changing a string will change all of the same value, etc.</p>
<p><strong>1) Stack Access</strong></p>
<pre><code>TValue *o = XLUA_INDEX_TO_ADDRESS(L, index);
</code></pre>
<p>This returns a TValue pointer of a value residing on the Lua stack. Usually, that's your starting point. As mentioned before, d'Arc does not alter the Lua stack.</p>
<p>If you're only starting out with Lua C programming: the Lua stack is not the C stack, it's a specific, Lua VM structure used for the values the Lua VM swishes around.</p>
<p><strong>2) Type Tests</strong></p>
<pre><code>XLUA_IS_NIL(o)
XLUA_IS_TRUE(o)
XLUA_IS_FALSE(o)
XLUA_IS_BOOLEAN(o)
XLUA_IS_NUMBER(o)
XLUA_IS_STRING(o)
XLUA_IS_TABLE(o)
XLUA_IS_FUNCTION(o)
XLUA_IS_USERDATA(o)
XLUA_IS_THREAD(o)
XLUA_IS_LIGHTUSERDATA(o)
</code></pre>
<p>These take a TValue pointer as argument (o) and return 0 (false) or 1 (true).</p>
<p><strong>3) Value Access</strong></p>
<pre><code>XLUA_BOOLEAN(o)
XLUA_NUMBER(o)
XLUA_STRING(o)
XLUA_STRING_LENGTH(o)
XLUA_TABLE(o)
</code></pre>
<p>These also take a TValue pointer as argument (o) and return int, int, char *, size_t, TValue respectively. Remember, Lua allows \0 as part of strings, and strings are interned.</p>
<p>And to say that again: the above compiles for both Lua and LuaJIT, that's the point.</p>
<p><strong>4) Table Traversal</strong></p>
<pre><code>int darc_traverse(const Table *t, foldfunc fold, void *state);
</code></pre>
<p>This function is used to traverse a table, see the sample below. It is implemented in a fashion akin to the internal rehash functions of the VMs, which of course are highly optimized. The function applies the 'foldfunc' callback function that you define, to every table element. </p>
<pre><code>typedef int (*foldfunc)(TValue *o, void *state);
</code></pre>
<p>The sample below will make things quite clear.</p>
<p><strong>5) Table Entry Access</strong></p>
<pre><code>TValue *o = XLUA_NODE_KEYVAL(node);
TValue *o = XLUA_NODE_VAL(node);
</code></pre>
<p>Less frequently of interest, these functions are used on the 'nodes' that tables consist of: each node combines one key and its value. the results of these macros are TValue pointers that e.g. can be used as arguments to the type test and value access macros listed above. You may find use for these two macros, if you started decomposing and reinterpreting the darc.c source, to traverse tables yet <em>more</em> streamlined than by using darc_traverse(). Otherwise, you probably won't run into nodes in the beginning. But maybe once you dig deeper, so here you are.</p>
<h2>Sample</h2>
<p>A swearword filter, which returns true when a bad word is found in a Lua value:</p>
<pre><code>> v={{'help!',{22, {'Oh fuck', 1}}, nil}
> print(filter.check(v))
true
</code></pre>
<p>The source is in <a href="http://hdiedrich.github.com/darc/doc/sample.html">sample/filter/filter.c</a>. </p>
<p>Most of that file is boilerplate to get it to play with Lua as a library. The core of it is the following function. This is such a <strong>foldfunc</strong> function, as discussed above, which is of the type</p>
<pre><code>typedef int (*foldfunc)(TValue *o, void *state);
</code></pre>
<p>This function is the central vehicle of the table traversal in d'Arc: </p>
<ol>
<li><p>the foldfunc is passed a Lua VM value to process, TValue *o. This is a table element, and it can also be a nested table.</p></li>
<li><p>if you need to collect state for your work inside the table, and to return results, you can pass a data structure in using the <strong>state</strong> pointer </p></li>
<li><p>if foldfunc returns 0, the traversal is stopped, and at the top level, 0 is returned</p></li>
</ol>
<p>In the case of the filter.c sample, you can follow how the foldfunc <em>indirectly calls itself</em>, by passing itself to darc_traverse as function pointer. This should be the usual way to traverse into nested tables.</p>
<pre><code>int lame_word_filter(TValue *subject, void *state)
{
if(XLUA_IS_STRING(subject))
/* actually act on the string. */
return inspect(XLUA_STRING(subject));
else if(XLUA_IS_TABLE(subject))
/* traverse down into a table. */
return darc_traverse(XLUA_TABLE(subject), lame_word_filter, state);
/* ignore all other types. */
return 1;
}
</code></pre>
<p>Generally, traversing down into a <em>nested</em> table that you encounter, should be <em>initiated</em> in that foldfunc. Which is completely straight forward: since where you start from is usually a TValue, which could be a table, or not. Therefore, seen from the outer, Lua-registered function, you would usually start with a call to your 'foldfunc', not darc_traverse(). It's your foldfunc that then calls darc_traverse() first, if appropriate. (Or it does something else completely, e.g. in case the top value is not a table anyway.) Now, because your foldfunc will usually call darc_traverse() with itself as argument, that darc_traverse() call inside your foldfunc will be the one and only call you write, and will handle all nested tables recursively. Are you with me? If you know a better way to put this, don't hesitate to let me know.</p>
<p>And, again: this source compiles for Lua and LuaJIT, even though it doesn't use the official API. It accesses the values more directly, eg. using the macros XLUA_IS_STRING(), XLUA_STRING() etc. On the other hand, the source shown here is not optimized to the hilt so as to remain instructive.</p>
<p>The above function lame_word_filter() is tied into Lua by this generic function:</p>
<pre><code>static int filter_check(lua_State *L) {
lua_settop(L, 1);
const TValue *subject = index2addr(L, -1);
lua_pop(L, 1);
int ok = lame_word_filter(subject, (void *)0);
lua_pushboolean(L, !ok);
return 1;
}
</code></pre>
<p>For this sample, the <strong>integer return value</strong> is quite usefull. It suffices to report back 'yes' or 'no'. And that's what it always does, it signals if the traversal was complete (1) or broken off (0). In this case, that is used to report back whether an offensive word was found, or not. For more interesting stuff, you would use the state pointer.</p>
<p>Please send feedback, advise and corrections to hd2010@eonblast.com, or send me a <a href="https://github.com/inbox/new/hdiedrich">message</a>, or open an <a href="https://github.com/hdiedrich/darc/issues">issue</a> on github.com. </p>
<p>Thanks, <br/>
Henning</p>
<p><center><a href="http://hdiedrich.github.com/darc/index.html">Home</a></center></p>
<br />
<center>
<small style='color:gray'>
© 2011 Henning Diedrich
</small>
</center>
</div>
<div class=foot></div>
</body></html>