Author: Armin Rigo <[email protected]>
Branch:
Changeset: r2671:a2bdd438efba
Date: 2016-04-21 11:02 +0200
http://bitbucket.org/cffi/cffi/changeset/a2bdd438efba/
Log: Move the FFI Interface and Conversion reference sections to their
own page.
diff --git a/doc/source/embedding.rst b/doc/source/embedding.rst
--- a/doc/source/embedding.rst
+++ b/doc/source/embedding.rst
@@ -216,7 +216,7 @@
.. __: using.html#working
.. __: using.html#def-extern
-.. __: using.html#ffi-new_handle
+.. __: ref.html#ffi-new-handle
.. __: cdef.html#cdef
.. _`Using the ffi/lib objects`: using.html
diff --git a/doc/source/index.rst b/doc/source/index.rst
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -17,6 +17,7 @@
installation
overview
using
+ ref
cdef
embedding
diff --git a/doc/source/ref.rst b/doc/source/ref.rst
new file mode 100644
--- /dev/null
+++ b/doc/source/ref.rst
@@ -0,0 +1,590 @@
+================================
+CFFI Reference
+================================
+
+.. contents::
+
+
+FFI Interface
+-------------
+
+
+ffi.NULL
+++++++++
+
+**ffi.NULL**: a constant NULL of type ``<cdata 'void *'>``.
+
+
+ffi.error
++++++++++
+
+**ffi.error**: the Python exception raised in various cases. (Don't
+confuse it with ``ffi.errno``.)
+
+
+ffi.new()
++++++++++
+
+**ffi.new(cdecl, init=None)**:
+allocate an instance according to the specified C type and return a
+pointer to it. The specified C type must be either a pointer or an
+array: ``new('X *')`` allocates an X and returns a pointer to it,
+whereas ``new('X[n]')`` allocates an array of n X'es and returns an
+array referencing it (which works mostly like a pointer, like in C).
+You can also use ``new('X[]', n)`` to allocate an array of a
+non-constant length n. See the `detailed documentation`__ for other
+valid initializers.
+
+.. __: using.html#working
+
+When the returned ``<cdata>`` object goes out of scope, the memory is
+freed. In other words the returned ``<cdata>`` object has ownership of
+the value of type ``cdecl`` that it points to. This means that the raw
+data can be used as long as this object is kept alive, but must not be
+used for a longer time. Be careful about that when copying the
+pointer to the memory somewhere else, e.g. into another structure.
+
+
+ffi.cast()
+++++++++++
+
+**ffi.cast("C type", value)**: similar to a C cast: returns an
+instance of the named C type initialized with the given value. The
+value is casted between integers or pointers of any type.
+
+
+ffi.errno, ffi.getwinerror()
+++++++++++++++++++++++++++++
+
+**ffi.errno**: the value of ``errno`` received from the most recent C call
+in this thread, and passed to the following C call. (This is a read-write
+property.)
+
+**ffi.getwinerror(code=-1)**: on Windows, in addition to ``errno`` we
+also save and restore the ``GetLastError()`` value across function
+calls. This function returns this error code as a tuple ``(code,
+message)``, adding a readable message like Python does when raising
+WindowsError. If the argument ``code`` is given, format that code into
+a message instead of using ``GetLastError()``.
+(Note that it is also possible to declare and call the ``GetLastError()``
+function as usual.)
+
+
+ffi.string(), ffi.unpack()
+++++++++++++++++++++++++++
+
+**ffi.string(cdata, [maxlen])**: return a Python string (or unicode
+string) from the 'cdata'.
+
+- If 'cdata' is a pointer or array of characters or bytes, returns the
+ null-terminated string. The returned string extends until the first
+ null character, or at most 'maxlen' characters. If 'cdata' is an
+ array then 'maxlen' defaults to its length. See ``ffi.buffer()`` below
+ for a way to continue past the first null character. *Python 3:* this
+ returns a ``bytes``, not a ``str``.
+
+- If 'cdata' is a pointer or array of wchar_t, returns a unicode string
+ following the same rules.
+
+- If 'cdata' is a single character or byte or a wchar_t, returns it as a
+ byte string or unicode string. (Note that in some situation a single
+ wchar_t may require a Python unicode string of length 2.)
+
+- If 'cdata' is an enum, returns the value of the enumerator as a string.
+ If the value is out of range, it is simply returned as the stringified
+ integer.
+
+**ffi.unpack(...)**: XXXXXXXXXXX
+
+
+ffi.buffer(), ffi.from_buffer()
++++++++++++++++++++++++++++++++
+
+**ffi.buffer(cdata, [size])**: return a buffer object that references
+the raw C data pointed to by the given 'cdata', of 'size' bytes. The
+'cdata' must be a pointer or an array. If unspecified, the size of the
+buffer is either the size of what ``cdata`` points to, or the whole size
+of the array. Getting a buffer is useful because you can read from it
+without an extra copy, or write into it to change the original value.
+
+Here are a few examples of where buffer() would be useful:
+
+- use ``file.write()`` and ``file.readinto()`` with
+ such a buffer (for files opened in binary mode)
+
+- use ``ffi.buffer(mystruct[0])[:] = socket.recv(len(buffer))`` to read
+ into a struct over a socket, rewriting the contents of mystruct[0]
+
+Remember that like in C, you can use ``array + index`` to get the pointer
+to the index'th item of an array.
+
+The returned object is not a built-in buffer nor memoryview object,
+because these objects' API changes too much across Python versions.
+Instead it has the following Python API (a subset of Python 2's
+``buffer``):
+
+- ``buf[:]`` or ``bytes(buf)``: fetch a copy as a regular byte string (or
+ ``buf[start:end]`` for a part)
+
+- ``buf[:] = newstr``: change the original content (or ``buf[start:end]
+ = newstr``)
+
+- ``len(buf), buf[index], buf[index] = newchar``: access as a sequence
+ of characters.
+
+The buffer object returned by ``ffi.buffer(cdata)`` keeps alive the
+``cdata`` object: if it was originally an owning cdata, then its
+owned memory will not be freed as long as the buffer is alive.
+
+Python 2/3 compatibility note: you should avoid using ``str(buf)``,
+because it gives inconsistent results between Python 2 and Python 3.
+(This is similar to how ``str()`` gives inconsistent results on regular
+byte strings). Use ``buf[:]`` instead.
+
+**ffi.from_buffer(python_buffer)**: return a ``<cdata 'char[]'>`` that
+points to the data of the given Python object, which must support the
+buffer interface. This is the opposite of ``ffi.buffer()``. It gives
+a reference to the existing data, not a copy; for this
+reason, and for PyPy compatibility, it does not work with the built-in
+types str or unicode or bytearray (or buffers/memoryviews on them).
+It is meant to be used on objects
+containing large quantities of raw data, like ``array.array`` or numpy
+arrays. It supports both the old buffer API (in Python 2.x) and the
+new memoryview API. Note that if you pass a read-only buffer object,
+you still get a regular ``<cdata 'char[]'>``; it is your responsibility
+not to write there if the original buffer doesn't expect you to.
+The original object is kept alive (and, in case
+of memoryview, locked) as long as the cdata object returned by
+``ffi.from_buffer()`` is alive. *New in version 0.9.*
+
+
+ffi.memmove()
++++++++++++++
+
+**ffi.memmove(dest, src, n)**: copy ``n`` bytes from memory area
+``src`` to memory area ``dest``. See examples below. Inspired by the
+C functions ``memcpy()`` and ``memmove()``---like the latter, the
+areas can overlap. Each of ``dest`` and ``src`` can be either a cdata
+pointer or a Python object supporting the buffer/memoryview interface.
+In the case of ``dest``, the buffer/memoryview must be writable.
+Unlike ``ffi.from_buffer()``, there are no restrictions on the type of
+buffer. *New in version 1.3.* Examples:
+
+* ``ffi.memmove(myptr, b"hello", 5)`` copies the 5 bytes of
+ ``b"hello"`` to the area that ``myptr`` points to.
+
+* ``ba = bytearray(100); ffi.memmove(ba, myptr, 100)`` copies 100
+ bytes from ``myptr`` into the bytearray ``ba``.
+
+* ``ffi.memmove(myptr + 1, myptr, 100)`` shifts 100 bytes from
+ the memory at ``myptr`` to the memory at ``myptr + 1``.
+
+
+ffi.typeof(), ffi.sizeof(), ffi.alignof()
++++++++++++++++++++++++++++++++++++++++++
+
+**ffi.typeof("C type" or cdata object)**: return an object of type
+``<ctype>`` corresponding to the parsed string, or to the C type of the
+cdata instance. Usually you don't need to call this function or to
+explicitly manipulate ``<ctype>`` objects in your code: any place that
+accepts a C type can receive either a string or a pre-parsed ``ctype``
+object (and because of caching of the string, there is no real
+performance difference). It can still be useful in writing typechecks,
+e.g.:
+
+.. code-block:: python
+
+ def myfunction(ptr):
+ assert ffi.typeof(ptr) is ffi.typeof("foo_t*")
+ ...
+
+Note also that the mapping from strings like ``"foo_t*"`` to the
+``<ctype>`` objects is stored in some internal dictionary. This
+guarantees that there is only one ``<ctype 'foo_t *'>`` object, so you
+can use the ``is`` operator to compare it. The downside is that the
+dictionary entries are immortal for now. In the future, we may add
+transparent reclamation of old, unused entries. In the meantime, note
+that using strings like ``"int[%d]" % length`` to name a type will
+create many immortal cached entries if called with many different
+lengths.
+
+**ffi.sizeof("C type" or cdata object)**: return the size of the
+argument in bytes. The argument can be either a C type, or a cdata object,
+like in the equivalent ``sizeof`` operator in C.
+
+**ffi.alignof("C type")**: return the natural alignment size in bytes of
+the argument. Corresponds to the ``__alignof__`` operator in GCC.
+
+
+.. _ffi-addressof:
+
+ffi.offsetof(), ffi.addressof()
++++++++++++++++++++++++++++++++
+
+**ffi.offsetof("C struct or array type", \*fields_or_indexes)**: return the
+offset within the struct of the given field. Corresponds to ``offsetof()``
+in C.
+
+*New in version 0.9:*
+You can give several field names in case of nested structures. You
+can also give numeric values which correspond to array items, in case
+of a pointer or array type. For example, ``ffi.offsetof("int[5]", 2)``
+is equal to the size of two integers, as is ``ffi.offsetof("int *", 2)``.
+
+
+**ffi.addressof(cdata, \*fields_or_indexes)**: limited equivalent to
+the '&' operator in C:
+
+1. ``ffi.addressof(<cdata 'struct-or-union'>)`` returns a cdata that
+is a pointer to this struct or union. The returned pointer is only
+valid as long as the original ``cdata`` object is; be sure to keep it
+alive if it was obtained directly from ``ffi.new()``.
+
+2. ``ffi.addressof(<cdata>, field-or-index...)`` returns the address
+of a field or array item inside the given structure or array. In case
+of nested structures or arrays, you can give more than one field or
+index to look recursively. Note that ``ffi.addressof(array, index)``
+can also be expressed as ``array + index``: this is true both in CFFI
+and in C, where ``&array[index]`` is just ``array + index``.
+
+3. ``ffi.addressof(<library>, "name")`` returns the address of the
+named function or global variable from the given library object.
+*New in version 1.1:* for functions, it returns a regular cdata
+object containing a pointer to the function.
+
+Note that the case 1. cannot be used to take the address of a
+primitive or pointer, but only a struct or union. It would be
+difficult to implement because only structs and unions are internally
+stored as an indirect pointer to the data. If you need a C int whose
+address can be taken, use ``ffi.new("int[1]")`` in the first place;
+similarly, for a pointer, use ``ffi.new("foo_t *[1]")``.
+
+
+ffi.CData, ffi.CType
+++++++++++++++++++++
+
+**ffi.CData, ffi.CType**: the Python type of the objects referred to
+as ``<cdata>`` and ``<ctype>`` in the rest of this document. Note
+that some cdata objects may be actually of a subclass of
+``ffi.CData``, and similarly with ctype, so you should check with
+``if isinstance(x, ffi.CData)``. Also, ``<ctype>`` objects have
+a number of attributes for introspection: ``kind`` and ``cname`` are
+always present, and depending on the kind they may also have
+``item``, ``length``, ``fields``, ``args``, ``result``, ``ellipsis``,
+``abi``, ``elements`` and ``relements``.
+
+
+ffi.gc()
+++++++++
+
+**ffi.gc(cdata, destructor)**: return a new cdata object that points to the
+same data. Later, when this new cdata object is garbage-collected,
+``destructor(old_cdata_object)`` will be called. Example of usage:
+``ptr = ffi.gc(lib.malloc(42), lib.free)``. Note that like objects
+returned by ``ffi.new()``, the returned pointer objects have *ownership*,
+which means the destructor is called as soon as *this* exact returned
+object is garbage-collected.
+
+Note that this should be avoided for large memory allocations or
+for limited resources. This is particularly true on PyPy: its GC does
+not know how much memory or how many resources the returned ``ptr``
+holds. It will only run its GC when enough memory it knows about has
+been allocated (and thus run the destructor possibly later than you
+would expect). Moreover, the destructor is called in whatever thread
+PyPy is at that moment, which might be a problem for some C libraries.
+In these cases, consider writing a wrapper class with custom ``__enter__()``
+and ``__exit__()`` methods, allocating and freeing the C data at known
+points in time, and using it in a ``with`` statement.
+
+
+ffi.new_handle(), ffi.from_handle()
++++++++++++++++++++++++++++++++++++
+
+**ffi.new_handle(python_object)**: return a non-NULL cdata of type
+``void *`` that contains an opaque reference to ``python_object``. You
+can pass it around to C functions or store it into C structures. Later,
+you can use **ffi.from_handle(p)** to retrieve the original
+``python_object`` from a value with the same ``void *`` pointer.
+*Calling ffi.from_handle(p) is invalid and will likely crash if
+the cdata object returned by new_handle() is not kept alive!*
+
+(In case you are wondering, this ``void *`` is not the ``PyObject *``
+pointer. This wouldn't make sense on PyPy anyway.)
+
+The ``ffi.new_handle()/from_handle()`` functions *conceptually* work
+like this:
+
+* ``new_handle()`` returns cdata objects that contains references to
+ the Python objects; we call them collectively the "handle" cdata
+ objects. The ``void *`` value in these handle cdata objects are
+ random but unique.
+
+* ``from_handle(p)`` searches all live "handle" cdata objects for the
+ one that has the same value ``p`` as its ``void *`` value. It then
+ returns the Python object referenced by that handle cdata object.
+ If none is found, you get "undefined behavior" (i.e. crashes).
+
+The "handle" cdata object keeps the Python object alive, similar to
+how ``ffi.new()`` returns a cdata object that keeps a piece of memory
+alive. If the handle cdata object *itself* is not alive any more,
+then the association ``void * -> python_object`` is dead and
+``from_handle()`` will crash.
+
+*New in version 1.4:* two calls to ``new_handle(x)`` are guaranteed to
+return cdata objects with different ``void *`` values, even with the
+same ``x``. This is a useful feature that avoids issues with unexpected
+duplicates in the following trick: if you need to keep alive the
+"handle" until explicitly asked to free it, but don't have a natural
+Python-side place to attach it to, then the easiest is to ``add()`` it
+to a global set. It can later be removed from the set by
+``global_set.discard(p)``, with ``p`` any cdata object whose ``void *``
+value compares equal.
+
+
+ffi.dlopen(), ffi.dlclose()
++++++++++++++++++++++++++++
+
+**ffi.dlopen(libpath, [flags])**: opens and returns a "handle" to a
+dynamic library, as a ``<lib>`` object. See `Preparing and
+Distributing modules`_.
+
+**ffi.dlclose(lib)**: explicitly closes a ``<lib>`` object returned
+by ``ffi.dlopen()``.
+
+**ffi.RLTD_...**: constants: flags for ``ffi.dlopen()``.
+
+
+ffi.new_allocator()
++++++++++++++++++++
+
+**ffi.new_allocator(alloc=None, free=None, should_clear_after_alloc=True)**:
+returns a new allocator. An "allocator" is a callable that behaves like
+``ffi.new()`` but uses the provided low-level ``alloc`` and ``free``
+functions. *New in version 1.2.*
+
+``alloc()`` is invoked with the size as sole argument. If it returns
+NULL, a MemoryError is raised. Later, if ``free`` is not None, it will
+be called with the result of ``alloc()`` as argument. Both can be either
+Python function or directly C functions. If only ``free`` is None, then no
+free function is called. If both ``alloc`` and ``free`` are None, the
+default alloc/free combination is used. (In other words, the call
+``ffi.new(*args)`` is equivalent to ``ffi.new_allocator()(*args)``.)
+
+If ``should_clear_after_alloc`` is set to False, then the memory
+returned by ``alloc()`` is assumed to be already cleared (or you are
+fine with garbage); otherwise CFFI will clear it.
+
+
+ffi.init_once()
++++++++++++++++
+
+**ffi.init_once(function, tag)**: run ``function()`` once. The
+``tag`` should be a primitive object, like a string, that identifies
+the function: ``function()`` is only called the first time we see the
+``tag``. The return value of ``function()`` is remembered and
+returned by the current and all future ``init_once()`` with the same
+tag. If ``init_once()`` is called from multiple threads in parallel,
+all calls block until the execution of ``function()`` is done. If
+``function()`` raises an exception, it is propagated and nothing is
+cached (i.e. ``function()`` will be called again, in case we catch the
+exception and try ``init_once()`` again). *New in version 1.4.*
+
+Example::
+
+ from _xyz_cffi import ffi, lib
+
+ def initlib():
+ lib.init_my_library()
+
+ def make_new_foo():
+ ffi.init_once(initlib, "init")
+ return lib.make_foo()
+
+``init_once()`` is optimized to run very quickly if ``function()`` has
+already been called. (On PyPy, the cost is zero---the JIT usually
+removes everything in the machine code it produces.)
+
+*Note:* one motivation__ for ``init_once()`` is the CPython notion of
+"subinterpreters" in the embedded case. If you are using the
+out-of-line API mode, ``function()`` is called only once even in the
+presence of multiple subinterpreters, and its return value is shared
+among all subinterpreters. The goal is to mimic the way traditional
+CPython C extension modules have their init code executed only once in
+total even if there are subinterpreters. In the example above, the C
+function ``init_my_library()`` is called once in total, not once per
+subinterpreter. For this reason, avoid Python-level side-effects in
+``function()`` (as they will only be applied in the first
+subinterpreter to run); instead, return a value, as in the following
+example::
+
+ def init_get_max():
+ return lib.initialize_once_and_get_some_maximum_number()
+
+ def process(i):
+ if i > ffi.init_once(init_get_max, "max"):
+ raise IndexError("index too large!")
+ ...
+
+.. __: https://bitbucket.org/cffi/cffi/issues/233/
+
+
+ffi.getctype(), ffi.list_types()
+++++++++++++++++++++++++++++++++
+
+**ffi.getctype("C type" or <ctype>, extra="")**: return the string
+representation of the given C type. If non-empty, the "extra" string is
+appended (or inserted at the right place in more complicated cases); it
+can be the name of a variable to declare, or an extra part of the type
+like ``"*"`` or ``"[5]"``. For example
+``ffi.getctype(ffi.typeof(x), "*")`` returns the string representation
+of the C type "pointer to the same type than x"; and
+``ffi.getctype("char[80]", "a") == "char a[80]"``.
+
+**ffi.list_types()**: Returns the user type names known to this FFI
+instance. This returns a tuple containing three lists of names:
+``(typedef_names, names_of_structs, names_of_unions)``. *New in
+version 1.6.*
+
+
+.. _`Preparing and Distributing modules`: cdef.html#loading-libraries
+
+
+Conversions
+-----------
+
+This section documents all the conversions that are allowed when
+*writing into* a C data structure (or passing arguments to a function
+call), and *reading from* a C data structure (or getting the result of a
+function call). The last column gives the type-specific operations
+allowed.
+
++---------------+------------------------+------------------+----------------+
+| C type | writing into | reading from |other operations|
++===============+========================+==================+================+
+| integers | an integer or anything | a Python int or | int() |
+| and enums | on which int() works | long, depending | |
+| `(*****)` | (but not a float!). | on the type | |
+| | Must be within range. | | |
++---------------+------------------------+------------------+----------------+
+| ``char`` | a string of length 1 | a string of | int() |
+| | or another <cdata char>| length 1 | |
++---------------+------------------------+------------------+----------------+
+| ``wchar_t`` | a unicode of length 1 | a unicode of | |
+| | (or maybe 2 if | length 1 | int() |
+| | surrogates) or | (or maybe 2 if | |
+| | another <cdata wchar_t>| surrogates) | |
++---------------+------------------------+------------------+----------------+
+| ``float``, | a float or anything on | a Python float | float(), int() |
+| ``double`` | which float() works | | |
++---------------+------------------------+------------------+----------------+
+|``long double``| another <cdata> with | a <cdata>, to | float(), int() |
+| | a ``long double``, or | avoid loosing | |
+| | anything on which | precision `(***)`| |
+| | float() works | | |
++---------------+------------------------+------------------+----------------+
+| pointers | another <cdata> with | a <cdata> |``[]`` `(****)`,|
+| | a compatible type (i.e.| |``+``, ``-``, |
+| | same type or ``char*`` | |bool() |
+| | or ``void*``, or as an | | |
+| | array instead) `(*)` | | |
++---------------+------------------------+ | |
+| ``void *``, | another <cdata> with | | |
+| ``char *`` | any pointer or array | | |
+| | type | | |
++---------------+------------------------+ +----------------+
+| pointers to | same as pointers | | ``[]``, ``+``, |
+| structure or | | | ``-``, bool(), |
+| union | | | and read/write |
+| | | | struct fields |
++---------------+------------------------+ +----------------+
+| function | same as pointers | | bool(), |
+| pointers | | | call `(**)` |
++---------------+------------------------+------------------+----------------+
+| arrays | a list or tuple of | a <cdata> |len(), iter(), |
+| | items | |``[]`` `(****)`,|
+| | | |``+``, ``-`` |
++---------------+------------------------+ +----------------+
+| ``char[]`` | same as arrays, or a | | len(), iter(), |
+| | Python string | | ``[]``, ``+``, |
+| | | | ``-`` |
++---------------+------------------------+ +----------------+
+| ``wchar_t[]`` | same as arrays, or a | | len(), iter(), |
+| | Python unicode | | ``[]``, |
+| | | | ``+``, ``-`` |
+| | | | |
++---------------+------------------------+------------------+----------------+
+| structure | a list or tuple or | a <cdata> | read/write |
+| | dict of the field | | fields |
+| | values, or a same-type | | |
+| | <cdata> | | |
++---------------+------------------------+ +----------------+
+| union | same as struct, but | | read/write |
+| | with at most one field | | fields |
++---------------+------------------------+------------------+----------------+
+
+`(*)` ``item *`` is ``item[]`` in function arguments:
+
+ In a function declaration, as per the C standard, a ``item *``
+ argument is identical to a ``item[]`` argument (and ``ffi.cdef()``
+ doesn't record the difference). So when you call such a function,
+ you can pass an argument that is accepted by either C type, like
+ for example passing a Python string to a ``char *`` argument
+ (because it works for ``char[]`` arguments) or a list of integers
+ to a ``int *`` argument (it works for ``int[]`` arguments). Note
+ that even if you want to pass a single ``item``, you need to
+ specify it in a list of length 1; for example, a ``struct point_s
+ *`` argument might be passed as ``[[x, y]]`` or ``[{'x': 5, 'y':
+ 10}]``.
+
+ As an optimization, the CPython version of CFFI assumes that a
+ function with a ``char *`` argument to which you pass a Python
+ string will not actually modify the array of characters passed in,
+ and so passes directly a pointer inside the Python string object.
+ (PyPy might in the future do the same, but it is harder because
+ strings are not naturally zero-terminated in PyPy.)
+
+`(**)` C function calls are done with the GIL released.
+
+ Note that we assume that the called functions are *not* using the
+ Python API from Python.h. For example, we don't check afterwards
+ if they set a Python exception. You may work around it, but mixing
+ CFFI with ``Python.h`` is not recommended. (If you do that, on
+ PyPy and on some platforms like Windows, you may need to explicitly
+ link to ``libpypy-c.dll`` to access the CPython C API compatibility
+ layer; indeed, CFFI-generated modules on PyPy don't link to
+ ``libpypy-c.dll`` on their own. But really, don't do that in the
+ first place.)
+
+`(***)` ``long double`` support:
+
+ We keep ``long double`` values inside a cdata object to avoid
+ loosing precision. Normal Python floating-point numbers only
+ contain enough precision for a ``double``. If you really want to
+ convert such an object to a regular Python float (i.e. a C
+ ``double``), call ``float()``. If you need to do arithmetic on
+ such numbers without any precision loss, you need instead to define
+ and use a family of C functions like ``long double add(long double
+ a, long double b);``.
+
+`(****)` Slicing with ``x[start:stop]``:
+
+ Slicing is allowed, as long as you specify explicitly both ``start``
+ and ``stop`` (and don't give any ``step``). It gives a cdata
+ object that is a "view" of all items from ``start`` to ``stop``.
+ It is a cdata of type "array" (so e.g. passing it as an argument to a
+ C function would just convert it to a pointer to the ``start`` item).
+ As with indexing, negative bounds mean really negative indices, like in
+ C. As for slice assignment, it accepts any iterable, including a list
+ of items or another array-like cdata object, but the length must match.
+ (Note that this behavior differs from initialization: e.g. you can
+ say ``chararray[10:15] = "hello"``, but the assigned string must be of
+ exactly the correct length; no implicit null character is added.)
+
+`(*****)` Enums are handled like ints:
+
+ Like C, enum types are mostly int types (unsigned or signed, int or
+ long; note that GCC's first choice is unsigned). Reading an enum
+ field of a structure, for example, returns you an integer. To
+ compare their value symbolically, use code like ``if x.field ==
+ lib.FOO``. If you really want to get their value as a string, use
+ ``ffi.string(ffi.cast("the_enum_type", x.field))``.
diff --git a/doc/source/using.rst b/doc/source/using.rst
--- a/doc/source/using.rst
+++ b/doc/source/using.rst
@@ -96,7 +96,9 @@
There is no general equivalent to the ``&`` operator in C (because it
would not fit nicely in the model, and it does not seem to be needed
-here). But see `ffi.addressof()`_.
+here). But see `ffi.addressof()`__.
+
+.. __: ref.html#ffi-addressof
Any operation that would in C return a pointer or array or struct type
gives you a fresh cdata object. Unlike the "original" one, these fresh
@@ -330,10 +332,12 @@
lib.do_something_with_array([1, 2, 3, 4, 5])
-See `Reference: conversions`_ for a similar way to pass ``struct foo_s
+See `Reference: conversions`__ for a similar way to pass ``struct foo_s
*`` arguments---but in general, it is clearer to simply pass
``ffi.new('struct foo_s *', initializer)``.
+__ ref.html#conversions
+
CFFI supports passing and returning structs to functions and callbacks.
Example:
@@ -721,7 +725,9 @@
keep this object alive for as long as the callback may be invoked.
The easiest way to do that is to always use ``@ffi.callback()`` at
module-level only, and to pass "context" information around with
-`ffi.new_handle()`_, if possible. Example:
+`ffi.new_handle()`__, if possible. Example:
+
+.. __: ref.html#new-handle
.. code-block:: python
@@ -849,530 +855,6 @@
FFI Interface
-------------
-**ffi.new(cdecl, init=None)**:
-allocate an instance according to the specified C type and return a
-pointer to it. The specified C type must be either a pointer or an
-array: ``new('X *')`` allocates an X and returns a pointer to it,
-whereas ``new('X[n]')`` allocates an array of n X'es and returns an
-array referencing it (which works mostly like a pointer, like in C).
-You can also use ``new('X[]', n)`` to allocate an array of a
-non-constant length n. See above__ for other valid initializers.
+(The reference for the FFI interface has been moved to the `next page`__.)
-.. __: working_
-
-When the returned ``<cdata>`` object goes out of scope, the memory is
-freed. In other words the returned ``<cdata>`` object has ownership of
-the value of type ``cdecl`` that it points to. This means that the raw
-data can be used as long as this object is kept alive, but must not be
-used for a longer time. Be careful about that when copying the
-pointer to the memory somewhere else, e.g. into another structure.
-
-**ffi.cast("C type", value)**: similar to a C cast: returns an
-instance of the named C type initialized with the given value. The
-value is casted between integers or pointers of any type.
-
-**ffi.error**: the Python exception raised in various cases. (Don't
-confuse it with ``ffi.errno``.)
-
-**ffi.errno**: the value of ``errno`` received from the most recent C call
-in this thread, and passed to the following C call. (This is a read-write
-property.)
-
-**ffi.getwinerror(code=-1)**: on Windows, in addition to ``errno`` we
-also save and restore the ``GetLastError()`` value across function
-calls. This function returns this error code as a tuple ``(code,
-message)``, adding a readable message like Python does when raising
-WindowsError. If the argument ``code`` is given, format that code into
-a message instead of using ``GetLastError()``.
-(Note that it is also possible to declare and call the ``GetLastError()``
-function as usual.)
-
-**ffi.string(cdata, [maxlen])**: return a Python string (or unicode
-string) from the 'cdata'.
-
-- If 'cdata' is a pointer or array of characters or bytes, returns the
- null-terminated string. The returned string extends until the first
- null character, or at most 'maxlen' characters. If 'cdata' is an
- array then 'maxlen' defaults to its length. See ``ffi.buffer()`` below
- for a way to continue past the first null character. *Python 3:* this
- returns a ``bytes``, not a ``str``.
-
-- If 'cdata' is a pointer or array of wchar_t, returns a unicode string
- following the same rules.
-
-- If 'cdata' is a single character or byte or a wchar_t, returns it as a
- byte string or unicode string. (Note that in some situation a single
- wchar_t may require a Python unicode string of length 2.)
-
-- If 'cdata' is an enum, returns the value of the enumerator as a string.
- If the value is out of range, it is simply returned as the stringified
- integer.
-
-
-**ffi.buffer(cdata, [size])**: return a buffer object that references
-the raw C data pointed to by the given 'cdata', of 'size' bytes. The
-'cdata' must be a pointer or an array. If unspecified, the size of the
-buffer is either the size of what ``cdata`` points to, or the whole size
-of the array. Getting a buffer is useful because you can read from it
-without an extra copy, or write into it to change the original value.
-
-Here are a few examples of where buffer() would be useful:
-
-- use ``file.write()`` and ``file.readinto()`` with
- such a buffer (for files opened in binary mode)
-
-- use ``ffi.buffer(mystruct[0])[:] = socket.recv(len(buffer))`` to read
- into a struct over a socket, rewriting the contents of mystruct[0]
-
-Remember that like in C, you can use ``array + index`` to get the pointer
-to the index'th item of an array.
-
-The returned object is not a built-in buffer nor memoryview object,
-because these objects' API changes too much across Python versions.
-Instead it has the following Python API (a subset of Python 2's
-``buffer``):
-
-- ``buf[:]`` or ``bytes(buf)``: fetch a copy as a regular byte string (or
- ``buf[start:end]`` for a part)
-
-- ``buf[:] = newstr``: change the original content (or ``buf[start:end]
- = newstr``)
-
-- ``len(buf), buf[index], buf[index] = newchar``: access as a sequence
- of characters.
-
-The buffer object returned by ``ffi.buffer(cdata)`` keeps alive the
-``cdata`` object: if it was originally an owning cdata, then its
-owned memory will not be freed as long as the buffer is alive.
-
-Python 2/3 compatibility note: you should avoid using ``str(buf)``,
-because it gives inconsistent results between Python 2 and Python 3.
-(This is similar to how ``str()`` gives inconsistent results on regular
-byte strings). Use ``buf[:]`` instead.
-
-**ffi.from_buffer(python_buffer)**: return a ``<cdata 'char[]'>`` that
-points to the data of the given Python object, which must support the
-buffer interface. This is the opposite of ``ffi.buffer()``. It gives
-a reference to the existing data, not a copy; for this
-reason, and for PyPy compatibility, it does not work with the built-in
-types str or unicode or bytearray (or buffers/memoryviews on them).
-It is meant to be used on objects
-containing large quantities of raw data, like ``array.array`` or numpy
-arrays. It supports both the old buffer API (in Python 2.x) and the
-new memoryview API. Note that if you pass a read-only buffer object,
-you still get a regular ``<cdata 'char[]'>``; it is your responsibility
-not to write there if the original buffer doesn't expect you to.
-The original object is kept alive (and, in case
-of memoryview, locked) as long as the cdata object returned by
-``ffi.from_buffer()`` is alive. *New in version 0.9.*
-
-
-.. _memmove:
-
-**ffi.memmove(dest, src, n)**: copy ``n`` bytes from memory area
-``src`` to memory area ``dest``. See examples below. Inspired by the
-C functions ``memcpy()`` and ``memmove()``---like the latter, the
-areas can overlap. Each of ``dest`` and ``src`` can be either a cdata
-pointer or a Python object supporting the buffer/memoryview interface.
-In the case of ``dest``, the buffer/memoryview must be writable.
-Unlike ``ffi.from_buffer()``, there are no restrictions on the type of
-buffer. *New in version 1.3.* Examples:
-
-* ``ffi.memmove(myptr, b"hello", 5)`` copies the 5 bytes of
- ``b"hello"`` to the area that ``myptr`` points to.
-
-* ``ba = bytearray(100); ffi.memmove(ba, myptr, 100)`` copies 100
- bytes from ``myptr`` into the bytearray ``ba``.
-
-* ``ffi.memmove(myptr + 1, myptr, 100)`` shifts 100 bytes from
- the memory at ``myptr`` to the memory at ``myptr + 1``.
-
-
-**ffi.typeof("C type" or cdata object)**: return an object of type
-``<ctype>`` corresponding to the parsed string, or to the C type of the
-cdata instance. Usually you don't need to call this function or to
-explicitly manipulate ``<ctype>`` objects in your code: any place that
-accepts a C type can receive either a string or a pre-parsed ``ctype``
-object (and because of caching of the string, there is no real
-performance difference). It can still be useful in writing typechecks,
-e.g.:
-
-.. code-block:: python
-
- def myfunction(ptr):
- assert ffi.typeof(ptr) is ffi.typeof("foo_t*")
- ...
-
-Note also that the mapping from strings like ``"foo_t*"`` to the
-``<ctype>`` objects is stored in some internal dictionary. This
-guarantees that there is only one ``<ctype 'foo_t *'>`` object, so you
-can use the ``is`` operator to compare it. The downside is that the
-dictionary entries are immortal for now. In the future, we may add
-transparent reclamation of old, unused entries. In the meantime, note
-that using strings like ``"int[%d]" % length`` to name a type will
-create many immortal cached entries if called with many different
-lengths.
-
-**ffi.CData, ffi.CType**: the Python type of the objects referred to
-as ``<cdata>`` and ``<ctype>`` in the rest of this document. Note
-that some cdata objects may be actually of a subclass of
-``ffi.CData``, and similarly with ctype, so you should check with
-``if isinstance(x, ffi.CData)``. Also, ``<ctype>`` objects have
-a number of attributes for introspection: ``kind`` and ``cname`` are
-always present, and depending on the kind they may also have
-``item``, ``length``, ``fields``, ``args``, ``result``, ``ellipsis``,
-``abi``, ``elements`` and ``relements``.
-
-**ffi.NULL**: a constant NULL of type ``<cdata 'void *'>``.
-
-**ffi.sizeof("C type" or cdata object)**: return the size of the
-argument in bytes. The argument can be either a C type, or a cdata object,
-like in the equivalent ``sizeof`` operator in C.
-
-**ffi.alignof("C type")**: return the natural alignment size in bytes of
-the argument. Corresponds to the ``__alignof__`` operator in GCC.
-
-
-**ffi.offsetof("C struct or array type", \*fields_or_indexes)**: return the
-offset within the struct of the given field. Corresponds to ``offsetof()``
-in C.
-
-*New in version 0.9:*
-You can give several field names in case of nested structures. You
-can also give numeric values which correspond to array items, in case
-of a pointer or array type. For example, ``ffi.offsetof("int[5]", 2)``
-is equal to the size of two integers, as is ``ffi.offsetof("int *", 2)``.
-
-
-**ffi.getctype("C type" or <ctype>, extra="")**: return the string
-representation of the given C type. If non-empty, the "extra" string is
-appended (or inserted at the right place in more complicated cases); it
-can be the name of a variable to declare, or an extra part of the type
-like ``"*"`` or ``"[5]"``. For example
-``ffi.getctype(ffi.typeof(x), "*")`` returns the string representation
-of the C type "pointer to the same type than x"; and
-``ffi.getctype("char[80]", "a") == "char a[80]"``.
-
-
-**ffi.gc(cdata, destructor)**: return a new cdata object that points to the
-same data. Later, when this new cdata object is garbage-collected,
-``destructor(old_cdata_object)`` will be called. Example of usage:
-``ptr = ffi.gc(lib.malloc(42), lib.free)``. Note that like objects
-returned by ``ffi.new()``, the returned pointer objects have *ownership*,
-which means the destructor is called as soon as *this* exact returned
-object is garbage-collected.
-
-Note that this should be avoided for large memory allocations or
-for limited resources. This is particularly true on PyPy: its GC does
-not know how much memory or how many resources the returned ``ptr``
-holds. It will only run its GC when enough memory it knows about has
-been allocated (and thus run the destructor possibly later than you
-would expect). Moreover, the destructor is called in whatever thread
-PyPy is at that moment, which might be a problem for some C libraries.
-In these cases, consider writing a wrapper class with custom ``__enter__()``
-and ``__exit__()`` methods, allocating and freeing the C data at known
-points in time, and using it in a ``with`` statement.
-
-
-.. _ffi-new_handle:
-.. _`ffi.new_handle()`:
-
-**ffi.new_handle(python_object)**: return a non-NULL cdata of type
-``void *`` that contains an opaque reference to ``python_object``. You
-can pass it around to C functions or store it into C structures. Later,
-you can use **ffi.from_handle(p)** to retrieve the original
-``python_object`` from a value with the same ``void *`` pointer.
-*Calling ffi.from_handle(p) is invalid and will likely crash if
-the cdata object returned by new_handle() is not kept alive!*
-
-(In case you are wondering, this ``void *`` is not the ``PyObject *``
-pointer. This wouldn't make sense on PyPy anyway.)
-
-The ``ffi.new_handle()/from_handle()`` functions *conceptually* work
-like this:
-
-* ``new_handle()`` returns cdata objects that contains references to
- the Python objects; we call them collectively the "handle" cdata
- objects. The ``void *`` value in these handle cdata objects are
- random but unique.
-
-* ``from_handle(p)`` searches all live "handle" cdata objects for the
- one that has the same value ``p`` as its ``void *`` value. It then
- returns the Python object referenced by that handle cdata object.
- If none is found, you get "undefined behavior" (i.e. crashes).
-
-The "handle" cdata object keeps the Python object alive, similar to
-how ``ffi.new()`` returns a cdata object that keeps a piece of memory
-alive. If the handle cdata object *itself* is not alive any more,
-then the association ``void * -> python_object`` is dead and
-``from_handle()`` will crash.
-
-*New in version 1.4:* two calls to ``new_handle(x)`` are guaranteed to
-return cdata objects with different ``void *`` values, even with the
-same ``x``. This is a useful feature that avoids issues with unexpected
-duplicates in the following trick: if you need to keep alive the
-"handle" until explicitly asked to free it, but don't have a natural
-Python-side place to attach it to, then the easiest is to ``add()`` it
-to a global set. It can later be removed from the set by
-``global_set.discard(p)``, with ``p`` any cdata object whose ``void *``
-value compares equal.
-
-
-.. _`ffi.addressof()`:
-
-**ffi.addressof(cdata, \*fields_or_indexes)**: limited equivalent to
-the '&' operator in C:
-
-1. ``ffi.addressof(<cdata 'struct-or-union'>)`` returns a cdata that
-is a pointer to this struct or union. The returned pointer is only
-valid as long as the original ``cdata`` object is; be sure to keep it
-alive if it was obtained directly from ``ffi.new()``.
-
-2. ``ffi.addressof(<cdata>, field-or-index...)`` returns the address
-of a field or array item inside the given structure or array. In case
-of nested structures or arrays, you can give more than one field or
-index to look recursively. Note that ``ffi.addressof(array, index)``
-can also be expressed as ``array + index``: this is true both in CFFI
-and in C, where ``&array[index]`` is just ``array + index``.
-
-3. ``ffi.addressof(<library>, "name")`` returns the address of the
-named function or global variable from the given library object.
-*New in version 1.1:* for functions, it returns a regular cdata
-object containing a pointer to the function.
-
-Note that the case 1. cannot be used to take the address of a
-primitive or pointer, but only a struct or union. It would be
-difficult to implement because only structs and unions are internally
-stored as an indirect pointer to the data. If you need a C int whose
-address can be taken, use ``ffi.new("int[1]")`` in the first place;
-similarly, for a pointer, use ``ffi.new("foo_t *[1]")``.
-
-
-**ffi.dlopen(libpath, [flags])**: opens and returns a "handle" to a
-dynamic library, as a ``<lib>`` object. See `Preparing and
-Distributing modules`_.
-
-**ffi.dlclose(lib)**: explicitly closes a ``<lib>`` object returned
-by ``ffi.dlopen()``.
-
-**ffi.RLTD_...**: constants: flags for ``ffi.dlopen()``.
-
-
-.. _`alternative allocators`:
-
-**ffi.new_allocator(alloc=None, free=None, should_clear_after_alloc=True)**:
-returns a new allocator. An "allocator" is a callable that behaves like
-``ffi.new()`` but uses the provided low-level ``alloc`` and ``free``
-functions. *New in version 1.2.*
-
-``alloc()`` is invoked with the size as sole argument. If it returns
-NULL, a MemoryError is raised. Later, if ``free`` is not None, it will
-be called with the result of ``alloc()`` as argument. Both can be either
-Python function or directly C functions. If only ``free`` is None, then no
-free function is called. If both ``alloc`` and ``free`` are None, the
-default alloc/free combination is used. (In other words, the call
-``ffi.new(*args)`` is equivalent to ``ffi.new_allocator()(*args)``.)
-
-If ``should_clear_after_alloc`` is set to False, then the memory
-returned by ``alloc()`` is assumed to be already cleared (or you are
-fine with garbage); otherwise CFFI will clear it.
-
-.. _initonce:
-
-**ffi.init_once(function, tag)**: run ``function()`` once. The
-``tag`` should be a primitive object, like a string, that identifies
-the function: ``function()`` is only called the first time we see the
-``tag``. The return value of ``function()`` is remembered and
-returned by the current and all future ``init_once()`` with the same
-tag. If ``init_once()`` is called from multiple threads in parallel,
-all calls block until the execution of ``function()`` is done. If
-``function()`` raises an exception, it is propagated and nothing is
-cached (i.e. ``function()`` will be called again, in case we catch the
-exception and try ``init_once()`` again). *New in version 1.4.*
-
-Example::
-
- from _xyz_cffi import ffi, lib
-
- def initlib():
- lib.init_my_library()
-
- def make_new_foo():
- ffi.init_once(initlib, "init")
- return lib.make_foo()
-
-``init_once()`` is optimized to run very quickly if ``function()`` has
-already been called. (On PyPy, the cost is zero---the JIT usually
-removes everything in the machine code it produces.)
-
-*Note:* one motivation__ for ``init_once()`` is the CPython notion of
-"subinterpreters" in the embedded case. If you are using the
-out-of-line API mode, ``function()`` is called only once even in the
-presence of multiple subinterpreters, and its return value is shared
-among all subinterpreters. The goal is to mimic the way traditional
-CPython C extension modules have their init code executed only once in
-total even if there are subinterpreters. In the example above, the C
-function ``init_my_library()`` is called once in total, not once per
-subinterpreter. For this reason, avoid Python-level side-effects in
-``function()`` (as they will only be applied in the first
-subinterpreter to run); instead, return a value, as in the following
-example::
-
- def init_get_max():
- return lib.initialize_once_and_get_some_maximum_number()
-
- def process(i):
- if i > ffi.init_once(init_get_max, "max"):
- raise IndexError("index too large!")
- ...
-
-.. __: https://bitbucket.org/cffi/cffi/issues/233/
-
-**ffi.list_types()**: Returns the user type names known to this FFI
-instance. This returns a tuple containing three lists of names:
-``(typedef_names, names_of_structs, names_of_unions)``. *New in
-version 1.6.*
-
-
-.. _`Preparing and Distributing modules`: cdef.html#loading-libraries
-
-
-Reference: conversions
-----------------------
-
-This section documents all the conversions that are allowed when
-*writing into* a C data structure (or passing arguments to a function
-call), and *reading from* a C data structure (or getting the result of a
-function call). The last column gives the type-specific operations
-allowed.
-
-+---------------+------------------------+------------------+----------------+
-| C type | writing into | reading from |other operations|
-+===============+========================+==================+================+
-| integers | an integer or anything | a Python int or | int() |
-| and enums | on which int() works | long, depending | |
-| `(*****)` | (but not a float!). | on the type | |
-| | Must be within range. | | |
-+---------------+------------------------+------------------+----------------+
-| ``char`` | a string of length 1 | a string of | int() |
-| | or another <cdata char>| length 1 | |
-+---------------+------------------------+------------------+----------------+
-| ``wchar_t`` | a unicode of length 1 | a unicode of | |
-| | (or maybe 2 if | length 1 | int() |
-| | surrogates) or | (or maybe 2 if | |
-| | another <cdata wchar_t>| surrogates) | |
-+---------------+------------------------+------------------+----------------+
-| ``float``, | a float or anything on | a Python float | float(), int() |
-| ``double`` | which float() works | | |
-+---------------+------------------------+------------------+----------------+
-|``long double``| another <cdata> with | a <cdata>, to | float(), int() |
-| | a ``long double``, or | avoid loosing | |
-| | anything on which | precision `(***)`| |
-| | float() works | | |
-+---------------+------------------------+------------------+----------------+
-| pointers | another <cdata> with | a <cdata> |``[]`` `(****)`,|
-| | a compatible type (i.e.| |``+``, ``-``, |
-| | same type or ``char*`` | |bool() |
-| | or ``void*``, or as an | | |
-| | array instead) `(*)` | | |
-+---------------+------------------------+ | |
-| ``void *``, | another <cdata> with | | |
-| ``char *`` | any pointer or array | | |
-| | type | | |
-+---------------+------------------------+ +----------------+
-| pointers to | same as pointers | | ``[]``, ``+``, |
-| structure or | | | ``-``, bool(), |
-| union | | | and read/write |
-| | | | struct fields |
-+---------------+------------------------+ +----------------+
-| function | same as pointers | | bool(), |
-| pointers | | | call `(**)` |
-+---------------+------------------------+------------------+----------------+
-| arrays | a list or tuple of | a <cdata> |len(), iter(), |
-| | items | |``[]`` `(****)`,|
-| | | |``+``, ``-`` |
-+---------------+------------------------+ +----------------+
-| ``char[]`` | same as arrays, or a | | len(), iter(), |
-| | Python string | | ``[]``, ``+``, |
-| | | | ``-`` |
-+---------------+------------------------+ +----------------+
-| ``wchar_t[]`` | same as arrays, or a | | len(), iter(), |
-| | Python unicode | | ``[]``, |
-| | | | ``+``, ``-`` |
-| | | | |
-+---------------+------------------------+------------------+----------------+
-| structure | a list or tuple or | a <cdata> | read/write |
-| | dict of the field | | fields |
-| | values, or a same-type | | |
-| | <cdata> | | |
-+---------------+------------------------+ +----------------+
-| union | same as struct, but | | read/write |
-| | with at most one field | | fields |
-+---------------+------------------------+------------------+----------------+
-
-`(*)` ``item *`` is ``item[]`` in function arguments:
-
- In a function declaration, as per the C standard, a ``item *``
- argument is identical to a ``item[]`` argument (and ``ffi.cdef()``
- doesn't record the difference). So when you call such a function,
- you can pass an argument that is accepted by either C type, like
- for example passing a Python string to a ``char *`` argument
- (because it works for ``char[]`` arguments) or a list of integers
- to a ``int *`` argument (it works for ``int[]`` arguments). Note
- that even if you want to pass a single ``item``, you need to
- specify it in a list of length 1; for example, a ``struct point_s
- *`` argument might be passed as ``[[x, y]]`` or ``[{'x': 5, 'y':
- 10}]``.
-
- As an optimization, the CPython version of CFFI assumes that a
- function with a ``char *`` argument to which you pass a Python
- string will not actually modify the array of characters passed in,
- and so passes directly a pointer inside the Python string object.
- (PyPy might in the future do the same, but it is harder because
- strings are not naturally zero-terminated in PyPy.)
-
-`(**)` C function calls are done with the GIL released.
-
- Note that we assume that the called functions are *not* using the
- Python API from Python.h. For example, we don't check afterwards
- if they set a Python exception. You may work around it, but mixing
- CFFI with ``Python.h`` is not recommended. (If you do that, on
- PyPy and on some platforms like Windows, you may need to explicitly
- link to ``libpypy-c.dll`` to access the CPython C API compatibility
- layer; indeed, CFFI-generated modules on PyPy don't link to
- ``libpypy-c.dll`` on their own. But really, don't do that in the
- first place.)
-
-`(***)` ``long double`` support:
-
- We keep ``long double`` values inside a cdata object to avoid
- loosing precision. Normal Python floating-point numbers only
- contain enough precision for a ``double``. If you really want to
- convert such an object to a regular Python float (i.e. a C
- ``double``), call ``float()``. If you need to do arithmetic on
- such numbers without any precision loss, you need instead to define
- and use a family of C functions like ``long double add(long double
- a, long double b);``.
-
-`(****)` Slicing with ``x[start:stop]``:
-
- Slicing is allowed, as long as you specify explicitly both ``start``
- and ``stop`` (and don't give any ``step``). It gives a cdata
- object that is a "view" of all items from ``start`` to ``stop``.
- It is a cdata of type "array" (so e.g. passing it as an argument to a
- C function would just convert it to a pointer to the ``start`` item).
- As with indexing, negative bounds mean really negative indices, like in
- C. As for slice assignment, it accepts any iterable, including a list
- of items or another array-like cdata object, but the length must match.
- (Note that this behavior differs from initialization: e.g. you can
- say ``chararray[10:15] = "hello"``, but the assigned string must be of
- exactly the correct length; no implicit null character is added.)
-
-`(*****)` Enums are handled like ints:
-
- Like C, enum types are mostly int types (unsigned or signed, int or
- long; note that GCC's first choice is unsigned). Reading an enum
- field of a structure, for example, returns you an integer. To
- compare their value symbolically, use code like ``if x.field ==
- lib.FOO``. If you really want to get their value as a string, use
- ``ffi.string(ffi.cast("the_enum_type", x.field))``.
+.. __: ref.html
diff --git a/doc/source/whatsnew.rst b/doc/source/whatsnew.rst
--- a/doc/source/whatsnew.rst
+++ b/doc/source/whatsnew.rst
@@ -18,6 +18,9 @@
haven't yet figured out the hacks needed to convince ``pydoc`` to
show more. (You can use ``dir(lib)`` but it is not most helpful.)
+* Yet another attempt at robustness against CPython's interpreter
+ shutdown logic
+
v1.5.2
======
@@ -98,7 +101,7 @@
the docs`__ of ``ffi.new_handle()`` has been here since v0.8!)
.. __: using.html#extern-python
-.. __: using.html#initonce
+.. __: ref.html#ffi-initonce
.. __: using.html#ffi-new-handle
@@ -147,7 +150,7 @@
which had unwanted side-effects. Try saying ``import setuptools``
first, which patches distutils...
-.. _`ffi.memmove()`: using.html#memmove
+.. _`ffi.memmove()`: ref.html#ffi-memmove
.. __: https://bugs.python.org/issue23246
.. __:
https://bitbucket.org/cffi/cffi/pull-requests/65/remove-_hack_at_distutils-which-imports/diff
.. _`calling convention`: using.html#windows-calling-conventions
@@ -209,7 +212,7 @@
support for `alternative allocators`__.
.. __: using.html#callbacks
-.. __: using.html#alternative-allocators
+.. __: ref.html#new-allocator
v1.1.2
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit