컴파일러가 실제로 쓰는 나머지 표면이다. take 는 R7 대로 대체값을 남기고 꺼내므로 리스트에 구멍이 생기지 않는다. slice() 를 쓰려면 언어가 한 걸음 필요했다. &Self 로 읽어도 필드가 ^[]mut T 이니 슬라이스가 []mut T 로 나오는데, 선언한 반환은 []T 다. 호출 인자 자리의 약화만 있고 반환 자리에는 없었다. 반환 위치의 약화를 허용했다. R8 이 이미 그 파생을 허용한 뒤라면 []mut T 를 []T 로 넘기는 것은 가진 것보다 적게 넘기는 일이라 새 별칭을 만들지 않는다. &Self 메서드가 자기가 소유한 것의 읽기 전용 뷰를 내주는 길이 이것뿐이다. SPEC §4.2 에 적었고, let 은 여전히 안 된다는 것을 badletwk 가 고정한다. 243/243, 37/37.
88 lines
2.8 KiB
Plaintext
88 lines
2.8 KiB
Plaintext
unit std.list;
|
|
|
|
// A growable sequence. The buffer is owned, so a List owns its elements and
|
|
// releasing it releases them (SPEC 5 R1) -- which is also why there is no
|
|
// `drop` here: letting go of a List lets go of its buffer on its own. Growth
|
|
// doubles, which keeps the total copying proportional to the number of
|
|
// pushes.
|
|
|
|
pub struct List(T) {
|
|
items: ^[]mut T,
|
|
len: usize,
|
|
|
|
pub fn with_capacity(n: usize) -> !Self {
|
|
let room: ^[]mut T = try mem.alloc_slice(T, n);
|
|
return Self{ items: room, len: 0 };
|
|
}
|
|
|
|
pub fn count(self: &Self) -> usize { return self.len; }
|
|
|
|
pub fn at(self: &Self, i: usize) -> T {
|
|
return self.items.^[i];
|
|
}
|
|
|
|
pub fn set(self: &mut Self, i: usize, v: T) -> void {
|
|
self.items.^[i] = v;
|
|
}
|
|
|
|
pub fn push(self: &mut Self, v: T) -> !void {
|
|
if self.len == self.items.^.n { try self.grow(); }
|
|
self.items.^[self.len] = v;
|
|
self.len = self.len + 1;
|
|
return;
|
|
}
|
|
|
|
/// Take the last one off. Nothing to take is `null`, not a trap.
|
|
pub fn pop(self: &mut Self) -> ?T {
|
|
if self.len == 0 { return null; }
|
|
self.len = self.len - 1;
|
|
return self.items.^[self.len];
|
|
}
|
|
|
|
/// Move one out and leave `replacement` where it was (SPEC 5 R7). This is
|
|
/// how a `T` that owns something leaves the list without the list ending
|
|
/// up with a hole in it.
|
|
pub fn take(self: &mut Self, i: usize, replacement: T) -> T {
|
|
return mem.replace(&mut self.items.^[i], replacement);
|
|
}
|
|
|
|
/// Exchange two elements.
|
|
pub fn swap(self: &mut Self, i: usize, j: usize) -> void {
|
|
if i == j { return; }
|
|
let first: T = self.items.^[i];
|
|
let second: T = mem.replace(&mut self.items.^[j], first);
|
|
self.items.^[i] = second;
|
|
return;
|
|
}
|
|
|
|
/// The elements as a slice, so `for x in xs.slice()` walks them. R8(a):
|
|
/// derived from `self`, so the borrow belongs to the caller.
|
|
pub fn slice(self: &Self) -> []T {
|
|
return self.items.^[0..self.len];
|
|
}
|
|
|
|
pub fn slice_mut(self: &mut Self) -> []mut T {
|
|
return self.items.^[0..self.len];
|
|
}
|
|
|
|
/// Forget the elements and keep the buffer.
|
|
pub fn clear(self: &mut Self) -> void { self.len = 0; return; }
|
|
|
|
/// Move to a buffer twice the size. Kept apart from `push` because the
|
|
/// borrow that hands over the old buffer must not be live while the old
|
|
/// buffer is still being read (SPEC 5 R6).
|
|
fn grow(self: &mut Self) -> !void {
|
|
var room: usize = self.items.^.n * 2;
|
|
if room == 0 { room = 4; }
|
|
let bigger: ^[]mut T = try mem.alloc_slice(T, room);
|
|
var i: usize = 0;
|
|
while i < self.len {
|
|
bigger.^[i] = self.items.^[i];
|
|
i = i + 1;
|
|
}
|
|
let old: ^[]mut T = mem.replace(&mut self.items, bigger);
|
|
mem.destroy(old);
|
|
return;
|
|
}
|
|
}
|