Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Adding Sphinx documentation for config and core

This patch moves all of the Doxygen documentation into a new Sphinx
document collection.  This makes it a lot easier to write the
documentation as running text, that happens to include a reference entry
for each type and function, rather than as an API reference that happens
to have explanatory text thrown in in places.
  • Loading branch information...
commit e00cd51572961e804c9d53a2f263271c67a7b7a0 1 parent e4a2fcf
@dcreager dcreager authored
Showing with 1,838 additions and 1,904 deletions.
  1. +2 −2 README.markdown
  2. +323 −0 docs/allocation.rst
  3. +87 −0 docs/attributes.rst
  4. +115 −0 docs/basic-types.rst
  5. +144 −0 docs/byte-order.rst
  6. +12 −11 docs/conf.py
  7. +83 −0 docs/config.rst
  8. +299 −0 docs/errors.rst
  9. +329 −0 docs/gc.rst
  10. +67 −0 docs/hash-values.rst
  11. +35 −3 docs/index.rst
  12. +126 −0 docs/net-addresses.rst
  13. +65 −0 docs/timestamps.rst
  14. +0 −9 include/libcork/config.h
  15. +2 −107 include/libcork/config/config.h
  16. +0 −8 include/libcork/config/gcc.h
  17. +0 −9 include/libcork/config/linux.h
  18. +0 −8 include/libcork/config/macosx.h
  19. +0 −54 include/libcork/core.h
  20. +14 −229 include/libcork/core/allocator.h
  21. +26 −80 include/libcork/core/attributes.h
  22. +46 −425 include/libcork/core/byte-order.h
  23. +3 −175 include/libcork/core/error.h
  24. +11 −156 include/libcork/core/gc.h
  25. +0 −52 include/libcork/core/hash.h
  26. +8 −227 include/libcork/core/net-addresses.h
  27. +0 −151 include/libcork/core/timestamp.h
  28. +6 −131 include/libcork/core/types.h
  29. +25 −44 src/libcork/core/allocator.c
  30. +10 −23 src/libcork/core/gc.c
