Commit | Line | Data |
---|---|---|
b1a20bee MW |
1 | /* -*-c-*- |
2 | * | |
3 | * Test-vector framework basic register types | |
4 | * | |
5 | * (c) 2024 Straylight/Edgeware | |
6 | */ | |
7 | ||
8 | /*----- Licensing notice --------------------------------------------------* | |
9 | * | |
10 | * This file is part of the mLib utilities library. | |
11 | * | |
12 | * mLib is free software: you can redistribute it and/or modify it under | |
13 | * the terms of the GNU Library General Public License as published by | |
14 | * the Free Software Foundation; either version 2 of the License, or (at | |
15 | * your option) any later version. | |
16 | * | |
17 | * mLib is distributed in the hope that it will be useful, but WITHOUT | |
18 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
19 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public | |
20 | * License for more details. | |
21 | * | |
22 | * You should have received a copy of the GNU Library General Public | |
23 | * License along with mLib. If not, write to the Free Software | |
24 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | |
25 | * USA. | |
26 | */ | |
27 | ||
28 | #ifndef MLIB_TVEC_TYPES_H | |
29 | #define MLIB_TVEC_TYPES_H | |
30 | ||
31 | #ifdef __cplusplus | |
32 | extern "C" { | |
33 | #endif | |
34 | ||
35 | /*----- Header files ------------------------------------------------------*/ | |
36 | ||
37 | #ifndef MLIB_TVEC_H | |
38 | # include "tvec.h" | |
39 | #endif | |
40 | ||
41 | /*----- Integer types: signed and unsigned --------------------------------*/ | |
42 | ||
43 | /* Integers may be input in decimal, hex, binary, or octal, following | |
44 | * approximately usual conventions. | |
45 | * | |
46 | * * Signed integers may be preceded with a `+' or `-' sign. | |
47 | * | |
48 | * * Decimal integers are just a sequence of decimal digits `0' ... `9'. | |
49 | * | |
50 | * * Octal integers are a sequence of digits `0' ... `7', preceded by `0o' | |
51 | * or `0O'. | |
52 | * | |
53 | * * Hexadecimal integers are a sequence of digits `0' ... `9', `a' | |
54 | * ... `f', or `A' ... `F', preceded by `0x' or `0X'. | |
55 | * | |
56 | * * Radix-B integers are a sequence of digits `0' ... `9', `a' ... `f', or | |
57 | * `A' ... `F', each with value less than B, preceded by `Br' or `BR', | |
58 | * where 0 < B < 36 is expressed in decimal without any leading `0' or | |
59 | * internal underscores `_'. | |
60 | * | |
61 | * * A digit sequence may contain internal underscore `_' separators, but | |
62 | * not before or after all of the digits; and two consecutive `_' | |
63 | * characters are not permitted. | |
64 | */ | |
65 | ||
66 | extern const struct tvec_regty tvty_int, tvty_uint; | |
67 | ||
68 | /* The @arg.p@ slot may be null or a pointer to @struct tvec_irange@ or | |
69 | * @struct tvec_urange@ as appropriate. The bounds are inclusive; use, e.g., | |
70 | * @LONG_MAX@ explicitly if one or the other bound is logically inapplicable. | |
71 | * If %$m$% is nonzero, then the value must additionally be congruent to | |
72 | * %$a$% modulo %$m$%. | |
73 | */ | |
74 | struct tvec_irange { long min, max, m, a; }; | |
75 | struct tvec_urange { unsigned long min, max, m, a; }; | |
76 | ||
77 | /* Bounds corresponding to common integer types. */ | |
78 | extern const struct tvec_irange | |
79 | tvrange_schar, tvrange_short, tvrange_int, tvrange_long, | |
80 | tvrange_sbyte, tvrange_i16, tvrange_i32; | |
81 | extern const struct tvec_urange | |
82 | tvrange_uchar, tvrange_ushort, tvrange_uint, tvrange_ulong, tvrange_size, | |
83 | tvrange_byte, tvrange_u16, tvrange_u32; | |
84 | ||
85 | /* --- @tvec_claimeq_int@, @TVEC_CLAIMEQ_INT@ --- * | |
86 | * | |
87 | * Arguments: @struct tvec_state *tv@ = test-vector state | |
88 | * @long i0, i1@ = two signed integers | |
89 | * @const char *file@, @unsigned @lno@ = calling file and line | |
90 | * @const char *expr@ = the expression to quote on failure | |
91 | * | |
92 | * Returns: Nonzero if @i0@ and @i1@ are equal, otherwise zero. | |
93 | * | |
94 | * Use: Check that values of @i0@ and @i1@ are equal. As for | |
95 | * @tvec_claim@ above, a test case is automatically begun and | |
96 | * ended if none is already underway. If the values are | |
97 | * unequal, then @tvec_fail@ is called, quoting @expr@, and the | |
98 | * mismatched values are dumped: @i0@ is printed as the output | |
99 | * value and @i1@ is printed as the input reference. | |
100 | * | |
101 | * The @TVEC_CLAIM_INT@ macro is similar, only it (a) identifies | |
102 | * the file and line number of the call site automatically, and | |
103 | * (b) implicitly quotes the source text of the @i0@ and @i1@ | |
104 | * arguments in the failure message. | |
105 | */ | |
106 | ||
107 | extern int tvec_claimeq_int(struct tvec_state */*tv*/, | |
108 | long /*i0*/, long /*i1*/, | |
109 | const char */*file*/, unsigned /*lno*/, | |
110 | const char */*expr*/); | |
111 | #define TVEC_CLAIMEQ_INT(tv, i0, i1) \ | |
112 | (tvec_claimeq_int(tv, i0, i1, __FILE__, __LINE__, #i0 " /= " #i1)) | |
113 | ||
114 | /* --- @tvec_claimeq_uint@, @TVEC_CLAIMEQ_UINT@ --- * | |
115 | * | |
116 | * Arguments: @struct tvec_state *tv@ = test-vector state | |
117 | * @unsigned long u0, u1@ = two unsigned integers | |
118 | * @const char *file@, @unsigned @lno@ = calling file and line | |
119 | * @const char *expr@ = the expression to quote on failure | |
120 | * | |
121 | * Returns: Nonzero if @u0@ and @u1@ are equal, otherwise zero. | |
122 | * | |
123 | * Use: Check that values of @u0@ and @u1@ are equal. As for | |
124 | * @tvec_claim@ above, a test case is automatically begun and | |
125 | * ended if none is already underway. If the values are | |
126 | * unequal, then @tvec_fail@ is called, quoting @expr@, and the | |
127 | * mismatched values are dumped: @u0@ is printed as the output | |
128 | * value and @u1@ is printed as the input reference. | |
129 | * | |
130 | * The @TVEC_CLAIM_UINT@ macro is similar, only it (a) | |
131 | * identifies the file and line number of the call site | |
132 | * automatically, and (b) implicitly quotes the source text of | |
133 | * the @u0@ and @u1@ arguments in the failure message. | |
134 | */ | |
135 | ||
136 | extern int tvec_claimeq_uint(struct tvec_state */*tv*/, | |
137 | unsigned long /*u0*/, unsigned long /*u1*/, | |
138 | const char */*file*/, unsigned /*lno*/, | |
139 | const char */*expr*/); | |
140 | #define TVEC_CLAIMEQ_UINT(tv, u0, u1) \ | |
141 | (tvec_claimeq_uint(tv, u0, u1, __FILE__, __LINE__, #u0 " /= " #u1)) | |
142 | ||
143 | /*----- Size type ---------------------------------------------------------*/ | |
144 | ||
145 | /* A size is an unsigned integer followed by an optional unit specifier | |
146 | * consisting of an SI unit prefix and (optionally) the letter `B'. | |
147 | */ | |
148 | ||
149 | extern const struct tvec_regty tvty_size; | |
150 | ||
151 | /* --- @tvec_claimeq_size@ --- * | |
152 | * | |
153 | * Arguments: @struct tvec_state *tv@ = test-vector state | |
154 | * @unsigned long sz0, sz1@ = two sizes | |
155 | * @const char *file@, @unsigned @lno@ = calling file and line | |
156 | * @const char *expr@ = the expression to quote on failure | |
157 | * | |
158 | * Returns: Nonzero if @sz0@ and @sz1@ are equal, otherwise zero. | |
159 | * | |
160 | * Use: Check that values of @u0@ and @u1@ are equal. As for | |
161 | * @tvec_claim@ above, a test case is automatically begun and | |
162 | * ended if none is already underway. If the values are | |
163 | * unequal, then @tvec_fail@ is called, quoting @expr@, and the | |
164 | * mismatched values are dumped: @u0@ is printed as the output | |
165 | * value and @u1@ is printed as the input reference. | |
166 | * | |
167 | * The @TVEC_CLAIM_SIZE@ macro is similar, only it (a) | |
168 | * identifies the file and line number of the call site | |
169 | * automatically, and (b) implicitly quotes the source text of | |
170 | * the @u0@ and @u1@ arguments in the failure message. | |
171 | */ | |
172 | ||
173 | int tvec_claimeq_size(struct tvec_state *tv, | |
174 | unsigned long sz0, unsigned long sz1, | |
175 | const char *file, unsigned lno, const char *expr); | |
176 | #define TVEC_CLAIMEQ_UINT(tv, u0, u1) \ | |
177 | (tvec_claimeq_uint(tv, u0, u1, __FILE__, __LINE__, #u0 " /= " #u1)) | |
178 | ||
179 | /*----- Floating-point type -----------------------------------------------*/ | |
180 | ||
181 | /* Floating-point values are either NaN (%|#nan|%, if supported by the | |
182 | * platform); positive or negative infinity (%|#inf|%, %|+#inf|%, or | |
183 | * %|#+inf|% (preferring the last), and %|-#inf|% or %|#-inf|% (preferring | |
184 | * the latter), if supported by the platform); or a number in strtod(3) | |
185 | * syntax. | |
186 | * | |
187 | * The comparison rules for floating-point numbers are complex: see | |
188 | * @tvec_claimeqish_float@ for details. | |
189 | */ | |
190 | ||
191 | extern const struct tvec_regty tvty_float; | |
192 | ||
193 | struct tvec_floatinfo { | |
194 | /* Details about acceptable floating-point values. */ | |
195 | ||
196 | unsigned f; /* flags (@TVFF_...@ bits) */ | |
197 | #define TVFF_NOMIN 0x0001 /* ignore @min@ (allow -∞) */ | |
198 | #define TVFF_NOMAX 0x0002 /* ignore @max@ (allow +∞) */ | |
199 | #define TVFF_NANOK 0x0004 /* permit NaN */ | |
200 | #define TVFF_NEGINFOK 0x0008 /* permit -∞, check finite */ | |
201 | #define TVFF_POSINFOK 0x0010 /* permit +∞, check finite */ | |
202 | #define TVFF_INFOK (TVFF_NEGINFOK | TVFF_POSINFOK) /* permit ±∞ */ | |
203 | #define TVFF_EQMASK 0x0f00 /* how to compare */ | |
204 | #define TVFF_EXACT 0x0000 /* must equal exactly */ | |
205 | #define TVFF_ABSDELTA 0x0100 /* must be within @delta@ */ | |
206 | #define TVFF_RELDELTA 0x0200 /* diff < @delta@ fraction */ | |
207 | double min, max; /* smallest/largest value allowed */ | |
208 | double delta; /* maximum tolerable difference */ | |
209 | }; | |
210 | ||
211 | extern const struct tvec_floatinfo | |
212 | tvflt_float, tvflt_double, tvflt_finite, tvflt_nonneg; | |
213 | ||
214 | /* --- @tvec_claimeqish_float@, @TVEC_CLAIMEQISH_FLOAT@ --- * | |
215 | * | |
216 | * Arguments: @struct tvec_state *tv@ = test-vector state | |
217 | * @double f0, f1@ = two floating-point numbers | |
218 | * @unsigned f@ = flags (@TVFF_...@) | |
219 | * @double delta@ = maximum tolerable difference | |
220 | * @const char *file@, @unsigned @lno@ = calling file and line | |
221 | * @const char *expr@ = the expression to quote on failure | |
222 | * | |
223 | * Returns: Nonzero if @f0@ and @f1@ are sufficiently close, otherwise | |
224 | * zero. | |
225 | * | |
226 | * Use: Check that values of @f0@ and @f1@ are sufficiently close. | |
227 | * As for @tvec_claim@ above, a test case is automatically begun | |
228 | * and ended if none is already underway. If the values are | |
229 | * too far apart, then @tvec_fail@ is called, quoting @expr@, | |
230 | * and the mismatched values are dumped: @f0@ is printed as the | |
231 | * output value and @f1@ is printed as the input reference. | |
232 | * | |
233 | * The details for the comparison are as follows. | |
234 | * | |
235 | * * A NaN value matches any other NaN, and nothing else. | |
236 | * | |
237 | * * An infinity matches another infinity of the same sign, | |
238 | * and nothing else. | |
239 | * | |
240 | * * If @f&TVFF_EQMASK@ is @TVFF_EXACT@, then any | |
241 | * representable number matches only itself: in particular, | |
242 | * positive and negative zero are considered distinct. | |
243 | * (This allows tests to check that they land on the correct | |
244 | * side of branch cuts, for example.) | |
245 | * | |
246 | * * If @f&TVFF_EQMASK@ is @TVFF_ABSDELTA@, then %$x$% matches | |
247 | * %$y$% when %$|x - y| < \delta$%. | |
248 | * | |
249 | * * If @f&TVFF_EQMASK@ is @TVFF_RELDELTA@, then %$x$% matches | |
250 | * %$y$% when %$|1 - x/y| < \delta$%. (Note that this | |
251 | * criterion is asymmetric. Write %$x \approx_\delta y$% | |
252 | * if and only if %$|1 - x/y < \delta$%. Then, for example, | |
253 | * if %$y/(1 + \delta) < x < y (1 - \delta)$%, then | |
254 | * %$x \approx_\delta y$%, but %$y \not\approx_\delta x$%.) | |
255 | * | |
256 | * The @TVEC_CLAIM_FLOAT@ macro is similar, only it (a) | |
257 | * identifies the file and line number of the call site | |
258 | * automatically, and (b) implicitly quotes the source text of | |
259 | * the @f0@ and @f1@ arguments (and @delta@) in the failure | |
260 | * message. | |
261 | */ | |
262 | ||
263 | extern int tvec_claimeqish_float(struct tvec_state */*tv*/, | |
264 | double /*f0*/, double /*f1*/, | |
265 | unsigned /*f*/, double /*delta*/, | |
266 | const char */*file*/, unsigned /*lno*/, | |
267 | const char */*expr*/); | |
268 | #define TVEC_CLAIMEQISH_FLOAT(tv, f0, f1, f, delta) \ | |
269 | (tvec_claimeqish_float(tv, f0, f1, f, delta, __FILE__, __LINE__, \ | |
270 | #f0 " /= " #f1 " (+/- " #delta ")")) | |
271 | ||
272 | /* --- @tvec_claimeq_float@, @TVEC_CLAIMEQ_FLOAT@ --- * | |
273 | * | |
274 | * Arguments: @struct tvec_state *tv@ = test-vector state | |
275 | * @double f0, f1@ = two floating-point numbers | |
276 | * @const char *file@, @unsigned @lno@ = calling file and line | |
277 | * @const char *expr@ = the expression to quote on failure | |
278 | * | |
279 | * Returns: Nonzero if @f0@ and @u1@ are identical, otherwise zero. | |
280 | * | |
281 | * Use: Check that values of @f0@ and @f1@ are identical. The | |
282 | * function is exactly equivalent to @tvec_claimeqish_float@ | |
283 | * with @f == TVFF_EXACT@; the macro is similarly like | |
284 | * @TVEC_CLAIMEQISH_FLOAT@ with @f == TVFF_EXACT@, except that | |
285 | * it doesn't bother to quote a delta. | |
286 | */ | |
287 | ||
288 | extern int tvec_claimeq_float(struct tvec_state */*tv*/, | |
289 | double /*f0*/, double /*f1*/, | |
290 | const char */*file*/, unsigned /*lno*/, | |
291 | const char */*expr*/); | |
292 | #define TVEC_CLAIMEQ_FLOAT(tv, f0, f1) \ | |
293 | (tvec_claimeq_float(tv, f0, f1, __FILE__, __LINE__, #f0 " /= " #f1)) | |
294 | ||
295 | /*----- Durations ---------------------------------------------------------*/ | |
296 | ||
297 | /* A duration measures a time interval in seconds. The input format consists | |
298 | * of a nonnegative decimal floating-point number in @strtod@ format followed | |
299 | * by an optional unit specification. | |
300 | */ | |
301 | ||
302 | extern const struct tvec_regty tvty_duration; | |
303 | ||
304 | /* --- @tvec_parsedurunit@ --- * | |
305 | * | |
306 | * Arguments: @double *scale_out@ = where to leave the scale | |
307 | * @const char **p_inout@ = input unit string, updated | |
308 | * | |
309 | * Returns: Zero on success, %$-1$% on error. | |
310 | * | |
311 | * Use: If @*p_inout@ begins with a unit string followed by the end | |
312 | * of the string or some non-alphanumeric character, then store | |
313 | * the corresponding scale factor in @*scale_out@, advance | |
314 | * @*p_inout@ past the unit string, and return zero. Otherwise, | |
315 | * return %$-1$%. | |
316 | */ | |
317 | ||
318 | extern int tvec_parsedurunit(double */*scale_out*/, | |
319 | const char **/*p_inout*/); | |
320 | ||
321 | /* --- @tvec_claimeqish_duration@, @TVEC_CLAIMEQISH_DURATION@ --- * | |
322 | * | |
323 | * Arguments: @struct tvec_state *tv@ = test-vector state | |
324 | * @double t0, t1@ = two durations | |
325 | * @unsigned f@ = flags (@TVFF_...@) | |
326 | * @double delta@ = maximum tolerable difference | |
327 | * @const char *file@, @unsigned @lno@ = calling file and line | |
328 | * @const char *expr@ = the expression to quote on failure | |
329 | * | |
330 | * Returns: Nonzero if @t0@ and @t1@ are sufficiently close, otherwise | |
331 | * zero. | |
332 | * | |
333 | * Use: Check that values of @t0@ and @t1@ are sufficiently close. | |
334 | * This is essentially the same as @tvec_claimeqish_float@, only | |
335 | * it dumps the values as durations on a mismatch. | |
336 | * | |
337 | * The @TVEC_CLAIM_FLOAT@ macro is similar, only it (a) | |
338 | * identifies the file and line number of the call site | |
339 | * automatically, and (b) implicitly quotes the source text of | |
340 | * the @t0@ and @t1@ arguments (and @delta@) in the failure | |
341 | * message. | |
342 | */ | |
343 | ||
344 | extern int tvec_claimeqish_duration(struct tvec_state */*tv*/, | |
345 | double /*t0*/, double /*t1*/, | |
346 | unsigned /*f*/, double /*delta*/, | |
347 | const char */*file*/, unsigned /*lno*/, | |
348 | const char */*expr*/); | |
349 | #define TVEC_CLAIMEQISH_DURATION(tv, t0, t1, f, delta) \ | |
350 | (tvec_claimeqish_duration(tv, t0, t1, f, delta, __FILE__, __LINE__, \ | |
351 | #t0 " /= " #t1 " (+/- " #delta ")")) | |
352 | ||
353 | /* --- @tvec_claimeq_duration@, @TVEC_CLAIMEQ_DURATION@ --- * | |
354 | * | |
355 | * Arguments: @struct tvec_state *tv@ = test-vector state | |
356 | * @double t0, t1@ = two durations | |
357 | * @const char *file@, @unsigned @lno@ = calling file and line | |
358 | * @const char *expr@ = the expression to quote on failure | |
359 | * | |
360 | * Returns: Nonzero if @t0@ and @t1@ are identical, otherwise zero. | |
361 | * | |
362 | * Use: Check that values of @t0@ and @t1@ are identical. The | |
363 | * function is exactly equivalent to @tvec_claimeqish_duration@ | |
364 | * with @f == TVFF_EXACT@; the macro is similarly like | |
365 | * @TVEC_CLAIMEQISH_DURATION@ with @f == TVFF_EXACT@, except | |
366 | * that it doesn't bother to quote a delta. | |
367 | */ | |
368 | ||
369 | int tvec_claimeq_duration(struct tvec_state */*tv*/, | |
370 | double /*t0*/, double /*t1*/, | |
371 | const char */*file*/, unsigned /*lno*/, | |
372 | const char */*expr*/); | |
373 | #define TVEC_CLAIMEQ_DURATION(tv, t0, t1) \ | |
374 | (tvec_claimeq_float(tv, t0, t1, __FILE__, __LINE__, #t0 " /= " #t1)) | |
375 | ||
376 | /*----- Enumerated types --------------------------------------------------*/ | |
377 | ||
378 | /* An enumeration describes a set of values of some underlying type, each of | |
379 | * which has a symbolic name. Values outside of the defined set can occur -- | |
380 | * on output, because of bugs in the tested code, or on input to test | |
381 | * handling of unexpected values. | |
382 | * | |
383 | * There is a distinct enumerated type for each of the branches of | |
384 | * @tvec_misc@. In the following, we write @t@ for the type code, which is | |
385 | * @i@ for signed integer, @u@ for unsigned integer, @f@ for floating-point, | |
386 | * and @p@ for pointer. | |
387 | * | |
388 | * On input, an enumerated value may be given by name or as a literal value. | |
389 | * For enumerations based on numeric types, the literal values can be written | |
390 | * in the same syntax as the underlying values. For enumerations based on | |
391 | * pointers, the only permitted literal is %|#nil|%, which denotes a null | |
392 | * pointer. On output, names are preferred (with the underlying value given | |
393 | * in a comment). | |
394 | */ | |
395 | ||
396 | #define DEFENUMTY(tag, ty, slot) \ | |
397 | extern const struct tvec_regty tvty_##slot##enum; | |
398 | TVEC_MISCSLOTS(DEFENUMTY) | |
399 | #undef DEFENUMTY | |
400 | ||
401 | /* A @struct tvec_tassoc@ associates a string tag with a value. */ | |
402 | #define DEFASSOC(tag_, ty, slot) \ | |
403 | struct tvec_##slot##assoc { const char *tag; ty slot; }; | |
404 | TVEC_MISCSLOTS(DEFASSOC) | |
405 | #undef DEFASSOC | |
406 | ||
407 | #define TVEC_ENDENUM { 0, 0 } | |
408 | ||
409 | /* Information about an enumerated type. */ | |
410 | #define DEFINFO(tag, ty, slot) \ | |
411 | struct tvec_##slot##enuminfo { \ | |
412 | const char *name; /* type name for diagnostics */ \ | |
413 | const struct tvec_##slot##assoc *av; /* name/value mappings */ \ | |
414 | EXTRA_##tag##_INFOSLOTS /* type-specific extra info */ \ | |
415 | }; | |
416 | ||
417 | #define EXTRA_INT_INFOSLOTS \ | |
418 | const struct tvec_irange *ir; /* allowed range of raw values */ | |
419 | ||
420 | #define EXTRA_UINT_INFOSLOTS \ | |
421 | const struct tvec_urange *ur; /* allowed range of raw values */ | |
422 | ||
423 | #define EXTRA_FLT_INFOSLOTS \ | |
424 | const struct tvec_floatinfo *fi; /* range and matching policy */ | |
425 | ||
426 | #define EXTRA_PTR_INFOSLOTS /* (nothing) */ | |
427 | ||
428 | TVEC_MISCSLOTS(DEFINFO) | |
429 | ||
430 | #undef EXTRA_INT_INFOSLOTS | |
431 | #undef EXTRA_UINT_INFOSLOTS | |
432 | #undef EXTRA_FLT_INFOSLOTS | |
433 | #undef EXTRA_PTR_INFOSLOTS | |
434 | ||
435 | #undef DEFINFO | |
436 | ||
437 | /* Standard enumerations. */ | |
438 | extern const struct tvec_ienuminfo tvenum_bool; | |
439 | extern const struct tvec_ienuminfo tvenum_cmp; | |
440 | ||
441 | /* --- @tvec_claimeq_tenum@, @TVEC_CLAIMEQ_TENUM@ --- * | |
442 | * | |
443 | * Arguments: @struct tvec_state *tv@ = test-vector state | |
444 | * @const struct tvec_typeenuminfo *ei@ = enumeration type info | |
445 | * @ty t0, t1@ = two values | |
446 | * @const char *file@, @unsigned @lno@ = calling file and line | |
447 | * @const char *expr@ = the expression to quote on failure | |
448 | * | |
449 | * Returns: Nonzero if @t0@ and @t1@ are equal, otherwise zero. | |
450 | * | |
451 | * Use: Check that values of @t0@ and @t1@ are equal. As for | |
452 | * @tvec_claim@ above, a test case is automatically begun and | |
453 | * ended if none is already underway. If the values are | |
454 | * unequal, then @tvec_fail@ is called, quoting @expr@, and the | |
455 | * mismatched values are dumped: @t0@ is printed as the output | |
456 | * value and @t1@ is printed as the input reference. | |
457 | * | |
458 | * The @TVEC_CLAIM_TENUM@ macro is similar, only it (a) | |
459 | * identifies the file and line number of the call site | |
460 | * automatically, and (b) implicitly quotes the source text of | |
461 | * the @t0@ and @t1@ arguments in the failure message. | |
462 | */ | |
463 | ||
464 | #define DECLCLAIM(tag, ty, slot) \ | |
465 | extern int tvec_claimeq_##slot##enum \ | |
466 | (struct tvec_state */*tv*/, \ | |
467 | const struct tvec_##slot##enuminfo */*ei*/, \ | |
468 | ty /*t0*/, ty /*t1*/, \ | |
469 | const char */*file*/, unsigned /*lno*/, const char */*expr*/); | |
470 | TVEC_MISCSLOTS(DECLCLAIM) | |
471 | #undef DECLCLAIM | |
472 | #define TVEC_CLAIMEQ_IENUM(tv, ei, i0, i1) \ | |
473 | (tvec_claimeq_ienum(tv, ei, i0, i1, \ | |
474 | __FILE__, __LINE__, #i0 " /= " #i1)) | |
475 | #define TVEC_CLAIMEQ_UENUM(tv, ei, u0, u1) \ | |
476 | (tvec_claimeq_uenum(tv, ei, u0, u1, \ | |
477 | __FILE__, __LINE__, #u0 " /= " #u1)) | |
478 | #define TVEC_CLAIMEQ_FENUM(tv, ei, f0, f1) \ | |
479 | (tvec_claimeq_fenum(tv, ei, f0, f1, \ | |
480 | __FILE__, __LINE__, #f0 " /= " #f1)) | |
481 | #define TVEC_CLAIMEQ_PENUM(tv, ei, p0, p1) \ | |
482 | (tvec_claimeq_penum(tv, ei, p0, p1, \ | |
483 | __FILE__, __LINE__, #p0 " /= " #p1)) | |
484 | ||
485 | /*----- Flags type --------------------------------------------------------*/ | |
486 | ||
487 | /* A flags value packs a number of fields into a single nonnegative integer. | |
488 | * Symbolic names are associated with the possible values of the various | |
489 | * fields; more precisely, each name is associated with a value and a | |
490 | * covering bitmask. | |
491 | * | |
492 | * The input syntax is a sequence of items separated by `%|||%' signs. Each | |
493 | * item may be the symbolic name of a field value, or a literal unsigned | |
494 | * integer. The masks associated with the given symbolic names must be | |
495 | * disjoint. The resulting numerical value is simply the bitwise OR of the | |
496 | * given values. | |
497 | * | |
498 | * On output, the table of symbolic names and their associated values and | |
499 | * masks is repeatedly scanned, in order, to find disjoint matches -- i.e., | |
500 | * entries whose value matches the target value in the bit positions | |
501 | * indicated by the mask, and whose mask doesn't overlap with any previously | |
502 | * found matches; the names are then output, separated by `%|||%'. Any | |
503 | * remaining nonzero bits not covered by any of the matching masks are output | |
504 | * as a single literal integer, in hex. | |
505 | */ | |
506 | ||
507 | extern const struct tvec_regty tvty_flags; | |
508 | ||
509 | struct tvec_flag { | |
510 | /* Definition of a single flag or bitfield value. | |
511 | * | |
512 | * Each named setting comes with a value @v@ and a mask @m@; the mask | |
513 | * should cover all of the value bits, i.e., @(v&~m) == 0@. | |
514 | */ | |
515 | ||
516 | const char *tag; /* name */ | |
517 | unsigned long m, v; /* mask and value */ | |
518 | }; | |
519 | ||
520 | #define TVEC_ENDFLAGS { 0, 0, 0 } | |
521 | ||
522 | struct tvec_flaginfo { | |
523 | /* Information about a flags type. */ | |
524 | ||
525 | const char *name; /* type name for diagnostics */ | |
526 | const struct tvec_flag *fv; /* name/mask/value mappings */ | |
527 | const struct tvec_urange *range; /* permitted range for literals */ | |
528 | }; | |
529 | ||
530 | /* --- @tvec_claimeq_flags@, @TVEC_CLAIMEQ_FLAGS@ --- * | |
531 | * | |
532 | * Arguments: @struct tvec_state *tv@ = test-vector state | |
533 | * @const struct tvec_flaginfo *fi@ = flags type info | |
534 | * @unsigned long f0, f1@ = two values | |
535 | * @const char *file@, @unsigned @lno@ = calling file and line | |
536 | * @const char *expr@ = the expression to quote on failure | |
537 | * | |
538 | * Returns: Nonzero if @f0@ and @f1@ are equal, otherwise zero. | |
539 | * | |
540 | * Use: Check that values of @f0@ and @f1@ are equal. As for | |
541 | * @tvec_claim@ above, a test case is automatically begun and | |
542 | * ended if none is already underway. If the values are | |
543 | * unequal, then @tvec_fail@ is called, quoting @expr@, and the | |
544 | * mismatched values are dumped: @f0@ is printed as the output | |
545 | * value and @f1@ is printed as the input reference. | |
546 | * | |
547 | * The @TVEC_CLAIM_FLAGS@ macro is similar, only it (a) | |
548 | * identifies the file and line number of the call site | |
549 | * automatically, and (b) implicitly quotes the source text of | |
550 | * the @f0@ and @f1@ arguments in the failure message. | |
551 | */ | |
552 | ||
553 | extern int tvec_claimeq_flags(struct tvec_state */*tv*/, | |
554 | const struct tvec_flaginfo */*fi*/, | |
555 | unsigned long /*f0*/, unsigned long /*f1*/, | |
556 | const char */*file*/, unsigned /*lno*/, | |
557 | const char */*expr*/); | |
558 | #define TVEC_CLAIMEQ_FLAGS(tv, fi, f0, f1) \ | |
559 | (tvec_claimeq_flags(tv, fi, f0, f1, \ | |
560 | __FILE__, __LINE__, #f0 " /= " #f1)) | |
561 | ||
562 | /*----- Character type ----------------------------------------------------*/ | |
563 | ||
564 | /* A character value holds a character, as read by @fgetc@. The special | |
565 | * @EOF@ value can also be represented. | |
566 | * | |
567 | * On input, a character value can be given by symbolic name, with a leading | |
568 | * `%|#|%'; or a character or `%|\|%'-escape sequence, optionally in single | |
569 | * quotes. | |
570 | * | |
571 | * The following escape sequences and character names are recognized. | |
572 | * | |
573 | * * `%|#eof|%' is the special end-of-file marker. | |
574 | * | |
575 | * * `%|#nul|%' is the NUL character, sometimes used to terminate strings. | |
576 | * | |
577 | * * `%|bell|%', `%|bel|%', `%|ding|%', or `%|\a|%' is the BEL character | |
578 | * used to ring the terminal bell (or do some other thing to attract the | |
579 | * user's attention). | |
580 | * | |
581 | * * %|#backspace|%, %|#bs|%, or %|\b|% is the backspace character, used to | |
582 | * move the cursor backwords by one cell. | |
583 | * | |
584 | * * %|#escape|% %|#esc|%, or%|\e|% is the escape character, used to | |
585 | * introduce special terminal commands. | |
586 | * | |
587 | * * %|#formfeed|%, %|#ff|%, or %|\f|% is the formfeed character, used to | |
588 | * separate pages of text. | |
589 | * | |
590 | * * %|#newline|%, %|#linefeed|%, %|#lf|%, %|#nl|%, or %|\n|% is the | |
591 | * newline character, used to terminate lines of text or advance the | |
592 | * cursor to the next line (perhaps without returning it to the start of | |
593 | * the line). | |
594 | * | |
595 | * * %|#return|%, %|#carriage-return|%, %|#cr|%, or %|\r|% is the | |
596 | * carriage-return character, used to return the cursor to the start of | |
597 | * the line. | |
598 | * | |
599 | * * %|#tab|%, %|#horizontal-tab|%, %|#ht|%, or %|\t|% is the tab | |
600 | * character, used to advance the cursor to the next tab stop on the | |
601 | * current line. | |
602 | * | |
603 | * * %|#vertical-tab|%, %|#vt|%, %|\v|% is the vertical tab character. | |
604 | * | |
605 | * * %|#space|%, %|#spc|% is the space character. | |
606 | * | |
607 | * * %|#delete|%, %|#del|% is the delete character, used to erase the most | |
608 | * recent character. | |
609 | * | |
610 | * * %|\'|% is the single-quote character. | |
611 | * | |
612 | * * %|\\|% is the backslash character. | |
613 | * | |
614 | * * %|\"|% is the double-quote character. | |
615 | * | |
616 | * * %|\NNN|% or %|\{NNN}|% is the character with code NNN in octal. The | |
617 | * NNN may be up to three digits long. | |
618 | * | |
619 | * * %|\xNN|% or %|\x{NN}|% is the character with code NNN in hexadecimal. | |
620 | */ | |
621 | ||
622 | extern const struct tvec_regty tvty_char; | |
623 | ||
624 | /* --- @tvec_claimeq_char@, @TVEC_CLAIMEQ_CHAR@ --- * | |
625 | * | |
626 | * Arguments: @struct tvec_state *tv@ = test-vector state | |
627 | * @int ch0, ch1@ = two character codes | |
628 | * @const char *file@, @unsigned @lno@ = calling file and line | |
629 | * @const char *expr@ = the expression to quote on failure | |
630 | * | |
631 | * Returns: Nonzero if @ch0@ and @ch1@ are equal, otherwise zero. | |
632 | * | |
633 | * Use: Check that values of @ch0@ and @ch1@ are equal. As for | |
634 | * @tvec_claim@ above, a test case is automatically begun and | |
635 | * ended if none is already underway. If the values are | |
636 | * unequal, then @tvec_fail@ is called, quoting @expr@, and the | |
637 | * mismatched values are dumped: @ch0@ is printed as the output | |
638 | * value and @ch1@ is printed as the input reference. | |
639 | * | |
640 | * The @TVEC_CLAIM_CHAR@ macro is similar, only it (a) | |
641 | * identifies the file and line number of the call site | |
642 | * automatically, and (b) implicitly quotes the source text of | |
643 | * the @ch0@ and @ch1@ arguments in the failure message. | |
644 | */ | |
645 | ||
646 | extern int tvec_claimeq_char(struct tvec_state */*tv*/, | |
647 | int /*ch0*/, int /*ch1*/, | |
648 | const char */*file*/, unsigned /*lno*/, | |
649 | const char */*expr*/); | |
650 | #define TVEC_CLAIMEQ_CHAR(tv, c0, c1) \ | |
651 | (tvec_claimeq_char(tv, c0, c1, __FILE__, __LINE__, #c0 " /= " #c1)) | |
652 | ||
653 | /*----- Text and binary string types --------------------------------------*/ | |
654 | ||
655 | /* A string is a sequence of octets. Text and binary strings differ | |
656 | * primarily in presentation: text strings are shown as raw characters where | |
657 | * possible; binary strings are shown as hex dumps with an auxiliary text | |
658 | * display. Storage for strings always uses the standard C library | |
659 | * allocator, though applications will probably need to call @malloc@ or | |
660 | * @free@ only rarely. | |
661 | * | |
662 | * The input format for both kinds of strings is basically the same: a | |
663 | * `compound string', consisting of | |
664 | * | |
665 | * * single-quoted strings, which are interpreted entirely literally, but | |
666 | * can't contain single quotes or newlines; | |
667 | * | |
668 | * * double-quoted strings, in which `%|\|%'-escapes are interpreted as for | |
669 | * characters; | |
670 | * | |
671 | * * character names, marked by an initial `%|#|%' sign; | |
672 | * | |
673 | * * special tokens marked by an initial `%|!|%' sign; or | |
674 | * | |
675 | * * barewords interpreted according to the current coding scheme. | |
676 | * | |
677 | * The special tokens are | |
678 | * | |
679 | * * `%|!bare|%', which causes subsequent sequences of barewords to be | |
680 | * treated as plain text; | |
681 | * | |
682 | * * `%|!hex|%', `%|!base32|%', `%|!base64|%', which cause subsequent | |
683 | * barewords to be decoded in the requested manner. | |
684 | * | |
685 | * * `%|!repeat|% %$n$% %|{|% %%\textit{string}%% %|}|%', which includes | |
686 | * %$n$% copies of the (compound) string. | |
687 | * | |
688 | * The only difference between text and binary strings is that the initial | |
689 | * coding scheme is %|bare|% for text strings and %|hex|% for binary strings. | |
690 | * | |
691 | * Either kind of string can contain internal nul characters. A trailing nul | |
692 | * is appended -- beyond the stated input length -- to input strings as a | |
693 | * convenience to test functions. Test functions may include such a nul | |
694 | * character on output but this is not checked by the equality test. | |
695 | * | |
696 | * A @struct tvec_urange@ may be supplied as an argument: the length of the | |
697 | * string (in bytes) will be checked against the permitted range. | |
698 | */ | |
699 | ||
700 | extern const struct tvec_regty tvty_text, tvty_bytes; | |
701 | ||
702 | /* --- @tvec_alloctext@, @tvec_allocbytes@ --- * | |
703 | * | |
704 | * Arguments: @union tvec_regval *rv@ = register value | |
705 | * @size_t sz@ = required size | |
706 | * | |
707 | * Returns: --- | |
708 | * | |
709 | * Use: Allocated space in a text or binary string register. If the | |
710 | * current register size is sufficient, its buffer is left | |
711 | * alone; otherwise, the old buffer, if any, is freed and a | |
712 | * fresh buffer allocated. These functions are not intended to | |
713 | * be used to adjust a buffer repeatedly, e.g., while building | |
714 | * output incrementally: (a) they will perform badly, and (b) | |
715 | * the old buffer contents are simply discarded if reallocation | |
716 | * is necessary. Instead, use a @dbuf@ or @dstr@. | |
717 | * | |
718 | * The @tvec_alloctext@ function sneakily allocates an extra | |
719 | * byte for a terminating zero. The @tvec_allocbytes@ function | |
720 | * doesn't do this. | |
721 | */ | |
722 | ||
723 | extern void tvec_alloctext(union tvec_regval */*rv*/, size_t /*sz*/); | |
724 | extern void tvec_allocbytes(union tvec_regval */*rv*/, size_t /*sz*/); | |
725 | ||
726 | /* --- @tvec_claimeq_text@, @TVEC_CLAIMEQ_TEXT@ --- * | |
727 | * | |
728 | * Arguments: @struct tvec_state *tv@ = test-vector state | |
729 | * @const char *p0@, @size_t sz0@ = first string with length | |
730 | * @const char *p1@, @size_t sz1@ = second string with length | |
731 | * @const char *file@, @unsigned @lno@ = calling file and line | |
732 | * @const char *expr@ = the expression to quote on failure | |
733 | * | |
734 | * Returns: Nonzero if the strings at @p0@ and @p1@ are equal, otherwise | |
735 | * zero. | |
736 | * | |
737 | * Use: Check that strings at @p0@ and @p1@ are equal. As for | |
738 | * @tvec_claim@ above, a test case is automatically begun and | |
739 | * ended if none is already underway. If the values are | |
740 | * unequal, then @tvec_fail@ is called, quoting @expr@, and the | |
741 | * mismatched values are dumped: @p0@ is printed as the output | |
742 | * value and @p1@ is printed as the input reference. | |
743 | * | |
744 | * The @TVEC_CLAIM_TEXT@ macro is similar, only it (a) | |
745 | * identifies the file and line number of the call site | |
746 | * automatically, and (b) implicitly quotes the source text of | |
747 | * the @ch0@ and @ch1@ arguments in the failure message. | |
748 | */ | |
749 | ||
750 | extern int tvec_claimeq_text(struct tvec_state */*tv*/, | |
751 | const char */*p0*/, size_t /*sz0*/, | |
752 | const char */*p1*/, size_t /*sz1*/, | |
753 | const char */*file*/, unsigned /*lno*/, | |
754 | const char */*expr*/); | |
755 | #define TVEC_CLAIMEQ_TEXT(tv, p0, sz0, p1, sz1) \ | |
756 | (tvec_claimeq_text(tv, p0, sz0, p1, sz1, __FILE__, __LINE__, \ | |
757 | #p0 "[" #sz0 "] /= " #p1 "[" #sz1 "]")) | |
758 | ||
759 | /* --- @tvec_claimeq_textz@, @TVEC_CLAIMEQ_TEXTZ@ --- * | |
760 | * | |
761 | * Arguments: @struct tvec_state *tv@ = test-vector state | |
762 | * @const char *p0, *p1@ = two strings to compare | |
763 | * @const char *file@, @unsigned @lno@ = calling file and line | |
764 | * @const char *expr@ = the expression to quote on failure | |
765 | * | |
766 | * Returns: Nonzero if the strings at @p0@ and @p1@ are equal, otherwise | |
767 | * zero. | |
768 | * | |
769 | * Use: Check that strings at @p0@ and @p1@ are equal, as for | |
770 | * @tvec_claimeq_string@, except that the strings are assumed | |
771 | * null-terminated, so their lengths don't need to be supplied | |
772 | * explicitly. The macro is similarly like @TVEC_CLAIMEQ_TEXT@. | |
773 | */ | |
774 | ||
775 | extern int tvec_claimeq_textz(struct tvec_state */*tv*/, | |
776 | const char */*p0*/, const char */*p1*/, | |
777 | const char */*file*/, unsigned /*lno*/, | |
778 | const char */*expr*/); | |
779 | #define TVEC_CLAIMEQ_TEXTZ(tv, p0, p1) \ | |
780 | (tvec_claimeq_textz(tv, p0, p1, __FILE__, __LINE__, #p0 " /= " #p1)) | |
781 | ||
782 | /* --- @tvec_claimeq_bytes@, @TVEC_CLAIMEQ_BYTES@ --- * | |
783 | * | |
784 | * Arguments: @struct tvec_state *tv@ = test-vector state | |
785 | * @const void *p0@, @size_t sz0@ = first string with length | |
786 | * @const void *p1@, @size_t sz1@ = second string with length | |
787 | * @const char *file@, @unsigned @lno@ = calling file and line | |
788 | * @const char *expr@ = the expression to quote on failure | |
789 | * | |
790 | * Returns: Nonzero if the strings at @p0@ and @p1@ are equal, otherwise | |
791 | * zero. | |
792 | * | |
793 | * Use: Check that binary strings at @p0@ and @p1@ are equal. As for | |
794 | * @tvec_claim@ above, a test case is automatically begun and | |
795 | * ended if none is already underway. If the values are | |
796 | * unequal, then @tvec_fail@ is called, quoting @expr@, and the | |
797 | * mismatched values are dumped: @p0@ is printed as the output | |
798 | * value and @p1@ is printed as the input reference. | |
799 | * | |
800 | * The @TVEC_CLAIM_STRING@ macro is similar, only it (a) | |
801 | * identifies the file and line number of the call site | |
802 | * automatically, and (b) implicitly quotes the source text of | |
803 | * the @ch0@ and @ch1@ arguments in the failure message. | |
804 | */ | |
805 | ||
806 | extern int tvec_claimeq_bytes(struct tvec_state */*tv*/, | |
807 | const void */*p0*/, size_t /*sz0*/, | |
808 | const void */*p1*/, size_t /*sz1*/, | |
809 | const char */*file*/, unsigned /*lno*/, | |
810 | const char */*expr*/); | |
811 | #define TVEC_CLAIMEQ_BYTES(tv, p0, sz0, p1, sz1) \ | |
812 | (tvec_claimeq(tv, p0, sz0, p1, sz1, __FILE__, __LINE__, \ | |
813 | #p0 "[" #sz0 "] /= " #p1 "[" #sz1 "]")) | |
814 | ||
815 | /*----- Buffer type -------------------------------------------------------*/ | |
816 | ||
817 | /* Buffer registers are primarily used for benchmarking. Only a buffer's | |
818 | * allocation parameters are significant: its contents are ignored on | |
819 | * comparison and output, and unspecified on input. | |
820 | * | |
821 | * The input format gives the buffer's size, and an optional alignment | |
822 | * specification, in the form %|SZ [`@' M [`+' A]]|%. Each of %|SZ|%, %|M|% | |
823 | * and %|A|% are sizes, as an integer, optionally suffixed with a unit `kB', | |
824 | * `MB', `GB', `TB', `PB', `EB', `ZB', `YB' (with or without the `B') | |
825 | * denoting a power of 1024. The %|SZ|% gives the (effective) buffer size. | |
826 | * %|M|% is the `alignment quantum' and %|A|% is the `alignment offset'; both | |
827 | * default to zero, but if %|M|% is nonzero then the start of the buffer is | |
828 | * aligned such that it is %|A|% more than a multiple of %|M|% bytes. Note | |
829 | * that %|M|% need not be a power of two, though this is common. | |
830 | * | |
831 | * Units other than `B' are used on output only when the size would be | |
832 | * expressed exactly. | |
833 | * | |
834 | * Buffers are %%\emph{not}%% allocated by default. In benchmarks, this is | |
835 | * best done in a @before@ function. | |
836 | * | |
837 | * No @claimeq@ functions or macros are provided for buffers because they | |
838 | * don't seem very useful. | |
839 | */ | |
840 | ||
841 | extern const struct tvec_regty tvty_buffer; | |
842 | ||
843 | /* --- @tvec_initbuffer@ --- * | |
844 | * | |
845 | * Arguments: @union tvec_regval *rv@ = register value | |
846 | * @const union tvec_regval *ref@ = reference buffer | |
847 | * @size_t sz@ = size to allocate | |
848 | * | |
849 | * Returns: --- | |
850 | * | |
851 | * Use: Initialize the alignment parameters in @rv@ to match @ref@, | |
852 | * and the size to @sz@. | |
853 | */ | |
854 | ||
855 | extern void tvec_initbuffer(union tvec_regval */*rv*/, | |
856 | const union tvec_regval */*ref*/, size_t /*sz*/); | |
857 | ||
858 | /* --- @tvec_allocbuffer@ --- * | |
859 | * | |
860 | * Arguments: @union tvec_regval *rv@ = register value | |
861 | * | |
862 | * Returns: --- | |
863 | * | |
864 | * Use: Allocate @sz@ bytes to the buffer and fill the space with a | |
865 | * distinctive pattern. | |
866 | */ | |
867 | ||
868 | extern void tvec_allocbuffer(union tvec_regval */*rv*/); | |
869 | ||
870 | /*----- That's all, folks -------------------------------------------------*/ | |
871 | ||
872 | #ifdef __cplusplus | |
873 | } | |
874 | #endif | |
875 | ||
876 | #endif |