10
10
#define LIB_HPP_0IZKV7KG
11
11
12
12
#include " util/hash.hpp" // for make_hash
13
- #include < algorithm> // for max, min
13
+ #include < algorithm> // for max, min // IWYU pragma: keep
14
14
#include < cassert> // for assert
15
15
#include < compare> // for strong_ordering
16
+ #include < concepts> // for integral
16
17
#include < cstdlib> // for abs, size_t, exit
17
18
#include < fstream> // for ifstream // IWYU pragma: keep
18
19
#include < functional> // for hash
@@ -141,12 +142,15 @@ RelDirection relative_to(AbsDirection old_dir, AbsDirection new_dir) {
141
142
}
142
143
} // namespace directions
143
144
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;
147
150
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 )
150
154
: dx(0 ), dy(0 ) {
151
155
switch (dir) {
152
156
case AbsDirection::north:
@@ -167,133 +171,164 @@ struct Delta {
167
171
}
168
172
}
169
173
170
- constexpr int chebyshev_distance () const {
174
+ constexpr int_type chebyshev_distance () const {
171
175
return std::max (std::abs (dx), std::abs (dy));
172
176
}
173
177
174
- constexpr int manhattan_distance () const {
178
+ constexpr int_type manhattan_distance () const {
175
179
return std::abs (dx) + std::abs (dy);
176
180
}
177
181
178
182
// two Deltas can be added together
179
- Delta &operator +=(const Delta &rhs) {
183
+ GenericDelta &operator +=(const GenericDelta &rhs) {
180
184
dx += rhs.dx ;
181
185
dy += rhs.dy ;
182
186
return *this ;
183
187
}
184
188
185
189
// two Deltas can be subtracted
186
- Delta &operator -=(const Delta &rhs) {
190
+ GenericDelta &operator -=(const GenericDelta &rhs) {
187
191
dx -= rhs.dx ;
188
192
dy -= rhs.dy ;
189
193
return *this ;
190
194
}
191
195
192
196
// can be scaled by an integer
193
- Delta &operator *=(int rhs) {
197
+ GenericDelta &operator *=(int_type rhs) {
194
198
dx *= rhs;
195
199
dy *= rhs;
196
200
return *this ;
197
201
}
198
- Delta &operator /=(int rhs) {
202
+ GenericDelta &operator /=(int_type rhs) {
199
203
dx /= rhs;
200
204
dy /= rhs;
201
205
return *this ;
202
206
}
203
207
};
204
208
// 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) {
206
212
lhs += rhs;
207
213
return lhs;
208
214
}
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) {
210
218
lhs -= rhs;
211
219
return lhs;
212
220
}
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) {
214
224
lhs *= rhs;
215
225
return lhs;
216
226
}
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) {
218
230
rhs *= lhs;
219
231
return rhs;
220
232
}
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) {
222
236
lhs /= rhs;
223
237
return lhs;
224
238
}
225
239
// negation operator
226
- inline Delta operator -(Delta delta) {
240
+ template <std::integral int_type>
241
+ inline GenericDelta<int_type> operator -(GenericDelta<int_type> delta) {
227
242
delta.dx *= -1 ;
228
243
delta.dy *= -1 ;
229
244
return delta;
230
245
}
231
246
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 << " )" ;
234
251
return os;
235
252
}
236
253
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;
240
259
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) {}
243
262
244
263
// 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) {
246
265
x += rhs.dx ;
247
266
y += rhs.dy ;
248
267
return *this ;
249
268
}
250
- Pos &operator -=(const Delta &rhs) {
269
+ GenericPos &operator -=(const GenericDelta<int_type> &rhs) {
251
270
x -= rhs.dx ;
252
271
y -= rhs.dy ;
253
272
return *this ;
254
273
}
255
274
256
275
// can scale by an integer
257
- Pos &operator *=(int rhs) {
276
+ GenericPos &operator *=(int_type rhs) {
258
277
x *= rhs;
259
278
y *= rhs;
260
279
return *this ;
261
280
}
262
- Pos &operator /=(int rhs) {
281
+ GenericPos &operator /=(int_type rhs) {
263
282
x /= rhs;
264
283
y /= rhs;
265
284
return *this ;
266
285
}
267
286
268
- constexpr std::strong_ordering operator <=>(const Pos &) const = default ;
287
+ constexpr std::strong_ordering
288
+ operator <=>(const GenericPos<int_type> &) const = default ;
269
289
};
270
290
// 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) {
272
294
lhs += rhs;
273
295
return lhs;
274
296
}
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) {
276
300
lhs -= rhs;
277
301
return lhs;
278
302
}
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) {
280
305
lhs *= rhs;
281
306
return lhs;
282
307
}
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) {
284
310
lhs /= rhs;
285
311
return lhs;
286
312
}
287
313
// 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) {
289
317
return {lhs.x - rhs.x , lhs.y - rhs.y };
290
318
}
291
319
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 << " )" ;
294
323
return os;
295
324
}
296
325
326
+ using Delta = GenericDelta<int >;
327
+ using Pos = GenericPos<int >;
328
+
329
+ using LongDelta = GenericDelta<long >;
330
+ using LongPos = GenericPos<long >;
331
+
297
332
template <class T >
298
333
T intersect_ranges (const T &range_1, const T &range_2) {
299
334
const auto &[r1_lo, r1_hi] = range_1;
@@ -436,9 +471,10 @@ std::string read_whole_stream(std::istream &is) {
436
471
437
472
} // namespace aoc
438
473
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 {
442
478
// random number
443
479
std::size_t seed = 0xbedb5bb0b473b6b7ull ;
444
480
util::make_hash (seed, pos.x , pos.y );
0 commit comments