vec fixes for huonw

pull/10/head
Alexis Beingessner 9 years ago committed by Manish Goregaokar
parent b1529f107e
commit fe09c847aa

@ -61,9 +61,7 @@ like the standard library as much as possible, so we'll just kill the whole
program. program.
We said we don't want to use intrinsics, so doing *exactly* what `std` does is We said we don't want to use intrinsics, so doing *exactly* what `std` does is
out. `std::rt::util::abort` actually exists, but it takes a message to print, out. Instead, we'll call `std::process::exit` with some random number.
which will probably allocate. Also it's still unstable. Instead, we'll call
`std::process::exit` with some random number.
```rust ```rust
fn oom() { fn oom() {
@ -78,7 +76,7 @@ if cap == 0:
allocate() allocate()
cap = 1 cap = 1
else: else:
reallocate reallocate()
cap *= 2 cap *= 2
``` ```
@ -109,7 +107,7 @@ the same location in memory, the operations need to be done to the same value,
and they can't just be merged afterwards. and they can't just be merged afterwards.
When you use GEP inbounds, you are specifically telling LLVM that the offsets When you use GEP inbounds, you are specifically telling LLVM that the offsets
you're about to do are within the bounds of a single allocated entity. The you're about to do are within the bounds of a single "allocated" entity. The
ultimate payoff being that LLVM can assume that if two pointers are known to ultimate payoff being that LLVM can assume that if two pointers are known to
point to two disjoint objects, all the offsets of those pointers are *also* point to two disjoint objects, all the offsets of those pointers are *also*
known to not alias (because you won't just end up in some random place in known to not alias (because you won't just end up in some random place in
@ -162,7 +160,8 @@ elements. This is a runtime no-op because every element takes up no space,
and it's fine to pretend that there's infinite zero-sized types allocated and it's fine to pretend that there's infinite zero-sized types allocated
at `0x01`. No allocator will ever allocate that address, because they won't at `0x01`. No allocator will ever allocate that address, because they won't
allocate `0x00` and they generally allocate to some minimal alignment higher allocate `0x00` and they generally allocate to some minimal alignment higher
than a byte. than a byte. Also generally the whole first page of memory is
protected from being allocated anyway (a whole 4k, on many platforms).
However what about for positive-sized types? That one's a bit trickier. In However what about for positive-sized types? That one's a bit trickier. In
principle, you can argue that offsetting by 0 gives LLVM no information: either principle, you can argue that offsetting by 0 gives LLVM no information: either

@ -83,6 +83,7 @@ impl<T> Vec<T> {
pub fn into_iter(self) -> IntoIter<T> { pub fn into_iter(self) -> IntoIter<T> {
unsafe { unsafe {
let iter = RawValIter::new(&self); let iter = RawValIter::new(&self);
let buf = ptr::read(&self.buf); let buf = ptr::read(&self.buf);
mem::forget(self); mem::forget(self);
@ -112,7 +113,7 @@ pub struct Drain<'a, T: 'a> {
impl<'a, T> Iterator for Drain<'a, T> { impl<'a, T> Iterator for Drain<'a, T> {
type Item = T; type Item = T;
fn next(&mut self) -> Option<T> { self.iter.next_back() } fn next(&mut self) -> Option<T> { self.iter.next() }
fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() } fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
} }

@ -1,7 +1,10 @@
% Layout % Layout
First off, we need to come up with the struct layout. Naively we want this First off, we need to come up with the struct layout. A Vec has three parts:
design: a pointer to the allocation, the size of the allocation, and the number of
elements that have been initialized.
Naively, this means we just want this design:
```rust ```rust
pub struct Vec<T> { pub struct Vec<T> {

@ -1,9 +1,9 @@
% RawVec % RawVec
We've actually reached an interesting situation here: we've duplicated the logic We've actually reached an interesting situation here: we've duplicated the logic
for specifying a buffer and freeing its memory. Now that we've implemented it for specifying a buffer and freeing its memory in Vec and IntoIter. Now that
and identified *actual* logic duplication, this is a good time to perform some we've implemented it and identified *actual* logic duplication, this is a good
logic compression. time to perform some logic compression.
We're going to abstract out the `(ptr, cap)` pair and give them the logic for We're going to abstract out the `(ptr, cap)` pair and give them the logic for
allocating, growing, and freeing: allocating, growing, and freeing:
@ -64,7 +64,7 @@ impl<T> Drop for RawVec<T> {
} }
``` ```
And change vec as follows: And change Vec as follows:
```rust,ignore ```rust,ignore
pub struct Vec<T> { pub struct Vec<T> {

@ -12,7 +12,7 @@ bit nicer or efficient because intrinsics are permanently unstable. Although
many intrinsics *do* become stabilized elsewhere (`std::ptr` and `str::mem` many intrinsics *do* become stabilized elsewhere (`std::ptr` and `str::mem`
consist of many intrinsics). consist of many intrinsics).
Ultimately this means out implementation may not take advantage of all Ultimately this means our implementation may not take advantage of all
possible optimizations, though it will be by no means *naive*. We will possible optimizations, though it will be by no means *naive*. We will
definitely get into the weeds over nitty-gritty details, even definitely get into the weeds over nitty-gritty details, even
when the problem doesn't *really* merit it. when the problem doesn't *really* merit it.

Loading…
Cancel
Save