@@ -1710,6 +1710,268 @@ pub mod raw {
17101710 }
17111711}
17121712
1713+ /// An owned, partially type-converted vector.
1714+ ///
1715+ /// This struct takes two type parameters `T` and `U` which must be of the
1716+ /// same, non-zero size having the same minimal alignment.
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+ /// ```ignore
1731+ /// let pv = PartialVec::from_vec(vec![0u32, 1]);
1732+ /// assert_eq!(pv.pop(), Some(0));
1733+ /// assert_eq!(pv.pop(), Some(1));
1734+ /// assert_eq!(pv.pop(), None);
1735+ /// pv.push(2u32);
1736+ /// pv.push(3);
1737+ /// assert_eq!(pv.into_vec().as_slice(), &[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+ // (g) The size of `T` and `U` is equal and non-zero.
1759+ //
1760+ // (h) The `min_align_of` of `T` and `U` is equal.
1761+
1762+ struct PartialVec < T , U > {
1763+ vec : Vec < T > ,
1764+
1765+ start_u : * mut U ,
1766+ end_u : * mut U ,
1767+ start_t : * mut T ,
1768+ end_t : * mut T ,
1769+ }
1770+
1771+ impl < T , U > PartialVec < T , U > {
1772+ /// Creates a `PartialVec` from a `Vec`.
1773+ ///
1774+ /// # Failure
1775+ ///
1776+ /// Fails if `T` and `U` have differing sizes, are zero-sized or have
1777+ /// differing minimal alignments.
1778+ fn from_vec ( mut vec : Vec < T > ) -> PartialVec < T , U > {
1779+ // FIXME: Assert statically that the types `T` and `U` have the same
1780+ // size.
1781+ //
1782+ // These asserts make sure (g) and (h) are satisfied.
1783+ assert ! ( mem:: size_of:: <T >( ) != 0 ) ;
1784+ assert ! ( mem:: size_of:: <U >( ) != 0 ) ;
1785+ assert ! ( mem:: size_of:: <T >( ) == mem:: size_of:: <U >( ) ) ;
1786+ assert ! ( mem:: min_align_of:: <T >( ) == mem:: min_align_of:: <U >( ) ) ;
1787+
1788+ let start = vec. as_mut_ptr ( ) ;
1789+
1790+ // This `as int` cast is safe, because the size of the elements of the
1791+ // vector is not 0, and:
1792+ //
1793+ // 1) If the size of the elements in the vector is 1, the `int` may
1794+ // overflow, but it has the correct bit pattern so that the
1795+ // `.offset()` function will work.
1796+ //
1797+ // Example:
1798+ // Address space 0x0-0xF.
1799+ // `u8` array at: 0x1.
1800+ // Size of `u8` array: 0x8.
1801+ // Calculated `offset`: -0x8.
1802+ // After `array.offset(offset)`: 0x9.
1803+ // (0x1 + 0x8 = 0x1 - 0x8)
1804+ //
1805+ // 2) If the size of the elements in the vector is >1, the `uint` ->
1806+ // `int` conversion can't overflow.
1807+ let offset = vec. len ( ) as int ;
1808+
1809+ let start_u = start as * mut U ;
1810+ let end_u = start as * mut U ;
1811+ let start_t = start;
1812+
1813+ // This points inside the vector, as the vector has length `offset`.
1814+ let end_t = unsafe { start_t. offset ( offset) } ;
1815+
1816+ // (b) is satisfied, `start_u` points to the start of `vec`.
1817+ //
1818+ // (c) is also satisfied, `end_t` points to the end of `vec`.
1819+ //
1820+ // `start_u == end_u == start_t <= end_t`, so also `start_u <= end_u <=
1821+ // start_t <= end_t`, thus (b).
1822+ //
1823+ // As `start_u == end_u`, it is represented correctly that there are no
1824+ // instances of `U` in `vec`, thus (e) is satisfied.
1825+ //
1826+ // At start, there are only elements of type `T` in `vec`, so (f) is
1827+ // satisfied, as `start_t` points to the start of `vec` and `end_t` to
1828+ // the end of it.
1829+
1830+ PartialVec {
1831+ // (a) is satisfied, `vec` isn't modified in the function.
1832+ vec : vec,
1833+ start_u : start_u,
1834+ end_u : end_u,
1835+ start_t : start_t,
1836+ end_t : end_t,
1837+ }
1838+ }
1839+
1840+ /// Pops a `T` from the `PartialVec`.
1841+ ///
1842+ /// Removes the next `T` from the vector and returns it as `Some(T)`, or
1843+ /// `None` if there are none left.
1844+ fn pop ( & mut self ) -> Option < T > {
1845+ // The `if` ensures that there are more `T`s in `vec`.
1846+ if self . start_t < self . end_t {
1847+ let result;
1848+ unsafe {
1849+ // (f) is satisfied before, so in this if branch there actually
1850+ // is a `T` at `start_t`. After shifting the pointer by one,
1851+ // (f) is again satisfied.
1852+ result = ptr:: read ( self . start_t as * const T ) ;
1853+ self . start_t = self . start_t . offset ( 1 ) ;
1854+ }
1855+ Some ( result)
1856+ } else {
1857+ None
1858+ }
1859+ }
1860+
1861+ /// Pushes a new `U` to the `PartialVec`.
1862+ ///
1863+ /// # Failure
1864+ ///
1865+ /// Fails if not enough `T`s were popped to have enough space for the new
1866+ /// `U`.
1867+ fn push ( & mut self , value : U ) {
1868+ // The assert assures that still `end_u <= start_t` (d) after
1869+ // the function.
1870+ assert ! ( self . end_u as * const ( ) < self . start_t as * const ( ) ,
1871+ "writing more elements to PartialVec than reading from it" )
1872+ unsafe {
1873+ // (e) is satisfied before, and after writing one `U`
1874+ // to `end_u` and shifting it by one, it's again
1875+ // satisfied.
1876+ ptr:: write ( self . end_u , value) ;
1877+ self . end_u = self . end_u . offset ( 1 ) ;
1878+ }
1879+ }
1880+
1881+ /// Unwraps the new `Vec` of `U`s after having pushed enough `U`s and
1882+ /// popped all `T`s.
1883+ ///
1884+ /// # Failure
1885+ ///
1886+ /// Fails if not all `T`s were popped, also fails if not the same amount of
1887+ /// `U`s was pushed before calling `unwrap`.
1888+ fn into_vec ( mut self ) -> Vec < U > {
1889+ // If `self.end_u == self.end_t`, we know from (e) that there are no
1890+ // more `T`s in `vec`, we also know that the whole length of `vec` is
1891+ // now used by `U`s, thus we can just interpret `vec` as a vector of
1892+ // `U` safely.
1893+
1894+ assert ! ( self . end_u as * const ( ) == self . end_t as * const ( ) ,
1895+ "trying to unwrap a PartialVec before completing the writes to it" ) ;
1896+
1897+ // Extract `vec` and prevent the destructor of `PartialVec` from
1898+ // running. Note that none of the function calls can fail, thus no
1899+ // resources can be leaked (as the `vec` member of `PartialVec` is the
1900+ // only one which holds allocations -- and it is returned from this
1901+ // function.
1902+ unsafe {
1903+ let vec_len = self . vec . len ( ) ;
1904+ let vec_cap = self . vec . capacity ( ) ;
1905+ let vec_ptr = self . vec . as_mut_ptr ( ) as * mut U ;
1906+ mem:: forget ( self ) ;
1907+ Vec :: from_raw_parts ( vec_len, vec_cap, vec_ptr)
1908+ }
1909+ }
1910+ }
1911+
1912+ #[ unsafe_destructor]
1913+ impl < T , U > Drop for PartialVec < T , U > {
1914+ fn drop ( & mut self ) {
1915+ unsafe {
1916+ // As per (a) `vec` hasn't been modified until now. As it has a
1917+ // length currently, this would run destructors of `T`s which might
1918+ // not be there. So at first, set `vec`s length to `0`. This must
1919+ // be done at first to remain memory-safe as the destructors of `U`
1920+ // or `T` might cause unwinding where `vec`s destructor would be
1921+ // executed.
1922+ self . vec . set_len ( 0 ) ;
1923+
1924+ // As per (e) and (f) we have instances of `U`s and `T`s in `vec`.
1925+ // Destruct them.
1926+ while self . start_u < self . end_u {
1927+ let _ = ptr:: read ( self . start_u as * const U ) ; // Run a `U` destructor.
1928+ self . start_u = self . start_u . offset ( 1 ) ;
1929+ }
1930+ while self . start_t < self . end_t {
1931+ let _ = ptr:: read ( self . start_t as * const T ) ; // Run a `T` destructor.
1932+ self . start_t = self . start_t . offset ( 1 ) ;
1933+ }
1934+ // After this destructor ran, the destructor of `vec` will run,
1935+ // deallocating the underlying memory.
1936+ }
1937+ }
1938+ }
1939+
1940+ impl < T > Vec < T > {
1941+ /// Converts a `Vec<T>` to a `Vec<U>` where `T` and `U` have the same
1942+ /// non-zero size and the same minimal alignment.
1943+ ///
1944+ /// # Failure
1945+ ///
1946+ /// Fails if `T` and `U` have differing sizes, are zero-sized or have
1947+ /// differing minimal alignments.
1948+ ///
1949+ /// # Example
1950+ ///
1951+ /// ```
1952+ /// let v = vec![0u, 1, 2];
1953+ /// let w = v.map_in_place(|i| i + 3);
1954+ /// assert_eq!(w.as_slice(), [3, 4, 5].as_slice());
1955+ ///
1956+ /// #[deriving(PartialEq, Show)]
1957+ /// struct Newtype(u8);
1958+ /// let bytes = vec![0x11, 0x22];
1959+ /// let newtyped_bytes = bytes.map_in_place(|x| Newtype(x));
1960+ /// assert_eq!(newtyped_bytes.as_slice(), [Newtype(0x11), Newtype(0x22)].as_slice());
1961+ /// ```
1962+ pub fn map_in_place < U > ( self , f: |T | -> U ) -> Vec < U > {
1963+ let mut pv = PartialVec :: from_vec ( self ) ;
1964+ loop {
1965+ let maybe_t = pv. pop ( ) ;
1966+ match maybe_t {
1967+ Some ( t) => pv. push ( f ( t) ) ,
1968+ None => return pv. into_vec ( ) ,
1969+ } ;
1970+ }
1971+ }
1972+ }
1973+
1974+
17131975#[ cfg( test) ]
17141976mod tests {
17151977 extern crate test;
@@ -2041,6 +2303,19 @@ mod tests {
20412303 assert_eq ! ( vec. len( ) , 0 ) ;
20422304 }
20432305
2306+ #[ test]
2307+ #[ should_fail]
2308+ fn test_map_inp_lace_incompatible_types_fail ( ) {
2309+ let v = vec ! [ 0 u, 1 , 2 ] ;
2310+ v. map_in_place ( |_| ( ) ) ;
2311+ }
2312+
2313+ #[ test]
2314+ fn test_map_in_place ( ) {
2315+ let v = vec ! [ 0 u, 1 , 2 ] ;
2316+ assert_eq ! ( v. map_in_place( |i: uint| i as int - 1 ) . as_slice( ) , [ -1 i, 0 , 1 ] . as_slice( ) ) ;
2317+ }
2318+
20442319 #[ bench]
20452320 fn bench_new ( b : & mut Bencher ) {
20462321 b. iter ( || {
0 commit comments