X-Git-Url: https://git.distorted.org.uk/~mdw/sod/blobdiff_plain/4e3a7cb2594e9dd94ac6ad32e66cdfc50ee764a4..dc162ca6f0f2bbcb045a03df61c76e37c48d85a7:/doc/runtime.tex diff --git a/doc/runtime.tex b/doc/runtime.tex index 0a44f91..a4a15ed 100644 --- a/doc/runtime.tex +++ b/doc/runtime.tex @@ -43,9 +43,9 @@ The header file defines two simple structure types, and a function type which will be described later. \begin{describe}[struct kwval]{type} - {struct kwval \{ \\ \ind - const char *kw; \\ - const void *val; \- \\ + {struct kwval \{ \\ \ind + const char *kw; \\ + const void *val; \-\\ \};} The @|kwval| structure describes a keyword argument name/value pair. The @@ -56,9 +56,9 @@ will be described later. \end{describe} \begin{describe}[struct kwtab]{type} - {struct kwtab \{ \\ \ind - const struct kwval *v; \\ - size_t n; \- \\ + {struct kwtab \{ \\ \ind + const struct kwval *v; \\ + size_t n; \-\\ \};} The @|kwtab| structure describes a list of keyword arguments, represented @@ -203,8 +203,8 @@ list items of the form \end{prog} with no separation between them. For example: \begin{prog} - \#define example_KWSET(_) @\\ \\ \ind - _(int, x, 0) @\\ \\ + \#define example_KWSET(_) \macsl \\ \ind + _(int, x, 0) \macsl \\ _(const char *, y, NULL) \end{prog} @@ -285,9 +285,10 @@ keyword arguments. The macro @|KWSET_PARSEFN| defines a keyword argument \emph{parser function} \begin{prog} - void @{}_kwparse(\=struct @{}_kwargs *@, - const char *@, va_list *@, \+ \\ - const struct kwval *@, size_t @); + void @{}_kwparse% + (\=struct @{}_kwargs *@, + const char *@, va_list *@, \+\\ + const struct kwval *@, size_t @); \end{prog} The macro call can (and usually will) be preceded by storage class specifiers such as @|static|, for example to adjust the linkage of the @@ -311,7 +312,7 @@ keyword arguments. purpose, the argument vector @ is scanned \emph{after} the variable-length argument tail captured in @.) - The variable-argument tail is read from the list described by @|* @|. + The variable-argument tail is read from the list described by @|*@|. The argument tail is expected to consist of alternating keyword strings (as ordinary null-terminated strings) and the corresponding values, terminated by a null pointer of type @|const char~*| in place of a keyword; except @@ -327,7 +328,7 @@ keyword arguments. which expects keyword arguments, but don't supply any and forget the null pointer which terminates the (empty) list.} % If @ is a null pointer, then @ need not be a valid pointer; - otherwise, the cursor object @|* @| will be modified as the function + otherwise, the cursor object @|*@| will be modified as the function extracts successive arguments from the tail. The keyword vector is read from the vector of @|kwval| structures starting @@ -417,9 +418,10 @@ allow keyword arguments. \end{describe} \begin{describe}[kw_parseempty]{fun} - {void kw_parseempty(\=const char *@, - const char *@, va_list *@, \+ \\ - const struct kwval *@, size_t @);} + {void kw_parseempty% + (\=const char *@, + const char *@, va_list *@, \+\\ + const struct kwval *@, size_t @);} This function checks an keyword argument list to make sure that contains no keyword arguments (other than the special ones described in \xref{sec:runtime.keywords.calling}). @@ -551,32 +553,33 @@ particular keyword argument. \begin{prog} \#define KWARGS_TEST(k, val) KWARGS(K(k, val) K(kw.unknown, 0)) - \\+ + \\+ static jmp_buf kw_test_jmp; - \\+ - static void kw_test_unknown(const char *set, const char *kw) \\ - \{ \\ \ind - if (strcmp(kw, "kw.unknown")) longjmp(kw_test_jmp, 1); \\ - else longjmp(kw_test_jmp, 2); \- \\ - \} - \\+ - \#define KW_TEST(flag, set, call) do \{ @\\ \\ \ind - kw_unkhookfn *oldunk = kw_unkhook; @\\ \\ - kw_unkhook = kw_test_unknown; @\\ \\ - switch (setjmp(kw_test_jmp)) \{ @\\ \\ \ind - case 0: call; abort(); @\\ \\ - case 1: flag = 1; break; @\\ \\ - case 2: flag = 0; break; @\\ \\ - default: abort(); \- @\\ \\ - \} @\\ \\ - kw_unkhook = oldunk; \- @\\ \\ - \} while (0) - \\+ - /* Example of use */ \\ - int f; \\ + \\+ + static void kw_test_unknown(const char *set, const char *kw) \\ + \{ \\ \ind + if (strcmp(kw, "kw.unknown")) longjmp(kw_test_jmp, 1); \\ + else longjmp(kw_test_jmp, 2); \-\\ + \} \\+ + + \#define KW_TEST(flag, set, call) do \{ \macsl \\ \ind + kw_unkhookfn *oldunk = kw_unkhook; \macsl \\ + kw_unkhook = kw_test_unknown; \macsl \\ + switch (setjmp(kw_test_jmp)) \{ \macsl \\ \ind + case 0: call; abort(); \macsl \\ + case 1: flag = 1; break; \macsl \\ + case 2: flag = 0; break; \macsl \\ + default: abort(); \macsl\-\\ + \} \macsl \\ + kw_unkhook = oldunk; \macsl\-\\ + \} while (0) \\+ + + @/* Example of use */ \\ + int f; \\ KW_TEST(f, somefunc(1, "two", 3, KWARGS_TEST("shiny", 68.7))); \\ - /\=* now f is nonzero if `somefunc' accepts the `shiny' keyword \+ \\ - {}* (which we hope wants a double argument) \\ + /\=* \comment{now @|f| is nonzero if @|somefunc| accepts the + @|shiny| keyword} \+\\ + {}* \comment{(which we hope wants a @|double| argument)} \\ {}*/ \end{prog} @@ -732,10 +735,51 @@ instance. The following macros and functions manage the standard steps along an instance's lifecycle. +\subsubsection{Low-level operations} +The following macros and functions are agnostic with respect to storage +allocation strategies. They don't concern themselves with allocation or +deallocation, and applications are free to use any suitable mechanism. + +\begin{describe*} + {\dhead[SOD_INIT]{mac} + {@ *SOD_INIT(@, void *@

