@@ -1697,27 +1697,169 @@ impl<T> [T] {
1697
1697
}
1698
1698
}
1699
1699
1700
- // #[unstable(feature = "slice_align_to", issue = "44488")]
1701
- // pub fn align_to<U>(&self) -> (&[T], &[U], &[T]) {
1702
- // // First, find at what point do we split between the first and 2nd slice.
1703
- // let x = self.as_ptr();
1704
- // let offset = x.align_offset(::mem::align_of::<U>());
1705
- // if offset > x * ::mem::size_of::<T>() {
1706
- // return (self, [], []);
1707
- // }
1708
-
1709
- // }
1710
-
1711
- // #[unstable(feature = "slice_align_to", issue = "44488")]
1712
- // pub fn align_to_mut<U>(&mut self) -> (&mut [T], &mut [U], &mut [T]) {
1713
- // }
1714
- } }
1700
+ /// Function to calculate lenghts of the middle and trailing slice for `align_to{,_mut}`.
1701
+ fn align_to_offsets < U > ( & self ) -> ( usize , usize ) {
1702
+ // What we gonna do about `rest` is figure out what multiple of `U`s we can put in a
1703
+ // lowest number of `T`s. And how many `T`s we need for each such "multiple".
1704
+ //
1705
+ // Consider for example T=u8 U=u16. Then we can put 1 U in 2 Ts. Simple. Now, consider
1706
+ // for example a case where size_of::<T> = 16, size_of::<U> = 24. We can put 2 Us in
1707
+ // place of every 3 Ts in the `rest` slice. A bit more complicated.
1708
+ //
1709
+ // Formula to calculate this is:
1710
+ //
1711
+ // Us = lcm(size_of::<T>, size_of::<U>) / size_of::<U>
1712
+ // Ts = lcm(size_of::<T>, size_of::<U>) / size_of::<T>
1713
+ //
1714
+ // Expanded and simplified:
1715
+ //
1716
+ // Us = size_of::<T> / gcd(size_of::<T>, size_of::<U>)
1717
+ // Ts = size_of::<U> / gcd(size_of::<T>, size_of::<U>)
1718
+ //
1719
+ // Luckily since all this is constant-evaluated... performance here matters not!
1720
+ #[ inline]
1721
+ fn gcd ( a : usize , b : usize ) -> usize {
1722
+ // iterative stein’s algorithm
1723
+ // We should still make this `const fn` (and revert to recursive algorithm if we do)
1724
+ // because relying on llvm to consteval all this is… well, it makes me
1725
+ let ( ctz_a, mut ctz_b) = unsafe {
1726
+ if a == 0 { return b; }
1727
+ if b == 0 { return a; }
1728
+ ( :: intrinsics:: cttz_nonzero ( a) , :: intrinsics:: cttz_nonzero ( b) )
1729
+ } ;
1730
+ let k = ctz_a. min ( ctz_b) ;
1731
+ let mut a = a >> ctz_a;
1732
+ let mut b = b;
1733
+ loop {
1734
+ // remove all factors of 2 from b
1735
+ b >>= ctz_b;
1736
+ if a > b {
1737
+ :: mem:: swap ( & mut a, & mut b) ;
1738
+ }
1739
+ b = b - a;
1740
+ unsafe {
1741
+ if b == 0 {
1742
+ break ;
1743
+ }
1744
+ ctz_b = :: intrinsics:: cttz_nonzero ( b) ;
1745
+ }
1746
+ }
1747
+ return a << k;
1748
+ }
1749
+ let gcd: usize = gcd ( :: mem:: size_of :: < T > ( ) , :: mem:: size_of :: < U > ( ) ) ;
1750
+ let ts: usize = :: mem:: size_of :: < U > ( ) / gcd;
1751
+ let us: usize = :: mem:: size_of :: < T > ( ) / gcd;
1715
1752
1716
- #[ lang = "slice" ]
1717
- #[ cfg( not( test) ) ]
1718
- #[ cfg( not( stage0) ) ]
1719
- impl < T > [ T ] {
1720
- slice_core_methods ! ( ) ;
1753
+ // Armed with this knowledge, we can find how many `U`s we can fit!
1754
+ let us_len = self . len ( ) / ts * us;
1755
+ // And how many `T`s will be in the trailing slice!
1756
+ let ts_len = self . len ( ) % ts;
1757
+ return ( us_len, ts_len) ;
1758
+ }
1759
+
1760
+ /// Transmute the slice to a slice of another type, ensuring aligment of the types is
1761
+ /// maintained.
1762
+ ///
1763
+ /// This method splits the slice into three distinct slices: prefix, correctly aligned middle
1764
+ /// slice of a new type, and the suffix slice. The middle slice will have the greatest length
1765
+ /// possible for a given type and input slice.
1766
+ ///
1767
+ /// This method has no purpose when either input element `T` or output element `U` are
1768
+ /// zero-sized and will return the original slice without splitting anything.
1769
+ ///
1770
+ /// # Unsafety
1771
+ ///
1772
+ /// This method is essentially a `transmute` with respect to the elements in the returned
1773
+ /// middle slice, so all the usual caveats pertaining to `transmute::<T, U>` also apply here.
1774
+ ///
1775
+ /// # Examples
1776
+ ///
1777
+ /// Basic usage:
1778
+ ///
1779
+ /// ```
1780
+ /// # #![feature(slice_align_to)]
1781
+ /// unsafe {
1782
+ /// let bytes: [u8; 7] = [1, 2, 3, 4, 5, 6, 7];
1783
+ /// let (prefix, shorts, suffix) = bytes.align_to::<u16>();
1784
+ /// // less_efficient_algorithm_for_bytes(prefix);
1785
+ /// // more_efficient_algorithm_for_aligned_shorts(shorts);
1786
+ /// // less_efficient_algorithm_for_bytes(suffix);
1787
+ /// }
1788
+ /// ```
1789
+ #[ unstable( feature = "slice_align_to" , issue = "44488" ) ]
1790
+ #[ cfg( not( stage0) ) ]
1791
+ pub unsafe fn align_to < U > ( & self ) -> ( & [ T ] , & [ U ] , & [ T ] ) {
1792
+ // Note that most of this function will be constant-evaluated,
1793
+ if :: mem:: size_of :: < U > ( ) == 0 || :: mem:: size_of :: < T > ( ) == 0 {
1794
+ // handle ZSTs specially, which is – don't handle them at all.
1795
+ return ( self , & [ ] , & [ ] ) ;
1796
+ }
1797
+ let ptr = self . as_ptr ( ) ;
1798
+ let offset = :: intrinsics:: align_offset ( ptr, :: mem:: align_of :: < U > ( ) ) ;
1799
+ if offset > self . len ( ) {
1800
+ return ( self , & [ ] , & [ ] ) ;
1801
+ } else {
1802
+ let ( left, rest) = self . split_at ( offset) ;
1803
+ let ( us_len, ts_len) = rest. align_to_offsets :: < U > ( ) ;
1804
+ return ( left,
1805
+ from_raw_parts ( rest. as_ptr ( ) as * const U , us_len) ,
1806
+ from_raw_parts ( rest. as_ptr ( ) . offset ( ( rest. len ( ) - ts_len) as isize ) , ts_len) )
1807
+ }
1808
+ }
1809
+
1810
+ /// Transmute the slice to a slice of another type, ensuring aligment of the types is
1811
+ /// maintained.
1812
+ ///
1813
+ /// This method splits the slice into three distinct slices: prefix, correctly aligned middle
1814
+ /// slice of a new type, and the suffix slice. The middle slice will have the greatest length
1815
+ /// possible for a given type and input slice.
1816
+ ///
1817
+ /// This method has no purpose when either input element `T` or output element `U` are
1818
+ /// zero-sized and will return the original slice without splitting anything.
1819
+ ///
1820
+ /// # Unsafety
1821
+ ///
1822
+ /// This method is essentially a `transmute` with respect to the elements in the returned
1823
+ /// middle slice, so all the usual caveats pertaining to `transmute::<T, U>` also apply here.
1824
+ ///
1825
+ /// # Examples
1826
+ ///
1827
+ /// Basic usage:
1828
+ ///
1829
+ /// ```
1830
+ /// # #![feature(slice_align_to)]
1831
+ /// unsafe {
1832
+ /// let mut bytes: [u8; 7] = [1, 2, 3, 4, 5, 6, 7];
1833
+ /// let (prefix, shorts, suffix) = bytes.align_to_mut::<u16>();
1834
+ /// // less_efficient_algorithm_for_bytes(prefix);
1835
+ /// // more_efficient_algorithm_for_aligned_shorts(shorts);
1836
+ /// // less_efficient_algorithm_for_bytes(suffix);
1837
+ /// }
1838
+ /// ```
1839
+ #[ unstable( feature = "slice_align_to" , issue = "44488" ) ]
1840
+ #[ cfg( not( stage0) ) ]
1841
+ pub unsafe fn align_to_mut < U > ( & mut self ) -> ( & mut [ T ] , & mut [ U ] , & mut [ T ] ) {
1842
+ // Note that most of this function will be constant-evaluated,
1843
+ if :: mem:: size_of :: < U > ( ) == 0 || :: mem:: size_of :: < T > ( ) == 0 {
1844
+ // handle ZSTs specially, which is – don't handle them at all.
1845
+ return ( self , & mut [ ] , & mut [ ] ) ;
1846
+ }
1847
+
1848
+ // First, find at what point do we split between the first and 2nd slice. Easy with
1849
+ // ptr.align_offset.
1850
+ let ptr = self . as_ptr ( ) ;
1851
+ let offset = :: intrinsics:: align_offset ( ptr, :: mem:: align_of :: < U > ( ) ) ;
1852
+ if offset > self . len ( ) {
1853
+ return ( self , & mut [ ] , & mut [ ] ) ;
1854
+ } else {
1855
+ let ( left, rest) = self . split_at_mut ( offset) ;
1856
+ let ( us_len, ts_len) = rest. align_to_offsets :: < U > ( ) ;
1857
+ let mut_ptr = rest. as_mut_ptr ( ) ;
1858
+ return ( left,
1859
+ from_raw_parts_mut ( mut_ptr as * mut U , us_len) ,
1860
+ from_raw_parts_mut ( mut_ptr. offset ( ( rest. len ( ) - ts_len) as isize ) , ts_len) )
1861
+ }
1862
+ }
1721
1863
}
1722
1864
1723
1865
#[ lang = "slice_u8" ]
0 commit comments