// See resample_name.h. #include "core/model/resample_name.h" #include namespace reasampler::model { namespace { constexpr const char* kFallbackStem = "resample"; constexpr int kFirstIteration = 2; // the source itself is iteration 1 // The " r" tail, if the name ends in one and the digits are a whole number > 0. // Returns 0 (no tail) otherwise; `stemLength` is then left untouched. int trailingIteration(const std::string& name, std::size_t& stemLength) { std::size_t digitsBegin = name.size(); while (digitsBegin > 0 && std::isdigit(static_cast(name[digitsBegin - 1]))) --digitsBegin; if (digitsBegin == name.size()) return 0; // no digits at the end if (digitsBegin < 2) return 0; // no room for " r" if (name[digitsBegin - 1] != 'r' || name[digitsBegin - 2] != ' ') return 0; // Overflow-safe accumulate: a pathological digit run stops counting rather than // wrapping into a small number and silently reusing an existing name. int value = 0; for (std::size_t i = digitsBegin; i < name.size(); ++i) { if (value > 1000000) return 0; value = value * 10 + (name[i] - '0'); } if (value <= 0) return 0; stemLength = digitsBegin - 2; return value; } } // namespace std::string nextIterationName(const std::string& sourceName) { if (sourceName.empty()) return std::string(kFallbackStem) + " r" + std::to_string(kFirstIteration); std::size_t stemLength = sourceName.size(); const int current = trailingIteration(sourceName, stemLength); if (current > 0) return sourceName.substr(0, stemLength) + " r" + std::to_string(current + 1); return sourceName + " r" + std::to_string(kFirstIteration); } } // namespace reasampler::model