Skip to content

Commit d13fe65

Browse files
committed
Make RangeBounds which is implemented by Range, RangeTo, RangeFrom, RangeFull
Introduce _r literals for writing range literals. "1..4"_r produces a Range. "1..=4"_r also does. "..4"_r produces a RangeTo. "4.."_r produces a RangeFrom. ".."_r produces a RangeFull. Slice range methods now take a RangeBounds instead of a Range, allowing them to operator on ranges with unbounded ends. Range and RangeFrom are Iterators over the values in their range. TODO: Need some helper functions to make ranges from dynamic values as the literals only work with constants (unlike in Rust).
1 parent 44fcb73 commit d13fe65

20 files changed

+561
-71
lines changed

.vscode/settings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
"-compile-commands-dir=out"
1515
],
1616
"cmake.configureSettings": {
17-
"CMAKE_MAKE_PROGRAM": "ninja"
17+
"CMAKE_MAKE_PROGRAM": "ninja",
1818
},
1919
"cmake.generator": "Ninja",
2020
"files.eol": "\n",

subdoc/lib/gen/files.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ inline std::filesystem::path construct_html_file_path_for_namespace(
7272
// The namespace path includes the namespace element itself, so drop
7373
// that one.
7474
sus::Slice<const Namespace> short_namespace_path =
75-
element.namespace_path.as_ref()[{1u, element.namespace_path.len()}];
75+
element.namespace_path.as_ref()["1.."_r];
7676

7777
std::string file_name = [&]() {
7878
if (element.namespace_name.which() == Namespace::Tag::Global) {

subdoc/lib/gen/generate_namespace.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ std::string namespace_display_name(const NamespaceElement& element) noexcept {
3535
// The namespace path includes the namespace we're generating for, so drop
3636
// that one.
3737
sus::Slice<const Namespace> short_namespace_path =
38-
element.namespace_path.as_ref()[{1u, element.namespace_path.len()}];
38+
element.namespace_path.as_ref()["1.."_r];
3939

4040
// For display in the html, we use the full path name of the namespace.
4141
return namespace_with_path_to_string(short_namespace_path,

subspace/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ target_sources(subspace PUBLIC
114114
"ops/eq.h"
115115
"ops/ord.h"
116116
"ops/range.h"
117+
"ops/range_literals.h"
117118
"result/__private/is_result_type.h"
118119
"result/__private/marker.h"
119120
"result/__private/storage.h"
@@ -176,6 +177,7 @@ add_executable(subspace_unittests
176177
"option/option_types_unittest.cc"
177178
"ops/eq_unittest.cc"
178179
"ops/ord_unittest.cc"
180+
"ops/range_unittest.cc"
179181
"result/result_unittest.cc"
180182
"result/result_types_unittest.cc"
181183
"tuple/tuple_types_unittest.cc"

subspace/containers/slice.h

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -142,12 +142,14 @@ class Slice {
142142
/// function will panic.
143143
/// #[doc.overloads=slice.index.range]
144144
constexpr inline Slice<T> operator[](
145-
const ::sus::ops::Range<usize> range) const noexcept {
146-
const usize len = range.end >= range.start ? range.end - range.start : 0u;
145+
const ::sus::ops::RangeBounds<usize> auto range) const noexcept {
146+
const usize start = range.start_bound().unwrap_or(0u);
147+
const usize end = range.end_bound().unwrap_or(len_);
148+
const usize len = end >= start ? end - start : 0u;
147149
::sus::check(len <= len_); // Avoid underflow below.
148150
// We allow start == len_ && end == len_, which returns an empty slice.
149-
::sus::check(range.start <= len_ && range.start <= len_ - len);
150-
return Slice(data_ + size_t{range.start}, len);
151+
::sus::check(start <= len_ && start <= len_ - len);
152+
return Slice(data_ + size_t{start}, len);
151153
}
152154

153155
/// Returns a subslice which contains elements in `range`, which specifies a
@@ -161,12 +163,14 @@ class Slice {
161163
/// Returns None if the Range would otherwise contain an element that is out
162164
/// of bounds.
163165
constexpr Option<Slice<T>> get_range(
164-
const ::sus::ops::Range<usize> range) const noexcept {
165-
const usize len = range.end >= range.start ? range.end - range.start : 0u;
166+
const ::sus::ops::RangeBounds<usize> auto range) const noexcept {
167+
const usize start = range.start_bound().unwrap_or(0u);
168+
const usize end = range.end_bound().unwrap_or(len_);
169+
const usize len = end >= start ? end - start : 0u;
166170
if (len > len_) return sus::none(); // Avoid underflow below.
167171
// We allow start == len_ && end == len_, which returns an empty slice.
168-
if (range.start > len_ || range.start > len_ - len) return sus::none();
169-
return sus::some(Slice(data_ + size_t{range.start}, len));
172+
if (start > len_ || start > len_ - len) return sus::none();
173+
return Option<Slice<T>>::some(Slice(data_ + size_t{start}, len));
170174
}
171175

172176
/// Returns a subslice which contains elements in `range`, which specifies a
@@ -182,9 +186,11 @@ class Slice {
182186
/// of bounds of the Slice, which can result in Undefined Behaviour.
183187
constexpr Slice<T> get_range_unchecked(
184188
::sus::marker::UnsafeFnMarker,
185-
const ::sus::ops::Range<usize> range) const noexcept {
186-
const usize len = range.end >= range.start ? range.end - range.start : 0u;
187-
return Slice(data_ + size_t{range.start}, len);
189+
const ::sus::ops::RangeBounds<usize> auto range) const noexcept {
190+
const usize start = range.start_bound().unwrap_or(0u);
191+
const usize end = range.end_bound().unwrap_or(len_);
192+
const usize len = end >= start ? end - start : 0u;
193+
return Slice(data_ + size_t{start}, len);
188194
}
189195

190196
/// Sorts the slice.

subspace/containers/slice_unittest.cc

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -127,27 +127,27 @@ TEST(Slice, IndexRange) {
127127
auto sc = Slice<const i32>::from_raw_parts(unsafe_fn, a, 3_usize);
128128
auto sm = Slice<i32>::from_raw_parts(unsafe_fn, a, 3_usize);
129129

130-
EXPECT_EQ((sc[{0u, 1u}][0u]), 1_i32);
131-
EXPECT_EQ((sc[{0u, 1u}].len()), 1_usize);
132-
EXPECT_EQ((sc[{1u, 3u}][1u]), 3_i32);
133-
EXPECT_EQ((sc[{1u, 3u}].len()), 2_usize);
130+
EXPECT_EQ((sc["0..1"_r][0u]), 1_i32);
131+
EXPECT_EQ((sc["0..1"_r].len()), 1_usize);
132+
EXPECT_EQ((sc["1..3"_r][1u]), 3_i32);
133+
EXPECT_EQ((sc["1..3"_r].len()), 2_usize);
134134

135-
EXPECT_EQ((sc[{1u, 1u}].len()), 0_usize);
135+
EXPECT_EQ((sc["1..1"_r].len()), 0_usize);
136136
// Start == End == the original End is an empty Slice.
137-
EXPECT_EQ((sc[{3u, 3u}].len()), 0_usize);
137+
EXPECT_EQ((sc["3..3"_r].len()), 0_usize);
138138

139-
EXPECT_EQ((sm[{0u, 3u}][0u]), 1_i32);
140-
EXPECT_EQ((sm[{0u, 3u}].len()), 3_usize);
141-
EXPECT_EQ((sm[{2u, 3u}][0u]), 3_i32);
142-
EXPECT_EQ((sm[{2u, 3u}].len()), 1_usize);
139+
EXPECT_EQ((sm["0..3"_r][0u]), 1_i32);
140+
EXPECT_EQ((sm["0..3"_r].len()), 3_usize);
141+
EXPECT_EQ((sm["2..3"_r][0u]), 3_i32);
142+
EXPECT_EQ((sm["2..3"_r].len()), 1_usize);
143143

144-
EXPECT_EQ((sm[{1u, 1u}].len()), 0_usize);
144+
EXPECT_EQ((sm["1..1"_r].len()), 0_usize);
145145
// Start == End == the original End is an empty Slice.
146-
EXPECT_EQ((sm[{3u, 3u}].len()), 0_usize);
146+
EXPECT_EQ((sm["3..3"_r].len()), 0_usize);
147147

148148
// Rvalue Slices are usable as they are reference types.
149-
EXPECT_EQ((sc[{1u, 3u}][{1u, 2u}][0u]), 3_i32);
150-
EXPECT_EQ((sm[{1u, 3u}][{1u, 2u}][0u]), 3_i32);
149+
EXPECT_EQ((sc["1..3"_r]["1..2"_r][0u]), 3_i32);
150+
EXPECT_EQ((sm["1..3"_r]["1..2"_r][0u]), 3_i32);
151151
}
152152

153153
TEST(SliceDeathTest, IndexRange) {
@@ -156,48 +156,48 @@ TEST(SliceDeathTest, IndexRange) {
156156
auto sm = Slice<i32>::from_raw_parts(unsafe_fn, a, 3_usize);
157157

158158
#if GTEST_HAS_DEATH_TEST
159-
EXPECT_DEATH((sc[{0u, 4u}]), "");
160-
EXPECT_DEATH((sc[{3u, 4u}]), "");
161-
EXPECT_DEATH((sm[{1u, 4u}]), "");
162-
EXPECT_DEATH((sm[{2u, 4u}]), "");
163-
EXPECT_DEATH((sm[{4u, 4u}]), "");
159+
EXPECT_DEATH((sc["0..4"_r]), "");
160+
EXPECT_DEATH((sc["3..4"_r]), "");
161+
EXPECT_DEATH((sm["1..4"_r]), "");
162+
EXPECT_DEATH((sm["2..4"_r]), "");
163+
EXPECT_DEATH((sm["4..4"_r]), "");
164164
#endif
165165
}
166166

167167
TEST(Slice, GetRange) {
168168
i32 a[] = {1, 2, 3};
169169
auto s = Slice<const i32>::from_raw_parts(unsafe_fn, a, 3_usize);
170-
EXPECT_EQ(s.get_range({0u, 3u}).unwrap()[1u], 2_i32);
171-
EXPECT_EQ(s.get_range({1u, 3u}).unwrap()[1u], 3_i32);
172-
EXPECT_EQ(s.get_range({1u, 4u}), sus::None);
173-
EXPECT_EQ(s.get_range({3u, 3u}).unwrap().len(), 0_usize);
174-
EXPECT_EQ(s.get_range({4u, 4u}), sus::None);
170+
EXPECT_EQ(s.get_range("0..3"_r).unwrap()[1u], 2_i32);
171+
EXPECT_EQ(s.get_range("1..3"_r).unwrap()[1u], 3_i32);
172+
EXPECT_EQ(s.get_range("1..4"_r), sus::None);
173+
EXPECT_EQ(s.get_range("3..3"_r).unwrap().len(), 0_usize);
174+
EXPECT_EQ(s.get_range("4..4"_r), sus::None);
175175

176176
auto sm = Slice<i32>::from_raw_parts(unsafe_fn, a, 3_usize);
177-
EXPECT_EQ(sm.get_range({0u, 3u}).unwrap()[1u], 2_i32);
178-
EXPECT_EQ(sm.get_range({1u, 3u}).unwrap()[1u], 3_i32);
179-
EXPECT_EQ(sm.get_range({1u, 4u}), sus::None);
180-
EXPECT_EQ(sm.get_range({3u, 3u}).unwrap().len(), 0_usize);
181-
EXPECT_EQ(sm.get_range({4u, 4u}), sus::None);
177+
EXPECT_EQ(sm.get_range("0..3"_r).unwrap()[1u], 2_i32);
178+
EXPECT_EQ(sm.get_range("1..3"_r).unwrap()[1u], 3_i32);
179+
EXPECT_EQ(sm.get_range("1..4"_r), sus::None);
180+
EXPECT_EQ(sm.get_range("3..3"_r).unwrap().len(), 0_usize);
181+
EXPECT_EQ(sm.get_range("4..4"_r), sus::None);
182182

183183
// Rvalue Slices are usable as they are reference types.
184-
EXPECT_EQ(s.get_range({3u, 3u}).unwrap().get_range({0u, 0u}).unwrap().len(),
184+
EXPECT_EQ(s.get_range("3..3"_r).unwrap().get_range("0..0"_r).unwrap().len(),
185185
0u);
186-
EXPECT_EQ(s.get_range({1u, 3u}).unwrap().get_range({1u, 2u}).unwrap().len(),
186+
EXPECT_EQ(s.get_range("1..3"_r).unwrap().get_range("1..2"_r).unwrap().len(),
187187
1u);
188-
EXPECT_EQ(s.get_range({1u, 3u}).unwrap().get_range({1u, 2u}).unwrap()[0u],
188+
EXPECT_EQ(s.get_range("1..3"_r).unwrap().get_range("1..2"_r).unwrap()[0u],
189189
3_i32);
190190
}
191191

192192
TEST(Slice, GetUncheckedRange) {
193193
i32 a[] = {1, 2, 3};
194194
auto s = Slice<const i32>::from_raw_parts(unsafe_fn, a, 3_usize);
195-
EXPECT_EQ(s.get_range_unchecked(unsafe_fn, {0u, 2u})[1u], 2_i32);
196-
EXPECT_EQ(s.get_range_unchecked(unsafe_fn, {2u, 3u})[0u], 3_i32);
195+
EXPECT_EQ(s.get_range_unchecked(unsafe_fn, "0..2"_r)[1u], 2_i32);
196+
EXPECT_EQ(s.get_range_unchecked(unsafe_fn, "2..3"_r)[0u], 3_i32);
197197

198198
auto sm = Slice<i32>::from_raw_parts(unsafe_fn, a, 3_usize);
199-
EXPECT_EQ(sm.get_range_unchecked(unsafe_fn, {0u, 2u})[1u], 2_i32);
200-
EXPECT_EQ(sm.get_range_unchecked(unsafe_fn, {2u, 3u})[0u], 3_i32);
199+
EXPECT_EQ(sm.get_range_unchecked(unsafe_fn, "0..2"_r)[1u], 2_i32);
200+
EXPECT_EQ(sm.get_range_unchecked(unsafe_fn, "2..3"_r)[0u], 3_i32);
201201
}
202202

203203
TEST(Slice, Into) {

subspace/containers/vec.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,10 @@ class Vec {
568568
decltype(capacity_));
569569
};
570570

571+
// Implicit for-ranged loop iteration via `Vec::iter()`.
572+
using sus::iter::__private::begin;
573+
using sus::iter::__private::end;
574+
571575
/// Used to construct a Vec<T> with the parameters as its values.
572576
///
573577
/// Calling vec() produces a hint to make a Vec<T> but does not actually

subspace/iter/__private/iterator_loop.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ namespace sus::iter::__private {
2121

2222
/// An adaptor for range-based for loops.
2323
template <class Iter>
24-
class IteratorLoop final {
24+
class [[nodiscard]] IteratorLoop final {
2525
using Item = typename std::remove_reference_t<Iter>::Item;
2626

2727
public:

subspace/iter/boxed_iterator.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class IteratorImpl;
3636
/// relocatable.
3737
template <class ItemT, size_t SubclassSize, size_t SubclassAlign,
3838
bool DoubleEnded>
39-
class [[sus_trivial_abi]] BoxedIterator final
39+
class [[nodiscard]] [[sus_trivial_abi]] BoxedIterator final
4040
: public IteratorImpl<
4141
BoxedIterator<ItemT, SubclassSize, SubclassAlign, DoubleEnded>,
4242
ItemT> {

subspace/iter/empty.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ namespace sus::iter {
2121

2222
/// An Iterator that never returns an `Item`.
2323
template <class ItemT>
24-
class [[sus_trivial_abi]] Empty final
24+
class [[nodiscard]] [[sus_trivial_abi]] Empty final
2525
: public IteratorImpl<Empty<ItemT>, ItemT> {
2626
public:
2727
using Item = ItemT;

0 commit comments

Comments
 (0)