summaryrefslogtreecommitdiffstats
path: root/server/src/time.cppm
diff options
context:
space:
mode:
Diffstat (limited to 'server/src/time.cppm')
-rw-r--r--server/src/time.cppm169
1 files changed, 12 insertions, 157 deletions
diff --git a/server/src/time.cppm b/server/src/time.cppm
index 8f53bd9..0007839 100644
--- a/server/src/time.cppm
+++ b/server/src/time.cppm
@@ -14,39 +14,13 @@ class period
14 timestamp end_; 14 timestamp end_;
15 15
16public: 16public:
17 explicit period(timestamp start, timestamp end) : start_{start}, end_{end} 17 explicit period(timestamp start, timestamp end);
18 {
19 if (start >= end)
20 {
21 throw std::invalid_argument("period: start should be before end");
22 }
23 }
24
25 [[nodiscard]] auto intersect(period other) const -> std::optional<period>
26 {
27 auto const new_start = start_ < other.start() ? other.start() : start_;
28 auto const new_end = other.end() < end_ ? other.end() : end_;
29 return new_start < new_end ? std::make_optional(period{new_start, new_end})
30 : std::nullopt;
31 }
32 18
19 [[nodiscard]] auto intersect(period other) const -> std::optional<period>;
33 [[nodiscard]] auto except(period other) const 20 [[nodiscard]] auto except(period other) const
34 -> std::pair<std::optional<period>, std::optional<period>> 21 -> std::pair<std::optional<period>, std::optional<period>>;
35 { 22 [[nodiscard]] auto start() const -> timestamp;
36 auto const before_start = start_; 23 [[nodiscard]] auto end() const -> timestamp;
37 auto const before_end = other.start();
38 auto const after_start = end_;
39 auto const after_end = other.end();
40 std::optional<period> before, after;
41 if (before_start < before_end)
42 before = period{before_start, before_end};
43 if (after_start < after_end)
44 after = period{after_end, after_start};
45 return std::make_pair(before, after);
46 }
47
48 [[nodiscard]] auto start() const -> timestamp { return start_; }
49 [[nodiscard]] auto end() const -> timestamp { return end_; }
50}; 24};
51 25
52class period_seq 26class period_seq
@@ -115,21 +89,7 @@ class period_seq
115 return periods; 89 return periods;
116 } 90 }
117 91
118 explicit period_seq(std::vector<period> periods) 92 explicit period_seq(std::vector<period> periods);
119 : periods_{std::move(periods)}
120 {
121 for (auto i = 0uz; i < periods_.size(); i++)
122 {
123 if (i + 1 < periods_.size())
124 {
125 if (periods_[i].end() >= periods_[i + 1].start())
126 {
127 throw std::logic_error{"period_seq: vector provided to private "
128 "constructor not ordered properly"};
129 }
130 }
131 }
132 }
133 93
134public: 94public:
135 template <std::input_iterator I, std::sentinel_for<I> S> 95 template <std::input_iterator I, std::sentinel_for<I> S>
@@ -138,119 +98,14 @@ public:
138 { 98 {
139 } 99 }
140 100
141 explicit period_seq(period singleton) : periods_{singleton} {} 101 explicit period_seq(period singleton);
142
143 [[nodiscard]] auto intersect(period_seq const& other) const -> period_seq
144 {
145 auto it1 = periods_.begin();
146 auto end1 = periods_.end();
147 auto it2 = other.periods_.begin();
148 auto end2 = other.periods_.end();
149
150 auto res = std::vector<period>{};
151 while (it1 != end1 && it2 != end2)
152 {
153 auto overlap = it1->intersect(*it2);
154 if (overlap)
155 {
156 res.push_back(*overlap);
157 if (it1->end() < it2->end())
158 {
159 it1++;
160 }
161 else
162 {
163 it2++;
164 }
165 }
166 else
167 {
168 if (it1->end() < it2->start())
169 {
170 it1++;
171 }
172 else
173 {
174 it2++;
175 }
176 }
177 }
178
179 return period_seq{res};
180 }
181
182 [[nodiscard]] auto except(period_seq const& other) const -> period_seq
183 {
184 // This code was pretty tricky to write, I wouldn't be surprised if it
185 // has some bugs in it.
186
187 auto it1 = periods_.begin();
188 auto end1 = periods_.end();
189 auto it2 = other.periods_.begin();
190 auto end2 = other.periods_.end();
191
192 auto res = std::vector<period>{};
193 if (it1 == end1)
194 return period_seq{res};
195 if (it2 == end2)
196 return period_seq{periods_};
197 auto period1 = period{*it1++};
198
199 while (it1 != end1 && it2 != end2)
200 {
201 if (period1.end() <= it2->start())
202 {
203 res.push_back(period1);
204 period1 = *it1++;
205 }
206 else if (it2->end() <= period1.start())
207 {
208 it2++;
209 }
210 else /* period1.begin() < it2->end() && it2->begin() <
211 period1.end() */
212 {
213 auto const [mbefore, mafter] = period1.except(*it2);
214 if (mbefore)
215 res.push_back(*mbefore);
216 if (mafter)
217 {
218 period1 = *mafter;
219 }
220 else
221 {
222 period1 = *it1++;
223 }
224 }
225 }
226
227 return period_seq{res};
228 }
229 102
230 [[nodiscard]] auto periods() const -> std::vector<period> const& 103 [[nodiscard]] auto intersect(period_seq const& other) const -> period_seq;
231 { 104 [[nodiscard]] auto except(period_seq const& other) const -> period_seq;
232 return periods_; 105 [[nodiscard]] auto periods() const -> std::vector<period> const&;
233 }
234}; 106};
235 107
236auto operator<<(std::ostream& os, period const& p) -> std::ostream& 108auto operator<<(std::ostream& os, period const& p) -> std::ostream&;
237{ 109auto operator<<(std::ostream& os, period_seq const& ps) -> std::ostream&;
238 return os << "[" << p.start() << ", " << p.end() << ")";
239}
240
241auto operator<<(std::ostream& os, period_seq const& ps) -> std::ostream&
242{
243 os << "{";
244 auto it = ps.periods().begin();
245 while (it != ps.periods().end())
246 {
247 os << " " << *it;
248 if (++it != ps.periods().end())
249 {
250 os << ",";
251 }
252 }
253 return os << " }";
254}
255 110
256} // namespace routemon::time 111} // namespace routemon::time