Files
salmanoff/include/user/intrinThresholdParams.h
T
hayodea 42c9fcdfdf Refactor intrinThresholdParams to use shared DAP helpers.
Delegate threshold param parsing to the new DeviceAttachmentSpec primitives
so intrin modules stay aligned with stimBuff param conventions.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-14 11:00:30 -04:00

235 lines
6.5 KiB
C++

#ifndef SMO_INTRIN_THRESHOLD_PARAMS_H
#define SMO_INTRIN_THRESHOLD_PARAMS_H
#include <array>
#include <cstddef>
#include <cstdint>
#include <optional>
#include <stdexcept>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
#include <user/deviceAttachmentSpec.h>
namespace smo::intrin {
enum class ThresholdUnit
{
Percentage,
Absolute,
};
struct ParsedThresholdParam
{
int value;
ThresholdUnit unit;
std::string_view matchedName;
bool wasSpecified;
};
/* Canonical unprefixed threshold-param names that live inside postrin(...) /
* negtrin(...) segments attached to a nontrin DAP spec. The "-pc" and
* "-percentage" variants are Percentage-unit; the "-thr", "-thresh" and
* "-threshold" variants are Absolute-unit.
*/
inline constexpr std::array<std::string_view, 2> kIntrinInterestPcNames = {
"interest-percentage",
"interest-pc",
};
inline constexpr std::array<std::string_view, 3> kIntrinInterestThrNames = {
"interest-threshold",
"interest-thresh",
"interest-thr",
};
inline constexpr std::array<std::string_view, 2> kIntrinDistractionPcNames = {
"distraction-percentage",
"distraction-pc",
};
inline constexpr std::array<std::string_view, 3> kIntrinDistractionThrNames = {
"distraction-threshold",
"distraction-thresh",
"distraction-thr",
};
inline constexpr std::array<std::string_view, 4> kIntrinStupefactionPcNames = {
"stupefaction-percentage",
"stupefaction-pc",
"stupefying-percentage",
"stupefying-pc",
};
inline constexpr std::array<std::string_view, 6> kIntrinStupefactionThrNames = {
"stupefaction-threshold",
"stupefaction-thresh",
"stupefaction-thr",
"stupefying-threshold",
"stupefying-thresh",
"stupefying-thr",
};
inline constexpr std::array<std::string_view, 2> kIntrinIntolerablePcNames = {
"intolerable-percentage",
"intolerable-pc",
};
inline constexpr std::array<std::string_view, 3> kIntrinIntolerableThrNames = {
"intolerable-threshold",
"intolerable-thresh",
"intolerable-thr",
};
/* Unitless stems are invalid — authors must name the unit via -pc/-percentage
* or -thr/-thresh/-threshold. We reject bare "interest", "distraction", etc.
*/
inline constexpr std::array<std::string_view, 5> kForbiddenUnitlessIntrinStems = {
"interest",
"distraction",
"stupefaction",
"stupefying",
"intolerable",
};
template <std::size_t N>
inline bool arrayContains(
const std::array<std::string_view, N>& names,
std::string_view candidate)
{
return device::DeviceAttachmentSpec::namesContain(names, candidate);
}
inline bool isKnownIntrinThresholdParamName(std::string_view name)
{
using device::DeviceAttachmentSpec;
return DeviceAttachmentSpec::namesContain(kIntrinInterestPcNames, name)
|| DeviceAttachmentSpec::namesContain(kIntrinInterestThrNames, name)
|| DeviceAttachmentSpec::namesContain(kIntrinDistractionPcNames, name)
|| DeviceAttachmentSpec::namesContain(kIntrinDistractionThrNames, name)
|| DeviceAttachmentSpec::namesContain(kIntrinStupefactionPcNames, name)
|| DeviceAttachmentSpec::namesContain(kIntrinStupefactionThrNames, name)
|| DeviceAttachmentSpec::namesContain(kIntrinIntolerablePcNames, name)
|| DeviceAttachmentSpec::namesContain(kIntrinIntolerableThrNames, name);
}
/* Intrin threshold params (interest-*, distraction-*, stupefaction-*,
* intolerable-*) must appear only inside postrin(...) / negtrin(...) segments
* on a DAP spec, never on qualeIfaceApi params. The deprecated `from-stimbuff`
* marker is also rejected — postrin/negtrin are now directly attached to the
* nontrin stimbuff they trigger from.
*/
inline void validateNoIntrinParamsOnQualeIface(
const std::string& qualeIfaceApi,
const std::vector<std::pair<std::string, std::string>>& params)
{
for (const auto& [name, value] : params)
{
(void)value;
if (isKnownIntrinThresholdParamName(name))
{
throw std::runtime_error(
"Intrinsic threshold param '" + name + "' is not valid on "
"qualeIfaceApi '" + qualeIfaceApi + "'. Declare it inside a "
"postrin(...) or negtrin(...) segment attached to this DAP "
"spec.");
}
if (arrayContains(kForbiddenUnitlessIntrinStems, name))
{
throw std::runtime_error(
"Intrinsic threshold param '" + name + "' on qualeIfaceApi '"
+ qualeIfaceApi + "' is invalid without a unit suffix and "
"does not belong on qualeIfaceApi params anyway. Use a "
"postrin(...) or negtrin(...) segment with a '-pc' or "
"'-thr' suffix.");
}
if (name == "from-stimbuff")
{
throw std::runtime_error(
"'from-stimbuff' is no longer supported. postrin(...) and "
"negtrin(...) are now attached directly to the nontrin DAP "
"spec they trigger from; remove 'from-stimbuff' from "
"qualeIfaceApi '" + qualeIfaceApi + "'.");
}
}
}
/* Accepts only unprefixed threshold names and the two passband modifiers that
* are defined on the sensory side. Rejects unit-less stems so that mis-typed
* params fail loudly.
*/
inline void validateIntrinSegmentParams(
std::string_view intrinKind, // "postrin" or "negtrin"
const std::vector<std::pair<std::string, std::string>>& params)
{
for (const auto& [name, value] : params)
{
(void)value;
if (arrayContains(kForbiddenUnitlessIntrinStems, name))
{
throw std::runtime_error(
std::string(intrinKind) + "(...) param '" + name + "' is "
"invalid without a unit suffix. Use '-pc'/'-percentage' or "
"'-thr'/'-thresh'/'-threshold'.");
}
}
}
inline ParsedThresholdParam parseOptionalThresholdParam(
const std::vector<std::pair<std::string, std::string>>& params,
const auto& percentageNames,
const auto& absoluteNames,
int defaultValue,
ThresholdUnit defaultUnit)
{
for (auto paramIt = params.rbegin(); paramIt != params.rend(); ++paramIt)
{
const auto& [name, value] = *paramIt;
ThresholdUnit unit;
if (device::DeviceAttachmentSpec::namesContain(percentageNames, name))
{ unit = ThresholdUnit::Percentage; }
else if (device::DeviceAttachmentSpec::namesContain(absoluteNames, name))
{ unit = ThresholdUnit::Absolute; }
else
{ continue; }
return ParsedThresholdParam{
.value = device::DeviceAttachmentSpec::parseParamValueAsInt(
name, value),
.unit = unit,
.matchedName = name,
.wasSpecified = true,
};
}
return ParsedThresholdParam{
.value = defaultValue,
.unit = defaultUnit,
.matchedName = {},
.wasSpecified = false,
};
}
inline uint32_t resolveThresholdValue(
const ParsedThresholdParam& param,
size_t percentageBase)
{
if (param.unit == ThresholdUnit::Percentage) {
return static_cast<uint32_t>((percentageBase * param.value) / 100);
}
return static_cast<uint32_t>(param.value);
}
} // namespace smo::intrin
#endif // SMO_INTRIN_THRESHOLD_PARAMS_H