perf: the console's constants move to flash, -378 B and -214 B of RAM
8382 -> 8004 B of flash, 725 -> 511 B of RAM on a part that has 2048. The command names were a std::to_array of string_view, and on a Harvard machine that is the worst of both: the characters land in .data and so does the table's own pointer-and-length pair for each of them, so the firmware carried 216 B of RAM for thirteen words that never change - and paid for them in flash too, since .data is copied out of an initialiser image at startup. They are one NUL-separated blob in flash now, walked with lpm. Separators rather than an offset table, because an offset table is the RAM this exists to give back; the names sit in it in match order, so the walk that finds a name is the same walk that compares it and measures it. Flash falls further than RAM does: the initialiser image and the two tables were 216 B of it, and the blob is 87. The header said the names "cannot" be in flash because they are matched at run time. Being matched at run time is not a reason to be in RAM on a machine with two address spaces - only being *written* is, and nothing writes these. Two smaller things came with it. `reset`'s exact-match rule was a bool on every entry to protect one; it is an index found by searching the list, so reordering the commands cannot move the protection onto a different one. And `version` was the last string_view left, holding its own characters and a pointer to them. The matching is now pinned rather than assumed: lookup() is constexpr and the battery asserts the load-bearing order the README documents - `s` is show and not statistics, `st` is statistics, no abbreviation of `reset` resolves, and `helpful` is not `help`. Red-checked by claiming `s` is statistics. Both modes byte-identical, ten tests green. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
#include <cstdint>
|
||||
|
||||
#include "curve.hpp"
|
||||
#include "terminal.hpp"
|
||||
#include "thermistor.hpp"
|
||||
|
||||
namespace {
|
||||
@@ -81,4 +82,39 @@ consteval bool thermistor_falls()
|
||||
}
|
||||
static_assert(thermistor_falls());
|
||||
|
||||
// The console's one parsing rule, read out of the flash blob the names live
|
||||
// in. Every case here is a property of the *order* the names sit in, so this
|
||||
// is what an edit to that list has to answer to.
|
||||
using app::terminal;
|
||||
|
||||
// Full names, and the ends of the list - a walk that miscounts a separator
|
||||
// lands on a neighbour rather than failing, so both ends are named.
|
||||
static_assert(terminal::lookup("help") == 0);
|
||||
static_assert(terminal::lookup("save") == 12);
|
||||
static_assert(terminal::lookup("bootloader") == 4);
|
||||
|
||||
// Abbreviations resolve to the first entry they prefix. `s` prefixes show,
|
||||
// statistics, set and save, and show is first - which is the original's
|
||||
// behaviour and the reason the list is ordered rather than sorted.
|
||||
static_assert(terminal::lookup("s") == 1);
|
||||
static_assert(terminal::lookup("st") == 6);
|
||||
static_assert(terminal::lookup("se") == 9);
|
||||
static_assert(terminal::lookup("sa") == 12);
|
||||
static_assert(terminal::lookup("up") == 5);
|
||||
static_assert(terminal::lookup("b") == 4);
|
||||
|
||||
// `reset` is the exception: it must be typed in full, so no abbreviation of it
|
||||
// resolves - and none of its prefixes names anything else either.
|
||||
static_assert(terminal::lookup("reset") == 8);
|
||||
static_assert(terminal::lookup("rese") == terminal::no_command);
|
||||
static_assert(terminal::lookup("res") == terminal::no_command);
|
||||
static_assert(terminal::lookup("r") == terminal::no_command);
|
||||
|
||||
// Nothing, and nothing that matches.
|
||||
static_assert(terminal::lookup("") == terminal::no_command);
|
||||
static_assert(terminal::lookup("xyzzy") == terminal::no_command);
|
||||
|
||||
// Longer than the name it prefixes is not a match: `helpful` is not `help`.
|
||||
static_assert(terminal::lookup("helpful") == terminal::no_command);
|
||||
|
||||
} // namespace
|
||||
|
||||
Reference in New Issue
Block a user