Q-W1 pt2: core/shell/app relocation + sub-namespaces; one concrete ui::Rect (LTRB fork retired); slot_map split from bank_book; BankIndex→BankModel; 59/59 green

This commit is contained in:
2026-07-28 20:48:56 -04:00
parent 67a41728f3
commit 847936f813
222 changed files with 2247 additions and 2079 deletions
+63
View File
@@ -0,0 +1,63 @@
// bank_sync.cpp — see bank_sync.h. Pure; standard library only.
#include "core/instrument/map/bank_sync.h"
#include <cstdint>
#include <string>
#include "core/wire/wire.h"
namespace reasampler::instrument::map {
std::int64_t parseBankGeneration(const std::string& raw) {
// Whole-string, non-negative decimal parse WITHOUT exceptions or locale
// surprises — the shared core/wire accumulate (Q-W1, T2-01b). A leading
// '+' / '-', any non-digit, an empty string, or overflow past int64 max all
// reject to the absent default (0); the guarded accumulate means a
// pathologically long digit run can never wrap into a bogus small value.
std::int64_t value = 0;
if (!wire::parseUnsignedDecimal(raw, value)) return kBankGenerationAbsent;
return value;
}
std::string formatBankGeneration(std::int64_t generation) {
// Non-negative decimal; a negative (should never be produced by the writer) formats as
// its std::to_string form and would parse back to 0, so the writer's monotonic counter
// stays in the >= 0 domain by construction.
return std::to_string(generation);
}
bool bankGenerationChanged(std::int64_t seen, std::int64_t current) {
return current != seen;
}
AssignConsumeDecision consumeDecision(const std::optional<AssignmentRequest>& request,
std::int64_t lastConsumed, bool resolves,
bool isFocusedTarget) {
AssignConsumeDecision d;
d.consumedGeneration = lastConsumed; // default: nothing changes
// Rule 1: no request, or not newer than what we already consumed -> nothing new.
if (!request) return d;
if (request->generation <= lastConsumed) return d;
// Rule 2: a new request, but this instance is not the target -> do not act, do NOT
// advance the marker (stay eligible if focus later lands here). No thundering herd.
if (!isFocusedTarget) return d;
// The request is new AND we are the target: it will be consumed-as-seen either way, so
// advance the marker to its generation so it is never re-evaluated.
d.consumedGeneration = request->generation;
// Rule 3: unresolvable (bankId, sampleId) -> DROP silently (reader requirement): marker
// advanced above, but no selection change.
if (!resolves) return d;
// Rule 4: new, target, resolvable -> apply the selection.
d.apply = true;
d.bankId = request->bankId;
d.sampleId = request->sampleId;
return d;
}
} // namespace reasampler::instrument::map