Skip to content

Commit e689749

Browse files
committed
---
yaml --- r: 133708 b: refs/heads/try c: dbc3cb3 h: refs/heads/master v: v3
1 parent a4a6fb9 commit e689749

File tree

3 files changed

+260
-2
lines changed

3 files changed

+260
-2
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
refs/heads/master: 0e784e16840e8a0c623cc6166de26da9334db3d6
33
refs/heads/snap-stage1: e33de59e47c5076a89eadeb38f4934f58a3618a6
44
refs/heads/snap-stage3: 828e075abd8ee2f8c16f6cb1b93c0d99307e704d
5-
refs/heads/try: 793a36617bdaec4ffb3fc0e8b1fb44d0b633ed5c
5+
refs/heads/try: dbc3cb3a54c02211d8e4f9ff082c4ee2d544ec7d
66
refs/tags/release-0.1: 1f5c5126e96c79d22cb7862f75304136e204f105
77
refs/heads/ndm: f3868061cd7988080c30d6d5bf352a5a5fe2460b
88
refs/heads/try2: 147ecfdd8221e4a4d4e090486829a06da1e0ca3c

branches/try/src/jemalloc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Subproject commit 2dba541881fb8e35246d653bbe2e7c7088777a4a
1+
Subproject commit aae04170ccbfeea620502106b581c3c216cd132a

branches/try/src/libcollections/vec.rs

Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1710,6 +1710,252 @@ pub mod raw {
17101710
}
17111711
}
17121712

