14
14
15
15
#pragma once
16
16
17
+ #include < type_traits>
18
+
17
19
#include " subspace/assertions/check.h"
20
+ #include " subspace/num/signed_integer.h"
18
21
#include " subspace/num/unsigned_integer.h"
19
22
#include " subspace/ops/range.h"
20
23
21
24
namespace sus ::ops {
22
25
23
26
namespace __private {
24
27
28
+ template <bool IsSigned>
25
29
struct RangeLiteralDeducer {
30
+ using Int =
31
+ std::conditional_t <IsSigned, ::sus::num::isize, ::sus::num::usize>;
32
+ using Digit = std::conditional_t <IsSigned, int , unsigned int >;
33
+
26
34
// A non-consteval method used to indicate failure in parsing, which produces
27
35
// a compiler error and still works in the presence of -fno-exceptions unlike
28
36
// `throw`.
@@ -32,17 +40,41 @@ struct RangeLiteralDeducer {
32
40
size_t i = 0u ;
33
41
34
42
bool has_lower = false ;
43
+ bool negate_lower = false ;
35
44
if (c[i] != ' .' ) {
45
+ if constexpr (IsSigned) {
46
+ if (c[i] == ' -' ) {
47
+ negate_lower = true ;
48
+ i += 1u ;
49
+ }
50
+ }
36
51
if (c[i] < ' 0' || c[i] > ' 9' )
37
52
invalid (" Invalid lower bound number in range literal" );
38
- lower = static_cast <unsigned int >(c[i] - ' 0' );
53
+ {
54
+ auto digit = static_cast <Digit>(c[i] - ' 0' );
55
+ if constexpr (IsSigned) {
56
+ if (negate_lower) digit = -digit;
57
+ }
58
+ lower = digit;
59
+ }
39
60
i += 1u ;
40
61
41
62
for (; c[i] != ' \0 ' && c[i] != ' .' ; i += 1u ) {
42
63
if (c[i] != ' \' ' ) {
43
64
if (c[i] < ' 0' || c[i] > ' 9' )
44
65
invalid (" Invalid lower bound number in range literal" );
45
- lower = lower * 10u + static_cast <unsigned int >(c[i] - ' 0' );
66
+ auto mul = lower.checked_mul (Digit{10 });
67
+ if (mul.is_none ()) invalid (" Lower bound is out of range" );
68
+ lower = ::sus::move (mul).unwrap ();
69
+ {
70
+ auto digit = static_cast <Digit>(c[i] - ' 0' );
71
+ if constexpr (IsSigned) {
72
+ if (negate_lower) digit = -digit;
73
+ }
74
+ auto add = lower.checked_add (digit);
75
+ if (add.is_none ()) invalid (" Lower bound is out of range" );
76
+ lower = ::sus::move (add).unwrap ();
77
+ }
46
78
} else if (c[i + 1 ] < ' 0' || c[i + 1 ] > ' 9' ) {
47
79
invalid (" Invalid lower bound number in range literal" );
48
80
}
@@ -73,16 +105,40 @@ struct RangeLiteralDeducer {
73
105
i += 1u ;
74
106
}
75
107
108
+ bool negate_upper = false ;
109
+ if constexpr (IsSigned) {
110
+ if (c[i] == ' -' ) {
111
+ negate_upper = true ;
112
+ i += 1u ;
113
+ }
114
+ }
76
115
if (c[i] < ' 0' || c[i] > ' 9' )
77
116
invalid (" Invalid upper bound number in range literal" );
78
- upper = static_cast <unsigned int >(c[i] - ' 0' );
117
+ {
118
+ auto digit = static_cast <Digit>(c[i] - ' 0' );
119
+ if constexpr (IsSigned) {
120
+ if (negate_upper) digit = -digit;
121
+ }
122
+ upper = digit;
123
+ }
79
124
i += 1u ;
80
125
81
126
for (; c[i] != ' \0 ' ; i += 1u ) {
82
127
if (c[i] != ' \' ' ) {
83
128
if (c[i] < ' 0' || c[i] > ' 9' )
84
129
invalid (" Invalid upper bound number in range literal" );
85
- upper = upper * 10u + static_cast <unsigned int >(c[i] - ' 0' );
130
+ auto mul = upper.checked_mul (Digit{10 });
131
+ if (mul.is_none ()) invalid (" Upper bound is out of range" );
132
+ upper = ::sus::move (mul).unwrap ();
133
+ {
134
+ auto digit = static_cast <Digit>(c[i] - ' 0' );
135
+ if constexpr (IsSigned) {
136
+ if (negate_upper) digit = -digit;
137
+ }
138
+ auto add = upper.checked_add (digit);
139
+ if (add.is_none ()) invalid (" Upper bound is out of range" );
140
+ upper = ::sus::move (add).unwrap ();
141
+ }
86
142
} else if (c[i + 1 ] < ' 0' || c[i + 1 ] > ' 9' ) {
87
143
invalid (" Invalid upper bound number in range literal" );
88
144
}
@@ -104,8 +160,8 @@ struct RangeLiteralDeducer {
104
160
UpperBound,
105
161
LowerAndUpperBound,
106
162
} type;
107
- ::sus::num::usize lower;
108
- ::sus::num::usize upper;
163
+ Int lower;
164
+ Int upper;
109
165
};
110
166
111
167
} // namespace __private
@@ -114,23 +170,62 @@ struct RangeLiteralDeducer {
114
170
115
171
// / Returns a range that satisfies the `RangeBounds<usize>` concept.
116
172
// /
173
+ // / Because `usize` is unsigned, numbers may not be negative.
174
+ // /
117
175
// / The syntax is:
118
- // / * `start..end` for a range including start and excluding end.
119
- // / * `start..=end` for a range including start and including end.
120
- // / * `start..` for a range including start and never ending.
176
+ // / * `start..end` for a range including start and excluding end. This returns a
177
+ // / `sus::ops::Range<usize>`.
178
+ // / * `start..=end` for a range including start and including end. This returns
179
+ // / a `sus::ops::Range<usize>`.
180
+ // / * `start..` for a range including start and never ending. This returns a
181
+ // / `sus::ops::RangeFrom<usize>`.
182
+ // / * `..end` for a range including everything up end. This returns a
183
+ // / `sus::ops::RangeTo<usize>`.
184
+ // / * `..=end` for a range including everything up and including end. This
185
+ // / returns a `sus::ops::RangeTo<usize>`.
121
186
// / * `..` for a range that has no bounds at all. Typically for a slicing range
122
- // / to indicate the entire slice.
123
- template <::sus::ops::__private::RangeLiteralDeducer D>
187
+ // / to indicate the entire slice. This returns a `sus::ops::RangeFull<usize>`.
188
+ template <::sus::ops::__private::RangeLiteralDeducer< false > D>
124
189
constexpr auto operator " " _r() {
125
190
using ::sus::ops::__private::RangeLiteralDeducer;
126
- if constexpr (D.type == RangeLiteralDeducer::NoBound)
191
+ if constexpr (D.type == RangeLiteralDeducer< false > ::NoBound)
127
192
return ::sus::ops::RangeFull<::sus::num::usize>();
128
- else if constexpr (D.type == RangeLiteralDeducer::LowerBound)
193
+ else if constexpr (D.type == RangeLiteralDeducer< false > ::LowerBound)
129
194
return ::sus::ops::RangeFrom<::sus::num::usize>(D.lower );
130
- else if constexpr (D.type == RangeLiteralDeducer::UpperBound)
195
+ else if constexpr (D.type == RangeLiteralDeducer< false > ::UpperBound)
131
196
return ::sus::ops::RangeTo<::sus::num::usize>(D.upper );
132
197
else
133
198
return ::sus::ops::Range<::sus::num::usize>(D.lower , D.upper );
134
199
}
135
200
201
+ // / Returns a range that satisfies the `RangeBounds<isize>` concept.
202
+ // /
203
+ // / Numbers may be positive or negative.
204
+ // /
205
+ // / The syntax is:
206
+ // / * `start..end` for a range including start and excluding end. This returns a
207
+ // / `sus::ops::Range<isize>`.
208
+ // / * `start..=end` for a range including start and including end. This returns
209
+ // / a `sus::ops::Range<isize>`.
210
+ // / * `start..` for a range including start and never ending. This returns a
211
+ // / `sus::ops::RangeFrom<isize>`.
212
+ // / * `..end` for a range including everything up end. This returns a
213
+ // / `sus::ops::RangeTo<isize>`.
214
+ // / * `..=end` for a range including everything up and including end. This
215
+ // / returns a `sus::ops::RangeTo<isize>`.
216
+ // / * `..` for a range that has no bounds at all. Typically for a slicing range
217
+ // / to indicate the entire slice. This returns a `sus::ops::RangeFull<isize>`.
218
+ template <::sus::ops::__private::RangeLiteralDeducer<true > D>
219
+ constexpr auto operator " " _rs() {
220
+ using ::sus::ops::__private::RangeLiteralDeducer;
221
+ if constexpr (D.type == RangeLiteralDeducer<true >::NoBound)
222
+ return ::sus::ops::RangeFull<::sus::num::isize>();
223
+ else if constexpr (D.type == RangeLiteralDeducer<true >::LowerBound)
224
+ return ::sus::ops::RangeFrom<::sus::num::isize>(D.lower );
225
+ else if constexpr (D.type == RangeLiteralDeducer<true >::UpperBound)
226
+ return ::sus::ops::RangeTo<::sus::num::isize>(D.upper );
227
+ else
228
+ return ::sus::ops::Range<::sus::num::isize>(D.lower , D.upper );
229
+ }
230
+
136
231
// TODO: _rs to make a signed RangeBounds over `isize`?
0 commit comments