Command finalization could refuse to finalize commands that were
allocated, because its rounding method added 4 extra bytes to commands
whose size is a multiple of 4. Such commands would still be instantiated
but without commands_length advancing, causing the underlying memory to
be reallocated later, leading to overlapping commands.
This commit changes the command generation mechanism. Instead of
creating a command on the stack then calling azrp_queue_command() which
does a needless copy, the new function azrp_new_command() allocates
directly inside the command buffer, avoiding the copy.
This concept is pushed further with the introduction of finer-grained
functions azrp_alloc_command(), azrp_finalize_command() and
azrp_instantiate_command(), which split this process in three steps.
This allows generating commands of variadic size in-place in the
command buffer as well as using non-interval fragment sets.
Currently only has hand-picked tests and very rough code, but it's a
start. In the future, I want to have better tests, more
options like printf's %e/%f/%g, and more versatile methods.
* Add a unit testing framework in libnum/test/. Assertions are checked
against sparse sets of input values (a couple thousands for each
type), distributed fractally.
* Add performance tests for num16.
* Fix an overly ambitious substitution of /256 by >>8 in num16::mul,
which would give some incorrect results for negative results.
* Also fix an incorrect sign extension in the num16->num32 conversion.
* Express comparison-with-int operators in terms of the integer even
though some versions are faster when expressed in terms of the fixed-
point value. This is because the integer is frequently known at
compile-time.
* Add minDouble and maxDouble static members to each num type to
programmatically supply the bounds of the type.
This change adds tests for libnum (run with `make -C build-x tests`)
that compile example programs with g++ and evaluate how optimized the
assembly code is. This is done by checking user-provided specifications
of what instructions should and shouldn't be used against the compiled
assembler.