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
\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
\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}
The macro @|KWSET_PARSEFN| defines a keyword argument \emph{parser
function}
\begin{prog}
- void @<set>{}_kwparse(\=struct @<set>{}_kwargs *@<kw>,
- const char *@<kwfirst>, va_list *@<ap>, \+ \\
- const struct kwval *@<v>, size_t @<n>);
+ void @<set>{}_kwparse%
+ (\=struct @<set>{}_kwargs *@<kw>,
+ const char *@<kwfirst>, va_list *@<ap>, \+\\
+ const struct kwval *@<v>, size_t @<n>);
\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
purpose, the argument vector @<v> is scanned \emph{after} the
variable-length argument tail captured in @<ap>.)
- The variable-argument tail is read from the list described by @|* @<ap>|.
+ The variable-argument tail is read from the list described by @|*@<ap>|.
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
which expects keyword arguments, but don't supply any and forget the null
pointer which terminates the (empty) list.} %
If @<kwfirst> is a null pointer, then @<ap> need not be a valid pointer;
- otherwise, the cursor object @|* @<ap>| will be modified as the function
+ otherwise, the cursor object @|*@<ap>| will be modified as the function
extracts successive arguments from the tail.
The keyword vector is read from the vector of @|kwval| structures starting
\end{describe}
\begin{describe}[kw_parseempty]{fun}
- {void kw_parseempty(\=const char *@<set>,
- const char *@<kwfirst>, va_list *@<ap>, \+ \\
- const struct kwval *@<v>, size_t @<n>);}
+ {void kw_parseempty%
+ (\=const char *@<set>,
+ const char *@<kwfirst>, va_list *@<ap>, \+\\
+ const struct kwval *@<v>, size_t @<n>);}
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}).
\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}
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}
+ {@<cls> *SOD_INIT(@<cls>, void *@<p>, @<keywords>);}
+ \dhead[sod_init]{fun}
+ {void *sod_init(const SodClass *@<cls>, void *@<p>, \dots);}
+ \dhead[sod_initv]{fun}
+ {void *sod_initv(const SodClass *@<cls>, void *@<p>, va_list @<ap>);}}
+ Imprints and initializes an instance of a class @<cls> in the storage
+ starting at address~@<p>.
+
+ 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 @<ap>.
+
+ The return value is an instance pointer for the class @<cls>; 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 @<p> by the layout rules described in
+ \xref{sec:structures.layout.instance}.
+\end{describe*}
+
+\begin{describe}[sod_teardown]{fun}{int sod_teardown(void *@<p>);}
+ 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(@<cls>, @<var>);}
+\begin{describe}[SOD_DECL]{mac}{SOD_DECL(@<cls>, @<var>, @<keywords>);}
Declares and initializes an instance with automatic storage duration.
Given a class name @<cls> and an identifier @<var>, @|SOD_DECL| declares
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}{@<cls> *SOD_MAKE(@<cls>, @<keywords>);}
+ \dhead[sod_make]{fun}{void *sod_make(const SodClass *@<cls>, \dots);}
+ \dhead[sod_makev]{fun}
+ {void *sod_makev(const SodClass *@<cls>, va_list @<ap>);}}
+ Constructs and returns a pointer to a new instance of @<cls>.
+
+ 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 @<ap>.
+
+ 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 @<cls>; 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 *@<p>);}
+ Tears down and frees an instance allocated using @|malloc|.
+
+ The pointer @<p> 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 --------------------------------------------------