void StandardCrontabItem::findMatchingPositionsImpl()

in bistro/cron/StandardCrontabItem.cpp [337:386]


void StandardCrontabItem::findMatchingPositionsImpl(
  MatchComputeState *s, int64_t carry_steps
) const {
  s->increaseDepth();
  const auto& sel = selectors_[(int)s->pos_];
  int64_t val = s->getVal(s->pos_);
  if (val < sel.getMin() || val > sel.getMax()) {
    throw logic_error(format(
      "{} not in [{}, {}]", val, sel.getMin(), sel.getMax()
    ).str());
  }
  int64_t new_val;
  bool carry_next;
  tie(new_val, carry_next) = sel.findFirstMatch(val + carry_steps);
  if (
    !carry_next && s->pos_ == Position::DAY_OF_MONTH &&
    new_val > s->getEndOfMonthDay()
  ) {
    carry_next = true;  // findFirstMatch may return 30 in February
  }
  if (carry_next) {
    if (s->pos_ == Position::YEAR) {
      // We exceeded the final year in matched by this crontab item,
      // so we won't be able to find a match.
      s->hasResult_ = false;
      return;
    }
    s->pos_ = prevPos(s->pos_);
    return findMatchingPositions(s, true);
  }
  // We know we didn't wrap around (carry_next is false here), so the value
  // can't go down (and goes up if we had an input carry).
  if (new_val < val || (carry_steps && new_val == val)) {
    throw logic_error(
      format("{} + {} went to {}", val, carry_steps, new_val).str()
    );
  }
  s->setVal(s->pos_, new_val);
  s->pos_ = nextPos(s->pos_);
  if (s->pos_ == Position::MAX) {
    return;  // All done!
  }
  // If this position advanced, we should reset all later ones, like 199 => 200
  if (new_val != val) {
    for (auto p = s->pos_; p < Position::MAX; p = nextPos(p)) {
      s->setVal(p, selectors_[(int)p].getMin());
    }
  }
  return findMatchingPositions(s, false);
}