Skip to content

Commit 2cdd597

Browse files
committed
aoc_lib: template Pos and Delta on the integer type
1 parent 8b2cabe commit 2cdd597

File tree

1 file changed

+76
-40
lines changed

1 file changed

+76
-40
lines changed

aoc_lib/src/lib.hpp

Lines changed: 76 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@
1010
#define LIB_HPP_0IZKV7KG
1111

1212
#include "util/hash.hpp" // for make_hash
13-
#include <algorithm> // for max, min
13+
#include <algorithm> // for max, min // IWYU pragma: keep
1414
#include <cassert> // for assert
1515
#include <compare> // for strong_ordering
16+
#include <concepts> // for integral
1617
#include <cstdlib> // for abs, size_t, exit
1718
#include <fstream> // for ifstream // IWYU pragma: keep
1819
#include <functional> // for hash
@@ -141,12 +142,15 @@ RelDirection relative_to(AbsDirection old_dir, AbsDirection new_dir) {
141142
}
142143
} // namespace directions
143144

144-
struct Delta {
145-
int dx;
146-
int dy;
145+
template <std::integral T = int>
146+
struct GenericDelta {
147+
using int_type = T;
148+
int_type dx;
149+
int_type dy;
147150

148-
constexpr Delta(int dx, int dy) : dx(dx), dy(dy) {}
149-
explicit constexpr Delta(AbsDirection dir, bool invert_vertical = false)
151+
constexpr GenericDelta(int_type dx, int_type dy) : dx(dx), dy(dy) {}
152+
explicit constexpr GenericDelta(AbsDirection dir,
153+
bool invert_vertical = false)
150154
: dx(0), dy(0) {
151155
switch (dir) {
152156
case AbsDirection::north:
@@ -167,133 +171,164 @@ struct Delta {
167171
}
168172
}
169173

170-
constexpr int chebyshev_distance() const {
174+
constexpr int_type chebyshev_distance() const {
171175
return std::max(std::abs(dx), std::abs(dy));
172176
}
173177

174-
constexpr int manhattan_distance() const {
178+
constexpr int_type manhattan_distance() const {
175179
return std::abs(dx) + std::abs(dy);
176180
}
177181

178182
// two Deltas can be added together
179-
Delta &operator+=(const Delta &rhs) {
183+
GenericDelta &operator+=(const GenericDelta &rhs) {
180184
dx += rhs.dx;
181185
dy += rhs.dy;
182186
return *this;
183187
}
184188

185189
// two Deltas can be subtracted
186-
Delta &operator-=(const Delta &rhs) {
190+
GenericDelta &operator-=(const GenericDelta &rhs) {
187191
dx -= rhs.dx;
188192
dy -= rhs.dy;
189193
return *this;
190194
}
191195

192196
// can be scaled by an integer
193-
Delta &operator*=(int rhs) {
197+
GenericDelta &operator*=(int_type rhs) {
194198
dx *= rhs;
195199
dy *= rhs;
196200
return *this;
197201
}
198-
Delta &operator/=(int rhs) {
202+
GenericDelta &operator/=(int_type rhs) {
199203
dx /= rhs;
200204
dy /= rhs;
201205
return *this;
202206
}
203207
};
204208
// this takes lhs by copy, so it doesn't modify the original lhs
205-
inline Delta operator+(Delta lhs, const Delta &rhs) {
209+
template <std::integral int_type>
210+
inline GenericDelta<int_type> operator+(GenericDelta<int_type> lhs,
211+
const GenericDelta<int_type> &rhs) {
206212
lhs += rhs;
207213
return lhs;
208214
}
209-
inline Delta operator-(Delta lhs, const Delta &rhs) {
215+
template <std::integral int_type>
216+
inline GenericDelta<int_type> operator-(GenericDelta<int_type> lhs,
217+
const GenericDelta<int_type> &rhs) {
210218
lhs -= rhs;
211219
return lhs;
212220
}
213-
inline Delta operator*(Delta lhs, int rhs) {
221+
template <std::integral int_type>
222+
inline GenericDelta<int_type> operator*(GenericDelta<int_type> lhs,
223+
int_type rhs) {
214224
lhs *= rhs;
215225
return lhs;
216226
}
217-
inline Delta operator*(int lhs, Delta rhs) {
227+
template <std::integral int_type>
228+
inline GenericDelta<int_type> operator*(int_type lhs,
229+
GenericDelta<int_type> rhs) {
218230
rhs *= lhs;
219231
return rhs;
220232
}
221-
inline Delta operator/(Delta lhs, int rhs) {
233+
template <std::integral int_type>
234+
inline GenericDelta<int_type> operator/(GenericDelta<int_type> lhs,
235+
int_type rhs) {
222236
lhs /= rhs;
223237
return lhs;
224238
}
225239
// negation operator
226-
inline Delta operator-(Delta delta) {
240+
template <std::integral int_type>
241+
inline GenericDelta<int_type> operator-(GenericDelta<int_type> delta) {
227242
delta.dx *= -1;
228243
delta.dy *= -1;
229244
return delta;
230245
}
231246

232-
std::ostream &operator<<(std::ostream &os, const Delta &delta) {
233-
os << "Delta(" << delta.dx << ", " << delta.dy << ")";
247+
template <std::integral int_type>
248+
std::ostream &operator<<(std::ostream &os,
249+
const GenericDelta<int_type> &delta) {
250+
os << "GenericDelta(" << delta.dx << ", " << delta.dy << ")";
234251
return os;
235252
}
236253

237-
struct Pos {
238-
int x;
239-
int y;
254+
template <std::integral T = int>
255+
struct GenericPos {
256+
using int_type = T;
257+
int_type x;
258+
int_type y;
240259

241-
constexpr Pos() : x(0), y(0) {}
242-
constexpr Pos(int x, int y) : x(x), y(y) {}
260+
constexpr GenericPos() : x(0), y(0) {}
261+
constexpr GenericPos(int_type x, int_type y) : x(x), y(y) {}
243262

244263
// we can add a Delta to a Pos, but not another Pos
245-
Pos &operator+=(const Delta &rhs) {
264+
GenericPos &operator+=(const GenericDelta<int_type> &rhs) {
246265
x += rhs.dx;
247266
y += rhs.dy;
248267
return *this;
249268
}
250-
Pos &operator-=(const Delta &rhs) {
269+
GenericPos &operator-=(const GenericDelta<int_type> &rhs) {
251270
x -= rhs.dx;
252271
y -= rhs.dy;
253272
return *this;
254273
}
255274

256275
// can scale by an integer
257-
Pos &operator*=(int rhs) {
276+
GenericPos &operator*=(int_type rhs) {
258277
x *= rhs;
259278
y *= rhs;
260279
return *this;
261280
}
262-
Pos &operator/=(int rhs) {
281+
GenericPos &operator/=(int_type rhs) {
263282
x /= rhs;
264283
y /= rhs;
265284
return *this;
266285
}
267286

268-
constexpr std::strong_ordering operator<=>(const Pos &) const = default;
287+
constexpr std::strong_ordering
288+
operator<=>(const GenericPos<int_type> &) const = default;
269289
};
270290
// this takes lhs by copy, so it doesn't modify the original lhs
271-
inline Pos operator+(Pos lhs, const Delta &rhs) {
291+
template <std::integral int_type>
292+
inline GenericPos<int_type> operator+(GenericPos<int_type> lhs,
293+
const GenericDelta<int_type> &rhs) {
272294
lhs += rhs;
273295
return lhs;
274296
}
275-
inline Pos operator-(Pos lhs, const Delta &rhs) {
297+
template <std::integral int_type>
298+
inline GenericPos<int_type> operator-(GenericPos<int_type> lhs,
299+
const GenericDelta<int_type> &rhs) {
276300
lhs -= rhs;
277301
return lhs;
278302
}
279-
inline Pos operator*(Pos lhs, int rhs) {
303+
template <std::integral int_type>
304+
inline GenericPos<int_type> operator*(GenericPos<int_type> lhs, int rhs) {
280305
lhs *= rhs;
281306
return lhs;
282307
}
283-
inline Pos operator/(Pos lhs, int rhs) {
308+
template <std::integral int_type>
309+
inline GenericPos<int_type> operator/(GenericPos<int_type> lhs, int rhs) {
284310
lhs /= rhs;
285311
return lhs;
286312
}
287313
// can subtract two Pos, yielding a Delta
288-
inline Delta operator-(const Pos &lhs, const Pos &rhs) {
314+
template <std::integral int_type>
315+
inline GenericDelta<int_type> operator-(const GenericPos<int_type> &lhs,
316+
const GenericPos<int_type> &rhs) {
289317
return {lhs.x - rhs.x, lhs.y - rhs.y};
290318
}
291319

292-
std::ostream &operator<<(std::ostream &os, const Pos &pos) {
293-
os << "Pos(" << pos.x << ", " << pos.y << ")";
320+
template <std::integral int_type>
321+
std::ostream &operator<<(std::ostream &os, const GenericPos<int_type> &pos) {
322+
os << "GenericPos(" << pos.x << ", " << pos.y << ")";
294323
return os;
295324
}
296325

326+
using Delta = GenericDelta<int>;
327+
using Pos = GenericPos<int>;
328+
329+
using LongDelta = GenericDelta<long>;
330+
using LongPos = GenericPos<long>;
331+
297332
template <class T>
298333
T intersect_ranges(const T &range_1, const T &range_2) {
299334
const auto &[r1_lo, r1_hi] = range_1;
@@ -436,9 +471,10 @@ std::string read_whole_stream(std::istream &is) {
436471

437472
} // namespace aoc
438473

439-
template <>
440-
struct std::hash<aoc::Pos> {
441-
std::size_t operator()(const aoc::Pos &pos) const noexcept {
474+
template <std::integral int_type>
475+
struct std::hash<aoc::GenericPos<int_type>> {
476+
std::size_t
477+
operator()(const aoc::GenericPos<int_type> &pos) const noexcept {
442478
// random number
443479
std::size_t seed = 0xbedb5bb0b473b6b7ull;
444480
util::make_hash(seed, pos.x, pos.y);

0 commit comments

Comments
 (0)