#ifndef SMO_INTRIN_THRESHOLD_PARAMS_H #define SMO_INTRIN_THRESHOLD_PARAMS_H #include #include #include #include #include #include #include #include #include namespace smo::intrin { enum class ThresholdUnit { Percentage, Absolute, }; struct ParsedThresholdParam { int value; ThresholdUnit unit; std::string_view matchedName; bool wasSpecified; }; inline constexpr std::array kPosIntPcParamNames = { "postrin-interest-percentage", "postrin-interest-pc", }; inline constexpr std::array kPosIntThrParamNames = { "postrin-interest-threshold", "postrin-interest-thresh", "postrin-interest-thr", }; inline constexpr std::array kNegIntPcParamNames = { "negtrin-interest-percentage", "negtrin-interest-pc", }; inline constexpr std::array kNegIntThrParamNames = { "negtrin-interest-threshold", "negtrin-interest-thresh", "negtrin-interest-thr", }; inline constexpr std::array kPosDistPcParamNames = { "postrin-distraction-percentage", "postrin-distraction-pc", }; inline constexpr std::array kPosDistThrParamNames = { "postrin-distraction-threshold", "postrin-distraction-thresh", "postrin-distraction-thr", }; inline constexpr std::array kNegDistPcParamNames = { "negtrin-distraction-percentage", "negtrin-distraction-pc", }; inline constexpr std::array kNegDistThrParamNames = { "negtrin-distraction-threshold", "negtrin-distraction-thresh", "negtrin-distraction-thr", }; inline constexpr std::array kStupefactionPcParamNames = { "postrin-stupefaction-percentage", "postrin-stupefaction-pc", "postrin-stupefying-percentage", "postrin-stupefying-pc", "stupefaction-percentage", "stupefaction-pc", "stupefying-percentage", "stupefying-pc", }; inline constexpr std::array kStupefactionThrParamNames = { "postrin-stupefaction-threshold", "postrin-stupefaction-thresh", "postrin-stupefaction-thr", "postrin-stupefying-threshold", "postrin-stupefying-thresh", "postrin-stupefying-thr", "stupefaction-threshold", "stupefaction-thresh", "stupefaction-thr", "stupefying-threshold", "stupefying-thresh", "stupefying-thr", }; inline constexpr std::array kIntolerablePcParamNames = { "negtrin-intolerable-percentage", "negtrin-intolerable-pc", "intolerable-percentage", "intolerable-pc", }; inline constexpr std::array kIntolerableThrParamNames = { "negtrin-intolerable-threshold", "negtrin-intolerable-thresh", "negtrin-intolerable-thr", "intolerable-threshold", "intolerable-thresh", "intolerable-thr", }; inline constexpr std::array kForbiddenUnitlessIntrinParamNames = { "postrin-interest", "negtrin-interest", "postrin-distraction", "negtrin-distraction", "postrin-stupefaction", "postrin-stupefying", "stupefaction", "stupefying", "negtrin-intolerable", "intolerable", }; template bool arrayContains( const std::array& names, std::string_view candidate) { for (const auto& name : names) { if (name == candidate) { return true; } } return false; } template bool namesContain( const NameCollectionT& names, std::string_view candidate) { for (const auto& name : names) { if (name == candidate) { return true; } } return false; } inline void validateNoForbiddenUnitlessIntrinParams( const std::vector>& params) { for (const auto& [name, value] : params) { (void)value; if (arrayContains(kForbiddenUnitlessIntrinParamNames, name)) { throw std::runtime_error( "Intrinsic threshold param '" + name + "' is invalid without a unit suffix. Use a " "'-percentage'/'-pc' or '-threshold'/'-thresh'/'-thr' variant."); } } } inline std::optional> findLastMatchingIntParam( const std::vector>& params, const auto& synonymNames) { for (auto paramIt = params.rbegin(); paramIt != params.rend(); ++paramIt) { const auto& [name, value] = *paramIt; if (!namesContain(synonymNames, name)) { continue; } try { return std::pair(name, std::stoi(value)); } catch (const std::exception& e) { throw std::runtime_error( "Failed to parse '" + name + "' param value '" + value + "' as integer: " + e.what()); } } return std::nullopt; } inline ParsedThresholdParam parseOptionalThresholdParam( const std::vector>& 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 (namesContain(percentageNames, name)) { unit = ThresholdUnit::Percentage; } else if (namesContain(absoluteNames, name)) { unit = ThresholdUnit::Absolute; } else { continue; } try { return ParsedThresholdParam{ .value = std::stoi(value), .unit = unit, .matchedName = name, .wasSpecified = true, }; } catch (const std::exception& e) { throw std::runtime_error( "Failed to parse '" + name + "' param value '" + value + "' as integer: " + e.what()); } } 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((percentageBase * param.value) / 100); } return static_cast(param.value); } } // namespace smo::intrin #endif // SMO_INTRIN_THRESHOLD_PARAMS_H