Skip to content

Commit a4f7ba3

Browse files
Add AccumulateVec, a potentially stack-allocated vector.
AccumulateVec is generic over the Array trait, which is currently only implemented for [T; 8].
1 parent d337f34 commit a4f7ba3

File tree

3 files changed

+163
-0
lines changed

3 files changed

+163
-0
lines changed
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
//! A vector type intended to be used for collecting from iterators onto the stack.
12+
//!
13+
//! Space for up to N elements is provided on the stack. If more elements are collected, Vec is
14+
//! used to store the values on the heap. This type does not support re-allocating onto the heap,
15+
//! and there is no way to push more elements onto the existing storage.
16+
//!
17+
//! The N above is determined by Array's implementor, by way of an associatated constant.
18+
19+
use std::ops::Deref;
20+
use std::iter::{IntoIterator, FromIterator};
21+
22+
use array_vec::{Array, ArrayVec};
23+
24+
#[derive(Debug)]
25+
pub enum AccumulateVec<A: Array> {
26+
Array(ArrayVec<A>),
27+
Heap(Vec<A::Element>)
28+
}
29+
30+
impl<A: Array> Deref for AccumulateVec<A> {
31+
type Target = [A::Element];
32+
fn deref(&self) -> &Self::Target {
33+
match *self {
34+
AccumulateVec::Array(ref v) => &v[..],
35+
AccumulateVec::Heap(ref v) => &v[..],
36+
}
37+
}
38+
}
39+
40+
impl<A: Array> FromIterator<A::Element> for AccumulateVec<A> {
41+
fn from_iter<I>(iter: I) -> AccumulateVec<A> where I: IntoIterator<Item=A::Element> {
42+
let iter = iter.into_iter();
43+
if iter.size_hint().1.map_or(false, |n| n <= A::LEN) {
44+
let mut v = ArrayVec::new();
45+
v.extend(iter);
46+
AccumulateVec::Array(v)
47+
} else {
48+
AccumulateVec::Heap(iter.collect())
49+
}
50+
}
51+
}
52+
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
//! A stack-allocated vector, allowing storage of N elements on the stack.
12+
//!
13+
//! Currently, only the N = 8 case is supported (due to Array only being impl-ed for [T; 8]).
14+
15+
use std::marker::Unsize;
16+
use std::iter::Extend;
17+
use std::ptr::drop_in_place;
18+
use std::ops::{Deref, DerefMut};
19+
use std::slice;
20+
use std::fmt;
21+
22+
pub unsafe trait Array {
23+
type Element;
24+
type PartialStorage: Default + Unsize<[ManuallyDrop<Self::Element>]>;
25+
const LEN: usize;
26+
}
27+
28+
unsafe impl<T> Array for [T; 8] {
29+
type Element = T;
30+
type PartialStorage = [ManuallyDrop<T>; 8];
31+
const LEN: usize = 8;
32+
}
33+
34+
pub struct ArrayVec<A: Array> {
35+
count: usize,
36+
values: A::PartialStorage
37+
}
38+
39+
impl<A: Array> ArrayVec<A> {
40+
pub fn new() -> Self {
41+
ArrayVec {
42+
count: 0,
43+
values: Default::default(),
44+
}
45+
}
46+
}
47+
48+
impl<A> fmt::Debug for ArrayVec<A>
49+
where A: Array,
50+
A::Element: fmt::Debug {
51+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
52+
self[..].fmt(f)
53+
}
54+
}
55+
56+
impl<A: Array> Deref for ArrayVec<A> {
57+
type Target = [A::Element];
58+
fn deref(&self) -> &Self::Target {
59+
unsafe {
60+
slice::from_raw_parts(&self.values as *const _ as *const A::Element, self.count)
61+
}
62+
}
63+
}
64+
65+
impl<A: Array> DerefMut for ArrayVec<A> {
66+
fn deref_mut(&mut self) -> &mut [A::Element] {
67+
unsafe {
68+
slice::from_raw_parts_mut(&mut self.values as *mut _ as *mut A::Element, self.count)
69+
}
70+
}
71+
}
72+
73+
impl<A: Array> Drop for ArrayVec<A> {
74+
fn drop(&mut self) {
75+
unsafe {
76+
drop_in_place(&mut self[..])
77+
}
78+
}
79+
}
80+
81+
impl<A: Array> Extend<A::Element> for ArrayVec<A> {
82+
fn extend<I>(&mut self, iter: I) where I: IntoIterator<Item=A::Element> {
83+
for el in iter {
84+
unsafe {
85+
let arr = &mut self.values as &mut [ManuallyDrop<_>];
86+
arr[self.count].value = el;
87+
}
88+
self.count += 1;
89+
}
90+
}
91+
}
92+
93+
// FIXME: This should use repr(transparent) from rust-lang/rfcs#1758.
94+
#[allow(unions_with_drop_fields)]
95+
pub union ManuallyDrop<T> {
96+
value: T,
97+
#[allow(dead_code)]
98+
empty: (),
99+
}
100+
101+
impl<T> Default for ManuallyDrop<T> {
102+
fn default() -> Self {
103+
ManuallyDrop { empty: () }
104+
}
105+
}
106+

src/librustc_data_structures/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@
3030
#![feature(staged_api)]
3131
#![feature(unboxed_closures)]
3232
#![feature(fn_traits)]
33+
#![feature(untagged_unions)]
34+
#![feature(associated_consts)]
35+
#![feature(unsize)]
3336

3437
#![cfg_attr(unix, feature(libc))]
3538
#![cfg_attr(test, feature(test))]
@@ -41,6 +44,8 @@ extern crate serialize as rustc_serialize; // used by deriving
4144
#[cfg(unix)]
4245
extern crate libc;
4346

47+
pub mod array_vec;
48+
pub mod accumulate_vec;
4449
pub mod bitslice;
4550
pub mod blake2b;
4651
pub mod bitvec;

0 commit comments

Comments
 (0)