1713+
// TODO: Find some way to statically assert that `T` and `U` have the same
1714+
// size.
1715+
//
1716+
/// An owned, partially type-converted vector.
1717+
///
1718+
/// No allocations are performed by usage, only a deallocation happens in the
1719+
/// destructor which should only run when unwinding.
1720+
///
1721+
/// It can be used to convert a vector of `T`s into a vector of `U`s, by
1722+
/// converting the individual elements one-by-one.
1723+
///
1724+
/// You may call the `push` method as often as you get a `Some(t)` from `pop`.
1725+
/// After pushing the same number of `U`s as you got `T`s, you can `unwrap` the
1726+
/// vector.
1727+
///
1728+
/// # Example
1729+
///
1730+
/// ```rust
1731+
/// let pv = PartialVec::new(vec![0u, 1]);
1732+
/// assert_eq!(pv.pop(), Some(0));
1733+
/// assert_eq!(pv.pop(), Some(1));
1734+
/// assert_eq!(pv.pop(), None);
1735+
/// pv.push(2u);
1736+
/// pv.push(3);
1737+
/// assert_eq!(pv.unwrap(), vec![2, 3]);
1738+
/// ```
1739+
//
1740+
// Upheld invariants:
1741+
//
1742+
// (a) `vec` isn't modified except when the `PartialVec` goes out of scope, the
1743+
// only thing it is used for is keeping the memory which the `PartialVec`
1744+
// uses for the inplace conversion.
1745+
//
1746+
// (b) `start_u` points to the start of the vector.
1747+
//
1748+
// (c) `end_u` points to one element beyond the vector.
1749+
//
1750+
// (d) `start_u` <= `end_u` <= `start_t` <= `end_t`.
1751+
//
1752+
// (e) From `start_u` (incl.) to `end_u` (excl.) there are sequential instances
1753+
// of type `U`.
1754+
//
1755+
// (f) From `start_t` (incl.) to `end_t` (excl.) there are sequential instances
1756+
// of type `T`.
1757+
1758+
pub struct PartialVec<T,U> {
1759+
vec: Vec<T>,
1760+
1761+
start_u: *mut U,
1762+
end_u: *mut U,
1763+
start_t: *mut T,
1764+
end_t: *mut T,
1765+
}
1766+
1767+
impl<T,U> PartialVec<T,U> {
1768+
/// Creates a `PartialVec` from a `Vec`.
1769+
pub fn new(mut vec: Vec<T>) -> PartialVec<T,U> {
1770+
// TODO: do this statically
1771+
assert!(mem::size_of::<T>() != 0);
1772+
assert!(mem::size_of::<U>() != 0);
1773+
assert!(mem::size_of::<T>() == mem::size_of::<U>());
1774+
1775+
let start = vec.as_mut_ptr();
1776+
1777+
// This `as int` cast is safe, because the size of the elements of the
1778+
// vector is not 0, and:
1779+
//
1780+
// 1) If the size of the elements in the vector is 1, the `int` may
1781+
// overflow, but it has the correct bit pattern so that the
1782+
// `.offset()` function will work.
1783+
//
1784+
// Example:
1785+
// Address space 0x0-0xF.
1786+
// `u8` array at: 0x1.
1787+
// Size of `u8` array: 0x8.
1788+
// Calculated `offset`: -0x8.
1789+
// After `array.offset(offset)`: 0x9.
1790+
// (0x1 + 0x8 = 0x1 - 0x8)
1791+
//
1792+
// 2) If the size of the elements in the vector is >1, the `uint` ->
1793+
// `int` conversion can't overflow.
1794+
let offset = vec.len() as int;
1795+
1796+
let start_u = start as *mut U;
1797+
let end_u = start as *mut U;
1798+
let start_t = start;
1799+
let end_t = unsafe { start_t.offset(offset) };
1800+
1801+
// (b) is satisfied, `start_u` points to the start of `vec`.
1802+
1803+
// (c) is also satisfied, `end_t` points to the end of `vec`.
1804+
1805+
// `start_u == end_u == start_t <= end_t`, so also `start_u <= end_u <=
1806+
// start_t <= end_t`, thus (b).
1807+
1808+
// As `start_u == end_u`, it is represented correctly that there are no
1809+
// instances of `U` in `vec`, thus (e) is satisfied.
1810+
1811+
// At start, there are only elements of type `T` in `vec`, so (f) is
1812+
// satisfied, as `start_t` points to the start of `vec` and `end_t` to
1813+
// the end of it.
1814+
1815+
// This points inside the vector, as the vector has length `offset`.
1816+
1817+
PartialVec {
1818+
// (a) is satisfied, `vec` isn't modified in the function.
1819+
vec: vec,
1820+
start_u: start_u,
1821+
end_u: end_u,
1822+
start_t: start_t,
1823+
end_t: end_t,
1824+
}
1825+
}
1826+
1827+
/// Pops a `T` from the `PartialVec`.
1828+
///
1829+
/// Returns `Some(t)` if there are more `T`s in the vector, otherwise
1830+
/// `None`.
1831+
fn pop(&mut self) -> Option<T> {
1832+
// The `if` ensures that there are more `T`s in `vec`.
1833+
if self.start_t < self.end_t {
1834+
let result;
1835+
unsafe {
1836+
// (f) is satisfied before, so in this if branch there actually
1837+
// is a `T` at `start_t`. After shifting the pointer by one,
1838+
// (f) is again satisfied.
1839+
result = ptr::read(self.start_t as *const T);
1840+
self.start_t = self.start_t.offset(1);
1841+
}
1842+
Some(result)
1843+
} else {
1844+
None
1845+
}
1846+
}
1847+
1848+
/// Pushes a new `U` to the `PartialVec`.
1849+
///
1850+
/// # Failure
1851+
///
1852+
/// Fails if not enough `T`s were popped to have enough space for the new
1853+
/// `U`.
1854+
pub fn push(&mut self, value: U) {
1855+
// The assert assures that still `end_u <= start_t` (d) after
1856+
// the function.
1857+
assert!(self.end_u as *const () < self.start_t as *const (),
1858+
"writing more elements to PartialVec than reading from it")
1859+
unsafe {
1860+
// (e) is satisfied before, and after writing one `U`
1861+
// to `end_u` and shifting it by one, it's again
1862+
// satisfied.
1863+
ptr::write(self.end_u, value);
1864+
self.end_u = self.end_u.offset(1);
1865+
}
1866+
}
1867+
1868+
/// Unwraps the new `Vec` of `U`s after having pushed enough `U`s and
1869+
/// popped all `T`s.
1870+
///
1871+
/// # Failure
1872+
///
1873+
/// Fails if not all `T`s were popped, also fails if not the same amount of
1874+
/// `U`s was pushed before calling `unwrap`.
1875+
pub fn unwrap(self) -> Vec<U> {
1876+
// If `self.end_u == self.end_t`, we know from (e) that there are no
1877+
// more `T`s in `vec`, we also know that the whole length of `vec` is
1878+
// now used by `U`s, thus we can just transmute `vec` from a vector of
1879+
// `T`s to a vector of `U`s safely.
1880+
1881+
assert!(self.end_u as *const () == self.end_t as *const (),
1882+
"trying to unwrap a PartialVec before completing the writes to it");
1883+
1884+
// Extract `vec` and prevent the destructor of `PartialVec` from
1885+
// running.
1886+
unsafe {
1887+
let vec = ptr::read(&self.vec);
1888+
mem::forget(self);
1889+
mem::transmute(vec)
1890+
}
1891+
}
1892+
}
1893+
1894+
#[unsafe_destructor]
1895+
impl<T,U> Drop for PartialVec<T,U> {
1896+
fn drop(&mut self) {
1897+
unsafe {
1898+
// As per (a) `vec` hasn't been modified until now. As it has a
1899+
// length currently, this would run destructors of `T`s which might
1900+
// not be there. So at first, set `vec`s length to `0`. This must
1901+
// be done at first to remain memory-safe as the destructors of `U`
1902+
// or `T` might cause unwinding where `vec`s destructor would be
1903+
// executed.
1904+
self.vec.set_len(0);
1905+
1906+
// As per (e) and (f) we have instances of `U`s and `T`s in `vec`.
1907+
// Destruct them.
1908+
while self.start_u < self.end_u {
1909+
let _ = ptr::read(self.start_u as *const U); // Run a `U` destructor.
1910+
self.start_u = self.start_u.offset(1);
1911+
}
1912+
while self.start_t < self.end_t {
1913+
let _ = ptr::read(self.start_t as *const T); // Run a `T` destructor.
1914+
self.start_t = self.start_t.offset(1);
1915+
}
1916+
// After this destructor ran, the destructor of `vec` will run,
1917+
// deallocating the underlying memory.
1918+
}
1919+
}
1920+
}
1921+
1922+
impl<T,U> Iterator<T> for PartialVec<T,U> {
1923+
fn next(&mut self) -> Option<T> {
1924+
self.pop()
1925+
}
1926+
}
1927+
1928+
impl<T> Vec<T> {
1929+
/// Converts a `Vec<T>` to a `Vec<U>` where `T` and `U` have the same size.
1930+
///
1931+
/// # Example
1932+
///
1933+
/// ```rust
1934+
/// let v = vec![0u, 1, 2];
1935+
/// let w = v.map_inplace(|i| i + 3);
1936+
/// assert_eq!(w.as_slice() == &[3, 4, 5]);
1937+
///
1938+
/// let big_endian_u16s = vec![0x1122u16, 0x3344];
1939+
/// let u8s = big_endian_u16s.map_inplace(|x| [
1940+
/// ((x >> 8) & 0xff) as u8,
1941+
/// (x & 0xff) as u8
1942+
/// ]);
1943+
/// assert_eq!(u8s.as_slice() == &[[0x11, 0x22], [0x33, 0x44]]);
1944+
/// ```
1945+
pub fn map_inplace<U>(self, f: |T| -> U) -> Vec<U> {
1946+
let mut pv = PartialVec::new(self);
1947+
loop {
1948+
// TODO: need this extra assignment for borrowck to pass
1949+
let maybe_t = pv.pop();
1950+
match maybe_t {
1951+
Some(t) => pv.push(f(t)),
1952+
None => return pv.unwrap(),
1953+
};
1954+
}
1955+
}
1956+
}
1957+
1958+
17131959
#[cfg(test)]
17141960
mod tests {
17151961
extern crate test;
@@ -2039,6 +2285,18 @@ mod tests {
20392285
assert_eq!(vec.as_ptr(), ptr);
20402286
assert_eq!(vec.capacity(), 7);
20412287
assert_eq!(vec.len(), 0);
2288+
2289+
#[test]
2290+
#[should_fail]
2291+
fn test_map_inplace_incompatible_types_fail() {
2292+
let v = vec![0u, 1, 2];
2293+
v.map_inplace(|_| ());
2294+
}
2295+
2296+
#[test]
2297+
fn test_map_inplace() {
2298+
let v = vec![0u, 1, 2];
2299+
assert_eq!(v.map_inplace(|i: uint| i as int - 1).as_slice, &[-1i, 0, 1]);
20422300
}
20432301

20442302
#[bench]

0 commit comments

Comments
 (0)