summaryrefslogtreecommitdiff
path: root/doc/ext_ffi_tutorial.html
diff options
context:
space:
mode:
Diffstat (limited to 'doc/ext_ffi_tutorial.html')
-rw-r--r--doc/ext_ffi_tutorial.html111
1 files changed, 81 insertions, 30 deletions
diff --git a/doc/ext_ffi_tutorial.html b/doc/ext_ffi_tutorial.html
index c43b223b..38126865 100644
--- a/doc/ext_ffi_tutorial.html
+++ b/doc/ext_ffi_tutorial.html
@@ -9,7 +9,12 @@
9<link rel="stylesheet" type="text/css" href="bluequad.css" media="screen"> 9<link rel="stylesheet" type="text/css" href="bluequad.css" media="screen">
10<link rel="stylesheet" type="text/css" href="bluequad-print.css" media="print"> 10<link rel="stylesheet" type="text/css" href="bluequad-print.css" media="print">
11<style type="text/css"> 11<style type="text/css">
12span.codemark { position:absolute; left: 16em; color: #4040c0; }
13span.mark { color: #4040c0; font-family: Courier New, Courier, monospace;
14 line-height: 1.1; }
15pre.mark { padding-left: 2em; }
12table.idiomtable { line-height: 1.2; } 16table.idiomtable { line-height: 1.2; }
17table.idiomtable tt { font-size: 100%; }
13tr.idiomhead td { font-weight: bold; } 18tr.idiomhead td { font-weight: bold; }
14td.idiomc { width: 12em; } 19td.idiomc { width: 12em; }
15td.idiomlua { width: 14em; } 20td.idiomlua { width: 14em; }
@@ -94,27 +99,46 @@ The following code explains how to access standard system functions.
94We slowly print two lines of dots by sleeping for 10&nbsp;milliseconds 99We slowly print two lines of dots by sleeping for 10&nbsp;milliseconds
95after each dot: 100after each dot:
96</p> 101</p>
97<pre class="code"> 102<pre class="code mark">
98local ffi = require("ffi") 103<span class="codemark">&nbsp;
99ffi.cdef[[ <span style="color:#f0f4ff;">//</span><span style="color:#4040c0;">&#9312;</span> 104&#9312;
105
106
107
108
109
110&#9313;
111&#9314;
112&#9315;
113
114
115
116&#9316;
117
118
119
120
121
122&#9317;</span>local ffi = require("ffi")
123ffi.cdef[[
100<span style="color:#00a000;">void Sleep(int ms); 124<span style="color:#00a000;">void Sleep(int ms);
101int poll(struct pollfd *fds, unsigned long nfds, int timeout);</span> 125int poll(struct pollfd *fds, unsigned long nfds, int timeout);</span>
102]] 126]]
103 127
104local sleep 128local sleep
105if ffi.os == "Windows" then <span style="color:#f0f4ff;">--</span><span style="color:#4040c0;">&#9313;</span> 129if ffi.os == "Windows" then
106 function sleep(s) <span style="color:#f0f4ff;">--</span><span style="color:#4040c0;">&#9314;</span> 130 function sleep(s)
107 ffi.C.Sleep(s*1000) <span style="color:#f0f4ff;">--</span><span style="color:#4040c0;">&#9315;</span> 131 ffi.C.Sleep(s*1000)
108 end 132 end
109else 133else
110 function sleep(s) 134 function sleep(s)
111 ffi.C.poll(nil, 0, s*1000) <span style="color:#f0f4ff;">--</span><span style="color:#4040c0;">&#9316;</span> 135 ffi.C.poll(nil, 0, s*1000)
112 end 136 end
113end 137end
114 138
115for i=1,160 do 139for i=1,160 do
116 io.write("."); io.flush() 140 io.write("."); io.flush()
117 sleep(0.01) <span style="color:#f0f4ff;">--</span><span style="color:#4040c0;">&#9317;</span> 141 sleep(0.01)
118end 142end
119io.write("\n") 143io.write("\n")
120</pre> 144</pre>
@@ -122,14 +146,14 @@ io.write("\n")
122Here's the step-by-step explanation: 146Here's the step-by-step explanation:
123</p> 147</p>
124<p> 148<p>
125<span style="color:#4040c0;">&#9312;</span> This defines the 149<span class="mark">&#9312;</span> This defines the
126C&nbsp;library functions we're going to use. The part inside the 150C&nbsp;library functions we're going to use. The part inside the
127double-brackets (in green) is just standard C&nbsp;syntax. You can 151double-brackets (in green) is just standard C&nbsp;syntax. You can
128usually get this info from the C&nbsp;header files or the 152usually get this info from the C&nbsp;header files or the
129documentation provided by each C&nbsp;library or C&nbsp;compiler. 153documentation provided by each C&nbsp;library or C&nbsp;compiler.
130</p> 154</p>
131<p> 155<p>
132<span style="color:#4040c0;">&#9313;</span> The difficulty we're 156<span class="mark">&#9313;</span> The difficulty we're
133facing here, is that there are different standards to choose from. 157facing here, is that there are different standards to choose from.
134Windows has a simple <tt>Sleep()</tt> function. On other systems there 158Windows has a simple <tt>Sleep()</tt> function. On other systems there
135are a variety of functions available to achieve sub-second sleeps, but 159are a variety of functions available to achieve sub-second sleeps, but
@@ -139,14 +163,14 @@ check for <tt>ffi.os</tt> makes sure we use the Windows-specific
139function only on Windows systems. 163function only on Windows systems.
140</p> 164</p>
141<p> 165<p>
142<span style="color:#4040c0;">&#9314;</span> Here we're wrapping the 166<span class="mark">&#9314;</span> Here we're wrapping the
143call to the C&nbsp;function in a Lua function. This isn't strictly 167call to the C&nbsp;function in a Lua function. This isn't strictly
144necessary, but it's helpful to deal with system-specific issues only 168necessary, but it's helpful to deal with system-specific issues only
145in one part of the code. The way we're wrapping it ensures the check 169in one part of the code. The way we're wrapping it ensures the check
146for the OS is only done during initialization and not for every call. 170for the OS is only done during initialization and not for every call.
147</p> 171</p>
148<p> 172<p>
149<span style="color:#4040c0;">&#9315;</span> A more subtle point is 173<span class="mark">&#9315;</span> A more subtle point is
150that we defined our <tt>sleep()</tt> function (for the sake of this 174that we defined our <tt>sleep()</tt> function (for the sake of this
151example) as taking the number of seconds, but accepting fractional 175example) as taking the number of seconds, but accepting fractional
152seconds. Multiplying this by 1000 gets us milliseconds, but that still 176seconds. Multiplying this by 1000 gets us milliseconds, but that still
@@ -165,7 +189,7 @@ FFI library automatically detects <tt>stdcall</tt> functions, so you
165don't need to declare them as such. 189don't need to declare them as such.
166</p> 190</p>
167<p> 191<p>
168<span style="color:#4040c0;">&#9316;</span> The <tt>poll()</tt> 192<span class="mark">&#9316;</span> The <tt>poll()</tt>
169function takes a couple more arguments we're not going to use. You can 193function takes a couple more arguments we're not going to use. You can
170simply use <tt>nil</tt> to pass a <tt>NULL</tt> pointer and <tt>0</tt> 194simply use <tt>nil</tt> to pass a <tt>NULL</tt> pointer and <tt>0</tt>
171for the <tt>nfds</tt> parameter. Please note that the 195for the <tt>nfds</tt> parameter. Please note that the
@@ -182,7 +206,7 @@ with this, as it's performed automatically and it's carefully designed
182to bridge the semantic differences between Lua and C. 206to bridge the semantic differences between Lua and C.
183</p> 207</p>
184<p> 208<p>
185<span style="color:#4040c0;">&#9317;</span> Now that we have defined 209<span class="mark">&#9317;</span> Now that we have defined
186our own <tt>sleep()</tt> function, we can just call it from plain Lua 210our own <tt>sleep()</tt> function, we can just call it from plain Lua
187code. That wasn't so bad, huh? Turning these boring animated dots into 211code. That wasn't so bad, huh? Turning these boring animated dots into
188a fascinating best-selling game is left as an exercise for the reader. 212a fascinating best-selling game is left as an exercise for the reader.
@@ -196,27 +220,54 @@ href="http://zlib.net/">zlib</a> compression library from Lua code.
196We'll define two convenience wrapper functions that take a string and 220We'll define two convenience wrapper functions that take a string and
197compress or uncompress it to another string: 221compress or uncompress it to another string:
198</p> 222</p>
199<pre class="code"> 223<pre class="code mark">
200local ffi = require("ffi") 224<span class="codemark">&nbsp;
201ffi.cdef[[ <span style="color:#f0f4ff;">//</span><span style="color:#4040c0;">&#9312;</span> 225&#9312;
226
227
228
229
230
231
232&#9313;
233
234
235&#9314;
236
237&#9315;
238
239
240&#9316;
241
242
243&#9317;
244
245
246
247
248
249
250
251&#9318;</span>local ffi = require("ffi")
252ffi.cdef[[
202<span style="color:#00a000;">unsigned long compressBound(unsigned long sourceLen); 253<span style="color:#00a000;">unsigned long compressBound(unsigned long sourceLen);
203int compress2(uint8_t *dest, unsigned long *destLen, 254int compress2(uint8_t *dest, unsigned long *destLen,
204 const uint8_t *source, unsigned long sourceLen, int level); 255 const uint8_t *source, unsigned long sourceLen, int level);
205int uncompress(uint8_t *dest, unsigned long *destLen, 256int uncompress(uint8_t *dest, unsigned long *destLen,
206 const uint8_t *source, unsigned long sourceLen);</span> 257 const uint8_t *source, unsigned long sourceLen);</span>
207]] 258]]
208local zlib = ffi.load(ffi.os == "Windows" and "zlib1" or "z") <span style="color:#f0f4ff;">--</span><span style="color:#4040c0;">&#9313;</span> 259local zlib = ffi.load(ffi.os == "Windows" and "zlib1" or "z")
209 260
210local function compress(txt) 261local function compress(txt)
211 local n = zlib.compressBound(#txt) <span style="color:#f0f4ff;">--</span><span style="color:#4040c0;">&#9314;</span> 262 local n = zlib.compressBound(#txt)
212 local buf = ffi.new("uint8_t[?]", n) 263 local buf = ffi.new("uint8_t[?]", n)
213 local buflen = ffi.new("unsigned long[1]", n) <span style="color:#f0f4ff;">--</span><span style="color:#4040c0;">&#9315;</span> 264 local buflen = ffi.new("unsigned long[1]", n)
214 local res = zlib.compress2(buf, buflen, txt, #txt, 9) 265 local res = zlib.compress2(buf, buflen, txt, #txt, 9)
215 assert(res == 0) 266 assert(res == 0)
216 return ffi.string(buf, buflen[0]) <span style="color:#f0f4ff;">--</span><span style="color:#4040c0;">&#9316;</span> 267 return ffi.string(buf, buflen[0])
217end 268end
218 269
219local function uncompress(comp, n) <span style="color:#f0f4ff;">--</span><span style="color:#4040c0;">&#9317;</span> 270local function uncompress(comp, n)
220 local buf = ffi.new("uint8_t[?]", n) 271 local buf = ffi.new("uint8_t[?]", n)
221 local buflen = ffi.new("unsigned long[1]", n) 272 local buflen = ffi.new("unsigned long[1]", n)
222 local res = zlib.uncompress(buf, buflen, comp, #comp) 273 local res = zlib.uncompress(buf, buflen, comp, #comp)
@@ -224,7 +275,7 @@ local function uncompress(comp, n) <span style="color:#f0f4ff;">--</span><span s
224 return ffi.string(buf, buflen[0]) 275 return ffi.string(buf, buflen[0])
225end 276end
226 277
227-- Simple test code. <span style="color:#f0f4ff;">--</span><span style="color:#4040c0;">&#9318;</span> 278-- Simple test code.
228local txt = string.rep("abcd", 1000) 279local txt = string.rep("abcd", 1000)
229print("Uncompressed size: ", #txt) 280print("Uncompressed size: ", #txt)
230local c = compress(txt) 281local c = compress(txt)
@@ -236,13 +287,13 @@ assert(txt2 == txt)
236Here's the step-by-step explanation: 287Here's the step-by-step explanation:
237</p> 288</p>
238<p> 289<p>
239<span style="color:#4040c0;">&#9312;</span> This defines some of the 290<span class="mark">&#9312;</span> This defines some of the
240C&nbsp;functions provided by zlib. For the sake of this example, some 291C&nbsp;functions provided by zlib. For the sake of this example, some
241type indirections have been reduced and it uses the pre-defined 292type indirections have been reduced and it uses the pre-defined
242fixed-size integer types, while still adhering to the zlib API/ABI. 293fixed-size integer types, while still adhering to the zlib API/ABI.
243</p> 294</p>
244<p> 295<p>
245<span style="color:#4040c0;">&#9313;</span> This loads the zlib shared 296<span class="mark">&#9313;</span> This loads the zlib shared
246library. On POSIX systems it's named <tt>libz.so</tt> and usually 297library. On POSIX systems it's named <tt>libz.so</tt> and usually
247comes pre-installed. Since <tt>ffi.load()</tt> automatically adds any 298comes pre-installed. Since <tt>ffi.load()</tt> automatically adds any
248missing standard prefixes/suffixes, we can simply load the 299missing standard prefixes/suffixes, we can simply load the
@@ -253,7 +304,7 @@ you'll have to download it first from the
253<tt>ffi.load()</tt>. 304<tt>ffi.load()</tt>.
254</p> 305</p>
255<p> 306<p>
256<span style="color:#4040c0;">&#9314;</span> First, the maximum size of 307<span class="mark">&#9314;</span> First, the maximum size of
257the compression buffer is obtained by calling the 308the compression buffer is obtained by calling the
258<tt>zlib.compressBound</tt> function with the length of the 309<tt>zlib.compressBound</tt> function with the length of the
259uncompressed string. The next line allocates a byte buffer of this 310uncompressed string. The next line allocates a byte buffer of this
@@ -262,7 +313,7 @@ variable-length array (VLA). The actual number of elements of this
262array is given as the 2nd argument to <tt>ffi.new()</tt>. 313array is given as the 2nd argument to <tt>ffi.new()</tt>.
263</p> 314</p>
264<p> 315<p>
265<span style="color:#4040c0;">&#9315;</span> This may look strange at 316<span class="mark">&#9315;</span> This may look strange at
266first, but have a look at the declaration of the <tt>compress2</tt> 317first, but have a look at the declaration of the <tt>compress2</tt>
267function from zlib: the destination length is defined as a pointer! 318function from zlib: the destination length is defined as a pointer!
268This is because you pass in the maximum buffer size and get back the 319This is because you pass in the maximum buffer size and get back the
@@ -276,7 +327,7 @@ initialized with the maximum buffer size in one step. Calling the
276actual <tt>zlib.compress2</tt> function is then straightforward. 327actual <tt>zlib.compress2</tt> function is then straightforward.
277</p> 328</p>
278<p> 329<p>
279<span style="color:#4040c0;">&#9316;</span> We want to return the 330<span class="mark">&#9316;</span> We want to return the
280compressed data as a Lua string, so we'll use <tt>ffi.string()</tt>. 331compressed data as a Lua string, so we'll use <tt>ffi.string()</tt>.
281It needs a pointer to the start of the data and the actual length. The 332It needs a pointer to the start of the data and the actual length. The
282length has been returned in the <tt>buflen</tt> array, so we'll just 333length has been returned in the <tt>buflen</tt> array, so we'll just
@@ -292,13 +343,13 @@ results in buffers instead of strings. This will reduce the overhead
292for garbage collection and string interning. 343for garbage collection and string interning.
293</p> 344</p>
294<p> 345<p>
295<span style="color:#4040c0;">&#9317;</span> The <tt>uncompress</tt> 346<span class="mark">&#9317;</span> The <tt>uncompress</tt>
296functions does the exact opposite of the <tt>compress</tt> function. 347functions does the exact opposite of the <tt>compress</tt> function.
297The compressed data doesn't include the size of the original string, 348The compressed data doesn't include the size of the original string,
298so this needs to be passed in. Otherwise no surprises here. 349so this needs to be passed in. Otherwise no surprises here.
299</p> 350</p>
300<p> 351<p>
301<span style="color:#4040c0;">&#9318;</span> The code, that makes use 352<span class="mark">&#9318;</span> The code, that makes use
302of the functions we just defined, is just plain Lua code. It doesn't 353of the functions we just defined, is just plain Lua code. It doesn't
303need to know anything about the LuaJIT FFI &mdash; the convenience 354need to know anything about the LuaJIT FFI &mdash; the convenience
304wrapper functions completely hide it. 355wrapper functions completely hide it.