View
4 README.markdown
@@ -55,8 +55,8 @@ on the library's design. In particular, we don't want to make any
assumptions about which build system you're embedding libcork into. We
happen to use CMake, but you might be using autotools, waf, scons, or
any number of others. Most cross-platform libraries follow the
-autotools model of perform some checks at compile time (maybe during a
-separate “configure” phase, maybe not) to choose the right API
+autotools model of performing some checks at compile time (maybe during
+a separate “configure” phase, maybe not) to choose the right API
implementation for the current platform. Since we can't assume a build
system, we have to take a different approach, and do as many checks as
we can using the C preprocessor. Any check that we can't make in the
View
323 docs/allocation.rst
@@ -0,0 +1,323 @@
+.. _allocation:
+
+*****************
+Custom allocation
+*****************
+
+.. highlight:: c
+
+::
+
+ #include <libcork/core.h>
+
+The types and functions in this section let you customize how libcork
+allocates objects and memory regions from the heap.
+
+There tend to be two common strategies prevelant in the wild for
+allowing the users of a library to provide custom allocation functions:
+the *global variable* approach, and the *context parameter* approach.
+In the global variable approach, there's a function that lets you
+register a custom allocator, which is then used for all allocations made
+by any function in the library. In the context parameter approach, the
+custom allocator is provided as a parameter to every function that needs
+to allocate memory. The global variable approach is usually seen as
+more convenient, since each function call is simpler, while the context
+parameter approach is more flexible, since you can use different
+allocators in different parts of a large program.
+
+In libcork, we use the context parameter approach; most libcork
+functions will take in a :c:type:`cork_alloc` pointer as their first
+parameter. This incurs a slight overhead in typing when you write code
+that uses libcork, but we feel that the increased flexibility is worth
+it.
+
+This means that if you're writing a library that uses libcork, you
+should write your functions to take in :c:type:`cork_alloc` pointers as
+parameters, just like libcork's functions do. This way, your library
+isn't tied to any particular custom allocator.
+
+If you're writing a program that uses libcork (or uses some other
+library that uses libcork), then part of your program's initialization
+will be to choose a particular allocator implementation to use, and then
+to pass that allocator object into any libcork functions that you call
+later on.
+
+This gives you a nice separation of concerns: choosing an allocator
+(whether :ref:`builtin <builtin-allocators>` or :ref:`custom
+<custom-allocators>`) is completely orthogonal to :ref:`using
+<using-allocators>` the allocator.
+
+
+.. _using-allocators:
+
+Using an allocator
+==================
+
+Given a custom allocator, you can use the functions in this section to
+allocate, reallocate, or free objects and memory regions.
+
+.. note::
+
+ One major difference between libcork's allocation functions and the
+ standard ``malloc``/``free`` function calls is that you need to
+ remember how large a memory region is when you reallocate or free it.
+ This tends not to be a problem, since in most cases, you're either
+ working with a fixed-size type (so you know at compile time what size
+ to pass into :c:func:`cork_free()`\ ), or you'll need to maintain the
+ size of a variable-size buffer anyway.
+
+
+Size-based functions
+--------------------
+
+.. function:: void \*cork_malloc(struct cork_alloc \*alloc, size_t size)
+
+ Allocates a new memory region of the given *size*. Returns ``NULL``
+ if the region can't be allocated.
+
+.. function:: void \*cork_realloc(struct cork_alloc \*alloc, void \*ptr, size_t old_size, size_t new_size)
+
+ Reallocates a memory region to a different size. If the memory
+ region can't be resized, then we free the existing memory region and
+ return ``NULL``. Otherwise we return a pointer to the reallocated
+ memory region. We don't make any guarantees about whether the
+ existing memory region can be reused, so the return value may or may
+ not be equal to *ptr*.
+
+.. function:: void cork_free(struct cork_alloc \*alloc, void \*ptr, size_t old_size)
+
+ Frees a memory region of the given size. It is your responsibility
+ to ensure that *old_size* matches the size that was used to allocate
+ (or most recently reallocate) *ptr*.
+
+
+Type-based functions
+--------------------
+
+.. function:: type \*cork_new(struct cork_alloc \*alloc, TYPE type)
+
+ Allocates a new instance of *type*. The size of the memory region to
+ allocate is calculated using the ``sizeof`` operator, and the result
+ will be automatically cast to ``type *``. Returns ``NULL`` if the
+ region can't be allocated.
+
+.. function:: void cork_delete(struct cork_alloc \*alloc, TYPE type, type \*instance)
+
+ Frees an instance of *type*. The size of the memory region is
+ calculated using the ``sizeof`` operator.
+
+
+String-related functions
+------------------------
+
+.. function:: const char \*cork_strdup(struct cork_alloc \*alloc, const char \*str)
+
+ Creates a copy of the given C string. You shouldn't modify the
+ contents of the copied string. You must use :c:func:`cork_strfree()`
+ to free the string when you're done with it.
+
+.. function:: void cork_strfree(struct cork_alloc \*alloc, const char \*str)
+
+ Frees *str*, which must have been created using
+ :c:func:`cork_strdup()`.
+
+
+.. _builtin-allocators:
+
+Built-in allocators
+===================
+
+When writing an application, you'll often just want to use the standard
+``malloc`` allocator provided by your C library. The functions in this
+section provide libcork custom allocator wrappers for this use case.
+
+.. note::
+
+ You'll still need to free your custom allocator object using
+ :c:func:`cork_allocator_free` as part of your program's cleanup.
+
+
+.. function:: struct cork_alloc \*cork_allocator_new_malloc(void)
+
+ Creates a new allocator object that uses the standard ``malloc``,
+ ``realloc``, and ``free`` functions.
+
+.. function:: struct cork_alloc \*cork_allocator_new_debug(void)
+
+ Creates a new allocator object that uses the standard ``malloc``,
+ ``realloc``, and ``free`` functions, and also performs the following
+ tests on the memory regions that are created by allocator:
+
+ * When an object is freed, we verify that the size of the object
+ that's passed into :c:func:`cork_free()` matches the size that was
+ used to allocate the object.
+
+ .. note::
+
+ This function is useful for test cases, but probably shouldn't be
+ used in production code.
+
+
+.. _custom-allocators:
+
+Writing a custom allocator
+==========================
+
+.. note::
+
+ You can safely ignore the contents of this section if you only plan
+ on using one of the :ref:`builtin-allocators`.
+
+
+No extra state
+--------------
+
+In the simplest case, your custom allocator is simply a wrapper around
+an existing allocation library. In this case, you just need to provide
+a function whose signature matches :c:type:`cork_alloc_func`, and then
+use :c:func:`cork_allocator_new()` to create your custom allocator
+object.
+
+This approach works great if you can call global functions in your
+wrapper function. (This is how the standard ``malloc``/``free`` wrapper
+is written, for instance.) If you need to maintain additional state,
+you'll have to write your own :c:type:`cork_alloc` :ref:`subclass
+<allocator-subclass>`.
+
+.. type:: void \* (\*cork_alloc_func)(struct cork_alloc \*alloc, void \*ptr, size_t osize, size_t nsize)
+
+ A function that can allocate, reallocate, or free a memory buffer.
+ *ptr* is a pointer to an existing memory location, *osize* is the
+ allocated size of this existing memory location, and *nsize* is the
+ desired new size of the allocation. (The caller will guarantee that
+ *ptr* is ``NULL`` iff *osize* is 0, and that *osize* and *nsize* will
+ not both be 0.)
+
+ This single function definition encompasses the standard ``malloc``,
+ ``realloc``, and ``free`` calls. If *osize* is 0, then the function
+ should allocate a new heap object, similar to ``malloc``. If neither
+ *osize* nor *nsize* are 0, then the function should reallocate an
+ existing heap object, similar to ``realloc``. If *osize* is not 0,
+ but *nsize* is 0, then the function should free an existing heap
+ object, similar to ``free``.
+
+ If the function is asked to allocate or reallocate a heap object, it
+ should return ``NULL`` if the allocation fails. If a reallocation
+ fails, it is the function's responsibility to free the existing heap
+ object, to prevent memory leaks.
+
+ If the function is asked to free an existing heap object, the
+ function must always returns ``NULL``.
+
+.. function:: struct cork_alloc \*cork_allocator_new(cork_alloc_func alloc_func)
+
+ Creates a new custom allocator object from the given allocation
+ function. You can use this function if you don't need to maintain
+ any additional state in your custom allocator object. In this case,
+ the ``struct cork_alloc`` type is completely sufficient for your
+ needs.
+
+ We'll allocate the ``struct cork_alloc`` instance using the
+ allocation function. You don't need to provide a :c:member:`free
+ <cork_alloc.free>` function; since we know how big the allocation
+ object will be, we can provide the correct ``free`` function for you.
+
+.. function:: void cork_allocator_free(struct cork_alloc \*alloc)
+
+ Finalizes and frees an allocator object. You should call this
+ function on any custom allocator object when you're done with it;
+ regardless of whether it's a custom implementation you've written
+ yourself, or one of the :ref:`builtin-allocators`.
+
+ .. note::
+
+ Don't confuse this function with :c:func:`cork_free()`. This
+ function is used to free the *allocator itself* when you're done
+ with it, whereas :c:func:`cork_free()` uses the custom allocator
+ to free some other memory region.
+
+
+.. _allocator-subclass:
+
+Allocator subclasses
+--------------------
+
+If you need to maintain any additional state, you should embed a
+``struct cork_alloc`` instance inside of some other type::
+
+ struct my_custom_alloc {
+ struct cork_alloc parent;
+ /* additional fields */
+ };
+
+ static void *
+ my_custom_alloc_func(struct cork_alloc *valloc, void *ptr, size_t os, size_t ns)
+ {
+ struct my_custom_alloc *alloc =
+ cork_container_of(valloc, struct my_custom_alloc, parent);
+ /* work some magic */
+ }
+
+Note how your :c:member:`allocation function <cork_alloc.alloc>` will
+always be given a pointer to a ``struct cork_alloc``. You can use the
+:c:func:`cork_container_of()` macro to obtain a pointer to your “real”
+allocator instance.
+
+You'll also need to provide functions for creating and destroying your
+custom allocator object. Notice how the finalizer function is
+``static``, since you'll still use the public
+:c:func:`cork_allocator_free()` function to free the allocator object.
+
+::
+
+ static void
+ my_custom_alloc_free(struct cork_alloc *valloc)
+ {
+ struct my_custom_alloc *alloc =
+ cork_container_of(valloc, struct my_custom_alloc, parent);
+ /* do any necessary cleanup */
+
+ /* Use the allocator to free itself */
+ cork_delete(valloc, struct my_custom_alloc, valloc);
+ }
+
+ struct cork_alloc *
+ my_custom_alloc_new(void)
+ {
+ /* Mimic a call to cork_new to create the allocator */
+ struct my_custom_alloc *alloc =
+ my_custom_alloc_func(NULL, NULL, 0, sizeof(struct my_custom_alloc));
+ if (alloc == NULL) {
+ return NULL;
+ }
+
+ /* Perform any additional initialization */
+
+ /* We need this trick since the alloc field is const in struct
+ * cork_alloc. (And by using a union, we don't violate any strict
+ * aliasing rules.) */
+ union {
+ struct cork_alloc *original;
+ cork_alloc_func *alloc;
+ } mutable;
+ mutable.original = &alloc->parent;
+ *mutable.alloc = my_custom_alloc_func;
+
+ alloc->parent.free = my_custom_alloc_free;
+ return &alloc->parent;
+ }
+
+
+.. type:: struct cork_alloc
+
+ .. member:: const cork_alloc_func alloc
+
+ The allocation function that we'll call to allocate and deallocate
+ memory regions.
+
+ .. member:: void (\*free)(struct cork_alloc \*alloc)
+
+ A function that will be used to free the ``struct cork_alloc``
+ instance when it's no longer needed. (We need a customizable
+ function here because we don't know how big the overall type is if
+ you embed the ``struct cork_alloc`` within some other type.)
View
87 docs/attributes.rst
@@ -0,0 +1,87 @@
+.. _attributes:
+
+*******************
+Compiler attributes
+*******************
+
+.. highlight:: c
+
+::
+
+ #include <libcork/core.h>
+
+The macros in this section define compiler-agnostic versions of several
+common compiler attributes.
+
+
+.. macro:: CORK_ATTR_CONST
+
+ Declare a “constant” function. The return value of a constant
+ function can only depend on its parameters. This is slightly more
+ strict than a “pure” function (declared by
+ :c:macro:`CORK_ATTR_PURE`); a constant function is not allowed to
+ read from global variables, whereas a pure function is.
+
+ .. note:: Note that the compiler won't verify that your function
+ meets the requirements of a constant function. Instead, this
+ attribute notifies the compiler of your intentions, which allows
+ the compiler to assume more about your function when optimizing
+ code that calls it.
+
+ ::
+
+ int square(int x) CORK_ATTR_CONST;
+
+
+.. macro:: CORK_ATTR_MALLOC
+
+ Declare a function that returns a newly allocated pointer. The
+ compiler can use this information to generate more accurate aliasing
+ information, since it can infer that the result of the function
+ cannot alias any other existing pointer.
+
+ ::
+
+ void *custom_malloc(size_t size) CORK_ATTR_MALLOC;
+
+
+.. macro:: CORK_ATTR_PRINTF(format_index, args_index)
+
+ Declare a function that takes in ``printf``\ -like parameters.
+ *format_index* is the index (starting from 1) of the parameter that
+ contains the ``printf`` format string. *args_index* is the index of
+ the first parameter that contains the data to format.
+
+
+.. macro:: CORK_ATTR_PURE
+
+ Declare a “pure” function. The return value of a pure function can
+ only depend on its parameters, and on global variables.
+
+ ::
+
+ static int _next_id;
+ int get_next_id(void) CORK_ATTR_PURE;
+
+
+.. macro:: CORK_ATTR_SENTINEL
+
+ Declare a var-arg function whose last parameter must be a ``NULL``
+ sentinel value. When the compiler supports this attribute, it will
+ check the actual parameters whenever this function is called, and
+ ensure that the last parameter is a ``NULL``.
+
+
+.. macro:: CORK_ATTR_UNUSED
+
+ Declare a entity that might not be used. This lets you keep
+ ``-Wall`` activated in several cases where you're obligated to define
+ something that you don't intend to use.
+
+ ::
+
+ CORK_ATTR_UNUSED static void
+ unused_function(void)
+ {
+ CORK_ATTR_UNUSED int unused_value;
+ }
View
115 docs/basic-types.rst
@@ -0,0 +1,115 @@
+.. _basic-types:
+
+***********
+Basic types
+***********
+
+.. highlight:: c
+
+::
+
+ #include <libcork/core.h>
+
+The types in this section ensure that the C99 integer types are
+available, regardless of platform. We also define some preprocessor
+macros that give the size of the non-fixed-size standard types. In
+addition, libcork defines some useful low-level types:
+
+.. toctree::
+ :maxdepth: 1
+
+ net-addresses
+ timestamps
+ hash-values
+
+Integral types
+==============
+
+.. type:: bool
+
+ A boolean. Where possible, we simply include ``<stdbool.h>`` to get
+ this type. It might be ``typedef``\ ed to ``int``\ . We also make
+ sure that the following constants are defined:
+
+ .. var:: bool false
+ bool true
+
+.. type:: int8_t
+ uint8_t
+ int16_t
+ uint16_t
+ int32_t
+ uint32_t
+ int64_t
+ uint64_t
+
+ Signed and unsigned, fixed-size integral types.
+
+.. type:: intptr_t
+ uintptr_t
+
+ Signed and unsigned integers that are guaranteed to be big enough to
+ hold a type-cast ``void *``\ .
+
+.. type:: size_t
+
+ An unsigned integer big enough to hold the size of a memory object,
+ or a maximal array index.
+
+.. type:: ptrdiff_t
+
+ A signed integer big enough to hold the difference between two
+ pointers.
+
+Size macros
+===========
+
+.. macro:: CORK_SIZEOF_SHORT
+ CORK_SIZEOF_INT
+ CORK_SIZEOF_LONG
+ CORK_SIZEOF_POINTER
+
+ The size (in bytes) of the ``short``, ``int``, ``long``, and ``void
+ *`` types, respectively.
+
+Embedded ``struct``\ s
+======================
+
+Quite often a callback function or API will take in a pointer to a
+particular ``struct``, with the expectation that you can embed that
+``struct`` into some other type for extension purposes. Kind of a
+bastardized subclassing mechanism for C code. The doubly-linked list
+module is a perfect example; you're meant to embed
+:c:type:`cork_dllist_item` within the linked list element type. You can
+use the following macro to obtain the pointer to the containing
+(“subclass”) ``struct``, when given a pointer to the contained
+(“superclass”) ``struct``:
+
+.. function:: struct_type \*cork_container_of(field_type \*field, TYPE struct_type, FIELD field_name)
+
+ The *struct_type* parameter must be the name of a ``struct`` type,
+ *field_name* must be the name of some field within that
+ ``struct``, and *field* must be a pointer to an instance of that
+ field. The macro returns a pointer to the containing ``struct``.
+ So, given the following definitions::
+
+ struct superclass {
+ int a;
+ };
+
+ struct subclass {
+ int b;
+ struct superclass parent;
+ };
+
+ struct subclass instance;
+
+ then the following identity holds::
+
+ cork_container_of(&instance.parent, struct subclass, parent) == &instance
+
+ .. note:: When the superclass ``struct`` appears as the first element
+ of the subclass ``struct``, you can obtain the same effect using a
+ simple type-cast. However, the ``cork_container_of`` macro is
+ more robust, since it also works when the superclass ``struct``
+ appears later on in the subclass ``struct``.
View
144 docs/byte-order.rst
@@ -0,0 +1,144 @@
+.. _byte-order:
+
+**********
+Byte order
+**********
+
+.. highlight:: c
+
+::
+
+ #include <libcork/core.h>
+
+This section contains definitions for determining the endianness of the
+host system, and for byte-swapping integer values of various sizes.
+
+
+Endianness detection
+====================
+
+.. macro:: CORK_LITTLE_ENDIAN
+ CORK_BIG_ENDIAN
+ CORK_HOST_ENDIANNESS
+ CORK_OTHER_ENDIANNESS
+
+ The ``CORK_HOST_ENDIANNESS`` macro can be used to determine the
+ endianness of the host system. It will be equal to either
+ ``CORK_LITTLE_ENDIAN`` or ``CORK_BIG_ENDIAN``. (The actual values
+ don't matter; you should always compare against the predefined
+ constants.) The ``CORK_OTHER_endianness`` macro is defined to be the
+ opposite endianness as ``CORK_HOST_ENDIANNESS``. A common use case
+ would be something like::
+
+ #if CORK_HOST_endianness == CORK_LITTLE_ENDIAN
+ /* do something to little-endian values */
+ #else
+ /* do something to big-endian values */
+ #endif
+
+.. macro:: CORK_HOST_ENDIANNESS_NAME
+ CORK_OTHER_ENDIANNESS_NAME
+
+ These macros give you a human-readable name of the host's endianness.
+ You can use this in debugging messages.
+
+ .. note:: You should *not* use these macros to detect the
+ endianness of the system, since we might change their definitions
+ at some point to support localization. For that,
+ use :macro:`CORK_LITTLE_ENDIAN` and :macro:`CORK_BIG_ENDIAN`.
+
+
+Byte swapping
+=============
+
+Swapping arbitrary expressions
+------------------------------
+
+All of the macros in this section take in an rvalue (i.e., any arbitrary
+expression) as a parameter. The result of the swap is returned as the
+value of the macro.
+
+.. function:: uint16_t CORK_SWAP_UINT16(uint16_t value)
+ uint32_t CORK_SWAP_UINT32(uint32_t value)
+ uint64_t CORK_SWAP_UINT64(uint64_t value)
+
+ These functions always perform a byte-swap, regardless of the
+ endianness of the host system.
+
+.. function:: uint16_t CORK_UINT16_BIG_TO_HOST(uint16_t value)
+ uint32_t CORK_UINT32_BIG_TO_HOST(uint32_t value)
+ uint64_t CORK_UINT64_BIG_TO_HOST(uint64_t value)
+
+ These functions convert a big-endian (or network-endian) value into
+ host endianness. (I.e., they only perform a swap if the current host
+ is little-endian.)
+
+.. function:: uint16_t CORK_UINT16_HOST_TO_BIG(uint16_t value)
+ uint32_t CORK_UINT32_HOST_TO_BIG(uint32_t value)
+ uint64_t CORK_UINT64_HOST_TO_BIG(uint64_t value)
+
+ These functions convert a host-endian value into big (or network)
+ endianness. (I.e., they only perform a swap if the current host is
+ little-endian.)
+
+.. function:: uint16_t CORK_UINT16_LITTLE_TO_HOST(uint16_t value)
+ uint32_t CORK_UINT32_LITTLE_TO_HOST(uint32_t value)
+ uint64_t CORK_UINT64_LITTLE_TO_HOST(uint64_t value)
+
+ These functions convert a little-endian value into host endianness.
+ (I.e., they only perform a swap if the current host is big-endian.)
+
+.. function:: uint16_t CORK_UINT16_HOST_TO_LITTLE(uint16_t value)
+ uint32_t CORK_UINT32_HOST_TO_LITTLE(uint32_t value)
+ uint64_t CORK_UINT64_HOST_TO_LITTLE(uint64_t value)
+
+ These functions convert a host-endian value into little endianness.
+ (I.e., they only perform a swap if the current host is big-endian.)
+
+Swapping values in place
+------------------------
+
+The macros in this section swap an integer *in place*, which means that
+the original value is overwritten with the result of the swap. To
+support this, you must pass in an *lvalue* as the parameter to the
+macro. (Note that you don't pass in a *pointer* to the original value;
+these operations are implemented as macros, and you just need to provide
+a reference to the variable to be swapped.)
+
+.. function:: void CORK_SWAP_UINT16_IN_PLACE(uint16_t &value)
+ void CORK_SWAP_UINT32_IN_PLACE(uint32_t &value)
+ void CORK_SWAP_UINT64_IN_PLACE(uint64_t &value)
+
+ These functions always perform a byte-swap, regardless of the
+ endianness of the host system.
+
+.. function:: void CORK_UINT16_BIG_TO_HOST_IN_PLACE(uint16_t &value)
+ void CORK_UINT32_BIG_TO_HOST_IN_PLACE(uint32_t &value)
+ void CORK_UINT64_BIG_TO_HOST_IN_PLACE(uint64_t &value)
+
+ These functions convert a big-endian (or network-endian) value into
+ host endianness, and vice versa. (I.e., they only perform a swap if
+ the current host is little-endian.)
+
+.. function:: void CORK_UINT16_HOST_TO_BIG_IN_PLACE(uint16_t &value)
+ void CORK_UINT32_HOST_TO_BIG_IN_PLACE(uint32_t &value)
+ void CORK_UINT64_HOST_TO_BIG_IN_PLACE(uint64_t &value)
+
+ These functions convert a host-endian value into big (or network)
+ endianness. (I.e., they only perform a swap if the current host is
+ little-endian.)
+
+.. function:: void CORK_UINT16_LITTLE_TO_HOST_IN_PLACE(uint16_t &value)
+ void CORK_UINT32_LITTLE_TO_HOST_IN_PLACE(uint32_t &value)
+ void CORK_UINT64_LITTLE_TO_HOST_IN_PLACE(uint64_t &value)
+
+ These functions convert a little-endian value into host endianness, and
+ vice versa. (I.e., they only perform a swap if the current host is
+ big-endian.)
+
+.. function:: void CORK_UINT16_HOST_TO_LITTLE_IN_PLACE(uint16_t &value)
+ void CORK_UINT32_HOST_TO_LITTLE_IN_PLACE(uint32_t &value)
+ void CORK_UINT64_HOST_TO_LITTLE_IN_PLACE(uint64_t &value)
+
+ These functions convert a host-endian value into little endianness.
+ (I.e., they only perform a swap if the current host is big-endian.)
View
23 docs/conf.py
@@ -25,7 +25,7 @@
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
-extensions = []
+extensions = ['sphinx.ext.mathjax']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
@@ -40,8 +40,8 @@
master_doc = 'index'
# General information about the project.
-project = u'APPNAME'
-copyright = u'2011, COMPANY'
+project = u'libcork'
+copyright = u'2011, RedJack, LLC'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
@@ -69,7 +69,8 @@
exclude_patterns = ['_build']
# The reST default role (used for this markup: `text`) to use for all documents.
-#default_role = None
+default_role = 'c:func'
+primary_domain = 'c'
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
@@ -166,7 +167,7 @@
#html_file_suffix = None
# Output file base name for HTML help builder.
-htmlhelp_basename = 'APPNAME-doc'
+htmlhelp_basename = 'libcork-doc'
# -- Options for LaTeX output --------------------------------------------------
@@ -185,8 +186,8 @@
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
- ('index', 'APPNAME.tex', u'APPNAME Documentation',
- u'COMPANY', 'manual'),
+ ('index', 'libcork.tex', u'libcork documentation',
+ u'RedJack, LLC', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
@@ -215,8 +216,8 @@
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
- ('index', 'APPNAME', u'APPNAME Documentation',
- [u'COMPANY'], 1)
+ ('index', 'libcork', u'libcork documentation',
+ [u'RedJack, LLC'], 1)
]
# If true, show URL addresses after external links.
@@ -229,8 +230,8 @@
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
- ('index', 'APPNAME', u'APPNAME Documentation',
- u'COMPANY', 'APPNAME', 'One line description of project.',
+ ('index', 'libcork', u'libcork documentation',
+ u'RedJack, LLC', 'libcork', 'One line description of project.',
'Miscellaneous'),
]
View
83 docs/config.rst
@@ -0,0 +1,83 @@
+.. _config:
+
+*******************
+Configuring libcork
+*******************
+
+.. highlight:: c
+
+::
+
+ #include <libcork/config.h>
+
+Several libcork features have different implementations on different
+platforms. Since we want libcork to be easily embeddable into projects
+with a wide range of build systems, we try to autodetect which
+implementations to use, using only the C preprocessor and the predefined
+macros that are available on the current system.
+
+This module provides a layer of indirection, with all of the
+preprocessor-based autodetection in one place. This module's task is to
+define a collection of libcork-specific configuration macros, which all
+other libcork modules will use to select which implementation to use.
+
+This design also lets you skip the autodetection, and provide values for
+the configuration macros directly. This is especially useful if you're
+embedding libcork into another project, and already have a ``configure``
+step in your build system that performs platform detection. See
+:c:macro:`CORK_CONFIG_SKIP_AUTODETECT` for details.
+
+.. note::
+
+ The autodetection logic is almost certainly incomplete. If you need
+ to port libcork to another platform, this is where an important chunk
+ of edits will take place. Patches are welcome!
+
+
+.. _configuration-macros:
+
+Configuration macros
+====================
+
+This section lists all of the macros that are defined by libcork's
+autodetection logic. Other libcork modules will use the values of these
+macros to choose among the possible implementations.
+
+.. macro:: CORK_CONFIG_IS_BIG_ENDIAN
+ CORK_CONFIG_IS_LITTLE_ENDIAN
+
+ Whether the current system is big-endian or little-endian. Exactly
+ one of these macros should be defined to ``1``; the other should be
+ defined to ``0``.
+
+
+.. macro:: CORK_CONFIG_HAVE_GCC_ATTRIBUTES
+
+ Whether the GCC-style syntax for compiler attributes is available.
+ (This doesn't imply that the compiler is specifically GCC.) Should
+ be defined to ``0`` or ``1``.
+
+
+.. _skipping-autodetection:
+
+Skipping autodetection
+======================
+
+
+.. macro:: CORK_CONFIG_SKIP_AUTODETECT
+
+ If you want to skip libcork's autodetection logic, then you are
+ responsible for providing the appropriate values for all of the
+ macros defined in :ref:`configuration-macros`. To do this, have your
+ build system define this macro, with a value of ``1``. This will
+ override the default value of ``0`` provided in the
+ ``libcork/config/config.h`` header file.
+
+ Then, create (or have your build system create) a
+ ``libcork/config/custom.h`` header file. You can place this file
+ anywhere in your header search path. We will load that file instead
+ of libcork's autodetection logic. Place the appropriate definitions
+ for each of the configuration macros into this file. If needed, you
+ can generate this file as part of the ``configure`` step of your
+ build system; the only requirement is that it's available once you
+ start compiling the libcork source files.
View
299 docs/errors.rst
@@ -0,0 +1,299 @@
+.. _errors:
+
+***************
+Error reporting
+***************
+
+.. highlight:: c
+
+::
+
+ #include <libcork/core.h>
+
+This section defines an API for reporting error conditions. It's
+loosely modeled on glib's *GError* API.
+
+The standard POSIX approach for reporting errors is to return an integer
+status code, and to store error codes into the ``errno`` global
+variable. This approach has a couple of drawbacks. The first is that
+you have to ensure that ``errno`` is placed in thread-local storage, so
+that separate threads have their own error condition variables. The
+second, and in our mind more important, is that the set of error codes
+is fixed and platform-dependent. It's difficult to add new error codes
+to represent application-level error conditions.
+
+The libcork error API is a way around this. Errors are represented by a
+tuple of an *error class* and an *error code*, along with a
+human-readable string description of the error. Error classes represent
+broad classes of errors, and usually correspond to a library or to an
+important group of related functions within a library. An error class
+is represented by a hash of some string identifying the library or group
+of functions. This “hash of a string” approach makes it easy to define
+new error classes, without needing any centralized mechanism for
+assigning IDs to the various classes. An error code is a simple
+integer, and only needs to be unique within a particular error class.
+This means that each error class is free to define its error codes
+however it wishes (usually via an ``enum`` type), without having to
+worry about them clashing with the codes of any other class.
+
+.. type:: struct cork_error
+
+ An object representing a particular error condition. This type
+ should be considered opaque; you should use the various accessor
+ functions described below to interrogate an error instance.
+
+.. macro:: CORK_ERROR_NONE
+
+ A special error class that signals that no error occurred.
+
+
+Calling a function that can return an error
+-------------------------------------------
+
+There are two basic forms for a function that can produce an error. The
+first is if the function returns a single pointer as its result::
+
+ TYPE *
+ my_function(/* parameters */, struct cork_error *err);
+
+The second is for any other function::
+
+ int
+ my_function(/* parameters */, struct cork_error *err);
+
+If you only want to check whether an error occurred or not, you can pass
+in ``NULL`` for the *err* parameter, and simply check the function's
+return value. If an error occurs, the function will return either
+``NULL`` or ``-1``, depending on its return type. Success will be
+indicated by a non-\ ``NULL`` pointer or a ``0``. (More complex return
+value schemes are possible, if the function needs to signal more than a
+simple “success” or “failure”; in that case, you'll need to check the
+function's documentation for details.)
+
+If you want to know specifics about the error, you need to create a
+:c:type:`cork_error` instance to pass in for the *err* parameter. The
+easiest way to do this is to simply allocate one on the stack::
+
+ struct cork_alloc *alloc = /* obtained elsewhere */;
+ struct cork_error err = CORK_ERROR_INIT(alloc);
+
+or::
+
+ struct cork_alloc *alloc = /* obtained elsewhere */;
+ struct cork_error err;
+ cork_error_init(alloc, &err);
+
+.. function:: bool cork_error_init(struct cork_alloc \*alloc, struct cork_error \*err)
+ struct cork_error CORK_ERROR_INIT(struct cork_alloc \*alloc)
+
+ Initializes an error instance that you've allocated on the stack or
+ in some other storage. The ``CORK_ERROR_INIT`` version can only be
+ used as a static initializer.
+
+When the function returns, there are several functions that you can use
+to interrogate the error instance.
+
+.. function:: bool cork_error_occurred(const struct cork_error \*err)
+
+ After passing *err* into a function that might return an error
+ condition, you can use this function to check whether an error
+ actually occurred.
+
+.. function:: cork_error_class cork_error_class(const struct cork_error \*err)
+ cork_error_code cork_error_code(const struct cork_error \*err)
+
+ Returns the class and code of an error condition. If no error
+ occurred, the error class will be :c:macro:`CORK_ERROR_NONE`, and the
+ code will be ``0``.
+
+.. function:: const char \*cork_error_message(const struct cork_error \*err)
+
+ Returns the human-readable string description of the error. If no
+ error occurred, the result of this function is undefined.
+
+.. note::
+
+ If you pass in a :c:type:`cork_error` instance to the function call,
+ you don't actually have to check the function's return value to see
+ if an error occurred; you can just call
+ :c:func:`cork_error_occurred()`.
+
+When you're done with your error instance, you should use
+``cork_error_done`` to dispose of it.
+
+.. function:: void cork_error_done(struct cork_error \*err)
+
+ Finalizes an error condition instance.
+
+
+Writing a function that can return an error
+-------------------------------------------
+
+When writing a function that might produce an error condition, your
+function signature should follow one of the two standard patterns
+described above::
+
+ int
+ my_function(/* parameters */, struct cork_error *err);
+
+ TYPE *
+ my_function(/* parameters */, struct cork_error *err);
+
+You should return ``-1`` or ``NULL`` if an error occurs, and ``0`` or a
+non-\ ``NULL`` pointer if it succeeds. If ``NULL`` is a valid
+“successful” result of the function, you should use the first form, and
+define a ``TYPE **`` output parameter to return the actual pointer
+value. (If you're using the first form, you can use additional return
+codes if there are other possible results besides a simple “success” and
+“failure”.)
+
+If your function results in an error, you should use the
+:c:func:`cork_error_set()` function to fill in the *err* parameter with
+details about the error, in addition to returning a ``NULL`` or ``-1``
+error code. Note that ``cork_error_set`` works just fine if the caller
+passed in a ``NULL`` *err* parameter (signifying that they don't care
+about the details of any error that occurs). In that case,
+``cork_error_set`` behaves just like a no-op.
+
+.. function:: void cork_error_set(struct cork_error \*err, cork_error_class cls, cork_error_code code, const char \*format, ...)
+
+ Fill in a :c:type:`cork_error` with information about an error
+ condition. If *err* is ``NULL``, then nothing occurs. Otherwise,
+ *err* will be filled in with the given error class and code, and with
+ a string description that's constructed from the given ``printf``
+ format and values.
+
+
+Propagating errors from nested function calls
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Things can be slightly more complicated if you're writing a function
+that returns an error condition, which in turn calls a different
+function that returns an error condition.
+
+Most of the time, you can get away with passing in your own *err*
+parameter when calling the nested function::
+
+ int
+ outer_function(/* parameters */, struct cork_error *err)
+ {
+ int rc;
+
+ rc = inner_function(/* more parameters */, err);
+ if (rc == -1) {
+ return rc;
+ }
+
+ /* do some more stuff */
+ return 0;
+ }
+
+This works because you don't need to interrogate *err* to determine if
+an error occurred; you can always check the inner function's result
+(looking for ``-1`` or ``NULL``).
+
+The complications show up if you need to check the error condition. For
+instance, your outer function might be able to recover from some error
+conditions, but not others. In that case, you **can't** pass your *err*
+parameter into the inner function, since the caller is free to pass in a
+``NULL`` :c:type:`cork_error` pointer. And that wouldn't be good, since
+then you wouldn't have an error condition to interrogate! Instead, you
+need to define your own ``cork_error`` instance, and then *clear* or
+*propagate* that into the caller's *err* instance as appropriate::
+
+ int
+ outer_function(struct cork_alloc *alloc, /* params */, struct cork_error *err)
+ {
+ struct cork_error suberr = CORK_ERROR_INIT(alloc);
+
+ inner_function(/* more params */, &suberr);
+ if (cork_error_occurred(&suberr)) {
+ /* As an example, let's say that we can recover from a
+ * CORK_NET_ADDRESS_PARSE_ERROR. */
+ if ((cork_error_class(&suberr) == CORK_NET_ADDRESS_ERROR) &&
+ (cork_error_code(&suberr) == CORK_NET_ADDRESS_PARSE_ERROR)) {
+ /* Perform some kind of recovery, and then clean up the error */
+ cork_error_done(&suberr);
+ } else {
+ /* We can't recover from this error, so propagate it on */
+ cork_error_propagate(err, &suberr);
+ return -1;
+ }
+ }
+
+ /* etc */
+ return 0;
+ }
+
+.. function:: void cork_error_clear(struct cork_error \*err)
+
+ Clears an error condition instance. If *err* is ``NULL``, then we
+ don't do anything, since there's no error to clear.
+
+.. function:: void cork_error_propagate(struct cork_error \*err, struct cork_error \*suberr)
+
+ Propagates an error condition from one instance to another. In the
+ most common case, *err* will be the error instance passed in from the
+ current function's caller, while *suberr* will be an instance
+ allocated in the current function. In other words, *err* might be
+ ``NULL``, while *suberr* never should be.
+
+ If *err* is ``NULL``, indicating that your caller doesn't care about
+ the details of the error, then we just finalize *suberr*. If *err*
+ is non-\ ``NULL``, then we move the contents of *suberr* into *err*.
+
+ In both cases, *suberr* will be finalized when
+ ``cork_error_propagate`` returns. You **should not** call
+ :c:func:`cork_error_done` on *suberr* afterwards.
+
+
+Defining a new error class
+--------------------------
+
+If none of the built-in error classes and codes suffice for an error
+condition that you need to report, you'll have to define our own error
+class. The first step is to decide on some string that will represent
+your error class. This string must be unique across all error classes,
+so it should include (at least) some representation of the library name.
+In libcork itself, we always use the name of the header file that the
+error class is defined in. (This limits us to one error class per
+header, but that's not a deal-breaker.) Thus, the
+:c:macro:`CORK_NET_ADDRESS_ERROR` error class is represented by the
+string ``"libcork/core/net-addresses.h"``.
+
+Given this string, you can produce the error class's hash value using
+the ``extras/hashstring.py`` script that's included in the libcork
+source::
+
+ $ python extras/hashstring.py "libcork/core/net-addresses.h"
+ 0x1f76fedf
+
+The next step is to define the error codes within the class. This is
+best done by creating an ``enum`` class. Taken together, we have the
+following definitions for the error conditions in the
+:ref:`net-addresses` module::
+
+ /* hash of "libcork/core/net-addresses.h" */
+ #define CORK_NET_ADDRESS_ERROR 0x1f76fedf
+
+ enum cork_net_address_error {
+ /* An unknown error while parsing a network address. */
+ CORK_NET_ADDRESS_UNKNOWN_ERROR,
+ /* A parse error while parsing a network address. */
+ CORK_NET_ADDRESS_PARSE_ERROR
+ };
+
+This gives us a constant for the error class, and a set of constants for
+each error code within the class, all of which start with a standard
+namespace prefix (``CORK_NET_ADDRESS_``).
+
+.. type:: uint32_t cork_error_class
+
+ An identifier for a class of error conditions. Should be the hash of
+ a unique string describing the error class.
+
+.. type:: unsigned int cork_error_code
+
+ An identifier for a particular type of error within an error class.
+ The particular values within an error class should be defined using
+ an ``enum`` type.
View
329 docs/gc.rst
@@ -0,0 +1,329 @@
+.. _gc:
+
+************************************
+Reference-counted garbage collection
+************************************
+
+.. highlight:: c
+
+::
+
+ #include <libcork/core.h>
+
+The functions in this section implement a reference counting garbage
+collector. The garbage collector handles reference cycles correctly.
+It is **not** a conservative garbage collector — i.e., we don't assume
+that every word inside an object might be a pointer. Instead, each
+garbage-collected object must provide a *recursion function* that knows
+how to delve down into any child objects that it references.
+
+The garbage collector is **not** thread-safe. If your application is
+multi-threaded, you must use a single collector per thread. There are
+two strategies that you can use when using the garbage collector in a
+multi-threaded application:
+
+* Have a single “master” thread be responsible for the lifecycle of
+ every object. This thread then maintains the garbage collector.
+ **No** other threads are allowed to call any of the functions in this
+ section, including the :c:func:`cork_gc_incref()` and
+ :c:func:`cork_gc_decref()` functions. Other threads are allowed to
+ access the objects that are managed by the garbage collector, but the
+ master thread must ensure that all objects are live whenever another
+ thread attempts to use them. This will require some kind of
+ thread-safe communication or synchronization between the master thread
+ and the worker threads.
+
+* Have a separate garbage collector per thread. Each object is “owned”
+ by a single thread, and the object is managed by that thread's garbage
+ collector. As with the first strategy, other threads can use any
+ object, as long as the object's owner thread is able to guarantee that
+ the object will be live for as long as it's needed. (Eventually we'll
+ also support migrating an object from one garbage collector to
+ another, but that feature isn't currently implemented.)
+
+The garbage collection implementation is based on the algorithm
+described in §3 of [1]_.
+
+.. [1] Bacon, DF and Rajan VT. *Concurrent cycle collection in
+ reference counted systems*. Proc. ECOOP 2001. LNCS 2072.
+
+
+Creating a garbage collector
+============================
+
+.. type:: struct cork_gc
+
+ A garbage collection context. You can consider this to be an opaque
+ wrapper around a :c:type:`cork_alloc` custom allocator. You should
+ not access any of the fields of this type directly.
+
+.. function:: int cork_gc_init(struct cork_gc \*gc, struct cork_alloc \*alloc)
+
+ Initalize a new garbage collection context. Unlike custom
+ allocators, you are responsible for allocation the storage for the
+ garbage collector object yourself. Usually, you can allocate this on
+ the stack of your ``main`` function::
+
+ int
+ main(int argc, char ** argv)
+ {
+ struct cork_alloc * alloc = cork_allocator_new_malloc();
+ struct cork_gc gc;
+ if (cork_gc_init(&gc, alloc) == -1) {
+ cork_allocator_free(alloc);
+ exit(1);
+ }
+ }
+
+.. function:: void cork_gc_done(struct cork_gc \*gc)
+
+ Finalize a garbage collection context. All objects created in this
+ garbage collection context will be freed when this function returns.
+
+
+Managing garbage-collected objects
+==================================
+
+A garbage collection context can't be used to manage arbitrary objects,
+since each garbage-collected class must define a couple of callback
+functions for interacting with the garbage collector. (The :ref:`next
+section <new-gc-class>` contains more details.)
+
+Each garbage-collected class will provide its own constructor function
+for instantiating a new instance of that class. The constructor will
+take in a :c:type:`cork_gc` pointer as its first parameter. There
+aren't any explicit destructors for garbage-collected objects; instead
+you manage “references” to the objects. Each pointer to a
+garbage-collected object is a reference, and each object maintains a
+count of the references to itself. A newly constructed object starts
+with a reference count of ``1``. Whenever you save a pointer to a
+garbage-collected object, you should increase the object's reference
+count. When you're done with the pointer, you decrease its reference
+count. When the reference count drops to ``0``, the garbage collector
+frees the object.
+
+.. function:: void \*cork_gc_incref(struct cork_gc \*gc, void \*obj)
+
+ Increments the reference count of an object *obj* that is managed by
+ garbage collector *gc*. We always return *obj* as a result, which
+ allows you to use the following idiom::
+
+ struct my_obj * my_copy_of_obj = cork_gc_incref(gc, obj);
+
+.. function:: void cork_gc_decref(struct cork_gc \*gc, void \*obj)
+
+ Decrements the reference count of an object *obj* that is managed by
+ garbage collector *gc*. If the reference count drops to ``0``, then
+ the garbage collector will free the object.
+
+ .. note::
+
+ It's safe to call this function with a ``NULL`` *obj* pointer; in
+ this case, the function acts as a no-op.
+
+.. _borrow-ref:
+
+Borrowing a reference
+---------------------
+
+While the strategy mentioned above implies that you should call
+:c:func:`cork_gc_incref()` and :c:func:`cork_gc_decref()` for *every*
+pointer to a garbage-collected object, you can sometimes get away
+without bumping the reference count. In particular, you can often
+*borrow* an existing reference to an object, if you can guarantee that
+the borrowed reference will exist for as long as you need access to the
+object. The most common example of this when you pass in a
+garbage-collected object as the parameter to a function::
+
+ int
+ use_new_reference(struct cork_gc *gc, struct my_obj *obj)
+ {
+ /* Here we're being pedantically correct, and incrementing obj's
+ * reference count since we've got our own pointer to the object. */
+ cork_gc_incref(gc, obj);
+
+ /* Do something useful with obj */
+
+ /* And now that we're done with it, decrement the reference count. */
+ cork_gc_decref(gc, obj);
+ }
+
+ int
+ borrowed_reference(struct cork_gc *gc, struct my_obj *obj)
+ {
+ /* We can assume that the caller has a valid reference to obj, so
+ * we're just going to borrow that reference. */
+
+ /* Do something useful with obj */
+ }
+
+In this example, ``borrowed_reference`` doesn't need to update *obj*\ 's
+reference count. We assume that the caller has a valid reference to
+*obj* when it makes the call to ``borrowed_reference``. Moreover, we
+know that the caller can't possibly release this reference (via
+:c:func:`cork_gc_decref()`) until ``borrowed_reference`` returns. Since
+we can guarantee that the caller's reference to *obj* will exist for the
+entire duration of ``borrowed_reference``, we don't need to protect it
+with an ``incref``/``decref`` pair.
+
+.. _steal-ref:
+
+Stealing a reference
+--------------------
+
+Another common pattern is for a “parent” object to maintain a reference
+to a “child” object. (For example, a container class might maintain
+references to all of the elements in container, assuming that the
+container and elements are all garbage-collected objects.) When you
+have a network of objects like this, the parent object's constructor
+will usually take in a pointer to the child object as a parameter. If
+we strictly follow the basic referencing counting rules described above,
+you'll end up with something like::
+
+ struct cork_gc *gc = /* from somewhere */;
+ struct child *child = child_new(gc);
+ struct parent *parent = parent_new(gc, child);
+ cork_gc_decref(gc, child);
+
+The ``child_new`` constructor gives us a reference to *child*. The
+``parent_new`` constructor then creates a new reference to *child*,
+which will be stored somewhere in *parent*. We no longer need our own
+reference to *child*, so we immediately decrement its reference count.
+
+This is a common enough occurrence that many constructor functions will
+instead *steal* the reference passed in as a parameter. This means that
+the constructor takes control of the caller's reference. This allows us
+to rewrite the example as::
+
+ struct cork_gc *gc = /* from somewhere */;
+ struct parent *parent = parent_new_stealing(gc, child_new(gc));
+
+For functions that steal a reference, the caller **cannot** assume that
+the object pointed to by the stolen reference exists when the function
+returns. (If there's an error in ``parent_new_stealing``, for instance,
+it must release the stolen reference to *child* to prevent a memory
+leak.) If a function is going to steal a reference, but you also need
+to use the object after the function call returns, then you need to
+explicitly increment the reference count *before* calling the function::
+
+ struct cork_gc *gc = /* from somewhere */;
+ struct child *child = child_new(gc);
+ struct parent *parent = parent_new_stealing(gc, cork_gc_incref(gc, child));
+ /* Do something with child. */
+ /* And then release our reference when we're done. */
+ cork_gc_decref(gc, child);
+
+.. note::
+
+ It's important to point out that not every constructor will steal the
+ references passed in as parameters. Moreover, there are some
+ constructors that steal references for some parameters but not for
+ others. It entirely depends on what the “normal” use case is for the
+ constructor. If you're almost always going to pass in a child object
+ that was just created, and that will always be accessed via the
+ parent, then the constructor will usually steal the reference. If
+ the child can be referenced by many parents, then the constructor
+ will usually *not* steal the reference. The documentation for each
+ constructor function will explicitly state which references are
+ stolen and which objects it creates new references for.
+
+
+.. _new-gc-class:
+
+Writing a new garbage-collected class
+=====================================
+
+When you are creating a new class that you want to be managed by a
+garbage collector, there are two basic steps you need to follow:
+
+* Implement a set of callback functions that allow the garbage collector
+ to interact with objects of the new class.
+
+* Use the garbage collector's allocation functions, instead of the basic
+ :ref:`custom allocator functions <using-allocators>`, in your class's
+ constructor function.
+
+You won't need to write a public destructor function, since objects of
+the new class will be destroyed automatically when the garbage collector
+determines that they're no longer needed.
+
+Garbage collector callback interface
+------------------------------------
+
+Each garbage-collected class must provide an implementation of the
+“callback interface”:
+
+.. type:: struct cork_gc_obj_iface
+
+ .. member:: void (\*free)(struct cork_gc \*gc, void \*obj)
+
+ This callback is called when a garbage-collected object is about
+ to be freed. You can perform any special cleanup steps in this
+ callback. You do **not** need to deallocate the object's storage,
+ and you do **not** need to release any references that you old to
+ other objects. Both of these steps will be taken care of for you
+ by the garbage collector.
+
+ If your class doesn't need any additional finalization steps, this
+ entry in the callback interface can be ``NULL``.
+
+ .. member:: void (\*recurse)(void \*self, cork_gc_recurser recurse, void \*ud)
+
+ This callback is how you inform the garbage collector of your
+ references to other garbage-collected objects.
+
+ The garbage collector will call this function whenever it needs to
+ traverse through a graph of object references. Your
+ implementation of this callback should just call *recurse* with
+ each garbage-collected object that you hold a reference to. You
+ must pass in *ud* as the second parameter to each call to
+ *recurse*.
+
+ As an example, a tree class's implementation of this callback
+ might be::
+
+ static void
+ tree_recurser(void * vself, cork_gc_recurser recurse, void * ud)
+ {
+ struct tree * self = vself;
+ recurse(self->left, ud);
+ recurse(self->right, ud);
+ }
+
+ Note that it's fine to call *recurse* with a ``NULL`` object
+ pointer, which makes it slightly easier to write implementations
+ of this callback.
+
+ If instances of your class can never contain references to other
+ garbage-collected objects, this entry in the callback interface
+ can be ``NULL``.
+
+.. type:: void (\*cork_gc_recurser)(void \*obj, void \*ud)
+
+ An opaque callback provided by the garbage collector when it calls an
+ object's :c:member:`recurse <cork_gc_obj_iface.recurse>` method.
+
+Allocating new garbage-collected objects
+----------------------------------------
+
+In your garbage-collected class's constructor, you must use one of the
+following functions to allocate the object's storage. (The garbage
+collector hides some additional state in the object's memory region, so
+you can't allocate the storage using :c:func:`cork_malloc()` or
+:c:func:`cork_new()` directly.)
+
+.. function:: void \*cork_gc_alloc(struct cork_gc \*gc, size_t instance_size, struct cork_gc_obj_iface \*iface)
+
+ Allocates a new garbage-collected object that is *instance_size*
+ bytes large. *iface* should be a pointer to a callback interface for
+ the object. If there are any problems allocating the new instance,
+ we'll return ``NULL``.
+
+.. function:: type \*cork_gc_new(struct cork_gc \*gc, TYPE type, struct cork_gc_obj_iface \*iface)
+
+ Allocates a new garbage-collected instance of *type*. The size of
+ the memory region to allocate is calculated using the ``sizeof``
+ operator, and the result will be automatically cast to ``type *``.
+ *iface* should be a pointer to a callback interface for the object.
+ If there are any problems allocating the new instance, we'll return
+ ``NULL``.
View
67 docs/hash-values.rst
@@ -0,0 +1,67 @@
+.. _hash-values:
+
+***********
+Hash values
+***********
+
+.. highlight:: c
+
+::
+
+ #include <libcork/core.h>
+
+
+The functions in this section can be used to produce fast, good hash
+values. The implementation provides by these functions can change over
+time, and doesn't have to be consistent across different platforms. The
+only guarantee is that hash values will be consistest for the duration
+of the current process.
+
+.. note::
+
+ For the curious, libcork currently uses the public-domain
+ `MurmurHash3 <http://code.google.com/p/smhasher/>`_ as its hash
+ implementation.
+
+A common pattern would be something along the lines of::
+
+ struct my_type {
+ int a;
+ long b;
+ double c;
+ size_t name_length;
+ const char *name;
+ };
+
+ cork_hash
+ my_type_hash(const struct my_type *self)
+ {
+ /* hash of "struct my_type" */
+ cork_hash hash = 0xd4a130d8;
+ hash = cork_hash_variable(hash, self->a);
+ hash = cork_hash_variable(hash, self->b);
+ hash = cork_hash_variable(hash, self->c);
+ hash = cork_hash_buffer(hash, self->name, self->name_length);
+ return hash;
+ }
+
+In this example, the seed value (``0xd4a130d8``) is the hash of the
+constant string ``"struct my_type"``. You can produce seed values like
+this using the ``extras/hashstring.py`` script that's included in the
+libcork source::
+
+ $ python extras/hashstring.py "struct my_type"
+ 0xd4a130d8
+
+
+.. type:: uint32_t cork_hash
+
+.. function:: cork_hash cork_hash_buffer(cork_hash seed, const void \*src, size_t len)
+
+ Incorporate the contents of the given binary buffer into a hash
+ value.
+
+.. function:: cork_hash cork_hash_variable(cork_hash seed, TYPE val)
+
+ Incorporate the contents of a variable into the hash value. *val*
+ must be an lvalue visible in the current scope.
View
38 docs/index.rst
@@ -1,16 +1,48 @@
-.. APPNAME documentation master file, created by
+.. libcork documentation master file, created by
sphinx-quickstart on Thu Nov 10 15:10:57 2011.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
-APPNAME documentation
+libcork documentation
=====================
-Contents:
+This is the documentation for libcork |release|, last updated |today|.
+
+
+Introduction
+------------
+
+So what is libcork, exactly? It's a “simple, easily embeddable, cross-platform
+C library”. It falls roughly into the same category as glib_ or APR_ in the C
+world; the STL, POCO_, or QtCore_ in the C++ world; or the standard libraries
+of any decent dynamic language.
+
+So if libcork has all of these comparables, why a new library? Well, none of
+the C++ options are really applicable here. And none of the C options work,
+because one of the main goals is to have the library be highly modular, and
+useful in resource-constrained systems. Once we describe some of the design
+decisions that we've made in libcork, you'll hopefully see how this fits into
+an interesting niche of its own.
+
+.. _glib: http://library.gnome.org/devel/glib/
+.. _APR: http://apr.apache.org/
+.. _POCO: http://pocoproject.org/
+.. _QtCore: http://qt.nokia.com/
+
+
+Contents
+--------
.. toctree::
:maxdepth: 2
+ config
+ basic-types
+ byte-order
+ attributes
+ allocation
+ errors
+ gc
Indices and tables
View
126 docs/net-addresses.rst
@@ -0,0 +1,126 @@
+.. _net-addresses:
+
+*****************
+Network addresses
+*****************
+
+.. highlight:: c
+
+::
+
+ #include <libcork/core.h>
+
+
+IP addresses
+------------
+
+libcork provides C types for storing IPv4 and IPv6 addresses, as well as
+a union type for storing a generic IP address, regardless of whether
+it's IPv4 or IPv6. (This lets you distinguish between an IPv4 address
+and the equivalent ``::ffff:0:0/96`` IPv4-mapped IPv6 address.)
+
+.. type:: struct cork_ipv4
+ struct cork_ipv6
+
+ An IPv4 or IPv6 address. The address is stored in memory exactly as
+ it would be if sent over a network connection — i.e., in
+ network-endian order, regardless of the endianness of the current
+ host. The types are also guaranteed to be exactly the size of an
+ actual IPv4 or IPv6 address (without additional padding), so they can
+ be embedded directly into ``struct`` types that represent binary
+ disk/wire formats.
+
+ The contents of these types should be considered opaque. You should
+ use the accessor functions defined below to interact with the IP
+ address.
+
+.. type:: struct cork_ip
+
+ A single union type that can contain either an IPv4 or IPv6 address.
+ This type contains a discriminator field, so you can't use it
+ directly in a binary disk/wire format type.
+
+ .. member:: unsigned int version
+
+ Either ``4`` or ``6``, indicating whether the current IP address
+ is an IPv4 address or an IPv6 address.
+
+ .. member:: struct cork_ipv4 ip.v4
+ struct cork_ipv6 ip.v6
+
+ Gives you access to the underlying :c:type:`cork_ipv4` or
+ :c:type:`cork_ipv6` instance for the current address. It's your
+ responsibility to check the :c:member:`cork_ip.version` field and
+ only access the union branch that corresponds to the current IP
+ version.
+
+
+.. function:: bool cork_ipv4_copy(struct cork_ipv4 \*addr, const void \*src)
+ bool cork_ipv6_copy(struct cork_ipv6 \*addr, const void \*src)
+ bool cork_ip_from_ipv4(struct cork_ip \*addr, const void \*src)
+ bool cork_ip_from_ipv6(struct cork_ip \*addr, const void \*src)
+
+ Initializes a :c:type:`cork_ipv4`, :c:type:`cork_ipv6`, or
+ :c:type:`cork_ip` instance from an existing IP address somewhere in
+ memory. The existing address doesn't have to be an instance of the
+ :c:type:`cork_ipv4` or :c:type:`cork_ipv6` types, but it does have to
+ be a well-formed address. (For IPv4, it must be 4 bytes long; for
+ IPv6, 16 bytes long. And in both cases, the address must already be
+ in network-endian order, regardless of the host's endianness.)
+
+
+.. function:: bool cork_ipv4_init(struct cork_ipv4 \*addr, const char \*str, struct cork_error \*err)
+ bool cork_ipv6_init(struct cork_ipv6 \*addr, const char \*str, struct cork_error \*err)
+ bool cork_ip_init(struct cork_ip \*addr, const char \*str, struct cork_error \*err)
+
+ Initializes a :c:type:`cork_ipv4`, :c:type:`cork_ipv6`, or
+ :c:type:`cork_ip` instance from the string representation of an IP
+ address. *str* must point to a string containing a well-formed IP
+ address. (Dotted-quad for an IPv4, and colon-hex for IPv6.)
+ Moreover, the version of the IP address in *str* must be compatible
+ with the function that you call: it can't be an IPv6 address if you
+ call ``cork_ipv4_init``, and it can't be an IPv4 address if you call
+ ``cork_ipv6_init``.
+
+ If *str* doesn't represent a valid address (of a compatible IP
+ version), then we leave *addr* unchanged, fill in *err* with a
+ :c:data:`CORK_NET_ADDRESS_PARSE_ERROR` error, and return ``false``.
+
+
+.. function:: bool cork_ipv4_equal(const struct cork_ipv4 \*addr1, const struct cork_ipv4 \*addr2)
+ bool cork_ipv6_equal(const struct cork_ipv6 \*addr1, const struct cork_ipv6 \*addr2)
+ bool cork_ip_equal(const struct cork_ip \*addr1, const struct cork_ip \*addr2)
+
+ Checks two IP addresses for equality.
+
+
+.. macro:: CORK_IPV4_STRING_LENGTH
+ CORK_IPV6_STRING_LENGTH
+ CORK_IP_STRING_LENGTH
+
+ The maximum length of the string representation of an IPv4, IPv6, or
+ generic IP address, including a ``NUL`` terminator.
+
+.. function:: void cork_ipv4_to_raw_string(const struct cork_ipv4 \*addr, char \*dest)
+ void cork_ipv6_to_raw_string(const struct cork_ipv6 \*addr, char \*dest)
+ void cork_ip_to_raw_string(const struct cork_ip \*addr, char \*dest)
+
+ Fills in *dest* with the string representation of an IPv4, IPv6, or
+ generic IP address. You are responsible for ensuring that *dest* is
+ large enough to hold the string representation of any valid IP
+ address of the given version. The
+ :c:macro:`CORK_IPV4_STRING_LENGTH`,
+ :c:macro:`CORK_IPV6_STRING_LENGTH`, and
+ :c:macro:`CORK_IP_STRING_LENGTH` macros can be helpful for this::
+
+ char buf[CORK_IPV4_STRING_LENGTH];
+ struct cork_ipv4 addr;
+ cork_ipv4_to_raw_string(&addr, buf);
+
+
+.. macro:: CORK_NET_ADDRESS_ERROR
+ CORK_NET_ADDRESS_UNKNOWN_ERROR
+ CORK_NET_ADDRESS_PARSE_ERROR
+
+ The error class and codes used for :ref:`error conditions <errors>`
+ raised by the functions in this section.
View
65 docs/timestamps.rst
@@ -0,0 +1,65 @@
+.. _timestamps:
+
+*************************
+High-precision timestamps
+*************************
+
+.. highlight:: c
+
+::
+
+ #include <libcork/core.h>
+
+
+.. type:: uint64_t cork_timestamp
+
+ A high-precision timestamp type. A timestamp is represented by a
+ 64-bit integer, whose unit is the *gammasecond* (γsec), where
+ :math:`1~\textrm{γsec} = \frac{1}{2^{32}} \textrm{sec}`. With this
+ representation, the upper 32 bits of a timestamp value represent the
+ timestamp truncated (towards zero) to seconds.
+
+ For this type, we don't concern ourselves with any higher-level
+ issues of clock synchronization or time zones. ``cork_timestamp``
+ values can be used to represent any time quantity, regardless of
+ which time standard (UTC, GMT, TAI) you use, or whether it takes into
+ account the local time zone.
+
+
+.. function:: void cork_timestamp_init_sec(cork_timestamp \*ts, uint32_t sec)
+ void cork_timestamp_init_msec(cork_timestamp \*ts, uint32_t sec, uint32_t msec)
+ void cork_timestamp_init_usec(cork_timestamp \*ts, uint32_t sec, uint32_t usec)
+
+ Initializes a timestamp from a separate seconds part and fractional
+ part. For the ``_sec`` variant, the fractional part will be set to
+ ``0``. For the ``_msec`` and ``_usec`` variants, the fractional part
+ will be translated into gammaseconds from milliseconds or
+ microseconds, respectively.
+
+
+.. function:: void cork_timestamp_init_now(cork_timestamp \*ts)
+
+ Initializes a timestamp with the current UTC time of day.
+
+ .. note::
+
+ The resolution of this function is system-dependent.
+
+
+.. function:: uint32_t cork_timestamp_sec(const cork_timestamp ts)
+ uint32_t cork_timestamp_gsec(const cork_timestamp ts)
+
+ Returns the seconds or fractional portion, respectively, of a
+ timestamp. The fractional portion is represented in gammaseconds.
+
+
+.. function:: bool cork_timestamp_format_utc(const cork_timestamp ts, const char \*format, char \*buf, size_t size)
+ bool cork_timestamp_format_local(const cork_timestamp ts, const char \*format, char \*buf, size_t size)
+
+ Fills in *buf* with the string representation of the given timestamp,
+ according to *fmt*, which should be a format string compatible with
+ the POSIX ``strftime`` function. *size* must be the size (in bytes)
+ of *buf*. If we can't format the timestamp for any reason, we return
+ ``false``. The ``_utc`` variant assumes that *ts* represents a UTC
+ time, whereas teh ``_local`` variant assumes that it represents a
+ time in the local time zone.
View
9 include/libcork/config.h
@@ -11,15 +11,6 @@
#ifndef LIBCORK_CONFIG_H
#define LIBCORK_CONFIG_H
-/**
- * @file
- * @brief Pulls in all features of the @ref config
- */
-
-/**
- * @defgroup config Configuration module
- */
-
/*** include all of the parts ***/
#include <libcork/config/config.h>
View
109 include/libcork/config/config.h
@@ -11,118 +11,14 @@
#ifndef LIBCORK_CONFIG_CONFIG_H
#define LIBCORK_CONFIG_CONFIG_H
-/**
- * @file
- * @brief Implementation of the @ref config module
- */
-
-/**
- * @addtogroup config
- *
- * <tt>#%include \<libcork/config.h\></tt>
- *
- * Several libcork features have different implementations on different
- * platforms. Since we want libcork to be easily embeddable into
- * projects with a wide range of build systems, we try to autodetect
- * which implementations to use, strictly using the C preprocessor, and
- * the predefined macros that are available on different systems.
- *
- * This module provides a layer of indirection, encapsulating all of the
- * preprocessor-based autodetection into one place. The goal of this
- * module is to define a collection of libcork-specific configuration
- * macros, which all other libcork modules will use to select which
- * implementation to use.
- *
- * If you want to skip libcork's autodetection, you can; see @ref
- * CORK_CONFIG_SKIP_AUTODETECT for details.
- *
- * @{
- */
-
-
-/*-----------------------------------------------------------------------
- * Skipping autodetection
- */
+/* If you want to skip autodetection, define this to 1, and provide a
+ * libcork/config/custom.h header file. */
-/**
- * @brief Whether to skip libcork's autodetection logic
- *
- * If you want to skip libcork's autodetection logic, then you are
- * responsible for providing the appropriate values for all of the
- * macros defined in this section. To do this, have your build system
- * define this macro, with a value of 1. This will override the default
- * value of 0 provided in the libcork/config/config.h header file.
- *
- * Then, create a <tt>libcork/config/custom.h</tt> header file. You can
- * place this file anywhere in your header search path. We will load
- * that file instead of libcork's autodetection logic. Place the
- * appropriate definitions for each of the configuration macros into
- * this file. If needed, you can generate this file as part of the
- * “configure” step of your build system; the only requirement is that
- * it's available once you start compiling the libcork source files.
- *
- * @showinitializer
- * @since 0.1
- */
-
-#if defined(CORK_DOCUMENTATION)
-#define CORK_CONFIG_SKIP_AUTODETECT 0
-#else
#if !defined(CORK_CONFIG_SKIP_AUTODETECT)
#define CORK_CONFIG_SKIP_AUTODETECT 0
#endif
-#endif
-
-
-/*-----------------------------------------------------------------------
- * Endianness
- */
-
-/**
- * @brief Whether this is a big-endian system.
- * @since 0.1
- */
-
-#if defined(CORK_DOCUMENTATION)
-#define CORK_CONFIG_IS_BIG_ENDIAN 0
-#endif
-
-/**
- * @brief Whether this is a little-endian system.
- * @since 0.1
- */
-
-#if defined(CORK_DOCUMENTATION)
-#define CORK_CONFIG_IS_LITTLE_ENDIAN 0
-#endif
-
-
-/*-----------------------------------------------------------------------
- * Compiler attributes
- */
-
-/**
- * @brief Whether the GCC compiler attributes are available.
- * @since 0.1
- */
-
-#if defined(CORK_DOCUMENTATION)
-#define CORK_CONFIG_HAVE_GCC_ATTRIBUTES 0
-#endif
-
-
-/* end of config group */
-/**
- * @}
- */
-
-/*-----------------------------------------------------------------------
- * Auto-detection
- */
-/* don't bother autodetecting if we're just building the docs */
-#if !defined(CORK_DOCUMENTATION)
#if CORK_CONFIG_SKIP_AUTODETECT
/* The user has promised that they'll define everything themselves. */
@@ -155,7 +51,6 @@
#endif /* autodetect or not */
-#endif /* documentation check */
#endif /* LIBCORK_CONFIG_CONFIG_H */
View
8 include/libcork/config/gcc.h
@@ -11,13 +11,6 @@
#ifndef LIBCORK_CONFIG_GCC_H
#define LIBCORK_CONFIG_GCC_H
-/**
- * @file
- * @brief GCC-specific configuration auto-detection
- */
-
-#if !defined(CORK_DOCUMENTATION)
-
/* Figure out the GCC version */
#if defined(__GNUC_PATCHLEVEL__)
@@ -45,5 +38,4 @@
#endif
-#endif /* !CORK_DOCUMENTATION */
#endif /* LIBCORK_CONFIG_GCC_H */
View
9 include/libcork/config/linux.h
@@ -11,14 +11,6 @@
#ifndef LIBCORK_CONFIG_LINUX_H
#define LIBCORK_CONFIG_LINUX_H
-/**
- * @file
- * @brief Linux-specific configuration auto-detection
- */
-
-#if !defined(CORK_DOCUMENTATION)
-
-
/*-----------------------------------------------------------------------
* Endianness
*/
@@ -36,5 +28,4 @@
#endif
-#endif /* !CORK_DOCUMENTATION */
#endif /* LIBCORK_CONFIG_LINUX_H */
View
8 include/libcork/config/macosx.h
@@ -11,13 +11,6 @@
#ifndef LIBCORK_CONFIG_MACOSX_H
#define LIBCORK_CONFIG_MACOSX_H
-/**
- * @file
- * @brief Mac OS X-specific configuration auto-detection
- */
-
-#if !defined(CORK_DOCUMENTATION)
-
/*-----------------------------------------------------------------------
* Endianness
@@ -36,5 +29,4 @@
#endif
-#endif /* !CORK_DOCUMENTATION */
#endif /* LIBCORK_CONFIG_MACOSX_H */
View
54 include/libcork/core.h
@@ -11,60 +11,6 @@
#ifndef LIBCORK_CORE_H
#define LIBCORK_CORE_H
-/**
- * @file
- * @brief Pulls in all features of the @ref core
- */
-
-/**
- * @defgroup core Core module
- *
- * <tt>#%include \<libcork/core.h\></tt>
- */
-
-/*** order of groups in documentation ***/
-
-/**
- * @defgroup basic_types Basic types
- * @ingroup core
- */
-
-/**
- * @defgroup byte_order Byte order
- * @ingroup core
- */
-
-/**
- * @defgroup compiler_attrs Compiler attributes
- * @ingroup core
- */
-
-/**
- * @defgroup allocator Custom allocation
- * @ingroup core
- */
-
-/**
- * @defgroup error Error conditions
- * @ingroup core
- */
-
-/**
- * @defgroup hier_alloc Hierarchical allocation
- * @ingroup core
- */
-
-/**
- * @defgroup hashing Hash values
- * @ingroup core
- */
-
-/**
- * @defgroup gc Reference-counted garbage collection
- * @ingroup core
- */
-
-
/*** include all of the parts ***/
#include <libcork/core/allocator.h>
View
243 include/libcork/core/allocator.h
@@ -11,164 +11,44 @@
#ifndef LIBCORK_CORE_ALLOCATOR_H
#define LIBCORK_CORE_ALLOCATOR_H
-/**
- * @file
- * @brief Implementation of the @ref allocator and @ref hier_alloc
- * submodules
- */
-
#include <libcork/core/types.h>
-/**
- * @addtogroup allocator
- *
- * <tt>#%include &lt;libcork/core/allocator.h&gt;</tt>
- *
- * The functions in this section allow you to control how libcork
- * allocates memory for its internal objects.
- *
- * The allocator is provided as a single generic function
- * (cork_alloc_func_t), which can emulate the standard malloc, realloc,
- * and free functions. The design of this allocation interface is
- * inspired by the implementation of the Lua interpreter.
- *
- * @{
- */
-
+/* Forward declaration */
struct cork_alloc;
-
-/**
- * @brief A function that can allocate, reallocate, or free a memory
- * buffer.
+/*
+ * Should mimic:
+ * malloc() if osize == 0
+ * realloc() if osize != 0 && nsize != 0
+ * free() if osize != 0 && nsize == 0
*
- * The @a ptr parameter will be the location of any existing memory
- * buffer. The @a osize parameter will be the size of this existing
- * buffer. If @a ptr is @c NULL, then @a osize will be 0. The @a nsize
- * parameter will be the size of the new buffer, or 0 if the new buffer
- * should be freed.
- *
- * If @a nsize is 0, then the allocation function must return @c NULL.
- * If @a nsize is not 0, then it should return @c NULL if the allocation
- * fails.
- *
- * @param[in] alloc A reference to the allocator object, in case you
- * need access to any additional state that you've stashed in there.
- *
- * @param[in] ptr For reallocations and frees, a pointer to the
- * existing memory buffer. For new allocations, @c NULL.
- *
- * @param[in] osize For reallocations and frees, the size of the buffer
- * pointed to by @a ptr. For new allocations, 0.
- *
- * @param[in] nsize For new allocations and reallocations, the desired
- * size of the memory buffer. For frees, 0.
- *
- * @returns For new allocations and reallocations, a pointer to the new
- * memory buffer, or @c NULL if the buffer cannot be (re)allocated. For
- * frees, @c NULL.
- *
- * @since 0.2
+ * (ptr will always be NULL if osize == 0)
*/
-
typedef void *
(*cork_alloc_func)(struct cork_alloc *alloc, void *ptr,
size_t osize, size_t nsize);
-
-/**
- * @brief An object that encapsulates a custom allocation function.
- *
- * If you need to pass additional information into the allocation
- * function, you can create a subclass of this struct:
- *
- * @code
- * struct custom_allocator {
- * struct cork_alloc parent;
- * // any additional state here
- * };
- * @endcode
- *
- * @since 0.2
- */
-
struct cork_alloc {
- /**
- * @brief An allocation function.
- *
- * See @ref cork_alloc_func for details on the function's
- * interface.
- */
-
const cork_alloc_func alloc;
- /**
- * @brief A function that can free this allocator object.
- */
-
void
(*free)(struct cork_alloc *alloc);
};
-/* end of allocator group */
-/**
- * @}
- */
-
-
-/**
- * @brief Create a new allocator object that uses the standard @c
- * malloc, @c realloc, and @c free functions.
- *
- * @public @memberof cork_alloc
- * @since 0.2
- */
+/* Uses standard malloc/realloc/free */
struct cork_alloc *
cork_allocator_new_malloc(void);
-
-/**
- * @brief Create a new allocator object that uses a default debugging
- * allocation function.
- *
- * @note This function is useful for test cases, but probably shouldn't
- * be used in production code.
- *
- * @public @memberof cork_alloc
- * @since 0.2
- */
-
+/* Verifies sizes when freeing */
struct cork_alloc *
cork_allocator_new_debug(void);
-
-/**
- * @brief Create a new allocator object that uses the given allocation
- * function.
- *
- * This function provides a simpler interface if you don't need to
- * include extra fields in a @c struct cork_alloc subclass.
- *
- * @param[in] alloc_func The custom allocation function to use with
- * this context.
- *
- * @public @memberof cork_alloc
- * @since 0.2
- */
-
+/* Wraps a custom allocation function with no extra state */
struct cork_alloc *
cork_allocator_new(cork_alloc_func alloc_func);
-
-/**
- * @brief Finalizes and frees an allocator object.
- * @param[in] alloc The allocator object to free.
- * @public @memberof cork_alloc
- * @since 0.2
- */
-
void
cork_allocator_free(struct cork_alloc *alloc);
@@ -177,120 +57,25 @@ cork_allocator_free(struct cork_alloc *alloc);
* Raw allocation macros
*/
-/**
- * @brief Allocate a new memory region using a custom allocator.
- * @param[in] alloc The custom allocator to use
- * @param[in] size The requested size of the new memory region
- * @returns A pointer to the new memory region, or @c NULL if the region
- * can't be allocated.
- * @public @memberof cork_alloc
- * @since 0.2
- */
-
-#if defined(CORK_DOCUMENTATION)
-void *
-cork_malloc(struct cork_alloc *alloc, size_t size);
-#else
+/* size-based macros */
#define cork_malloc(_alloc, sz) \
((_alloc)->alloc((_alloc), NULL, 0, (sz)))
-#endif
-
-
-/**
- * @brief Reallocate a memory region using a custom allocator.
- * @param[in] alloc The custom allocator to use
- * @param[in] ptr The memory region to resize
- * @param[in] osize The old size of the memory region
- * @param[in] nsize The requested new size of the memory region
- * @returns A pointer to the resized memory region (which may or may not
- * be the same as @a ptr), or @c NULL if the region can't be resized.
- * @public @memberof cork_alloc
- * @since 0.2
- */
-
-#if defined(CORK_DOCUMENTATION)
-void *
-cork_realloc(struct cork_alloc *alloc, void *ptr,
- size_t osize, size_t nsize);
-#else
#define cork_realloc(_alloc, ptr, osz, nsz) \
((_alloc)->alloc((_alloc), (ptr), (osz), (nsz)))
-#endif
-
-
-/**
- * @brief Free a memory region using a custom allocator.
- * @param[in] alloc The custom allocator to use
- * @param[in] ptr The memory region to free
- * @param[in] osize The old size of the memory region
- * @public @memberof cork_alloc
- * @since 0.2
- */
-
-#if defined(CORK_DOCUMENTATION)
-void
-cork_free(struct cork_alloc *alloc, void *ptr, size_t osize);
-#else
#define cork_free(_alloc, ptr, osz) \
((_alloc)->alloc((_alloc), (ptr), (osz), 0))
-#endif
-
-/**
- * @brief Allocate a new object using a custom allocator.
- * @param[in] alloc The custom allocator to use
- * @param[in] type The name of the object type to instantiate
- * @returns A pointer to a new, empty instance of the given type, or @c
- * NULL if the instance can't be allocated.
- * @public @memberof cork_alloc
- * @since 0.2
- */
-
-#if defined(CORK_DOCUMENTATION)
-type *cork_new(struct cork_alloc *alloc, TYPE_NAME type);
-#else
+/* type-based macros */
#define cork_new(alloc, type) \
((type *) cork_malloc(alloc, sizeof(type)))
-#endif
-
-
-/**
- * @brief Free an object using a custom allocator.
- * @param[in] alloc The custom allocator to use
- * @param[in] type The name of the object type to free
- * @param[in] instance The object instance to free
- * @public @memberof cork_alloc
- * @since 0.2
- */
-
-#if defined(CORK_DOCUMENTATION)
-void cork_delete(struct cork_alloc *alloc,
- TYPE_NAME type, type *instance);
-#else
#define cork_delete(alloc, type, instance) \
cork_free(alloc, instance, sizeof(type))
-#endif
-/**
- * @brief Allocate a copy of a C string.
- *
- * You must use @ref cork_strfree to free the string.
- *
- * @param[in] alloc The custom allocator to use
- * @param[in] str The string to copy
- * @public @memberof cork_alloc
- * @since 0.2-dev
- */
+/* string-related functions */
+
const char *
cork_strdup(struct cork_alloc *alloc, const char *str);
-/**
- * @brief Free a string created using @ref cork_strdup
- * @param[in] alloc The custom allocator to use
- * @param[in] str The string to free
- * @public @memberof cork_alloc
- * @since 0.2-dev
- */
void
cork_strfree(struct cork_alloc *alloc, const char *str);
View
106 include/libcork/core/attributes.h
@@ -11,126 +11,81 @@
#ifndef LIBCORK_CORE_ATTRIBUTES_H
#define LIBCORK_CORE_ATTRIBUTES_H
-/**
- * @file
- * @brief Implementation of the @ref compiler_attrs submodule
- */
-
#include <libcork/config.h>
-/**
- * @addtogroup compiler_attrs
- *
- * <tt>#%include \<libcork/core/attributes.h\></tt>
- *
- * The macros in this section define compiler-agnostic versions of
- * several compiler attributes.
- *
- * @{
- */
-
-/**
- * @brief Declare a “const” function.
+/*
+ * Declare a “const” function.
*
* A const function is one whose return value depends only on its
* parameters. This is slightly more strict than a “pure” function; a
* const function is not allowed to read from global variables, whereas
* a pure function is.
*
- * @code
- * int square(int x) CORK_ATTR_CONST;
- * @endcode
- *
- * @since 0.1
+ * int square(int x) CORK_ATTR_CONST;
*/
-#if defined(CORK_DOCUMENTATION)
-#define CORK_ATTR_CONST
-#elif CORK_CONFIG_HAVE_GCC_ATTRIBUTES
+#if CORK_CONFIG_HAVE_GCC_ATTRIBUTES
#define CORK_ATTR_CONST __attribute__((const))
#else
#define CORK_ATTR_CONST
#endif
-/**
- * @brief Declare a “pure” function.
+/*
+ * Declare a “pure” function.
*
* A pure function is one whose return value depends only on its
* parameters, and global variables.
*
- * @code
- * int square(int x) CORK_ATTR_PURE;
- * @endcode
- *
- * @since 0.1
+ * int square(int x) CORK_ATTR_PURE;
*/
-#if defined(CORK_DOCUMENTATION)
-#define CORK_ATTR_PURE
-#elif CORK_CONFIG_HAVE_GCC_ATTRIBUTES
+#if CORK_CONFIG_HAVE_GCC_ATTRIBUTES
#define CORK_ATTR_PURE __attribute__((pure))
#else
#define CORK_ATTR_PURE
#endif
-/**
- * @brief Declare that a function returns a newly allocated pointer.
+/*
+ * Declare that a function returns a newly allocated pointer.
*
* The compiler can use this information to generate more accurate
* aliasing information, since it can infer that the result of the
* function cannot alias any other existing pointer.
- *
- * @since 0.1
*/