Cut core/wire and shell/persist comment bloat ~46% (comments only, zero code change)

This commit is contained in:
2026-07-29 20:49:28 -04:00
parent 1f24c4b095
commit 8dac5b4a54
19 changed files with 638 additions and 1286 deletions
+45 -66
View File
@@ -1,20 +1,14 @@
// usage_scan.cpp — see usage_scan.h. The REAPER reads behind the pS-usage prune
// protection; every decision is in the pure sample_usage module, this TU only reads.
// usage_scan.cpp — see usage_scan.h. The REAPER reads behind the instance-usage
// prune protection; every decision is in the pure sample_usage module, this TU
// only reads.
//
// Compiled into the reaper_reasampler MODULE. Includes reaper_plugin_functions.h
// WITHOUT REAPERAPI_IMPLEMENT — main.cpp is the one TU that defines the API pointers
// (CLAUDE.md §contract). Every REAPER symbol used here is verified against
// vendor/reaper-sdk/sdk/reaper_plugin_functions.h:
// * EnumProjExtState(proj, extname, idx, keyOut, sz, valOut, sz) -> bool (~1272)
// * GetProjExtState(proj, extname, key, valOut, sz) -> int (~2591)
// * CountTracks / GetTrack / GetMasterTrack (track scan)
// * TrackFX_GetCount(MediaTrack*) / TrackFX_GetRecCount(MediaTrack*) (~7283/7570)
// * TrackFX_GetNamedConfigParm(MediaTrack*, int, parm, buf, sz) -> bool (~7377)
// * CountMediaItems / GetMediaItem (~423/1964)
// * CountTakes(MediaItem*) / GetMediaItemTake(MediaItem*, int) (~471/2029)
// * GetMediaItemTrack(MediaItem*) (~2133)
// * TakeFX_GetCount / TakeFX_GetNamedConfigParm (~6710/6774)
// * guidToString (via track_guid::guidString)
// Compiled into the reaper_reasampler module. Includes reaper_plugin_functions.h
// WITHOUT REAPERAPI_IMPLEMENT — main.cpp is the one TU that defines the API
// pointers (CLAUDE.md §contract). REAPER symbols used here (EnumProjExtState,
// GetProjExtState, CountTracks/GetTrack/GetMasterTrack, TrackFX_GetCount/
// GetRecCount/GetNamedConfigParm, CountMediaItems/GetMediaItem, CountTakes/
// GetMediaItemTake, GetMediaItemTrack, TakeFX_GetCount/GetNamedConfigParm) are
// verified against vendor/reaper-sdk/sdk/reaper_plugin_functions.h.
#include "shell/persist/usage_scan.h"
@@ -26,11 +20,11 @@
#include <vector>
#include "core/version/app_version.h" // vstPluginName / vstOutputName (channel name needles)
#include "core/wire/ext_state_read.h" // readProjExtStateGrowing (T2-04: the ONE grow-loop policy)
#include "core/wire/ext_state_read.h" // readProjExtStateGrowing — the shared grow-loop policy
#include "ext_keys.h" // kProjExtNamespace / kProjExtUsageKeyPrefix
#include "core/wire/instrument_drop.h" // vstClassIdHex — the frozen channel class-UID hex
#include "core/wire/sample_usage.h" // identityMatches, foldUsageRecords (the pure decisions)
#include "shell/capture/track_guid.h" // guidString — the ONE canonical GUID key formatter
#include "shell/capture/track_guid.h" // guidString — the canonical GUID key formatter
#define REAPERAPI_MINIMAL
#define REAPERAPI_WANT_EnumProjExtState
@@ -52,10 +46,9 @@
namespace reasampler {
// Real-namespace-home using-directive (Q-W6: the namespaces.h shim is retired):
// this TU speaks the sample_usage wire vocabulary wholesale (UsageRecord /
// decodeUsageRecord / foldUsageRecords / identityMatches / toUpperAscii) plus the
// channel-identity accessors + the preset class-id hex.
// This TU speaks the sample_usage wire vocabulary wholesale (UsageRecord /
// decodeUsageRecord / foldUsageRecords / identityMatches / toUpperAscii) plus
// the channel-identity accessors + the preset class-id hex.
using namespace reasampler::wire;
using version::vstOutputName;
using version::vstPluginName;
@@ -76,16 +69,15 @@ struct FxIdentityNeedles {
using FxParmGetter =
std::function<std::string(int fxId, const char* parm)>;
// True if any FX in the (possibly container-nested) sub-chain rooted at `fxId` is a
// ReaSampler 9000. BOTH fx_ident and original_name are checked on BOTH chain kinds (a
// renamed instance may keep its original_name; fx_ident carries the module path — the
// primary identification net is the module filename base via fx_ident, which holds even
// after a user renames the FX instance). Containers are walked via
// the documented container_count / container_item.X addressing (v7.06+); on a chain
// kind or REAPER version without containers the parm read returns empty and recursion
// is a no-op. `depth` bounds pathological nesting. fx_ident is queried per FX — chain
// enumeration is chunk-level, so OFFLINE instances match too (load-bearing: a
// Design-View-parked instance must keep protecting its holds).
// True if any FX in the (possibly container-nested) sub-chain rooted at
// `fxId` is a ReaSampler 9000. Both fx_ident and original_name are checked (a
// renamed instance may keep its original_name; fx_ident carries the module
// path and survives a rename). Containers are walked via the documented
// container_count / container_item.X addressing (v7.06+); on a chain kind or
// REAPER version without containers the parm read returns empty and
// recursion is a no-op. `depth` bounds pathological nesting. fx_ident is
// queried per FX — chain enumeration is chunk-level, so OFFLINE instances
// match too (a Design-View-parked instance must keep protecting its holds).
bool fxSubtreeHasInstance(const FxParmGetter& parm, int fxId,
const FxIdentityNeedles& id, int depth) {
if (identityMatches(parm(fxId, "fx_ident"), id.uidHexUpper, id.nameUpper,
@@ -96,12 +88,9 @@ bool fxSubtreeHasInstance(const FxParmGetter& parm, int fxId,
const std::string countStr = parm(fxId, "container_count");
if (countStr.empty()) return false; // not a container; no children to miss
if (depth <= 0) {
// This node IS a container but we have exhausted our descent budget. We cannot
// prove that none of its children is a ReaSampler 9000 instance treat the
// incomplete walk as a positive identification (the protect direction). This is
// defense-in-depth: kMaxContainerDepth = 32 should prevent reaching this branch
// in any real project, but if it IS reached the fail-safe fires rather than
// silently missing a live nested instance.
// Descent budget exhausted on a node that IS a container: we cannot
// prove none of its children is an instance, so treat the incomplete
// walk as a positive identification (protect direction).
return true;
}
const int n = std::atoi(countStr.c_str());
@@ -116,9 +105,9 @@ bool fxSubtreeHasInstance(const FxParmGetter& parm, int fxId,
return false;
}
// Raised from 8 to 32 (defense in depth against truncation). Real-world FX containers
// are typically 24 levels deep; 32 is unreachable in practice while remaining finite.
// Even at 32, the truncation→protect-all guard below is the primary protection.
// Real-world FX containers are typically 2-4 levels deep; 32 is unreachable
// in practice while remaining finite. The truncation->protect-all guard above
// is the primary protection even at this depth.
constexpr int kMaxContainerDepth = 32;
std::string trackFxParm(MediaTrack* tr, int fxId, const char* parm) {
@@ -153,11 +142,9 @@ bool trackHasInstance(MediaTrack* tr, const FxIdentityNeedles& id) {
return false;
}
// True if any take FX on `item` is a ReaSampler 9000 (all takes, not just active — a
// non-active take's instance still exists in the project and reactivates with the
// take). The SAME identity walk as the track path: fx_ident + original_name + container
// recursion (an unrecognized exotic still lands in the pure protect-all net — records
// with zero identified instances protect everything rather than nothing).
// True if any take FX on `item` is a ReaSampler 9000 (all takes, not just
// active — a non-active take's instance still exists and reactivates with
// the take). Same identity walk as the track path.
bool itemHasInstance(MediaItem* item, const FxIdentityNeedles& id) {
const int takes = CountTakes(item);
for (int t = 0; t < takes; ++t) {
@@ -174,15 +161,11 @@ bool itemHasInstance(MediaItem* item, const FxIdentityNeedles& id) {
return false;
}
// Growing GetProjExtState read: the usage record scales with the hold count, so a
// fixed buffer risks a truncated decode. The retry policy is the SHARED pure
// wire::readProjExtStateGrowing (T2-04 — one loop for persist, this
// prune-safety-adjacent read, and the VST bridge; the rules cannot drift).
// Returns nullopt when the key cannot be read WHOLE — absent-after-enumeration
// (rv <= 0) or pathologically large (> 16 MB give-up). The caller only queries keys
// the enumeration just listed, so a nullopt here is a PRESENT-BUT-UNREADABLE record:
// it folds to abortPrune (fail-safe — silently reduced protection is the delete
// direction).
// The usage record scales with the hold count, so a fixed buffer risks a
// truncated decode; uses the shared grow-loop policy. Returns nullopt when
// the key cannot be read whole (absent, or > 16 MB give-up). The caller only
// queries keys the enumeration just listed, so nullopt here is a
// present-but-unreadable record: it folds to abortPrune.
std::optional<std::string> readExtStateValue(ReaProject* proj, const char* key) {
const GrowingExtStateRead read = readProjExtStateGrowing(
[&](char* buf, int cap) {
@@ -198,10 +181,8 @@ UsageScanResult liveInstanceHeldPaths(void* projOpaque) {
ReaProject* proj = static_cast<ReaProject*>(projOpaque);
UsageScanResult result;
// 1. Enumerate the rsusage_* keys and read+decode each record. Key names first
// (values via the growing reader — EnumProjExtState's fixed val buffer could
// truncate a large record). A nullopt element = present-but-unreadable/
// undecodable -> the pure fold ABORTS the prune.
// Enumerate rsusage_* keys, then read+decode via the growing reader
// (EnumProjExtState's fixed val buffer could truncate a large record).
std::vector<std::string> usageKeys;
{
const std::string prefix = kProjExtUsageKeyPrefix; // hoisted: one alloc, not N
@@ -232,8 +213,8 @@ UsageScanResult liveInstanceHeldPaths(void* projOpaque) {
decoded.push_back(rec); // undecodable nullopt -> abort
}
// 2. Enumerate live ReaSampler 9000 hosts. One channel-frozen needle set drives
// every match; a track needs only ONE instance to keep all its records live.
// Enumerate live ReaSampler 9000 hosts; a track needs only one instance to
// keep all its records live.
FxIdentityNeedles id;
id.uidHexUpper = toUpperAscii(vstClassIdHex());
id.outputNameUpper = toUpperAscii(vstOutputName());
@@ -270,14 +251,12 @@ UsageScanResult liveInstanceHeldPaths(void* projOpaque) {
}
}
// 3. The pure fold decides: abort on any unreadable record; protect-all when zero
// instances were identified; otherwise the per-record liveness rule.
// The pure fold decides: abort on any unreadable record; protect-all when
// zero instances were identified; otherwise the per-record liveness rule.
const UsageFoldResult fold = foldUsageRecords(decoded, liveTrackGuids, anyLive);
result.abortPrune = fold.abortPrune;
result.heldPaths = fold.heldPaths;
// offendingKeys already populated above (unreadable + undecodable entries);
// clear it on success so callers see it only when abortPrune is set.
if (!result.abortPrune) result.offendingKeys.clear();
if (!result.abortPrune) result.offendingKeys.clear(); // only meaningful on abort
return result;
}