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