summaryrefslogtreecommitdiffstats
path: root/server/src/time.cpp
diff options
context:
space:
mode:
authorRutger Broekhoff2026-08-29 12:01:42 +0200
committerRutger Broekhoff2026-08-29 12:01:42 +0200
commit52b3cd46c76fd4be18aeb8422a08a073484b9fad (patch)
treeb4f23957c096e6bce5369bb94a4e8e23de71761a /server/src/time.cpp
parent35878b76049b9c3e752480e9f298b7e2da6fdf1f (diff)
downloadroutemon-52b3cd46c76fd4be18aeb8422a08a073484b9fad.tar.gz
routemon-52b3cd46c76fd4be18aeb8422a08a073484b9fad.zip
More module implementation partition units
Diffstat (limited to 'server/src/time.cpp')
-rw-r--r--server/src/time.cpp173
1 files changed, 173 insertions, 0 deletions
diff --git a/server/src/time.cpp b/server/src/time.cpp
new file mode 100644
index 0000000..8f99dd2
--- /dev/null
+++ b/server/src/time.cpp
@@ -0,0 +1,173 @@
1module routemon:time$impl;
2
3import :time;
4
5export namespace routemon::time {
6
7using timestamp = std::chrono::time_point<std::chrono::utc_clock>;
8
9period::period(timestamp start, timestamp end) : start_{start}, end_{end}
10{
11 if (start >= end)
12 {
13 throw std::invalid_argument("period: start should be before end");
14 }
15}
16
17auto period::intersect(period other) const -> std::optional<period>
18{
19 auto const new_start = start_ < other.start() ? other.start() : start_;
20 auto const new_end = other.end() < end_ ? other.end() : end_;
21 return new_start < new_end ? std::make_optional(period{new_start, new_end})
22 : std::nullopt;
23}
24
25auto period::except(period other) const
26 -> std::pair<std::optional<period>, std::optional<period>>
27{
28 auto const before_start = start_;
29 auto const before_end = other.start();
30 auto const after_start = end_;
31 auto const after_end = other.end();
32 std::optional<period> before, after;
33 if (before_start < before_end)
34 before = period{before_start, before_end};
35 if (after_start < after_end)
36 after = period{after_end, after_start};
37 return std::make_pair(before, after);
38}
39
40auto period::start() const -> timestamp { return start_; }
41auto period::end() const -> timestamp { return end_; }
42
43period_seq::period_seq(std::vector<period> periods)
44 : periods_{std::move(periods)}
45{
46 for (auto i = 0uz; i < periods_.size(); i++)
47 {
48 if (i + 1 < periods_.size())
49 {
50 if (periods_[i].end() >= periods_[i + 1].start())
51 {
52 throw std::logic_error{"period_seq: vector provided to private "
53 "constructor not ordered properly"};
54 }
55 }
56 }
57}
58
59period_seq::period_seq(period singleton) : periods_{singleton} {}
60
61auto period_seq::intersect(period_seq const& other) const -> period_seq
62{
63 auto it1 = periods_.begin();
64 auto end1 = periods_.end();
65 auto it2 = other.periods_.begin();
66 auto end2 = other.periods_.end();
67
68 auto res = std::vector<period>{};
69 while (it1 != end1 && it2 != end2)
70 {
71 auto overlap = it1->intersect(*it2);
72 if (overlap)
73 {
74 res.push_back(*overlap);
75 if (it1->end() < it2->end())
76 {
77 it1++;
78 }
79 else
80 {
81 it2++;
82 }
83 }
84 else
85 {
86 if (it1->end() < it2->start())
87 {
88 it1++;
89 }
90 else
91 {
92 it2++;
93 }
94 }
95 }
96
97 return period_seq{res};
98}
99
100auto period_seq::except(period_seq const& other) const -> period_seq
101{
102 // This code was pretty tricky to write, I wouldn't be surprised if it
103 // has some bugs in it.
104
105 auto it1 = periods_.begin();
106 auto end1 = periods_.end();
107 auto it2 = other.periods_.begin();
108 auto end2 = other.periods_.end();
109
110 auto res = std::vector<period>{};
111 if (it1 == end1)
112 return period_seq{res};
113 if (it2 == end2)
114 return period_seq{periods_};
115 auto period1 = period{*it1++};
116
117 while (it1 != end1 && it2 != end2)
118 {
119 if (period1.end() <= it2->start())
120 {
121 res.push_back(period1);
122 period1 = *it1++;
123 }
124 else if (it2->end() <= period1.start())
125 {
126 it2++;
127 }
128 else /* period1.begin() < it2->end() && it2->begin() <
129 period1.end() */
130 {
131 auto const [mbefore, mafter] = period1.except(*it2);
132 if (mbefore)
133 res.push_back(*mbefore);
134 if (mafter)
135 {
136 period1 = *mafter;
137 }
138 else
139 {
140 period1 = *it1++;
141 }
142 }
143 }
144
145 return period_seq{res};
146}
147
148auto period_seq::periods() const -> std::vector<period> const&
149{
150 return periods_;
151}
152
153auto operator<<(std::ostream& os, period const& p) -> std::ostream&
154{
155 return os << "[" << p.start() << ", " << p.end() << ")";
156}
157
158auto operator<<(std::ostream& os, period_seq const& ps) -> std::ostream&
159{
160 os << "{";
161 auto it = ps.periods().begin();
162 while (it != ps.periods().end())
163 {
164 os << " " << *it;
165 if (++it != ps.periods().end())
166 {
167 os << ",";
168 }
169 }
170 return os << " }";
171}
172
173} // namespace routemon::time