diff options
author | Mike Pall <mike> | 2011-02-11 13:50:01 +0100 |
---|---|---|
committer | Mike Pall <mike> | 2011-02-11 14:51:20 +0100 |
commit | 1f0006ac71fd4eb308ab900b0b9917e1dd046680 (patch) | |
tree | 93a6e6435ef45c776c28da2d3f4c8330e0e72968 /doc/ext_ffi_tutorial.html | |
parent | a5aade2fa9ff89f9f3c4a91261071299de0d0fa4 (diff) | |
download | luajit2-1f0006ac71fd4eb308ab900b0b9917e1dd046680.tar.gz |
Cleanup of docs.
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 @@ <link rel="stylesheet" type="text/css" href="bluequad.css" media="screen"> <link rel="stylesheet" type="text/css" href="bluequad-print.css" media="print"> <style type="text/css"> +span.codemark { position:absolute; left: 16em; color: #4040c0; } +span.mark { color: #4040c0; font-family: Courier New, Courier, monospace; + line-height: 1.1; } +pre.mark { padding-left: 2em; } table.idiomtable { line-height: 1.2; } +table.idiomtable tt { font-size: 100%; } tr.idiomhead td { font-weight: bold; } td.idiomc { width: 12em; } td.idiomlua { width: 14em; } @@ -94,27 +99,46 @@ The following code explains how to access standard system functions. We slowly print two lines of dots by sleeping for 10 milliseconds after each dot: </p> -<pre class="code"> -local ffi = require("ffi") -ffi.cdef[[ <span style="color:#f0f4ff;">//</span><span style="color:#4040c0;">①</span> +<pre class="code mark"> +<span class="codemark"> +① + + + + + +② +③ +④ + + + +⑤ + + + + + +⑥</span>local ffi = require("ffi") +ffi.cdef[[ <span style="color:#00a000;">void Sleep(int ms); int poll(struct pollfd *fds, unsigned long nfds, int timeout);</span> ]] local sleep -if ffi.os == "Windows" then <span style="color:#f0f4ff;">--</span><span style="color:#4040c0;">②</span> - function sleep(s) <span style="color:#f0f4ff;">--</span><span style="color:#4040c0;">③</span> - ffi.C.Sleep(s*1000) <span style="color:#f0f4ff;">--</span><span style="color:#4040c0;">④</span> +if ffi.os == "Windows" then + function sleep(s) + ffi.C.Sleep(s*1000) end else function sleep(s) - ffi.C.poll(nil, 0, s*1000) <span style="color:#f0f4ff;">--</span><span style="color:#4040c0;">⑤</span> + ffi.C.poll(nil, 0, s*1000) end end for i=1,160 do io.write("."); io.flush() - sleep(0.01) <span style="color:#f0f4ff;">--</span><span style="color:#4040c0;">⑥</span> + sleep(0.01) end io.write("\n") </pre> @@ -122,14 +146,14 @@ io.write("\n") Here's the step-by-step explanation: </p> <p> -<span style="color:#4040c0;">①</span> This defines the +<span class="mark">①</span> This defines the C library functions we're going to use. The part inside the double-brackets (in green) is just standard C syntax. You can usually get this info from the C header files or the documentation provided by each C library or C compiler. </p> <p> -<span style="color:#4040c0;">②</span> The difficulty we're +<span class="mark">②</span> The difficulty we're facing here, is that there are different standards to choose from. Windows has a simple <tt>Sleep()</tt> function. On other systems there 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 function only on Windows systems. </p> <p> -<span style="color:#4040c0;">③</span> Here we're wrapping the +<span class="mark">③</span> Here we're wrapping the call to the C function in a Lua function. This isn't strictly necessary, but it's helpful to deal with system-specific issues only in one part of the code. The way we're wrapping it ensures the check for the OS is only done during initialization and not for every call. </p> <p> -<span style="color:#4040c0;">④</span> A more subtle point is +<span class="mark">④</span> A more subtle point is that we defined our <tt>sleep()</tt> function (for the sake of this example) as taking the number of seconds, but accepting fractional 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 don't need to declare them as such. </p> <p> -<span style="color:#4040c0;">⑤</span> The <tt>poll()</tt> +<span class="mark">⑤</span> The <tt>poll()</tt> function takes a couple more arguments we're not going to use. You can simply use <tt>nil</tt> to pass a <tt>NULL</tt> pointer and <tt>0</tt> 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 to bridge the semantic differences between Lua and C. </p> <p> -<span style="color:#4040c0;">⑥</span> Now that we have defined +<span class="mark">⑥</span> Now that we have defined our own <tt>sleep()</tt> function, we can just call it from plain Lua code. That wasn't so bad, huh? Turning these boring animated dots into 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. We'll define two convenience wrapper functions that take a string and compress or uncompress it to another string: </p> -<pre class="code"> -local ffi = require("ffi") -ffi.cdef[[ <span style="color:#f0f4ff;">//</span><span style="color:#4040c0;">①</span> +<pre class="code mark"> +<span class="codemark"> +① + + + + + + +② + + +③ + +④ + + +⑤ + + +⑥ + + + + + + + +⑦</span>local ffi = require("ffi") +ffi.cdef[[ <span style="color:#00a000;">unsigned long compressBound(unsigned long sourceLen); int compress2(uint8_t *dest, unsigned long *destLen, const uint8_t *source, unsigned long sourceLen, int level); int uncompress(uint8_t *dest, unsigned long *destLen, const uint8_t *source, unsigned long sourceLen);</span> ]] -local zlib = ffi.load(ffi.os == "Windows" and "zlib1" or "z") <span style="color:#f0f4ff;">--</span><span style="color:#4040c0;">②</span> +local zlib = ffi.load(ffi.os == "Windows" and "zlib1" or "z") local function compress(txt) - local n = zlib.compressBound(#txt) <span style="color:#f0f4ff;">--</span><span style="color:#4040c0;">③</span> + local n = zlib.compressBound(#txt) local buf = ffi.new("uint8_t[?]", n) - local buflen = ffi.new("unsigned long[1]", n) <span style="color:#f0f4ff;">--</span><span style="color:#4040c0;">④</span> + local buflen = ffi.new("unsigned long[1]", n) local res = zlib.compress2(buf, buflen, txt, #txt, 9) assert(res == 0) - return ffi.string(buf, buflen[0]) <span style="color:#f0f4ff;">--</span><span style="color:#4040c0;">⑤</span> + return ffi.string(buf, buflen[0]) end -local function uncompress(comp, n) <span style="color:#f0f4ff;">--</span><span style="color:#4040c0;">⑥</span> +local function uncompress(comp, n) local buf = ffi.new("uint8_t[?]", n) local buflen = ffi.new("unsigned long[1]", n) local res = zlib.uncompress(buf, buflen, comp, #comp) @@ -224,7 +275,7 @@ local function uncompress(comp, n) <span style="color:#f0f4ff;">--</span><span s return ffi.string(buf, buflen[0]) end --- Simple test code. <span style="color:#f0f4ff;">--</span><span style="color:#4040c0;">⑦</span> +-- Simple test code. local txt = string.rep("abcd", 1000) print("Uncompressed size: ", #txt) local c = compress(txt) @@ -236,13 +287,13 @@ assert(txt2 == txt) Here's the step-by-step explanation: </p> <p> -<span style="color:#4040c0;">①</span> This defines some of the +<span class="mark">①</span> This defines some of the C functions provided by zlib. For the sake of this example, some type indirections have been reduced and it uses the pre-defined fixed-size integer types, while still adhering to the zlib API/ABI. </p> <p> -<span style="color:#4040c0;">②</span> This loads the zlib shared +<span class="mark">②</span> This loads the zlib shared library. On POSIX systems it's named <tt>libz.so</tt> and usually comes pre-installed. Since <tt>ffi.load()</tt> automatically adds any missing standard prefixes/suffixes, we can simply load the @@ -253,7 +304,7 @@ you'll have to download it first from the <tt>ffi.load()</tt>. </p> <p> -<span style="color:#4040c0;">③</span> First, the maximum size of +<span class="mark">③</span> First, the maximum size of the compression buffer is obtained by calling the <tt>zlib.compressBound</tt> function with the length of the 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 array is given as the 2nd argument to <tt>ffi.new()</tt>. </p> <p> -<span style="color:#4040c0;">④</span> This may look strange at +<span class="mark">④</span> This may look strange at first, but have a look at the declaration of the <tt>compress2</tt> function from zlib: the destination length is defined as a pointer! 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 actual <tt>zlib.compress2</tt> function is then straightforward. </p> <p> -<span style="color:#4040c0;">⑤</span> We want to return the +<span class="mark">⑤</span> We want to return the compressed data as a Lua string, so we'll use <tt>ffi.string()</tt>. It needs a pointer to the start of the data and the actual length. The 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 for garbage collection and string interning. </p> <p> -<span style="color:#4040c0;">⑥</span> The <tt>uncompress</tt> +<span class="mark">⑥</span> The <tt>uncompress</tt> functions does the exact opposite of the <tt>compress</tt> function. The compressed data doesn't include the size of the original string, so this needs to be passed in. Otherwise no surprises here. </p> <p> -<span style="color:#4040c0;">⑦</span> The code, that makes use +<span class="mark">⑦</span> The code, that makes use of the functions we just defined, is just plain Lua code. It doesn't need to know anything about the LuaJIT FFI — the convenience wrapper functions completely hide it. |