Skip to content

Commit c75dc9a

Browse files
committed
Fix an empty split bug
Fixes a bug in the tutorial that happened when `split_before` and `split_after` resulted in an empty split. This was fixed by checking for an empty split and updating the `front` and `back` pointers accordingly. This change-set fixes both the final code and the tutorial text.
1 parent bb9cdb5 commit c75dc9a

File tree

4 files changed

+125
-11
lines changed

4 files changed

+125
-11
lines changed

.github/workflows/main.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ name: Rust
33
on:
44
push:
55
branches:
6-
- "master"
7-
- "!gh-pages"
6+
- 'master'
7+
- '!gh-pages'
88
pull_request:
99

1010
jobs:

lists/src/sixth.rs

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -535,8 +535,13 @@ impl<'a, T> CursorMut<'a, T> {
535535

536536
// What the output will become
537537
let output_len = old_len - new_len;
538-
let output_front = self.list.front;
539-
let output_back = prev;
538+
let mut output_front = self.list.front;
539+
let mut output_back = prev;
540+
541+
if output_len == 0 {
542+
output_front = None;
543+
output_back = None;
544+
}
540545

541546
// Break the links between cur and prev
542547
if let Some(prev) = prev {
@@ -597,8 +602,13 @@ impl<'a, T> CursorMut<'a, T> {
597602

598603
// What the output will become
599604
let output_len = old_len - new_len;
600-
let output_front = next;
601-
let output_back = self.list.back;
605+
let mut output_front = next;
606+
let mut output_back = self.list.back;
607+
608+
if output_len == 0 {
609+
output_front = None;
610+
output_back = None;
611+
}
602612

603613
// Break the links between cur and next
604614
if let Some(next) = next {
@@ -1190,6 +1200,33 @@ mod test {
11901200
);
11911201
}
11921202

1203+
#[test]
1204+
fn test_empty_slice() {
1205+
let mut list = LinkedList::new();
1206+
list.push_back(7);
1207+
list.push_back(8);
1208+
list.push_back(9);
1209+
1210+
let mut cur = list.cursor_mut();
1211+
cur.move_next(); // Point at the first node
1212+
let result = cur.split_before(); // Everything before the first node
1213+
1214+
assert_eq!(result.len, 0);
1215+
assert_eq!(result.front(), None);
1216+
assert_eq!(result.back(), None);
1217+
1218+
assert_eq!(list.len, 3);
1219+
assert_eq!(list.front(), Some(7).as_ref());
1220+
1221+
let mut cur = list.cursor_mut();
1222+
cur.move_prev(); // Point at the last node
1223+
let result = cur.split_after(); // Everything after the last node
1224+
1225+
assert_eq!(result.len, 0);
1226+
assert_eq!(result.front(), None);
1227+
assert_eq!(result.back(), None);
1228+
}
1229+
11931230
fn check_links<T: Eq + std::fmt::Debug>(list: &LinkedList<T>) {
11941231
let from_front: Vec<_> = list.iter().collect();
11951232
let from_back: Vec<_> = list.iter().rev().collect();

src/sixth-cursors-testing.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,46 @@ DONE.
377377

378378
Done.
379379

380+
> **Community Contribution:** After completing the exercises a small bug was discovered when creating an empty slice from the list.
381+
382+
```rust ,ignore
383+
#[test]
384+
fn test_empty_slice() {
385+
let mut list = LinkedList::new();
386+
list.push_back(7);
387+
list.push_back(8);
388+
list.push_back(9);
389+
390+
let mut cur = list.cursor_mut();
391+
cur.move_next(); // Point at the first node
392+
let result = cur.split_before(); // Everything before the first node
393+
394+
assert_eq!(result.len, 0);
395+
assert_eq!(result.front(), None);
396+
assert_eq!(result.back(), None);
397+
398+
assert_eq!(list.len, 3);
399+
assert_eq!(list.front(), Some(7).as_ref());
400+
401+
let mut cur = list.cursor_mut();
402+
cur.move_prev(); // Point at the last node
403+
let result = cur.split_after(); // Everything after the last node
404+
405+
assert_eq!(result.len, 0);
406+
assert_eq!(result.front(), None);
407+
assert_eq!(result.back(), None);
408+
}
409+
```
410+
411+
In this case, we attempt to create a slice from all the elements before the first node (which should be empty). This is because the `split_before` method does not set the front and back pointers to None when the list is empty. This can be fixed by adding the following line to the `split_before` method:
412+
413+
```rust ,ignore
414+
if self.len == 0 {
415+
self.front = None;
416+
self.back = None;
417+
}
418+
```
419+
380420
We did it. We made a god damn production-quality LinkedList, with basically all the same functionality as the one in std. Are we missing little convenience methods here and there? Absolutely. Will I add them into the final published version of the crate? Probably!
381421

382422
But, I am, So Very Tired.

src/sixth-final.md

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -546,8 +546,13 @@ impl<'a, T> CursorMut<'a, T> {
546546

547547
// What the output will become
548548
let output_len = old_len - new_len;
549-
let output_front = self.list.front;
550-
let output_back = prev;
549+
let mut output_front = self.list.front;
550+
let mut output_back = prev;
551+
552+
if output_len == 0 {
553+
output_front = None;
554+
output_back = None;
555+
}
551556

552557
// Break the links between cur and prev
553558
if let Some(prev) = prev {
@@ -608,8 +613,13 @@ impl<'a, T> CursorMut<'a, T> {
608613

609614
// What the output will become
610615
let output_len = old_len - new_len;
611-
let output_front = next;
612-
let output_back = self.list.back;
616+
let mut output_front = next;
617+
let mut output_back = self.list.back;
618+
619+
if output_len == 0 {
620+
output_front = None;
621+
output_back = None;
622+
}
613623

614624
// Break the links between cur and next
615625
if let Some(next) = next {
@@ -1201,6 +1211,33 @@ mod test {
12011211
);
12021212
}
12031213

1214+
#[test]
1215+
fn test_empty_slice() {
1216+
let mut list = LinkedList::new();
1217+
list.push_back(7);
1218+
list.push_back(8);
1219+
list.push_back(9);
1220+
1221+
let mut cur = list.cursor_mut();
1222+
cur.move_next(); // Point at the first node
1223+
let result = cur.split_before(); // Everything before the first node
1224+
1225+
assert_eq!(result.len, 0);
1226+
assert_eq!(result.front(), None);
1227+
assert_eq!(result.back(), None);
1228+
1229+
assert_eq!(list.len, 3);
1230+
assert_eq!(list.front(), Some(7).as_ref());
1231+
1232+
let mut cur = list.cursor_mut();
1233+
cur.move_prev(); // Point at the last node
1234+
let result = cur.split_after(); // Everything after the last node
1235+
1236+
assert_eq!(result.len, 0);
1237+
assert_eq!(result.front(), None);
1238+
assert_eq!(result.back(), None);
1239+
}
1240+
12041241
fn check_links<T: Eq + std::fmt::Debug>(list: &LinkedList<T>) {
12051242
let from_front: Vec<_> = list.iter().collect();
12061243
let from_back: Vec<_> = list.iter().rev().collect();
@@ -1209,4 +1246,4 @@ mod test {
12091246
assert_eq!(from_front, re_reved);
12101247
}
12111248
}
1212-
```
1249+
```

0 commit comments

Comments
 (0)