data/FreeSlots.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "FreeSlots.h" | ||
| 2 | |||
| 3 | #include <algorithm> | ||
| 4 | |||
| 5 | namespace FreeSlots { | ||
| 6 | |||
| 7 | 23 | QList<Interval> find(const QList<Interval> &busy, const Options &options) { | |
| 8 | 23 | QList<Interval> found; | |
| 9 |
6/7✓ Branch 2 → 3 taken 23 times.
✓ Branch 3 → 4 taken 23 times.
✗ Branch 3 → 7 not taken.
✓ Branch 6 → 7 taken 1 time.
✓ Branch 6 → 8 taken 22 times.
✓ Branch 9 → 10 taken 1 time.
✓ Branch 9 → 11 taken 22 times.
|
23 | if (!options.from.isValid() || options.dayEnd <= options.dayStart) return found; |
| 10 |
1/1✓ Branch 11 → 12 taken 22 times.
|
22 | const int days = std::clamp(options.days, 1, 60); |
| 11 |
1/1✓ Branch 12 → 13 taken 22 times.
|
22 | const int duration = std::clamp(options.durationMinutes, 5, 480); |
| 12 |
1/1✓ Branch 13 → 14 taken 22 times.
|
22 | const int step = std::clamp(options.stepMinutes, 5, 120); |
| 13 |
1/1✓ Branch 14 → 15 taken 22 times.
|
22 | const int maximum = std::clamp(options.maximum, 1, 500); |
| 14 | // Busy intervals sorted by start; invalid or empty ones are ignored. | ||
| 15 | 22 | QList<Interval> sorted; | |
| 16 |
2/2✓ Branch 31 → 17 taken 24 times.
✓ Branch 31 → 32 taken 22 times.
|
46 | for (const Interval &interval : busy) |
| 17 |
8/12✓ Branch 18 → 19 taken 24 times.
✓ Branch 19 → 20 taken 24 times.
✗ Branch 19 → 26 not taken.
✓ Branch 20 → 21 taken 24 times.
✓ Branch 21 → 22 taken 24 times.
✗ Branch 21 → 26 not taken.
✓ Branch 22 → 23 taken 24 times.
✓ Branch 24 → 25 taken 24 times.
✗ Branch 24 → 26 not taken.
✓ Branch 27 → 28 taken 24 times.
✗ Branch 27 → 29 not taken.
✓ Branch 28 → 29 taken 24 times.
|
24 | if (interval.start.isValid() && interval.end.isValid() && interval.end > interval.start) sorted.append(interval); |
| 18 |
3/3✓ Branch 32 → 33 taken 22 times.
✓ Branch 33 → 34 taken 22 times.
✓ Branch 34 → 35 taken 22 times.
|
42 | std::sort(sorted.begin(), sorted.end(), [](const Interval &a, const Interval &b) { return a.start < b.start; }); |
| 19 | 759 | const auto overlaps = [&sorted](const QDateTime &start, const QDateTime &end) { | |
| 20 |
4/4✓ Branch 2 → 3 taken 759 times.
✓ Branch 3 → 4 taken 759 times.
✓ Branch 16 → 5 taken 858 times.
✓ Branch 16 → 17 taken 429 times.
|
1287 | for (const Interval &interval : sorted) { |
| 21 |
3/3✓ Branch 6 → 7 taken 858 times.
✓ Branch 8 → 9 taken 237 times.
✓ Branch 8 → 10 taken 621 times.
|
951 | if (interval.start >= end) return false; |
| 22 |
3/3✓ Branch 10 → 11 taken 621 times.
✓ Branch 12 → 13 taken 93 times.
✓ Branch 12 → 14 taken 528 times.
|
621 | if (interval.end > start) return true; |
| 23 | } | ||
| 24 | 429 | return false; | |
| 25 | 22 | }; | |
| 26 |
6/6✓ Branch 103 → 104 taken 86 times.
✓ Branch 103 → 107 taken 4 times.
✓ Branch 105 → 106 taken 68 times.
✓ Branch 105 → 107 taken 18 times.
✓ Branch 108 → 36 taken 68 times.
✓ Branch 108 → 109 taken 22 times.
|
90 | for (int day = 0; day < days && found.size() < maximum; ++day) { |
| 27 |
1/1✓ Branch 36 → 37 taken 68 times.
|
68 | const QDate date = options.from.addDays(day); |
| 28 |
3/3✓ Branch 37 → 38 taken 68 times.
✓ Branch 39 → 40 taken 4 times.
✓ Branch 39 → 41 taken 64 times.
|
68 | if (!options.workingDays.contains(date.dayOfWeek())) continue; |
| 29 |
1/1✓ Branch 41 → 42 taken 64 times.
|
64 | const QDateTime dayEnd(date, options.dayEnd, options.zone); |
| 30 |
8/9✓ Branch 89 → 90 taken 1113 times.
✓ Branch 90 → 91 taken 1113 times.
✗ Branch 90 → 97 not taken.
✓ Branch 93 → 94 taken 1069 times.
✓ Branch 93 → 97 taken 44 times.
✓ Branch 95 → 96 taken 1051 times.
✓ Branch 95 → 97 taken 18 times.
✓ Branch 98 → 43 taken 1051 times.
✓ Branch 98 → 99 taken 62 times.
|
1113 | for (QTime time = options.dayStart; time.isValid() && time < options.dayEnd && found.size() < maximum;) { |
| 31 |
1/1✓ Branch 43 → 44 taken 1051 times.
|
1051 | const QDateTime start(date, time, options.zone); |
| 32 |
1/1✓ Branch 44 → 45 taken 1051 times.
|
1051 | const QDateTime end = start.addSecs(qint64(duration) * 60); |
| 33 | // The spring gap: Qt moves a missing wall time; such a slot is skipped. | ||
| 34 |
7/9✓ Branch 45 → 46 taken 1051 times.
✓ Branch 46 → 47 taken 1051 times.
✗ Branch 46 → 54 not taken.
✓ Branch 47 → 48 taken 1051 times.
✓ Branch 49 → 50 taken 1049 times.
✓ Branch 49 → 54 taken 2 times.
✓ Branch 50 → 51 taken 1049 times.
✓ Branch 52 → 53 taken 1049 times.
✗ Branch 52 → 54 not taken.
|
1051 | const bool exists = start.isValid() && start.time() == time && start.date() == date; |
| 35 |
13/13✓ Branch 55 → 56 taken 1049 times.
✓ Branch 55 → 67 taken 2 times.
✓ Branch 56 → 57 taken 1049 times.
✓ Branch 58 → 59 taken 1005 times.
✓ Branch 58 → 67 taken 44 times.
✓ Branch 59 → 60 taken 1005 times.
✓ Branch 60 → 61 taken 981 times.
✓ Branch 60 → 64 taken 24 times.
✓ Branch 61 → 62 taken 981 times.
✓ Branch 63 → 64 taken 735 times.
✓ Branch 63 → 67 taken 246 times.
✓ Branch 68 → 69 taken 666 times.
✓ Branch 68 → 74 taken 385 times.
|
1810 | if (exists && end <= dayEnd && (!options.notBefore.isValid() || start >= options.notBefore) && |
| 36 |
3/3✓ Branch 64 → 65 taken 759 times.
✓ Branch 65 → 66 taken 666 times.
✓ Branch 65 → 67 taken 93 times.
|
759 | !overlaps(start, end)) |
| 37 | 666 | found.append({start, end}); | |
| 38 |
1/1✓ Branch 74 → 75 taken 1051 times.
|
1051 | const QTime next = time.addSecs(step * 60); |
| 39 |
2/2✓ Branch 77 → 78 taken 2 times.
✓ Branch 77 → 79 taken 1049 times.
|
1051 | if (next <= time) break; // past midnight |
| 40 | 1049 | time = next; | |
| 41 | 1053 | } | |
| 42 | 64 | } | |
| 43 | 22 | return found; | |
| 44 | 688 | } | |
| 45 | |||
| 46 | 45 | QList<Span> daySpans(const QList<Interval> &busy, const QDate &day, const QTime &dayStart, const QTime &dayEnd, | |
| 47 | const QTimeZone &zone) { | ||
| 48 |
1/1✓ Branch 2 → 3 taken 45 times.
|
45 | const QDateTime windowStart(day, dayStart, zone); |
| 49 |
1/1✓ Branch 3 → 4 taken 45 times.
|
45 | const QDateTime windowEnd(day, dayEnd, zone); |
| 50 |
1/1✓ Branch 4 → 5 taken 45 times.
|
45 | const double length = double(windowStart.msecsTo(windowEnd)); |
| 51 | 45 | QList<Span> spans; | |
| 52 |
8/10✓ Branch 5 → 6 taken 45 times.
✓ Branch 6 → 7 taken 45 times.
✗ Branch 6 → 10 not taken.
✓ Branch 7 → 8 taken 45 times.
✓ Branch 8 → 9 taken 45 times.
✗ Branch 8 → 10 not taken.
✓ Branch 9 → 10 taken 1 time.
✓ Branch 9 → 11 taken 44 times.
✓ Branch 12 → 13 taken 1 time.
✓ Branch 12 → 15 taken 44 times.
|
45 | if (!windowStart.isValid() || !windowEnd.isValid() || length <= 0) return spans; |
| 53 |
2/2✓ Branch 41 → 17 taken 56 times.
✓ Branch 41 → 42 taken 44 times.
|
100 | for (const Interval &interval : busy) { |
| 54 |
1/1✓ Branch 18 → 19 taken 56 times.
|
56 | const QDateTime start = std::max(interval.start, windowStart); |
| 55 |
1/1✓ Branch 20 → 21 taken 56 times.
|
56 | const QDateTime end = std::min(interval.end, windowEnd); |
| 56 |
3/3✓ Branch 22 → 23 taken 56 times.
✓ Branch 24 → 25 taken 31 times.
✓ Branch 24 → 26 taken 25 times.
|
56 | if (end <= start) continue; |
| 57 |
3/3✓ Branch 26 → 27 taken 25 times.
✓ Branch 27 → 28 taken 25 times.
✓ Branch 28 → 29 taken 25 times.
|
25 | spans.append({windowStart.msecsTo(start) / length, windowStart.msecsTo(end) / length}); |
| 58 | 87 | } | |
| 59 |
3/3✓ Branch 42 → 43 taken 44 times.
✓ Branch 43 → 44 taken 44 times.
✓ Branch 44 → 45 taken 44 times.
|
64 | std::sort(spans.begin(), spans.end(), [](const Span &a, const Span &b) { return a.from < b.from; }); |
| 60 | 44 | QList<Span> merged; | |
| 61 |
4/4✓ Branch 45 → 46 taken 44 times.
✓ Branch 46 → 47 taken 44 times.
✓ Branch 63 → 48 taken 25 times.
✓ Branch 63 → 64 taken 44 times.
|
69 | for (const Span &span : spans) { |
| 62 |
9/9✓ Branch 50 → 51 taken 10 times.
✓ Branch 50 → 54 taken 15 times.
✓ Branch 51 → 52 taken 10 times.
✓ Branch 52 → 53 taken 2 times.
✓ Branch 52 → 54 taken 8 times.
✓ Branch 55 → 56 taken 2 times.
✓ Branch 55 → 60 taken 23 times.
✓ Branch 56 → 57 taken 2 times.
✓ Branch 58 → 59 taken 2 times.
|
25 | if (!merged.isEmpty() && span.from <= merged.last().to) merged.last().to = std::max(merged.last().to, span.to); |
| 63 |
1/1✓ Branch 60 → 61 taken 23 times.
|
23 | else merged.append(span); |
| 64 | } | ||
| 65 | 44 | return merged; | |
| 66 | 45 | } | |
| 67 | |||
| 68 | } // namespace FreeSlots | ||
| 69 |