# include "dstr.h"
#endif
+#ifndef MLIB_GPRINTF_H
+# include "gprintf.h"
+#endif
+
#ifndef MLIB_MACROS_H
# include "macros.h"
#endif
#define TVEC_MISCSLOTS(_) \
_(PTR, const void *, p) /* arbitrary pointer */ \
_(INT, long, i) /* signed integer */ \
- _(UINT, unsigned long, u) /* signed integer */
+ _(UINT, unsigned long, u) /* signed integer */ \
+ _(FLT, double, f) /* floating point */
union tvec_misc {
#define TVEC_DEFSLOT(tag, ty, slot) ty slot;
long i; /* signed integer */
unsigned long u; /* unsigned integer */
void *p; /* pointer */
+ double f; /* floating point */
struct { unsigned char *p; size_t sz; } bytes; /* binary string of bytes */
struct { char *p; size_t sz; } str; /* text string */
#ifdef TVEC_REGSLOTS
union tvec_misc arg; /* extra detail for the type */
};
-extern int tvec_serialize(const struct tvec_reg */*rv*/,
+/* @TVEC_GREG(vec, i, regsz)@
+ *
+ * If @vec@ is a data pointer which happens to contain the address of a
+ * vector of @struct tvec_reg@ objects, @i@ is an integer, and @regsz@ is the
+ * size of a @struct tvec_reg@, then this evaluates to the address of the
+ * @i@th element of the vector.
+ *
+ * This is the general tool you need for accessing register vectors when you
+ * don't have absolute knowledge of the size of a @union tvec_regval@.
+ * Usually you want to access one of the register vectors in a @struct
+ * tvec_state@, and @TVEC_REG@ will be more convenient.
+ */
+#define TVEC_GREG(vec, i, regsz) \
+ ((struct tvec_reg *)((unsigned char *)(vec) + (i)*(regsz)))
+
+/*------ Serialization utilities ------------------------------------------*/
+
+/* --- @tvec_serialize@ --- *
+ *
+ * Arguments: @const struct tvec_reg *rv@ = vector of registers
+ * @buf *b@ = buffer to write on
+ * @const struct tvec_regdef *regs@ = vector of register
+ * descriptions, terminated by an entry with a null
+ * @name@ slot
+ * @unsigned nr@ = number of entries in the @rv@ vector
+ * @size_t regsz@ = true size of each element of @rv@
+ *
+ * Returns: Zero on success, @-1@ on failure.
+ *
+ * Use: Serialize a collection of register values.
+ *
+ * The `candidate register definitions' are those entries @r@ in
+ * the @regs@ vector whose index @r.i@ is strictly less than
+ * @nr@. The `selected register definitions' are those
+ * candidate register definitions @r@ for which the indicated
+ * register @rv[r.i]@ has the @TVRF_LIVE@ flag set. The
+ * serialized output begins with a header bitmap: if there are
+ * %$n$% candidate register definitions then the header bitmap
+ * consists of %$\lceil n/8 \rceil$% bytes. Bits are ordered
+ * starting from the least significant bit of the first byte,
+ * end ending at the most significant bit of the final byte.
+ * The bit corresponding to a candidate register definition is
+ * set if and only if that register defintion is selected. The
+ * header bitmap is then followed by the serializations of the
+ * selected registers -- i.e., for each selected register
+ * definition @r@, the serialized value of register @rv[r.i]@ --
+ * simply concatenated together, with no padding or alignment.
+ *
+ * The serialized output is written to the buffer @b@. Failure
+ * can be caused by running out of buffer space, or a failing
+ * type handler.
+ */
+
+extern int tvec_serialize(const struct tvec_reg */*rv*/, buf */*b*/,
const struct tvec_regdef */*regs*/,
- unsigned /*nr*/, size_t /*regsz*/,
- void **/*p_out*/, size_t */*sz_out*/);
+ unsigned /*nr*/, size_t /*regsz*/);
-extern int tvec_deserialize(struct tvec_reg */*rv*/,
+/* --- @tvec_deserialize@ --- *
+ *
+ * Arguments: @struct tvec_reg *rv@ = vector of registers
+ * @buf *b@ = buffer to write on
+ * @const struct tvec_regdef *regs@ = vector of register
+ * descriptions, terminated by an entry with a null
+ * @name@ slot
+ * @unsigned nr@ = number of entries in the @rv@ vector
+ * @size_t regsz@ = true size of each element of @rv@
+ *
+ * Returns: Zero on success, @-1@ on failure.
+ *
+ * Use: Deserialize a collection of register values.
+ *
+ * The size of the register vector @nr@ and the register
+ * definitions @regs@ must match those used when producing the
+ * serialization. For each serialized register value,
+ * deserialize and store the value into the appropriate register
+ * slot, and set the @TVRF_LIVE@ flag on the register. See
+ * @tvec_serialize@ for a description of the format.
+ *
+ * On successful completion, store the address of the first byte
+ * after the serialized data in @*end_out@ if @end_out@ is not
+ * null. Failure results only from a failing register type
+ * handler.
+ */
+
+extern int tvec_deserialize(struct tvec_reg */*rv*/, buf */*b*/,
const struct tvec_regdef */*regs*/,
- unsigned /*nr*/, size_t /*regsz*/,
- const void */*p*/, size_t /*sz*/);
+ unsigned /*nr*/, size_t /*regsz*/);
/*----- Test state --------------------------------------------------------*/
+/* Possible test outcomes. */
enum { TVOUT_LOSE, TVOUT_SKIP, TVOUT_WIN, TVOUT_LIMIT };
struct tvec_state {
+ /* The primary state structure for the test vector machinery. */
+
unsigned f; /* flags */
#define TVSF_SKIP 1u /* skip this test group */
#define TVSF_OPEN 2u /* test is open */
#define TVSF_ERROR 8u /* an error occurred */
#define TVSF_OUTMASK 0xf0 /* test outcome */
#define TVSF_OUTSHIFT 4
+
+ /* Registers. Available to execution environments. */
unsigned nrout, nreg; /* number of output/total registers */
size_t regsz; /* size of register entry */
struct tvec_reg *in, *out; /* register vectors */
- char expst, st; /* progress status codes */
+
+ /* Test groups state. Available to output formatters. */
const struct tvec_test *tests, *test; /* all tests and current test */
+
+ /* Test scoreboard. Available to output formatters. */
unsigned curr[TVOUT_LIMIT], all[TVOUT_LIMIT], grps[TVOUT_LIMIT];
+
+ /* Output machinery. */
struct tvec_output *output; /* output formatter */
+
+ /* Input machinery. Available to type parsers. */
const char *infile; unsigned lno, test_lno; /* input file name, line */
FILE *fp; /* input file stream */
};
-#define TVEC_GREG(vec, i, regsz) \
- ((struct tvec_reg *)((unsigned char *)(vec) + (i)*(regsz)))
+/* @TVEC_REG(tv, vec, i)@
+ *
+ * If @tv@ is a pointer to a @struct tvec_state@, @vec@ is either @in@ or
+ * @out@, and @i@ is an integer, then this evaluates to the address of the
+ * @i@th register in the selected vector.
+ */
#define TVEC_REG(tv, vec, i) TVEC_GREG((tv)->vec, (i), (tv)->regsz)
/*----- Test descriptions -------------------------------------------------*/
-typedef int tvec_hookfn(struct tvec_state */*tv*/);
typedef void tvec_testfn(const struct tvec_reg */*in*/,
struct tvec_reg */*out*/,
void */*ctx*/);
+ /* A test function. It should read inputs from @in@ and write outputs to
+ * @out@. The @TVRF_LIVE@ is set on inputs which are actually present, and
+ * on outputs which are wanted to test. A test function can set additional
+ * `gratuitous outputs' by setting @TVRF_LIVE@ on them; clearing
+ * @TVRF_LIVE@ on a wanted output causes a mismatch.
+ *
+ * A test function may be called zero or more times by the environment. In
+ * particular, it may be called multiple times, though usually by prior
+ * arrangement with the environment.
+ *
+ * The @ctx@ is supplied by the environment's @run@ function (see below).
+ * The default environment calls the test function once, with a null
+ * @ctx@. There is no expectation that the environment's context has
+ * anything to do with the test function's context.
+ */
+
+struct tvec_env {
+ /* A test environment sets things up for and arranges to run the test.
+ *
+ * The caller is responsible for allocating storage for the environment's
+ * context, based on the @ctxsz@ slot, and freeing it later; this space is
+ * passed in as the @ctx@ parameter to the remaining functions; if @ctxsz@
+ * is zero then @ctx@ is null.
+ */
+
+ size_t ctxsz; /* environment context size */
+
+ int (*setup)(struct tvec_state */*tv*/, const struct tvec_env */*env*/,
+ void */*pctx*/, void */*ctx*/);
+ /* Initialize the context; called at the start of a test group. Return
+ * zero on success, or @-1@ on failure. If setup fails, the context is
+ * freed, and the test group is skipped.
+ */
+
+ int (*set)(struct tvec_state */*tv*/, const char */*var*/,
+ const struct tvec_env */*env*/, void */*ctx*/);
+ /* Called when the parser finds a %|@var|%' setting to parse and store
+ * the value. If @setup@ failed, this is still called (so as to skip the
+ * value), but @ctx@ is null.
+ */
+
+ int (*before)(struct tvec_state */*tv*/, void */*ctx*/);
+ /* Called prior to running a test. This is the right place to act on any
+ * `%|@var|%' settings. Return zero on success or @-1@ on failure (which
+ * causes the test to be skipped). This function is never called if the
+ * test group is skipped.
+ */
+
+ void (*run)(struct tvec_state */*tv*/, tvec_testfn */*fn*/, void */*ctx*/);
+ /* Run the test. It should either call @tvec_skip@, or run @fn@ one or
+ * more times. In the latter case, it is responsible for checking the
+ * outputs, and calling @tvec_fail@ as necessary; @tvec_checkregs@ will
+ * check the register values against the supplied test vector, while
+ * @tvec_check@ does pretty much everything necessary. This function is
+ * never called if the test group is skipped.
+ */
+
+ void (*after)(struct tvec_state */*tv*/, void */*ctx*/);
+ /* Called after running or skipping a test. Typical actions involve
+ * resetting whatever things were established by @set@. This function is
+ * never called if the test group is skipped.
+ */
+
+ void (*teardown)(struct tvec_state */*tv*/, void */*ctx*/);
+ /* Tear down the environment: called at the end of a test group. If the
+ * setup failed, then this function is still called, with a null @ctx@.
+ */
+};
struct tvec_test {
+ /* A test description. */
+
const char *name; /* name of the test */
const struct tvec_regdef *regs; /* descriptions of the registers */
- tvec_hookfn *preflight; /* check before starting */
- tvec_hookfn *run; /* test runner */
+ const struct tvec_env *env; /* environment to run test in */
tvec_testfn *fn; /* test function */
- union tvec_misc arg; /* additional parameter to `run' */
};
+
+enum {
+ /* Register output dispositions. */
+
+ TVRD_INPUT, /* input-only register */
+ TVRD_OUTPUT, /* output-only (input is dead) */
+ TVRD_MATCH, /* matching (equal) registers */
+ TVRD_FOUND, /* mismatching output register */
+ TVRD_EXPECT /* mismatching input register */
+};
+
+/* --- @tvec_skipgroup@, @tvec_skipgroup_v@ --- *
+ *
+ * Arguments: @struct tvec_state *tv@ = test-vector state
+ * @const char *excuse@, @va_list ap@ = reason why group skipped
+ *
+ * Returns: ---
+ *
+ * Use: Skip the current group. This should only be called from a
+ * test environment @setup@ function; a similar effect occurs if
+ * the @setup@ function fails.
+ */
+
extern void PRINTF_LIKE(2, 3)
- tvec_check(struct tvec_state */*tv*/, const char */*detail*/, ...);
-extern void tvec_check_v(struct tvec_state */*tv*/,
- const char */*detail*/, va_list */*ap*/);
+ tvec_skipgroup(struct tvec_state */*tv*/, const char */*excuse*/, ...);
+extern void tvec_skipgroup_v(struct tvec_state */*tv*/,
+ const char */*excuse*/, va_list */*ap*/);
-extern int tvec_runtest(struct tvec_state */*tv*/);
+/* --- @tvec_skip@, @tvec_skip_v@ --- *
+ *
+ * Arguments: @struct tvec_state *tv@ = test-vector state
+ * @const char *excuse@, @va_list ap@ = reason why test skipped
+ *
+ * Returns: ---
+ *
+ * Use: Skip the current test. This should only be called from a
+ * test environment @run@ function; a similar effect occurs if
+ * the @before@ function fails.
+ */
-/*----- Input utilities ---------------------------------------------------*/
+extern void PRINTF_LIKE(2, 3)
+ tvec_skip(struct tvec_state */*tv*/, const char */*excuse*/, ...);
+extern void tvec_skip_v(struct tvec_state */*tv*/,
+ const char */*excuse*/, va_list */*ap*/);
-extern void tvec_skipspc(struct tvec_state */*tv*/);
+/* --- @tvec_resetoutputs@ --- *
+ *
+ * Arguments: @struct tvec_state *tv@ = test-vector state
+ *
+ * Returns: ---
+ *
+ * Use: Reset (releases and reinitializes) the output registers in
+ * the test state. This is mostly of use to test environment
+ * @run@ functions, between invocations of the test function.
+ */
-#define TVFF_ALLOWANY 1u
-extern int tvec_flushtoeol(struct tvec_state */*tv*/, unsigned /*f*/);
+extern void tvec_resetoutputs(struct tvec_state */*tv*/);
-extern int PRINTF_LIKE(4, 5)
- tvec_readword(struct tvec_state */*tv*/, dstr */*d*/,
- const char */*delims*/, const char */*expect*/, ...);
-extern int tvec_readword_v(struct tvec_state */*tv*/, dstr */*d*/,
- const char */*delims*/, const char */*expect*/,
- va_list */*ap*/);
+/* --- @tvec_checkregs@ --- *
+ *
+ * Arguments: @struct tvec_state *tv@ = test-vector state
+ *
+ * Returns: Zero on success, @-1@ on mismatch.
+ *
+ * Use: Compare the active output registers (according to the current
+ * test group definition) with the corresponding input register
+ * values. A mismatch occurs if the two values differ
+ * (according to the register type's @eq@ method), or if the
+ * input is live but the output is dead.
+ *
+ * This function only checks for a mismatch and returns the
+ * result; it takes no other action. In particular, it doesn't
+ * report a failure, or dump register values.
+ */
-extern int tvec_nexttoken(struct tvec_state */*tv*/);
+extern int tvec_checkregs(struct tvec_state */*tv*/);
+
+/* --- @tvec_fail@, @tvec_fail_v@ --- *
+ *
+ * Arguments: @struct tvec_state *tv@ = test-vector state
+ * @const char *detail@, @va_list ap@ = description of test
+ *
+ * Returns: ---
+ *
+ * Use: Report the current test as a failure. This function can be
+ * called multiple times for a single test, e.g., if the test
+ * environment's @run@ function invokes the test function
+ * repeatedly; but a single test that fails repeatedly still
+ * only counts as a single failure in the statistics. The
+ * @detail@ string and its format parameters can be used to
+ * distinguish which of several invocations failed; it can
+ * safely be left null if the test function is run only once.
+ */
+
+extern void PRINTF_LIKE(2, 3)
+ tvec_fail(struct tvec_state */*tv*/, const char */*detail*/, ...);
+extern void tvec_fail_v(struct tvec_state */*tv*/,
+ const char */*detail*/, va_list */*ap*/);
+
+/* --- @tvec_dumpreg@ --- *
+ *
+ * Arguments: @struct tvec_state *tv@ = test-vector state
+ * @unsigned disp@ = the register disposition (@TVRD_...@)
+ * @const union tvec_regval *tv@ = register value
+ * @const struct tvec_regdef *rd@ = register definition
+ *
+ * Returns: ---
+ *
+ * Use: Dump a register value to the output. This is the lowest-
+ * level function for dumping registers, and calls the output
+ * formatter directly.
+ *
+ * Usually @tvec_mismatch@ is much more convenient. Low-level
+ * access is required for reporting `virtual' registers
+ * corresponding to test environment settings.
+ */
+
+extern void tvec_dumpreg(struct tvec_state */*tv*/,
+ unsigned /*disp*/, const union tvec_regval */*rv*/,
+ const struct tvec_regdef */*rd*/);
+
+/* --- @tvec_mismatch@ --- *
+ *
+ * Arguments: @struct tvec_state *tv@ = test-vector state
+ * @unsigned f@ = flags (@TVMF_...@)
+ *
+ * Returns: ---
+ *
+ * Use: Dumps registers suitably to report a mismatch. The flag bits
+ * @TVMF_IN@ and @TVF_OUT@ select input-only and output
+ * registers. If both are reset then nothing happens.
+ * Suppressing the output registers may be useful, e.g., if the
+ * test function crashed rather than returning outputs.
+ */
+
+#define TVMF_IN 1u
+#define TVMF_OUT 2u
+extern void tvec_mismatch(struct tvec_state */*tv*/, unsigned /*f*/);
+
+/* --- @tvec_check@, @tvec_check_v@ --- *
+ *
+ * Arguments: @struct tvec_state *tv@ = test-vector state
+ * @const char *detail@, @va_list ap@ = description of test
+ *
+ * Returns: ---
+ *
+ * Use: Check the register values, reporting a failure and dumping
+ * the registers in the event of a mismatch. This just wraps up
+ * @tvec_checkregs@, @tvec_fail@ and @tvec_mismatch@ in the
+ * obvious way.
+ */
+
+extern void PRINTF_LIKE(2, 3)
+ tvec_check(struct tvec_state */*tv*/, const char */*detail*/, ...);
+extern void tvec_check_v(struct tvec_state */*tv*/,
+ const char */*detail*/, va_list */*ap*/);
/*----- Session lifecycle -------------------------------------------------*/
/*----- Benchmarking ------------------------------------------------------*/
struct tvec_bench {
+ struct tvec_env _env; /* benchmarking is an environment */
+ struct bench_state **bst; /* benchmark state anchor or null */
unsigned long niter; /* iterations done per unit */
int riter, rbuf; /* iterations and buffer registers */
- size_t ctxsz; /* size of context */
- int (*setup)(const struct tvec_reg */*in*/, struct tvec_reg */*out*/,
- const union tvec_misc */*arg*/, void */*ctx*/); /* setup fn */
- void (*teardown)(void */*ctx*/); /* teardown function, or null */
- struct bench_state **b; /* benchmark state anchor or null */
- union tvec_misc arg; /* argument to setup */
+ const struct tvec_env *env; /* environment (per test, not grp) */
+};
+#define TVEC_BENCHENV \
+ { sizeof(struct tvec_benchctx), \
+ tvec_benchsetup, \
+ tvec_benchset, \
+ tvec_benchbefore, \
+ tvec_benchrun, \
+ tvec_benchafter, \
+ tvec_benchteardown }
+#define TVEC_BENCHINIT TVEC_BENCHENV, &tvec_benchstate
+
+struct tvec_benchctx {
+ const struct tvec_bench *b;
+ struct bench_state *bst;
+ double dflt_target;
+ void *subctx;
};
+struct bench_timing;
extern struct bench_state *tvec_benchstate;
-extern int tvec_ensurebench(struct tvec_state */*tv*/,
- struct bench_state **/*b_out*/);
-extern int tvec_bench(struct tvec_state */*tv*/);
+extern int tvec_benchsetup(struct tvec_state */*tv*/,
+ const struct tvec_env */*env*/,
+ void */*pctx*/, void */*ctx*/);
+extern int tvec_benchset(struct tvec_state */*tv*/, const char */*var*/,
+ const struct tvec_env */*env*/, void */*ctx*/);
+extern int tvec_benchbefore(struct tvec_state */*tv*/, void */*ctx*/);
+extern void tvec_benchrun(struct tvec_state */*tv*/,
+ tvec_testfn */*fn*/, void */*ctx*/);
+extern void tvec_benchafter(struct tvec_state */*tv*/, void */*ctx*/);
+extern void tvec_benchteardown(struct tvec_state */*tv*/, void */*ctx*/);
+
+extern void tvec_benchreport
+ (const struct gprintf_ops */*gops*/, void */*go*/,
+ unsigned /*unit*/, const struct bench_timing */*tm*/);
/*----- Ad-hoc testing ----------------------------------------------------*/
struct tvec_state *tv;
};
-struct bench_timing;
+enum { TVBU_OP, TVBU_BYTE };
struct tvec_outops {
void (*error)(struct tvec_output */*o*/,
const char */*msg*/, va_list */*ap*/);
void (*notice)(struct tvec_output */*o*/,
const char */*msg*/, va_list */*ap*/);
- void (*write)(struct tvec_output */*o*/, const char */*p*/, size_t /*sz*/);
void (*bsession)(struct tvec_output */*o*/);
int (*esession)(struct tvec_output */*o*/);
const char */*excuse*/, va_list */*ap*/);
void (*fail)(struct tvec_output */*o*/,
const char */*detail*/, va_list */*ap*/);
- void (*mismatch)(struct tvec_output */*o*/);
+ void (*dumpreg)(struct tvec_output */*o*/,
+ unsigned /*disp*/, const union tvec_regval */*rv*/,
+ const struct tvec_regdef */*rd*/);
void (*etest)(struct tvec_output */*o*/, unsigned /*outcome*/);
- void (*bbench)(struct tvec_output */*o*/);
+ void (*bbench)(struct tvec_output */*o*/,
+ const char */*ident*/, unsigned /*unit*/);
void (*ebench)(struct tvec_output */*o*/,
+ const char */*ident*/, unsigned /*unit*/,
const struct bench_timing */*tm*/);
void (*destroy)(struct tvec_output */*o*/);
extern int tvec_syntax_v(struct tvec_state */*tv*/, int /*ch*/,
const char */*expect*/, va_list */*ap*/);
-extern void PRINTF_LIKE(2, 3)
- tvec_skipgroup(struct tvec_state */*tv*/, const char */*note*/, ...);
-extern void tvec_skipgroup_v(struct tvec_state */*tv*/,
- const char */*note*/, va_list */*ap*/);
+extern struct tvec_output *tvec_humanoutput(FILE */*fp*/);
+extern struct tvec_output *tvec_tapoutput(FILE */*fp*/);
+extern struct tvec_output *tvec_dfltout(FILE */*fp*/);
-extern void PRINTF_LIKE(2, 3)
- tvec_skip(struct tvec_state */*tv*/, const char */*excuse*/, ...);
-extern void tvec_skip_v(struct tvec_state */*tv*/,
- const char */*excuse*/, va_list */*ap*/);
+/*----- Input utilities ---------------------------------------------------*/
-extern void PRINTF_LIKE(2, 3)
- tvec_fail(struct tvec_state */*tv*/, const char */*detail*/, ...);
-extern void tvec_fail_v(struct tvec_state */*tv*/,
- const char */*detail*/, va_list */*ap*/);
+extern void tvec_skipspc(struct tvec_state */*tv*/);
-extern void tvec_mismatch(struct tvec_state */*tv*/);
+#define TVFF_ALLOWANY 1u
+extern int tvec_flushtoeol(struct tvec_state */*tv*/, unsigned /*f*/);
-extern void PRINTF_LIKE(2, 3)
- tvec_write(struct tvec_state */*tv*/, const char */*p*/, ...);
-extern void tvec_write_v(struct tvec_state */*tv*/,
- const char */*p*/, va_list */*ap*/);
+extern int PRINTF_LIKE(4, 5)
+ tvec_readword(struct tvec_state */*tv*/, dstr */*d*/,
+ const char */*delims*/, const char */*expect*/, ...);
+extern int tvec_readword_v(struct tvec_state */*tv*/, dstr */*d*/,
+ const char */*delims*/, const char */*expect*/,
+ va_list */*ap*/);
-extern struct tvec_output *tvec_humanoutput(FILE */*fp*/);
-extern struct tvec_output *tvec_tapoutput(FILE */*fp*/);
-extern struct tvec_output *tvec_dfltout(FILE */*fp*/);
+extern int tvec_nexttoken(struct tvec_state */*tv*/);
/*----- Register types ----------------------------------------------------*/
int (*eq)(const union tvec_regval */*rv0*/,
const union tvec_regval */*rv1*/,
const struct tvec_regdef */*rd*/);
- size_t (*measure)(const union tvec_regval */*rv*/,
- const struct tvec_regdef */*rd*/);
int (*tobuf)(buf */*b*/, const union tvec_regval */*rv*/,
const struct tvec_regdef */*rd*/);
int (*frombuf)(buf */*b*/, union tvec_regval */*rv*/,
struct tvec_state */*tv*/);
void (*dump)(const union tvec_regval */*rv*/,
const struct tvec_regdef */*rd*/,
- struct tvec_state */*tv*/, unsigned /*style*/);
+ unsigned /*style*/,
+ const struct gprintf_ops */*gops*/, void */*go*/);
#define TVSF_COMPACT 1u
};
extern const struct tvec_urange
tvrange_uchar, tvrange_ushort, tvrange_uint, tvrange_ulong, tvrange_size,
tvrange_byte, tvrange_u16, tvrange_u32;
+extern const struct tvec_frange
+ tvrange_float, tvrange_double;
extern int tvec_claimeq_int(struct tvec_state */*tv*/,
long /*i0*/, long /*i1*/,
#define TVEC_CLAIMEQ_UINT(tv, u0, u1) \
(tvec_claimeq_uint(tv, u0, u1, __FILE__, __LINE__, #u0 " /= " #u1))
+extern const struct tvec_regty tvty_float;
+struct tvec_floatinfo {
+ unsigned f;
+#define TVFF_NOMIN 1u
+#define TVFF_NOMAX 2u
+#define TVFF_NANOK 4u
+#define TVFF_EXACT 0u
+#define TVFF_ABSDELTA 0x10
+#define TVFF_RELDELTA 0x20
+#define TVFF_EQMASK 0xf0
+ double min, max;
+ double delta;
+};
+
+extern int tvec_claimeqish_float(struct tvec_state */*tv*/,
+ double /*f0*/, double /*f1*/,
+ unsigned /*f*/, double /*delta*/,
+ const char */*file*/, unsigned /*lno*/,
+ const char */*expr*/);
+extern int tvec_claimeq_float(struct tvec_state */*tv*/,
+ double /*f0*/, double /*f1*/,
+ const char */*file*/, unsigned /*lno*/,
+ const char */*expr*/);
+#define TVEC_CLAIMEQISH_FLOAT(tv, f0, f1, f, delta) \
+ (tvec_claimeqish_float(tv, f0, f1, f, delta, , __FILE__, __LINE__, \
+ #f0 " /= " #f1 " (+/- " #delta ")"))
+#define TVEC_CLAIMEQ_FLOAT(tv, f0, f1) \
+ (tvec_claimeq_float(tv, f0, f1, __FILE__, __LINE__, #f0 " /= " #f1))
+
extern const struct tvec_regty tvty_enum;
#define DEFASSOC(tag_, ty, slot) \
TVEC_MISCSLOTS(DEFASSOC)
#undef DEFASSOC
-struct tvec_enuminfo {
- const char *name; unsigned mv;
- union {
-#define DEFENUMINFO(tag, ty, slot) struct { \
- const struct tvec_##slot##assoc *av; \
- RANGESLOT_##tag \
- } slot;
-#define RANGESLOT_INT const struct tvec_irange *ir;
-#define RANGESLOT_UINT const struct tvec_urange *ur;
-#define RANGESLOT_PTR
- TVEC_MISCSLOTS(DEFENUMINFO)
-#undef DEFENUMINFO
-#undef RANGESLOT_INT
-#undef RANGESLOT_UINT
-#undef RANGESLOT_PTR
- } u;
+struct tvec_enuminfo { const char *name; unsigned mv; /* ... */ };
+struct tvec_ienuminfo {
+ struct tvec_enuminfo _ei;
+ const struct tvec_iassoc *av;
+ const struct tvec_irange *ir;
+};
+struct tvec_uenuminfo {
+ struct tvec_enuminfo _ei;
+ const struct tvec_uassoc *av;
+ const struct tvec_urange *ur;
+};
+struct tvec_fenuminfo {
+ struct tvec_enuminfo _ei;
+ const struct tvec_fassoc *av;
+ const struct tvec_floatinfo *fi;
+};
+struct tvec_penuminfo {
+ struct tvec_enuminfo _ei;
+ const struct tvec_passoc *av;
};
+const struct tvec_ienuminfo tvenum_bool;
+
#define DECLCLAIM(tag, ty, slot) \
extern int tvec_claimeq_##slot##enum \
(struct tvec_state */*tv*/, \
- const struct tvec_enuminfo */*ei*/, ty /*e0*/, ty /*e1*/, \
+ const struct tvec_##slot##enuminfo */*ei*/, \
+ ty /*e0*/, ty /*e1*/, \
const char */*file*/, unsigned /*lno*/, const char */*expr*/);
TVEC_MISCSLOTS(DECLCLAIM)
#undef DECLCLAIM
#define TVEC_CLAIMEQ_UENUM(tv, ei, e0, e1) \
(tvec_claimeq_uenum(tv, ei, e0, e1, \
__FILE__, __LINE__, #e0 " /= " #e1))
+#define TVEC_CLAIMEQ_FENUM(tv, ei, e0, e1) \
+ (tvec_claimeq_fenum(tv, ei, e0, e1, \
+ __FILE__, __LINE__, #e0 " /= " #e1))
#define TVEC_CLAIMEQ_PENUM(tv, ei, e0, e1) \
(tvec_claimeq_penum(tv, ei, e0, e1, \
__FILE__, __LINE__, #e0 " /= " #e1))
(tvec_claimeq_flags(tv, fi, f0, f1, \
__FILE__, __LINE__, #f0 " /= " #f1))
+extern const struct tvec_regty tvty_char;
+extern int tvec_claimeq_char(struct tvec_state */*tv*/,
+ int /*ch0*/, int /*ch1*/,
+ const char */*file*/, unsigned /*lno*/,
+ const char */*expr*/);
+#define TVEC_CLAIMEQ_CHAR(tv, c0, c1) \
+ (tvec_claimeq_char(tv, c0, c1, __FILE__, __LINE__, #c0 " /= " #c1))
+
extern const struct tvec_regty tvty_string, tvty_bytes;
extern int tvec_claimeq_string(struct tvec_state */*tv*/,
const void */*p1*/, size_t /*sz1*/,
const char */*file*/, unsigned /*lno*/,
const char */*expr*/);
-
#define TVEC_CLAIMEQ_STRING(tv, p0, sz0, p1, sz1) \
(tvec_claimeq_string(tv, p0, sz0, p1, sz1, __FILE__, __LINE__, \
#p0 "[" #sz0 "] /= " #p1 "[" #sz1 "]"))