das2C
das core C utilities (v3)
Loading...
Searching...
No Matches
form.h
Go to the documentation of this file.
1/* Copyright (C) 2026 Chris Piker <chris-piker@uiowa.edu>
2 *
3 * Author: C. Piker, via Claude Opus 5
4 *
5 * This file is part of das2C, the Core Das2 C Library.
6 *
7 * Das2C is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU Lesser General Public License version 2.1 as published
9 * by the Free Software Foundation.
10 *
11 * Das2C is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * version 2.1 along with das2C; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20/* Note this is a library-internal file, no stable public API is defined here */
21
99#ifndef _das_form_h_
100#define _das_form_h_
101
102#include <das3/value.h>
103#include <das3/units.h>
104#include <das3/datum.h>
105#include <das3/operator.h>
106#include <das3/property.h>
107
108/* Only to get the VARIDX_* index vocabulary.
109 Nothing here uses generator functions or classes. */
110#include <das3/generator.h>
111
112#ifdef __cplusplus
113extern "C" {
114#endif
115
116/* A formalism's named references -- a frame, a body, a center -- are plain
117 strings stored on the form. */
118#define DASFORM_NAME_SZ 64
119
120struct das_buffer;
121
122typedef struct das_form DasForm;
123
124
125/* ========================================================================= *
126 * das_operand: what a variable tells a form.
127 * ========================================================================= */
128
139typedef struct das_operand {
140
141 /* The operand's formalism, carried so a form can recognize a partner by
142 vtable address. Peer to peer, never upward. */
143 const DasForm* pForm;
144
145 das_val_type vtElem; /* what one cell of this operand holds */
146 das_units units;
147
148 /* The internal shape as DECLARED. Rank matters and the product does not:
149 a 3;3 rotation and a nine component vector share an element count and
150 are not the same thing. */
151 int nIntRank; /* 0 for a scalar, aIntShape untouched */
152 ptrdiff_t aIntShape[VARIDX_MAX];
153
155
158DAS_API size_t das_operand_elems(const das_operand* pThis);
159
160
161/* ========================================================================= *
162 * DasBinOp: the resolved recipe for one pairing.
163 *
164 * Handed back by binOpLeft/binOpRight once, at DasVarBin construction. The
165 * walker reads six facts off it and then calls apply() per item forever; it
166 * never asks again what math made a value.
167 *
168 * Derived types carry whatever that pairing needs. This is where a unit
169 * conversion factor lives for linear, and a component permutation for
170 * rotation -- private to the pairing that needs it, not a field every
171 * formalism pays for.
172 * ========================================================================= */
173
174typedef struct das_binop DasBinOp;
175
176typedef struct DasBinOp_VTbl {
177
178 /* One item run from each side in, one item run out. Item-at-a-time is
179 the whole contract; see THE RULE above. */
180 bool (*apply)(
181 const DasBinOp* pThis, const ubyte* pLRun, const ubyte* pRRun,
182 ubyte* pOutRun
183 );
184
185 void (*release)(DasBinOp* pThis); /* derived storage, then free */
186
187} DasBinOp_VTbl;
188
189struct das_binop {
190
191 const DasBinOp_VTbl* pVTbl;
192
193 /* Everything the walker needs, settled once by the resolving form. */
194 DasForm* pForm; /* result formalism, owned here */
195 das_units units;
196 das_val_type vtOut;
197 int nIntRank; /* result item shape; a rotation */
198 ptrdiff_t aIntShape[VARIDX_MAX]; /* applied to a vector SHRINKS it */
199
200 int nRef;
201};
202
211typedef enum das_binop_stat_e {
212 dbsDecline = 0,
213 dbsOkay,
214 dbsRefuse
216
217DAS_API int DasBinOp_incRef(DasBinOp* pThis);
218DAS_API int DasBinOp_decRef(DasBinOp* pThis);
219
220#define DasBinOp_apply(P,L,R,O) ((P)->pVTbl->apply((P),(L),(R),(O)))
221
222
223/* ========================================================================= *
224 * DasForm, the base.
225 * ========================================================================= */
226
227typedef struct DasForm_VTbl {
228
229 const char* sKind; /* the wire kind= token, "vector", "rotation" */
230
231 /* An unbound instance for setParam to fill. Registering this in form.c's
232 kind table is the ENTIRE footprint of a new formalism outside its own
233 file; if it ever becomes more than that, this layer has failed. */
234 DasForm* (*create)(void);
235
236 /* Accept one <ops> attribute. A form refuses a name it does not know: a
237 reader that claims a kind must not skip a misspelled parameter. */
238 DasErrCode (*setParam)(
239 DasForm* pThis, const char* sName, const char* sVal
240 );
241
242 /* Is this form usable for a variable of this internal shape?
243 *
244 * Called once when the form is attached to a variable.
245 *
246 * Derived classes of DasForm need to check to see if all their required
247 * parameters are initialize or the defaults are okay. It's also the time
248 * to see if the external world will hand-in element composites of the right
249 * shape. Basically the hand-shake agreement stage.
250 *
251 * NULL when a kind has nothing to insist on.
252 * @returns DAS_OKAY or error naming what is wrong.
253 */
254 DasErrCode (*validate)(
255 DasForm* pThis, int nIntRank, const ptrdiff_t* pIntShape
256 );
257
258 /* Read one formalism parameter.
259 *
260 * @param pType, when not NULL, receives a DASPROP_* code in that
261 * adheres to DasProp_type() return type. For formalisms an parameter
262 * names imply an explicit type, which is provided here.
263 *
264 * @returns NULL if this form has no such parameter. The returned string
265 * is owned by the form and lives as long as it does.
266 */
267 const char* (*getParam)(
268 const DasForm* pThis, const char* sName, ubyte* pType
269 );
270
271 /* Emit <ops .../>. TALKATIVE: state a parameter even at its default,
272 since the schema cannot carry a default behind an anyAttribute. */
273 DasErrCode (*encode)(
274 const DasForm* pThis, struct das_buffer* pBuf
275 );
276
277 /* Read one item run into a typed datum. NULL when the kind has no single
278 datum form. */
279 bool (*pack)(
280 const DasForm* pThis, const das_operand* pOp, const ubyte* pRun,
281 das_datum* pOut
282 );
283
284 /* The das_val_type a datum from this kind carries, vtUnknown to fall back
285 to the element type. */
286 das_val_type (*datumType)(const DasForm* pThis);
287
288 /* Render one item run. NULL means "no rendering of my own", and the
289 caller falls back to printing the cells as plain numbers. */
290 char* (*prnRun)(
291 const DasForm* pThis, const ubyte* pRun, uint32_t nElems,
292 das_val_type et, char* sBuf, int nLen
293 );
294
295 /* The canonical symbol for one component, in storage order. NULL if this
296 * kind has no named components, or none for that component.
297 *
298 * No shape argument. A form is owned outright by one variable and was
299 * handed that variable's intern= at validate(), so it already knows how
300 * many components it is describing.
301 */
302 const char* (*compSym)(const DasForm* pThis, int iComp);
303
304 /* Claim a pairing, or decline it for the other side to try.
305 *
306 * pThis is pL->pForm in the Left hook and pR->pForm in the Right one; it
307 * rides along so every slot has the same shape. The operands are NEVER
308 * reordered by either hook, so an undefined pairing fails loud instead of
309 * silently commuting.
310 *
311 * nOp is a D2BOP_* code from operator.h. There is no separate formalism
312 * op enum; the library already has one vocabulary for operators and
313 * das_vt_merge() and Units_canMerge() both speak it.
314 */
315 das_binop_stat (*binOpLeft)(
316 const DasForm* pThis, const das_operand* pL, int nOp,
317 const das_operand* pR, DasBinOp** ppOut
318 );
319 das_binop_stat (*binOpRight)(
320 const DasForm* pThis, const das_operand* pL, int nOp,
321 const das_operand* pR, DasBinOp** ppOut
322 );
323
324 DasForm* (*copy)(const DasForm* pThis);
325 void (*release)(DasForm* pThis);
326
327} DasForm_VTbl;
328
329struct das_form {
330 const DasForm_VTbl* pVTbl;
331};
332
334#define DasForm_kindStr(P) ((P)->pVTbl->sKind)
335
347#define DasForm_isKind(P,VT) (((P) != NULL)&&((P)->pVTbl == (VT)))
348
349/* The vtable every unrecognized kind= binds to. Exported so that its address
350 can be compared. Client code uses the DAS_FORM_EXT macro below and has no
351 reason to name this directly. */
352DAS_API extern const DasForm_VTbl das_form_generic_vtbl;
353
360#define DAS_FORM_EXT (&das_form_generic_vtbl)
361
364DAS_API const char* DasFormGeneric_kind(const DasForm* pThis);
365
372DAS_API bool DasFormGeneric_paramAt(
373 const DasForm* pThis, int iParam, const char** psName, const char** psVal
374);
375
383DAS_API void del_DasForm(DasForm* pThis);
384
388DAS_API DasForm* DasForm_copy(const DasForm* pThis);
389
402DAS_API const char* DasForm_getParam(
403 const DasForm* pThis, const char* sName, ubyte* pType
404);
405
423DAS_API DasForm* new_DasForm_pairs(const char** psAttr);
424
450DAS_API const char* DasForm_compSym(const DasForm* pThis, int iComp);
451
452DAS_API char* DasForm_prnRun(
453 const DasForm* pThis, const ubyte* pRun, uint32_t nElems,
454 das_val_type et, char* sBuf, int nLen
455);
456
466DAS_API char* DasForm_toStr(const DasForm* pThis, char* sBuf, int nLen);
467
475DAS_API DasErrCode DasForm_validate(
476 DasForm* pThis, int nIntRank, const ptrdiff_t* pIntShape
477);
478
479/* INTERNAL, shared by the formalisms that carry a component order. Emits
480 sysorder= when it says something the default does not: a non-ascending
481 order, printed to the component count recorded when validate() was run.
482
483 Use sysorder= in XML headers when the order is not ascending. pOrder is
484 uComps entries long slot to canonical component, so this works for a nine
485 element rotation as readily as a three element vector. */
486DasErrCode _das_form_prnOrder(
487 struct das_buffer* pBuf, const ubyte* pOrder, ubyte uComps
488);
489
492DAS_API const DasForm_VTbl* das_form_lookup(const char* sKind);
493
494#ifdef __cplusplus
495}
496#endif
497
498#endif /* _das_form_h_ */
DAS_API const DasForm_VTbl * das_form_lookup(const char *sKind)
The vtable for a wire token, or NULL on a miss.
das_binop_stat
Was this pairing claimed?
Definition form.h:211
DAS_API size_t das_operand_elems(const das_operand *pThis)
Total elements in one item run, the product of the internal extents.
Value sources for the DasVar layer.
#define VARIDX_MAX
Max index count for the model.
Definition generator.h:55
int DasErrCode
return code type 0 indicates success, negative integer indicates failure
Definition defs.h:184
const char * das_units
Handle SI and other units, with accommodations for Epoch systems, from units.h.
Definition units.h:144
das_val_type
Enumeration of types stored in Das Array (DasAry) objects from value.h.
Definition value.h:81
The form layer's currency: a snapshot of the facts a formalism may need.
Definition form.h:139
Defines units used for items in the stream, most notably time units that reference an epoch and a ste...
A generic value type for use in arrays, datums and variables.