, @);} + \dhead[sod_init]{fun} + {void *sod_init(const SodClass *@, void *@

, \dots);} + \dhead[sod_initv]{fun} + {void *sod_initv(const SodClass *@, void *@

, va_list @);}} + Imprints and initializes an instance of a class @ in the storage + starting at address~@

. + + The direct class for the new instance is specified as a class name to + @|SOD_INIT|, or a pointer to a class object to the functions. + + Keyword arguments for the initialization message may be provided. The + @|SOD_INIT| macro expects a single preprocessor-time argument which is + a use of one of \descref{KWARGS}{mac} or \descref{NO_KWARGS}{mac}; the + @|sod_init| function expects the keywords as a variable-length argument + tail; and @|sod_initv| expects the keywords to be passed indirectly, + through the captured argument-tail cursor @. + + The return value is an instance pointer for the class @; the + @|SOD_INIT| macro will have converted it to the correct type, so it should + probably be used where possible. In fact, this is guaranteed to be equal + to @

by the layout rules described in + \xref{sec:structures.layout.instance}. +\end{describe*} + +\begin{describe}[sod_teardown]{fun}{int sod_teardown(void *@

);} + Tears down an instance of a class, releasing any resources it holds. + + This function is a very thin wrapper around sending the @|obj.teardown| + message. See the description of that message + (page~\pageref{msg:obj.teardown}) and \xref{sec:concepts.lifecycle.death} + for details. +\end{describe} + \subsubsection{Automatic storage duration} The following macro constructs an instance with automatic storage duration. -\begin{describe}[SOD_DECL]{mac}{SOD_DECL(@, @);} +\begin{describe}[SOD_DECL]{mac}{SOD_DECL(@, @, @);} Declares and initializes an instance with automatic storage duration. Given a class name @ and an identifier @, @|SOD_DECL| declares @@ -744,8 +788,56 @@ The following macro constructs an instance with automatic storage duration. up, and slots for which initializers are defined are set to the appropriate initial values. + Keyword arguments for the initialization message may be provided. The + macro expects a single preprocessor-time argument which is a use of one of + \descref{KWARGS}{mac} or \descref{NO_KWARGS}{mac}. + The instance has automatic storage duration: pointers to it will become - invalid when control exits the scope of the declaration. + invalid when control exits the scope of the declaration. If necessary, the + instance should be torn down before this happens, using the + \descref{sod_teardown}[function]{fun}. +\end{describe} + +\subsubsection{Dynamic allocation} +The following macros and functions deal with objects allocated from the +standard C heap. They don't work in freestanding implementations where +@|malloc| and @|free| are not available. + +\begin{describe*} + {\dhead[SOD_MAKE]{mac}{@ *SOD_MAKE(@, @);} + \dhead[sod_make]{fun}{void *sod_make(const SodClass *@, \dots);} + \dhead[sod_makev]{fun} + {void *sod_makev(const SodClass *@, va_list @);}} + Constructs and returns a pointer to a new instance of @. + + The direct class for the new instance is specified as a class name to + @|SOD_MAKE|, or a class object to the functions. + + Keyword arguments for the initialization message may be provided. The + @|SOD_MAKE| macro expects a single preprocessor-time argument which is + a use of one of \descref{KWARGS}{mac} or \descref{NO_KWARGS}{mac}; the + @|sod_make| function expects the keywords as a variable-length argument + tail; and @|sod_makev| expects the keywords to be passed indirectly, + through the captured argument-tail cursor @. + + Storage for the new instance will have been allocated using the standard + @|malloc| function. The easiest way to destroy the instance, when it is no + longer needed, is probably to call the + \descref{sod_destroy}[function]{fun}. + + The return value is an instance pointer for the class @; the + @|SOD_MAKE| macro will have converted it to the correct type, so it should + probably be used where possible. +\end{describe*} + +\begin{describe}[sod_destroy]{fun}{int sod_destroy(void *@

);} + Tears down and frees an instance allocated using @|malloc|. + + The pointer @

should be an instance pointer, i.e., a pointer to any of + an instance's chains. The instance is torn down, by sending it the + \descref{obj.teardown}[message]{msg}. If the instance reports itself ready + for deallocation, then its storage is released using @|free|. The return + value is the value returned by the @|obj.teardown| message. \end{describe} %%%----- That's all, folks --------------------------------------------------