Auto merge of #41098 - arielb1:rollup, r=arielb1
Rollup of 12 pull requests - Successful merges: #40479, #40561, #40709, #40815, #40909, #40927, #40943, #41015, #41028, #41052, #41054, #41065 - Failed merges:
This commit is contained in:
commit
6cd15a0e8f
@ -49,12 +49,17 @@ pub fn install(build: &Build, stage: u32, host: &str) {
|
||||
install_sh(&build, "docs", "rust-docs", stage, host, &prefix,
|
||||
&docdir, &libdir, &mandir, &empty_dir);
|
||||
}
|
||||
|
||||
for target in build.config.target.iter() {
|
||||
install_sh(&build, "std", "rust-std", stage, target, &prefix,
|
||||
&docdir, &libdir, &mandir, &empty_dir);
|
||||
}
|
||||
|
||||
if build.config.rust_save_analysis {
|
||||
install_sh(&build, "analysis", "rust-analysis", stage, host, &prefix,
|
||||
&docdir, &libdir, &mandir, &empty_dir);
|
||||
}
|
||||
install_sh(&build, "std", "rust-std", stage, host, &prefix,
|
||||
&docdir, &libdir, &mandir, &empty_dir);
|
||||
|
||||
install_sh(&build, "rustc", "rustc", stage, host, &prefix,
|
||||
&docdir, &libdir, &mandir, &empty_dir);
|
||||
t!(fs::remove_dir_all(&empty_dir));
|
||||
|
@ -123,6 +123,7 @@
|
||||
- [no_debug](no-debug.md)
|
||||
- [non_ascii_idents](non-ascii-idents.md)
|
||||
- [nonzero](nonzero.md)
|
||||
- [offset_to](offset-to.md)
|
||||
- [omit_gdb_pretty_printer_section](omit-gdb-pretty-printer-section.md)
|
||||
- [on_unimplemented](on-unimplemented.md)
|
||||
- [once_poison](once-poison.md)
|
||||
@ -171,6 +172,7 @@
|
||||
- [slice_concat_ext](slice-concat-ext.md)
|
||||
- [slice_get_slice](slice-get-slice.md)
|
||||
- [slice_patterns](slice-patterns.md)
|
||||
- [slice_rsplit](slice-rsplit.md)
|
||||
- [sort_internals](sort-internals.md)
|
||||
- [sort_unstable](sort-unstable.md)
|
||||
- [specialization](specialization.md)
|
||||
|
7
src/doc/unstable-book/src/offset-to.md
Normal file
7
src/doc/unstable-book/src/offset-to.md
Normal file
@ -0,0 +1,7 @@
|
||||
# `offset_to`
|
||||
|
||||
The tracking issue for this feature is: [#41079]
|
||||
|
||||
[#41079]: https://github.com/rust-lang/rust/issues/41079
|
||||
|
||||
------------------------
|
10
src/doc/unstable-book/src/slice-rsplit.md
Normal file
10
src/doc/unstable-book/src/slice-rsplit.md
Normal file
@ -0,0 +1,10 @@
|
||||
# `slice_rsplit`
|
||||
|
||||
The tracking issue for this feature is: [#41020]
|
||||
|
||||
[#41020]: https://github.com/rust-lang/rust/issues/41020
|
||||
|
||||
------------------------
|
||||
|
||||
The `slice_rsplit` feature enables two methods on slices:
|
||||
`slice.rsplit(predicate)` and `slice.rsplit_mut(predicate)`.
|
@ -76,6 +76,66 @@ def get_codepoints(f):
|
||||
for c in range(prev_codepoint + 1, NUM_CODEPOINTS):
|
||||
yield Codepoint(c, None)
|
||||
|
||||
def compress_singletons(singletons):
|
||||
uppers = [] # (upper, # items in lowers)
|
||||
lowers = []
|
||||
|
||||
for i in singletons:
|
||||
upper = i >> 8
|
||||
lower = i & 0xff
|
||||
if len(uppers) == 0 or uppers[-1][0] != upper:
|
||||
uppers.append((upper, 1))
|
||||
else:
|
||||
upper, count = uppers[-1]
|
||||
uppers[-1] = upper, count + 1
|
||||
lowers.append(lower)
|
||||
|
||||
return uppers, lowers
|
||||
|
||||
def compress_normal(normal):
|
||||
# lengths 0x00..0x7f are encoded as 00, 01, ..., 7e, 7f
|
||||
# lengths 0x80..0x7fff are encoded as 80 80, 80 81, ..., ff fe, ff ff
|
||||
compressed = [] # [truelen, (truelenaux), falselen, (falselenaux)]
|
||||
|
||||
prev_start = 0
|
||||
for start, count in normal:
|
||||
truelen = start - prev_start
|
||||
falselen = count
|
||||
prev_start = start + count
|
||||
|
||||
assert truelen < 0x8000 and falselen < 0x8000
|
||||
entry = []
|
||||
if truelen > 0x7f:
|
||||
entry.append(0x80 | (truelen >> 8))
|
||||
entry.append(truelen & 0xff)
|
||||
else:
|
||||
entry.append(truelen & 0x7f)
|
||||
if falselen > 0x7f:
|
||||
entry.append(0x80 | (falselen >> 8))
|
||||
entry.append(falselen & 0xff)
|
||||
else:
|
||||
entry.append(falselen & 0x7f)
|
||||
|
||||
compressed.append(entry)
|
||||
|
||||
return compressed
|
||||
|
||||
def print_singletons(uppers, lowers, uppersname, lowersname):
|
||||
print("const {}: &'static [(u8, u8)] = &[".format(uppersname))
|
||||
for u, c in uppers:
|
||||
print(" ({:#04x}, {}),".format(u, c))
|
||||
print("];")
|
||||
print("const {}: &'static [u8] = &[".format(lowersname))
|
||||
for i in range(0, len(lowers), 8):
|
||||
print(" {}".format(" ".join("{:#04x},".format(l) for l in lowers[i:i+8])))
|
||||
print("];")
|
||||
|
||||
def print_normal(normal, normalname):
|
||||
print("const {}: &'static [u8] = &[".format(normalname))
|
||||
for v in normal:
|
||||
print(" {}".format(" ".join("{:#04x},".format(i) for i in v)))
|
||||
print("];")
|
||||
|
||||
def main():
|
||||
file = get_file("http://www.unicode.org/Public/UNIDATA/UnicodeData.txt")
|
||||
|
||||
@ -111,6 +171,11 @@ def main():
|
||||
else:
|
||||
normal0.append((a, b - a))
|
||||
|
||||
singletons0u, singletons0l = compress_singletons(singletons0)
|
||||
singletons1u, singletons1l = compress_singletons(singletons1)
|
||||
normal0 = compress_normal(normal0)
|
||||
normal1 = compress_normal(normal1)
|
||||
|
||||
print("""\
|
||||
// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
@ -125,38 +190,49 @@ def main():
|
||||
// NOTE: The following code was generated by "src/etc/char_private.py",
|
||||
// do not edit directly!
|
||||
|
||||
use slice::SliceExt;
|
||||
|
||||
fn check(x: u16, singletons: &[u16], normal: &[u16]) -> bool {
|
||||
for &s in singletons {
|
||||
if x == s {
|
||||
return false;
|
||||
} else if x < s {
|
||||
break;
|
||||
}
|
||||
}
|
||||
for w in normal.chunks(2) {
|
||||
let start = w[0];
|
||||
let len = w[1];
|
||||
let difference = (x as i32) - (start as i32);
|
||||
if 0 <= difference {
|
||||
if difference < len as i32 {
|
||||
return false;
|
||||
fn check(x: u16, singletonuppers: &[(u8, u8)], singletonlowers: &[u8],
|
||||
normal: &[u8]) -> bool {
|
||||
let xupper = (x >> 8) as u8;
|
||||
let mut lowerstart = 0;
|
||||
for &(upper, lowercount) in singletonuppers {
|
||||
let lowerend = lowerstart + lowercount as usize;
|
||||
if xupper == upper {
|
||||
for &lower in &singletonlowers[lowerstart..lowerend] {
|
||||
if lower == x as u8 {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
} else if xupper < upper {
|
||||
break;
|
||||
}
|
||||
lowerstart = lowerend;
|
||||
}
|
||||
true
|
||||
|
||||
let mut x = x as i32;
|
||||
let mut normal = normal.iter().cloned();
|
||||
let mut current = true;
|
||||
while let Some(v) = normal.next() {
|
||||
let len = if v & 0x80 != 0 {
|
||||
((v & 0x7f) as i32) << 8 | normal.next().unwrap() as i32
|
||||
} else {
|
||||
v as i32
|
||||
};
|
||||
x -= len;
|
||||
if x < 0 {
|
||||
break;
|
||||
}
|
||||
current = !current;
|
||||
}
|
||||
current
|
||||
}
|
||||
|
||||
pub fn is_printable(x: char) -> bool {
|
||||
let x = x as u32;
|
||||
let lower = x as u16;
|
||||
if x < 0x10000 {
|
||||
check(lower, SINGLETONS0, NORMAL0)
|
||||
check(lower, SINGLETONS0U, SINGLETONS0L, NORMAL0)
|
||||
} else if x < 0x20000 {
|
||||
check(lower, SINGLETONS1, NORMAL1)
|
||||
check(lower, SINGLETONS1U, SINGLETONS1L, NORMAL1)
|
||||
} else {\
|
||||
""")
|
||||
for a, b in extra:
|
||||
@ -169,22 +245,10 @@ pub fn is_printable(x: char) -> bool {
|
||||
}\
|
||||
""")
|
||||
print()
|
||||
print("const SINGLETONS0: &'static [u16] = &[")
|
||||
for s in singletons0:
|
||||
print(" 0x{:x},".format(s))
|
||||
print("];")
|
||||
print("const SINGLETONS1: &'static [u16] = &[")
|
||||
for s in singletons1:
|
||||
print(" 0x{:x},".format(s))
|
||||
print("];")
|
||||
print("const NORMAL0: &'static [u16] = &[")
|
||||
for a, b in normal0:
|
||||
print(" 0x{:x}, 0x{:x},".format(a, b))
|
||||
print("];")
|
||||
print("const NORMAL1: &'static [u16] = &[")
|
||||
for a, b in normal1:
|
||||
print(" 0x{:x}, 0x{:x},".format(a, b))
|
||||
print("];")
|
||||
print_singletons(singletons0u, singletons0l, 'SINGLETONS0U', 'SINGLETONS0L')
|
||||
print_singletons(singletons1u, singletons1l, 'SINGLETONS1U', 'SINGLETONS1L')
|
||||
print_normal(normal0, 'NORMAL0')
|
||||
print_normal(normal1, 'NORMAL1')
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
@ -52,6 +52,7 @@
|
||||
#![feature(shared)]
|
||||
#![feature(slice_get_slice)]
|
||||
#![feature(slice_patterns)]
|
||||
#![feature(slice_rsplit)]
|
||||
#![cfg_attr(not(test), feature(sort_unstable))]
|
||||
#![feature(specialization)]
|
||||
#![feature(staged_api)]
|
||||
@ -62,6 +63,7 @@
|
||||
#![feature(untagged_unions)]
|
||||
#![cfg_attr(not(test), feature(str_checked_slicing))]
|
||||
#![cfg_attr(test, feature(rand, test))]
|
||||
#![feature(offset_to)]
|
||||
|
||||
#![no_std]
|
||||
|
||||
|
@ -115,6 +115,8 @@
|
||||
pub use core::slice::{SplitMut, ChunksMut, Split};
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use core::slice::{SplitN, RSplitN, SplitNMut, RSplitNMut};
|
||||
#[unstable(feature = "slice_rsplit", issue = "41020")]
|
||||
pub use core::slice::{RSplit, RSplitMut};
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use core::slice::{from_raw_parts, from_raw_parts_mut};
|
||||
#[unstable(feature = "slice_get_slice", issue = "35729")]
|
||||
@ -779,6 +781,72 @@ pub fn split_mut<F>(&mut self, pred: F) -> SplitMut<T, F>
|
||||
core_slice::SliceExt::split_mut(self, pred)
|
||||
}
|
||||
|
||||
/// Returns an iterator over subslices separated by elements that match
|
||||
/// `pred`, starting at the end of the slice and working backwards.
|
||||
/// The matched element is not contained in the subslices.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(slice_rsplit)]
|
||||
///
|
||||
/// let slice = [11, 22, 33, 0, 44, 55];
|
||||
/// let mut iter = slice.rsplit(|num| *num == 0);
|
||||
///
|
||||
/// assert_eq!(iter.next().unwrap(), &[44, 55]);
|
||||
/// assert_eq!(iter.next().unwrap(), &[11, 22, 33]);
|
||||
/// assert_eq!(iter.next(), None);
|
||||
/// ```
|
||||
///
|
||||
/// As with `split()`, if the first or last element is matched, an empty
|
||||
/// slice will be the first (or last) item returned by the iterator.
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(slice_rsplit)]
|
||||
///
|
||||
/// let v = &[0, 1, 1, 2, 3, 5, 8];
|
||||
/// let mut it = v.rsplit(|n| *n % 2 == 0);
|
||||
/// assert_eq!(it.next().unwrap(), &[]);
|
||||
/// assert_eq!(it.next().unwrap(), &[3, 5]);
|
||||
/// assert_eq!(it.next().unwrap(), &[1, 1]);
|
||||
/// assert_eq!(it.next().unwrap(), &[]);
|
||||
/// assert_eq!(it.next(), None);
|
||||
/// ```
|
||||
#[unstable(feature = "slice_rsplit", issue = "41020")]
|
||||
#[inline]
|
||||
pub fn rsplit<F>(&self, pred: F) -> RSplit<T, F>
|
||||
where F: FnMut(&T) -> bool
|
||||
{
|
||||
core_slice::SliceExt::rsplit(self, pred)
|
||||
}
|
||||
|
||||
/// Returns an iterator over mutable subslices separated by elements that
|
||||
/// match `pred`, starting at the end of the slice and working
|
||||
/// backwards. The matched element is not contained in the subslices.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(slice_rsplit)]
|
||||
///
|
||||
/// let mut v = [100, 400, 300, 200, 600, 500];
|
||||
///
|
||||
/// let mut count = 0;
|
||||
/// for group in v.rsplit_mut(|num| *num % 3 == 0) {
|
||||
/// count += 1;
|
||||
/// group[0] = count;
|
||||
/// }
|
||||
/// assert_eq!(v, [3, 400, 300, 2, 600, 1]);
|
||||
/// ```
|
||||
///
|
||||
#[unstable(feature = "slice_rsplit", issue = "41020")]
|
||||
#[inline]
|
||||
pub fn rsplit_mut<F>(&mut self, pred: F) -> RSplitMut<T, F>
|
||||
where F: FnMut(&T) -> bool
|
||||
{
|
||||
core_slice::SliceExt::rsplit_mut(self, pred)
|
||||
}
|
||||
|
||||
/// Returns an iterator over subslices separated by elements that match
|
||||
/// `pred`, limited to returning at most `n` items. The matched element is
|
||||
/// not contained in the subslices.
|
||||
|
@ -973,6 +973,29 @@ pub fn push(&mut self, value: T) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a place for insertion at the back of the `Vec`.
|
||||
///
|
||||
/// Using this method with placement syntax is equivalent to [`push`](#method.push),
|
||||
/// but may be more efficient.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(collection_placement)]
|
||||
/// #![feature(placement_in_syntax)]
|
||||
///
|
||||
/// let mut vec = vec![1, 2];
|
||||
/// vec.place_back() <- 3;
|
||||
/// vec.place_back() <- 4;
|
||||
/// assert_eq!(&vec, &[1, 2, 3, 4]);
|
||||
/// ```
|
||||
#[unstable(feature = "collection_placement",
|
||||
reason = "placement protocol is subject to change",
|
||||
issue = "30172")]
|
||||
pub fn place_back(&mut self) -> PlaceBack<T> {
|
||||
PlaceBack { vec: self }
|
||||
}
|
||||
|
||||
/// Removes the last element from a vector and returns it, or [`None`] if it
|
||||
/// is empty.
|
||||
///
|
||||
@ -1267,29 +1290,6 @@ fn extend_with_element(&mut self, n: usize, value: T) {
|
||||
pub fn extend_from_slice(&mut self, other: &[T]) {
|
||||
self.spec_extend(other.iter())
|
||||
}
|
||||
|
||||
/// Returns a place for insertion at the back of the `Vec`.
|
||||
///
|
||||
/// Using this method with placement syntax is equivalent to [`push`](#method.push),
|
||||
/// but may be more efficient.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(collection_placement)]
|
||||
/// #![feature(placement_in_syntax)]
|
||||
///
|
||||
/// let mut vec = vec![1, 2];
|
||||
/// vec.place_back() <- 3;
|
||||
/// vec.place_back() <- 4;
|
||||
/// assert_eq!(&vec, &[1, 2, 3, 4]);
|
||||
/// ```
|
||||
#[unstable(feature = "collection_placement",
|
||||
reason = "placement protocol is subject to change",
|
||||
issue = "30172")]
|
||||
pub fn place_back(&mut self) -> PlaceBack<T> {
|
||||
PlaceBack { vec: self }
|
||||
}
|
||||
}
|
||||
|
||||
// Set the length of the vec when the `SetLenOnDrop` value goes out of scope.
|
||||
@ -2074,14 +2074,10 @@ fn next(&mut self) -> Option<T> {
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let diff = (self.end as usize) - (self.ptr as usize);
|
||||
let size = mem::size_of::<T>();
|
||||
let exact = diff /
|
||||
(if size == 0 {
|
||||
1
|
||||
} else {
|
||||
size
|
||||
});
|
||||
let exact = match self.ptr.offset_to(self.end) {
|
||||
Some(x) => x as usize,
|
||||
None => (self.end as usize).wrapping_sub(self.ptr as usize),
|
||||
};
|
||||
(exact, Some(exact))
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -358,12 +358,24 @@ impl<I> Iterator for Rev<I> where I: DoubleEndedIterator {
|
||||
fn next(&mut self) -> Option<<I as Iterator>::Item> { self.iter.next_back() }
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
|
||||
|
||||
fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
|
||||
where P: FnMut(&Self::Item) -> bool
|
||||
{
|
||||
self.iter.rfind(predicate)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<I> DoubleEndedIterator for Rev<I> where I: DoubleEndedIterator {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<<I as Iterator>::Item> { self.iter.next() }
|
||||
|
||||
fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item>
|
||||
where P: FnMut(&Self::Item) -> bool
|
||||
{
|
||||
self.iter.find(predicate)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
@ -467,7 +467,7 @@ fn rfind<P>(&mut self, mut predicate: P) -> Option<Self::Item> where
|
||||
Self: Sized,
|
||||
P: FnMut(&Self::Item) -> bool
|
||||
{
|
||||
for x in self.by_ref().rev() {
|
||||
while let Some(x) = self.next_back() {
|
||||
if predicate(&x) { return Some(x) }
|
||||
}
|
||||
None
|
||||
|
@ -500,6 +500,44 @@ pub fn wrapping_offset(self, count: isize) -> *const T where T: Sized {
|
||||
intrinsics::arith_offset(self, count)
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculates the distance between two pointers. The returned value is in
|
||||
/// units of T: the distance in bytes is divided by `mem::size_of::<T>()`.
|
||||
///
|
||||
/// If the address different between the two pointers ia not a multiple of
|
||||
/// `mem::size_of::<T>()` then the result of the division is rounded towards
|
||||
/// zero.
|
||||
///
|
||||
/// This function returns `None` if `T` is a zero-sized typed.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(offset_to)]
|
||||
///
|
||||
/// fn main() {
|
||||
/// let a = [0; 5];
|
||||
/// let ptr1: *const i32 = &a[1];
|
||||
/// let ptr2: *const i32 = &a[3];
|
||||
/// assert_eq!(ptr1.offset_to(ptr2), Some(2));
|
||||
/// assert_eq!(ptr2.offset_to(ptr1), Some(-2));
|
||||
/// assert_eq!(unsafe { ptr1.offset(2) }, ptr2);
|
||||
/// assert_eq!(unsafe { ptr2.offset(-2) }, ptr1);
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "offset_to", issue = "41079")]
|
||||
#[inline]
|
||||
pub fn offset_to(self, other: *const T) -> Option<isize> where T: Sized {
|
||||
let size = mem::size_of::<T>();
|
||||
if size == 0 {
|
||||
None
|
||||
} else {
|
||||
let diff = (other as isize).wrapping_sub(self as isize);
|
||||
Some(diff / size as isize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[lang = "mut_ptr"]
|
||||
@ -653,6 +691,44 @@ pub unsafe fn as_mut<'a>(self) -> Option<&'a mut T> where T: Sized {
|
||||
Some(&mut *self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculates the distance between two pointers. The returned value is in
|
||||
/// units of T: the distance in bytes is divided by `mem::size_of::<T>()`.
|
||||
///
|
||||
/// If the address different between the two pointers ia not a multiple of
|
||||
/// `mem::size_of::<T>()` then the result of the division is rounded towards
|
||||
/// zero.
|
||||
///
|
||||
/// This function returns `None` if `T` is a zero-sized typed.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(offset_to)]
|
||||
///
|
||||
/// fn main() {
|
||||
/// let mut a = [0; 5];
|
||||
/// let ptr1: *mut i32 = &mut a[1];
|
||||
/// let ptr2: *mut i32 = &mut a[3];
|
||||
/// assert_eq!(ptr1.offset_to(ptr2), Some(2));
|
||||
/// assert_eq!(ptr2.offset_to(ptr1), Some(-2));
|
||||
/// assert_eq!(unsafe { ptr1.offset(2) }, ptr2);
|
||||
/// assert_eq!(unsafe { ptr2.offset(-2) }, ptr1);
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "offset_to", issue = "41079")]
|
||||
#[inline]
|
||||
pub fn offset_to(self, other: *const T) -> Option<isize> where T: Sized {
|
||||
let size = mem::size_of::<T>();
|
||||
if size == 0 {
|
||||
None
|
||||
} else {
|
||||
let diff = (other as isize).wrapping_sub(self as isize);
|
||||
Some(diff / size as isize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Equality for pointers
|
||||
|
@ -81,6 +81,10 @@ pub trait SliceExt {
|
||||
fn split<P>(&self, pred: P) -> Split<Self::Item, P>
|
||||
where P: FnMut(&Self::Item) -> bool;
|
||||
|
||||
#[unstable(feature = "slice_rsplit", issue = "41020")]
|
||||
fn rsplit<P>(&self, pred: P) -> RSplit<Self::Item, P>
|
||||
where P: FnMut(&Self::Item) -> bool;
|
||||
|
||||
#[stable(feature = "core", since = "1.6.0")]
|
||||
fn splitn<P>(&self, n: usize, pred: P) -> SplitN<Self::Item, P>
|
||||
where P: FnMut(&Self::Item) -> bool;
|
||||
@ -159,6 +163,10 @@ fn get_mut<I>(&mut self, index: I) -> Option<&mut I::Output>
|
||||
fn split_mut<P>(&mut self, pred: P) -> SplitMut<Self::Item, P>
|
||||
where P: FnMut(&Self::Item) -> bool;
|
||||
|
||||
#[unstable(feature = "slice_rsplit", issue = "41020")]
|
||||
fn rsplit_mut<P>(&mut self, pred: P) -> RSplitMut<Self::Item, P>
|
||||
where P: FnMut(&Self::Item) -> bool;
|
||||
|
||||
#[stable(feature = "core", since = "1.6.0")]
|
||||
fn splitn_mut<P>(&mut self, n: usize, pred: P) -> SplitNMut<Self::Item, P>
|
||||
where P: FnMut(&Self::Item) -> bool;
|
||||
@ -293,6 +301,13 @@ fn split<P>(&self, pred: P) -> Split<T, P>
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn rsplit<P>(&self, pred: P) -> RSplit<T, P>
|
||||
where P: FnMut(&T) -> bool
|
||||
{
|
||||
RSplit { inner: self.split(pred) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn splitn<P>(&self, n: usize, pred: P) -> SplitN<T, P>
|
||||
where P: FnMut(&T) -> bool
|
||||
@ -300,8 +315,7 @@ fn splitn<P>(&self, n: usize, pred: P) -> SplitN<T, P>
|
||||
SplitN {
|
||||
inner: GenericSplitN {
|
||||
iter: self.split(pred),
|
||||
count: n,
|
||||
invert: false
|
||||
count: n
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -312,9 +326,8 @@ fn rsplitn<P>(&self, n: usize, pred: P) -> RSplitN<T, P>
|
||||
{
|
||||
RSplitN {
|
||||
inner: GenericSplitN {
|
||||
iter: self.split(pred),
|
||||
count: n,
|
||||
invert: true
|
||||
iter: self.rsplit(pred),
|
||||
count: n
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -475,6 +488,13 @@ fn split_mut<P>(&mut self, pred: P) -> SplitMut<T, P>
|
||||
SplitMut { v: self, pred: pred, finished: false }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn rsplit_mut<P>(&mut self, pred: P) -> RSplitMut<T, P>
|
||||
where P: FnMut(&T) -> bool
|
||||
{
|
||||
RSplitMut { inner: self.split_mut(pred) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn splitn_mut<P>(&mut self, n: usize, pred: P) -> SplitNMut<T, P>
|
||||
where P: FnMut(&T) -> bool
|
||||
@ -482,8 +502,7 @@ fn splitn_mut<P>(&mut self, n: usize, pred: P) -> SplitNMut<T, P>
|
||||
SplitNMut {
|
||||
inner: GenericSplitN {
|
||||
iter: self.split_mut(pred),
|
||||
count: n,
|
||||
invert: false
|
||||
count: n
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -494,9 +513,8 @@ fn rsplitn_mut<P>(&mut self, n: usize, pred: P) -> RSplitNMut<T, P> where
|
||||
{
|
||||
RSplitNMut {
|
||||
inner: GenericSplitN {
|
||||
iter: self.split_mut(pred),
|
||||
count: n,
|
||||
invert: true
|
||||
iter: self.rsplit_mut(pred),
|
||||
count: n
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1498,9 +1516,10 @@ unsafe impl<'a, T> TrustedLen for IterMut<'a, T> {}
|
||||
// Return the arithmetic difference if `T` is zero size.
|
||||
#[inline(always)]
|
||||
fn ptrdistance<T>(start: *const T, end: *const T) -> usize {
|
||||
let diff = (end as usize).wrapping_sub(start as usize);
|
||||
let size = mem::size_of::<T>();
|
||||
diff / (if size == 0 { 1 } else { size })
|
||||
match start.offset_to(end) {
|
||||
Some(x) => x as usize,
|
||||
None => (end as usize).wrapping_sub(start as usize),
|
||||
}
|
||||
}
|
||||
|
||||
// Extension methods for raw pointers, used by the iterators
|
||||
@ -1735,6 +1754,123 @@ fn next_back(&mut self) -> Option<&'a mut [T]> {
|
||||
#[unstable(feature = "fused", issue = "35602")]
|
||||
impl<'a, T, P> FusedIterator for SplitMut<'a, T, P> where P: FnMut(&T) -> bool {}
|
||||
|
||||
/// An iterator over subslices separated by elements that match a predicate
|
||||
/// function, starting from the end of the slice.
|
||||
///
|
||||
/// This struct is created by the [`rsplit`] method on [slices].
|
||||
///
|
||||
/// [`rsplit`]: ../../std/primitive.slice.html#method.rsplit
|
||||
/// [slices]: ../../std/primitive.slice.html
|
||||
#[unstable(feature = "slice_rsplit", issue = "41020")]
|
||||
#[derive(Clone)] // Is this correct, or does it incorrectly require `T: Clone`?
|
||||
pub struct RSplit<'a, T:'a, P> where P: FnMut(&T) -> bool {
|
||||
inner: Split<'a, T, P>
|
||||
}
|
||||
|
||||
#[unstable(feature = "slice_rsplit", issue = "41020")]
|
||||
impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for RSplit<'a, T, P> where P: FnMut(&T) -> bool {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("RSplit")
|
||||
.field("v", &self.inner.v)
|
||||
.field("finished", &self.inner.finished)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "slice_rsplit", issue = "41020")]
|
||||
impl<'a, T, P> Iterator for RSplit<'a, T, P> where P: FnMut(&T) -> bool {
|
||||
type Item = &'a [T];
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<&'a [T]> {
|
||||
self.inner.next_back()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.inner.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "slice_rsplit", issue = "41020")]
|
||||
impl<'a, T, P> DoubleEndedIterator for RSplit<'a, T, P> where P: FnMut(&T) -> bool {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<&'a [T]> {
|
||||
self.inner.next()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "slice_rsplit", issue = "41020")]
|
||||
impl<'a, T, P> SplitIter for RSplit<'a, T, P> where P: FnMut(&T) -> bool {
|
||||
#[inline]
|
||||
fn finish(&mut self) -> Option<&'a [T]> {
|
||||
self.inner.finish()
|
||||
}
|
||||
}
|
||||
|
||||
//#[unstable(feature = "fused", issue = "35602")]
|
||||
#[unstable(feature = "slice_rsplit", issue = "41020")]
|
||||
impl<'a, T, P> FusedIterator for RSplit<'a, T, P> where P: FnMut(&T) -> bool {}
|
||||
|
||||
/// An iterator over the subslices of the vector which are separated
|
||||
/// by elements that match `pred`, starting from the end of the slice.
|
||||
///
|
||||
/// This struct is created by the [`rsplit_mut`] method on [slices].
|
||||
///
|
||||
/// [`rsplit_mut`]: ../../std/primitive.slice.html#method.rsplit_mut
|
||||
/// [slices]: ../../std/primitive.slice.html
|
||||
#[unstable(feature = "slice_rsplit", issue = "41020")]
|
||||
pub struct RSplitMut<'a, T:'a, P> where P: FnMut(&T) -> bool {
|
||||
inner: SplitMut<'a, T, P>
|
||||
}
|
||||
|
||||
#[unstable(feature = "slice_rsplit", issue = "41020")]
|
||||
impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("RSplitMut")
|
||||
.field("v", &self.inner.v)
|
||||
.field("finished", &self.inner.finished)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "slice_rsplit", issue = "41020")]
|
||||
impl<'a, T, P> SplitIter for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool {
|
||||
#[inline]
|
||||
fn finish(&mut self) -> Option<&'a mut [T]> {
|
||||
self.inner.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "slice_rsplit", issue = "41020")]
|
||||
impl<'a, T, P> Iterator for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool {
|
||||
type Item = &'a mut [T];
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<&'a mut [T]> {
|
||||
self.inner.next_back()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.inner.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "slice_rsplit", issue = "41020")]
|
||||
impl<'a, T, P> DoubleEndedIterator for RSplitMut<'a, T, P> where
|
||||
P: FnMut(&T) -> bool,
|
||||
{
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<&'a mut [T]> {
|
||||
self.inner.next()
|
||||
}
|
||||
}
|
||||
|
||||
//#[unstable(feature = "fused", issue = "35602")]
|
||||
#[unstable(feature = "slice_rsplit", issue = "41020")]
|
||||
impl<'a, T, P> FusedIterator for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool {}
|
||||
|
||||
/// An private iterator over subslices separated by elements that
|
||||
/// match a predicate function, splitting at most a fixed number of
|
||||
/// times.
|
||||
@ -1742,7 +1878,6 @@ impl<'a, T, P> FusedIterator for SplitMut<'a, T, P> where P: FnMut(&T) -> bool {
|
||||
struct GenericSplitN<I> {
|
||||
iter: I,
|
||||
count: usize,
|
||||
invert: bool
|
||||
}
|
||||
|
||||
impl<T, I: SplitIter<Item=T>> Iterator for GenericSplitN<I> {
|
||||
@ -1753,10 +1888,7 @@ fn next(&mut self) -> Option<T> {
|
||||
match self.count {
|
||||
0 => None,
|
||||
1 => { self.count -= 1; self.iter.finish() }
|
||||
_ => {
|
||||
self.count -= 1;
|
||||
if self.invert {self.iter.next_back()} else {self.iter.next()}
|
||||
}
|
||||
_ => { self.count -= 1; self.iter.next() }
|
||||
}
|
||||
}
|
||||
|
||||
@ -1798,7 +1930,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
/// [slices]: ../../std/primitive.slice.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct RSplitN<'a, T: 'a, P> where P: FnMut(&T) -> bool {
|
||||
inner: GenericSplitN<Split<'a, T, P>>
|
||||
inner: GenericSplitN<RSplit<'a, T, P>>
|
||||
}
|
||||
|
||||
#[stable(feature = "core_impl_debug", since = "1.9.0")]
|
||||
@ -1841,7 +1973,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
/// [slices]: ../../std/primitive.slice.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct RSplitNMut<'a, T: 'a, P> where P: FnMut(&T) -> bool {
|
||||
inner: GenericSplitN<SplitMut<'a, T, P>>
|
||||
inner: GenericSplitN<RSplitMut<'a, T, P>>
|
||||
}
|
||||
|
||||
#[stable(feature = "core_impl_debug", since = "1.9.0")]
|
||||
|
@ -321,7 +321,7 @@ pub fn store(&self, val: bool, order: Ordering) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Stores a value into the bool, returning the old value.
|
||||
/// Stores a value into the bool, returning the previous value.
|
||||
///
|
||||
/// `swap` takes an [`Ordering`] argument which describes the memory ordering
|
||||
/// of this operation.
|
||||
@ -732,7 +732,7 @@ pub fn store(&self, ptr: *mut T, order: Ordering) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Stores a value into the pointer, returning the old value.
|
||||
/// Stores a value into the pointer, returning the previous value.
|
||||
///
|
||||
/// `swap` takes an [`Ordering`] argument which describes the memory ordering
|
||||
/// of this operation.
|
||||
@ -1047,7 +1047,7 @@ pub fn store(&self, val: $int_type, order: Ordering) {
|
||||
unsafe { atomic_store(self.v.get(), val, order); }
|
||||
}
|
||||
|
||||
/// Stores a value into the atomic integer, returning the old value.
|
||||
/// Stores a value into the atomic integer, returning the previous value.
|
||||
///
|
||||
/// `swap` takes an [`Ordering`] argument which describes the memory ordering of this
|
||||
/// operation.
|
||||
@ -1201,7 +1201,9 @@ pub fn compare_exchange_weak(&self,
|
||||
}
|
||||
}
|
||||
|
||||
/// Add to the current value, returning the previous value.
|
||||
/// Adds to the current value, returning the previous value.
|
||||
///
|
||||
/// This operation wraps around on overflow.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -1218,7 +1220,9 @@ pub fn fetch_add(&self, val: $int_type, order: Ordering) -> $int_type {
|
||||
unsafe { atomic_add(self.v.get(), val, order) }
|
||||
}
|
||||
|
||||
/// Subtract from the current value, returning the previous value.
|
||||
/// Subtracts from the current value, returning the previous value.
|
||||
///
|
||||
/// This operation wraps around on overflow.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -1235,7 +1239,12 @@ pub fn fetch_sub(&self, val: $int_type, order: Ordering) -> $int_type {
|
||||
unsafe { atomic_sub(self.v.get(), val, order) }
|
||||
}
|
||||
|
||||
/// Bitwise and with the current value, returning the previous value.
|
||||
/// Bitwise "and" with the current value.
|
||||
///
|
||||
/// Performs a bitwise "and" operation on the current value and the argument `val`, and
|
||||
/// sets the new value to the result.
|
||||
///
|
||||
/// Returns the previous value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -1251,7 +1260,12 @@ pub fn fetch_and(&self, val: $int_type, order: Ordering) -> $int_type {
|
||||
unsafe { atomic_and(self.v.get(), val, order) }
|
||||
}
|
||||
|
||||
/// Bitwise or with the current value, returning the previous value.
|
||||
/// Bitwise "or" with the current value.
|
||||
///
|
||||
/// Performs a bitwise "or" operation on the current value and the argument `val`, and
|
||||
/// sets the new value to the result.
|
||||
///
|
||||
/// Returns the previous value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -1267,7 +1281,12 @@ pub fn fetch_or(&self, val: $int_type, order: Ordering) -> $int_type {
|
||||
unsafe { atomic_or(self.v.get(), val, order) }
|
||||
}
|
||||
|
||||
/// Bitwise xor with the current value, returning the previous value.
|
||||
/// Bitwise "xor" with the current value.
|
||||
///
|
||||
/// Performs a bitwise "xor" operation on the current value and the argument `val`, and
|
||||
/// sets the new value to the result.
|
||||
///
|
||||
/// Returns the previous value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -1415,7 +1434,7 @@ unsafe fn atomic_swap<T>(dst: *mut T, val: T, order: Ordering) -> T {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the old value (like __sync_fetch_and_add).
|
||||
/// Returns the previous value (like __sync_fetch_and_add).
|
||||
#[inline]
|
||||
unsafe fn atomic_add<T>(dst: *mut T, val: T, order: Ordering) -> T {
|
||||
match order {
|
||||
@ -1428,7 +1447,7 @@ unsafe fn atomic_add<T>(dst: *mut T, val: T, order: Ordering) -> T {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the old value (like __sync_fetch_and_sub).
|
||||
/// Returns the previous value (like __sync_fetch_and_sub).
|
||||
#[inline]
|
||||
unsafe fn atomic_sub<T>(dst: *mut T, val: T, order: Ordering) -> T {
|
||||
match order {
|
||||
|
@ -25,6 +25,9 @@ pub fn block_data_mut(&mut self, blk: BasicBlock) -> &mut BasicBlockData<'tcx> {
|
||||
&mut self.basic_blocks[blk]
|
||||
}
|
||||
|
||||
// llvm.org/PR32488 makes this function use an excess of stack space. Mark
|
||||
// it as #[inline(never)] to keep rustc's stack use in check.
|
||||
#[inline(never)]
|
||||
pub fn start_new_block(&mut self) -> BasicBlock {
|
||||
self.basic_blocks.push(BasicBlockData::new(None))
|
||||
}
|
||||
|
@ -11,7 +11,6 @@
|
||||
use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
|
||||
use rustc::hir;
|
||||
use rustc::hir::itemlikevisit::ItemLikeVisitor;
|
||||
use rustc::lint;
|
||||
use rustc::traits::{self, Reveal};
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
|
||||
@ -53,12 +52,16 @@ enum Namespace {
|
||||
|
||||
for &item2 in &impl_items2[..] {
|
||||
if (name, namespace) == name_and_namespace(item2) {
|
||||
let msg = format!("duplicate definitions with name `{}`", name);
|
||||
let node_id = self.tcx.hir.as_local_node_id(item1).unwrap();
|
||||
self.tcx.sess.add_lint(lint::builtin::OVERLAPPING_INHERENT_IMPLS,
|
||||
node_id,
|
||||
self.tcx.span_of_impl(item1).unwrap(),
|
||||
msg);
|
||||
struct_span_err!(self.tcx.sess,
|
||||
self.tcx.span_of_impl(item1).unwrap(),
|
||||
E0592,
|
||||
"duplicate definitions with name `{}`",
|
||||
name)
|
||||
.span_label(self.tcx.span_of_impl(item1).unwrap(),
|
||||
&format!("duplicate definitions for `{}`", name))
|
||||
.span_label(self.tcx.span_of_impl(item2).unwrap(),
|
||||
&format!("other definition for `{}`", name))
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -472,7 +472,7 @@ fn pop_internal<K, V>(starting_bucket: FullBucketMut<K, V>)
|
||||
}
|
||||
|
||||
// Now we've done all our shifting. Return the value we grabbed earlier.
|
||||
(retkey, retval, gap.into_bucket().into_table())
|
||||
(retkey, retval, gap.into_table())
|
||||
}
|
||||
|
||||
/// Perform robin hood bucket stealing at the given `bucket`. You must
|
||||
@ -485,14 +485,14 @@ fn robin_hood<'a, K: 'a, V: 'a>(bucket: FullBucketMut<'a, K, V>,
|
||||
mut key: K,
|
||||
mut val: V)
|
||||
-> FullBucketMut<'a, K, V> {
|
||||
let start_index = bucket.index();
|
||||
let size = bucket.table().size();
|
||||
// Save the *starting point*.
|
||||
let mut bucket = bucket.stash();
|
||||
let raw_capacity = bucket.table().capacity();
|
||||
// There can be at most `size - dib` buckets to displace, because
|
||||
// in the worst case, there are `size` elements and we already are
|
||||
// `displacement` buckets away from the initial one.
|
||||
let idx_end = start_index + size - bucket.displacement();
|
||||
let idx_end = (bucket.index() + size - bucket.displacement()) % raw_capacity;
|
||||
// Save the *starting point*.
|
||||
let mut bucket = bucket.stash();
|
||||
|
||||
loop {
|
||||
let (old_hash, old_key, old_val) = bucket.replace(hash, key, val);
|
||||
@ -568,11 +568,8 @@ fn search_mut<'a, Q: ?Sized>(&'a mut self, q: &Q) -> InternalEntry<K, V, &'a mut
|
||||
// The caller should ensure that invariants by Robin Hood Hashing hold
|
||||
// and that there's space in the underlying table.
|
||||
fn insert_hashed_ordered(&mut self, hash: SafeHash, k: K, v: V) {
|
||||
let raw_cap = self.raw_capacity();
|
||||
let mut buckets = Bucket::new(&mut self.table, hash);
|
||||
// note that buckets.index() keeps increasing
|
||||
// even if the pointer wraps back to the first bucket.
|
||||
let limit_bucket = buckets.index() + raw_cap;
|
||||
let start_index = buckets.index();
|
||||
|
||||
loop {
|
||||
// We don't need to compare hashes for value swap.
|
||||
@ -585,7 +582,7 @@ fn insert_hashed_ordered(&mut self, hash: SafeHash, k: K, v: V) {
|
||||
Full(b) => b.into_bucket(),
|
||||
};
|
||||
buckets.next();
|
||||
debug_assert!(buckets.index() < limit_bucket);
|
||||
debug_assert!(buckets.index() != start_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1244,24 +1241,25 @@ pub fn remove<Q: ?Sized>(&mut self, k: &Q) -> Option<V>
|
||||
pub fn retain<F>(&mut self, mut f: F)
|
||||
where F: FnMut(&K, &mut V) -> bool
|
||||
{
|
||||
if self.table.capacity() == 0 || self.table.size() == 0 {
|
||||
if self.table.size() == 0 {
|
||||
return;
|
||||
}
|
||||
let mut elems_left = self.table.size();
|
||||
let mut bucket = Bucket::head_bucket(&mut self.table);
|
||||
bucket.prev();
|
||||
let tail = bucket.index();
|
||||
loop {
|
||||
let start_index = bucket.index();
|
||||
while elems_left != 0 {
|
||||
bucket = match bucket.peek() {
|
||||
Full(mut full) => {
|
||||
elems_left -= 1;
|
||||
let should_remove = {
|
||||
let (k, v) = full.read_mut();
|
||||
!f(k, v)
|
||||
};
|
||||
if should_remove {
|
||||
let prev_idx = full.index();
|
||||
let prev_raw = full.raw();
|
||||
let (_, _, t) = pop_internal(full);
|
||||
Bucket::new_from(prev_raw, prev_idx, t)
|
||||
Bucket::new_from(prev_raw, t)
|
||||
} else {
|
||||
full.into_bucket()
|
||||
}
|
||||
@ -1271,9 +1269,7 @@ pub fn retain<F>(&mut self, mut f: F)
|
||||
}
|
||||
};
|
||||
bucket.prev(); // reverse iteration
|
||||
if bucket.index() == tail {
|
||||
break;
|
||||
}
|
||||
debug_assert!(elems_left == 0 || bucket.index() != start_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -113,7 +113,7 @@ fn ptr(&self) -> *mut HashUint {
|
||||
/// when the RawTable is created and is accessible with the `tag` and `set_tag`
|
||||
/// functions.
|
||||
pub struct RawTable<K, V> {
|
||||
capacity: usize,
|
||||
capacity_mask: usize,
|
||||
size: usize,
|
||||
hashes: TaggedHashUintPtr,
|
||||
|
||||
@ -125,10 +125,13 @@ pub struct RawTable<K, V> {
|
||||
unsafe impl<K: Send, V: Send> Send for RawTable<K, V> {}
|
||||
unsafe impl<K: Sync, V: Sync> Sync for RawTable<K, V> {}
|
||||
|
||||
// An unsafe view of a RawTable bucket
|
||||
// Valid indexes are within [0..table_capacity)
|
||||
pub struct RawBucket<K, V> {
|
||||
hash: *mut HashUint,
|
||||
hash_start: *mut HashUint,
|
||||
// We use *const to ensure covariance with respect to K and V
|
||||
pair: *const (K, V),
|
||||
pair_start: *const (K, V),
|
||||
idx: usize,
|
||||
_marker: marker::PhantomData<(K, V)>,
|
||||
}
|
||||
|
||||
@ -141,7 +144,6 @@ fn clone(&self) -> RawBucket<K, V> {
|
||||
|
||||
pub struct Bucket<K, V, M> {
|
||||
raw: RawBucket<K, V>,
|
||||
idx: usize,
|
||||
table: M,
|
||||
}
|
||||
|
||||
@ -154,13 +156,11 @@ fn clone(&self) -> Bucket<K, V, M> {
|
||||
|
||||
pub struct EmptyBucket<K, V, M> {
|
||||
raw: RawBucket<K, V>,
|
||||
idx: usize,
|
||||
table: M,
|
||||
}
|
||||
|
||||
pub struct FullBucket<K, V, M> {
|
||||
raw: RawBucket<K, V>,
|
||||
idx: usize,
|
||||
table: M,
|
||||
}
|
||||
|
||||
@ -232,13 +232,17 @@ fn can_alias_safehash_as_hash() {
|
||||
assert_eq!(size_of::<SafeHash>(), size_of::<HashUint>())
|
||||
}
|
||||
|
||||
// RawBucket methods are unsafe as it's possible to
|
||||
// make a RawBucket point to invalid memory using safe code.
|
||||
impl<K, V> RawBucket<K, V> {
|
||||
unsafe fn offset(self, count: isize) -> RawBucket<K, V> {
|
||||
RawBucket {
|
||||
hash: self.hash.offset(count),
|
||||
pair: self.pair.offset(count),
|
||||
_marker: marker::PhantomData,
|
||||
}
|
||||
unsafe fn hash(&self) -> *mut HashUint {
|
||||
self.hash_start.offset(self.idx as isize)
|
||||
}
|
||||
unsafe fn pair(&self) -> *mut (K, V) {
|
||||
self.pair_start.offset(self.idx as isize) as *mut (K, V)
|
||||
}
|
||||
unsafe fn hash_pair(&self) -> (*mut HashUint, *mut (K, V)) {
|
||||
(self.hash(), self.pair())
|
||||
}
|
||||
}
|
||||
|
||||
@ -258,7 +262,7 @@ pub fn into_table(self) -> M {
|
||||
}
|
||||
/// Get the raw index.
|
||||
pub fn index(&self) -> usize {
|
||||
self.idx
|
||||
self.raw.idx
|
||||
}
|
||||
/// Get the raw bucket.
|
||||
pub fn raw(&self) -> RawBucket<K, V> {
|
||||
@ -280,7 +284,7 @@ pub fn table_mut(&mut self) -> &mut M {
|
||||
impl<K, V, M> Bucket<K, V, M> {
|
||||
/// Get the raw index.
|
||||
pub fn index(&self) -> usize {
|
||||
self.idx
|
||||
self.raw.idx
|
||||
}
|
||||
/// get the table.
|
||||
pub fn into_table(self) -> M {
|
||||
@ -331,12 +335,11 @@ pub fn new(table: M, hash: SafeHash) -> Bucket<K, V, M> {
|
||||
Bucket::at_index(table, hash.inspect() as usize)
|
||||
}
|
||||
|
||||
pub fn new_from(r: RawBucket<K, V>, i: usize, t: M)
|
||||
pub fn new_from(r: RawBucket<K, V>, t: M)
|
||||
-> Bucket<K, V, M>
|
||||
{
|
||||
Bucket {
|
||||
raw: r,
|
||||
idx: i,
|
||||
table: t,
|
||||
}
|
||||
}
|
||||
@ -346,18 +349,16 @@ pub fn at_index(table: M, ib_index: usize) -> Bucket<K, V, M> {
|
||||
// This is an uncommon case though, so avoid it in release builds.
|
||||
debug_assert!(table.capacity() > 0,
|
||||
"Table should have capacity at this point");
|
||||
let ib_index = ib_index & (table.capacity() - 1);
|
||||
let ib_index = ib_index & table.capacity_mask;
|
||||
Bucket {
|
||||
raw: unsafe { table.first_bucket_raw().offset(ib_index as isize) },
|
||||
idx: ib_index,
|
||||
raw: table.raw_bucket_at(ib_index),
|
||||
table: table,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn first(table: M) -> Bucket<K, V, M> {
|
||||
Bucket {
|
||||
raw: table.first_bucket_raw(),
|
||||
idx: 0,
|
||||
raw: table.raw_bucket_at(0),
|
||||
table: table,
|
||||
}
|
||||
}
|
||||
@ -401,48 +402,30 @@ pub fn head_bucket(table: M) -> Bucket<K, V, M> {
|
||||
/// the appropriate types to call most of the other functions in
|
||||
/// this module.
|
||||
pub fn peek(self) -> BucketState<K, V, M> {
|
||||
match unsafe { *self.raw.hash } {
|
||||
match unsafe { *self.raw.hash() } {
|
||||
EMPTY_BUCKET => {
|
||||
Empty(EmptyBucket {
|
||||
raw: self.raw,
|
||||
idx: self.idx,
|
||||
table: self.table,
|
||||
})
|
||||
}
|
||||
_ => {
|
||||
Full(FullBucket {
|
||||
raw: self.raw,
|
||||
idx: self.idx,
|
||||
table: self.table,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Modifies the bucket pointer in place to make it point to the next slot.
|
||||
/// Modifies the bucket in place to make it point to the next slot.
|
||||
pub fn next(&mut self) {
|
||||
self.idx += 1;
|
||||
let range = self.table.capacity();
|
||||
// This code is branchless thanks to a conditional move.
|
||||
let dist = if self.idx & (range - 1) == 0 {
|
||||
1 - range as isize
|
||||
} else {
|
||||
1
|
||||
};
|
||||
unsafe {
|
||||
self.raw = self.raw.offset(dist);
|
||||
}
|
||||
self.raw.idx = self.raw.idx.wrapping_add(1) & self.table.capacity_mask;
|
||||
}
|
||||
|
||||
/// Modifies the bucket pointer in place to make it point to the previous slot.
|
||||
/// Modifies the bucket in place to make it point to the previous slot.
|
||||
pub fn prev(&mut self) {
|
||||
let range = self.table.capacity();
|
||||
let new_idx = self.idx.wrapping_sub(1) & (range - 1);
|
||||
let dist = (new_idx as isize).wrapping_sub(self.idx as isize);
|
||||
self.idx = new_idx;
|
||||
unsafe {
|
||||
self.raw = self.raw.offset(dist);
|
||||
}
|
||||
self.raw.idx = self.raw.idx.wrapping_sub(1) & self.table.capacity_mask;
|
||||
}
|
||||
}
|
||||
|
||||
@ -458,7 +441,6 @@ pub fn next(self) -> Bucket<K, V, M> {
|
||||
pub fn into_bucket(self) -> Bucket<K, V, M> {
|
||||
Bucket {
|
||||
raw: self.raw,
|
||||
idx: self.idx,
|
||||
table: self.table,
|
||||
}
|
||||
}
|
||||
@ -466,7 +448,6 @@ pub fn into_bucket(self) -> Bucket<K, V, M> {
|
||||
pub fn gap_peek(self) -> Result<GapThenFull<K, V, M>, Bucket<K, V, M>> {
|
||||
let gap = EmptyBucket {
|
||||
raw: self.raw,
|
||||
idx: self.idx,
|
||||
table: (),
|
||||
};
|
||||
|
||||
@ -494,15 +475,14 @@ impl<K, V, M> EmptyBucket<K, V, M>
|
||||
/// Use `make_hash` to construct a `SafeHash` to pass to this function.
|
||||
pub fn put(mut self, hash: SafeHash, key: K, value: V) -> FullBucket<K, V, M> {
|
||||
unsafe {
|
||||
*self.raw.hash = hash.inspect();
|
||||
ptr::write(self.raw.pair as *mut (K, V), (key, value));
|
||||
*self.raw.hash() = hash.inspect();
|
||||
ptr::write(self.raw.pair(), (key, value));
|
||||
|
||||
self.table.borrow_table_mut().size += 1;
|
||||
}
|
||||
|
||||
FullBucket {
|
||||
raw: self.raw,
|
||||
idx: self.idx,
|
||||
table: self.table,
|
||||
}
|
||||
}
|
||||
@ -510,15 +490,14 @@ pub fn put(mut self, hash: SafeHash, key: K, value: V) -> FullBucket<K, V, M> {
|
||||
/// Puts given key, remain value uninitialized.
|
||||
/// It is only used for inplacement insertion.
|
||||
pub unsafe fn put_key(mut self, hash: SafeHash, key: K) -> FullBucket<K, V, M> {
|
||||
*self.raw.hash = hash.inspect();
|
||||
let pair_mut = self.raw.pair as *mut (K, V);
|
||||
ptr::write(&mut (*pair_mut).0, key);
|
||||
*self.raw.hash() = hash.inspect();
|
||||
let pair_ptr = self.raw.pair();
|
||||
ptr::write(&mut (*pair_ptr).0, key);
|
||||
|
||||
self.table.borrow_table_mut().size += 1;
|
||||
|
||||
FullBucket {
|
||||
raw: self.raw,
|
||||
idx: self.idx,
|
||||
table: self.table,
|
||||
}
|
||||
}
|
||||
@ -536,7 +515,6 @@ pub fn next(self) -> Bucket<K, V, M> {
|
||||
pub fn into_bucket(self) -> Bucket<K, V, M> {
|
||||
Bucket {
|
||||
raw: self.raw,
|
||||
idx: self.idx,
|
||||
table: self.table,
|
||||
}
|
||||
}
|
||||
@ -546,7 +524,6 @@ pub fn into_bucket(self) -> Bucket<K, V, M> {
|
||||
pub fn stash(self) -> FullBucket<K, V, Self> {
|
||||
FullBucket {
|
||||
raw: self.raw,
|
||||
idx: self.idx,
|
||||
table: self,
|
||||
}
|
||||
}
|
||||
@ -560,17 +537,20 @@ pub fn displacement(&self) -> usize {
|
||||
// Calculates the distance one has to travel when going from
|
||||
// `hash mod capacity` onwards to `idx mod capacity`, wrapping around
|
||||
// if the destination is not reached before the end of the table.
|
||||
(self.idx.wrapping_sub(self.hash().inspect() as usize)) & (self.table.capacity() - 1)
|
||||
(self.raw.idx.wrapping_sub(self.hash().inspect() as usize)) & self.table.capacity_mask
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn hash(&self) -> SafeHash {
|
||||
unsafe { SafeHash { hash: *self.raw.hash } }
|
||||
unsafe { SafeHash { hash: *self.raw.hash() } }
|
||||
}
|
||||
|
||||
/// Gets references to the key and value at a given index.
|
||||
pub fn read(&self) -> (&K, &V) {
|
||||
unsafe { (&(*self.raw.pair).0, &(*self.raw.pair).1) }
|
||||
unsafe {
|
||||
let pair_ptr = self.raw.pair();
|
||||
(&(*pair_ptr).0, &(*pair_ptr).1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -586,11 +566,10 @@ pub fn take(mut self) -> (EmptyBucket<K, V, &'t mut RawTable<K, V>>, K, V) {
|
||||
self.table.size -= 1;
|
||||
|
||||
unsafe {
|
||||
*self.raw.hash = EMPTY_BUCKET;
|
||||
let (k, v) = ptr::read(self.raw.pair);
|
||||
*self.raw.hash() = EMPTY_BUCKET;
|
||||
let (k, v) = ptr::read(self.raw.pair());
|
||||
(EmptyBucket {
|
||||
raw: self.raw,
|
||||
idx: self.idx,
|
||||
table: self.table,
|
||||
},
|
||||
k,
|
||||
@ -604,9 +583,9 @@ pub fn take(mut self) -> (EmptyBucket<K, V, &'t mut RawTable<K, V>>, K, V) {
|
||||
pub unsafe fn remove_key(&mut self) {
|
||||
self.table.size -= 1;
|
||||
|
||||
*self.raw.hash = EMPTY_BUCKET;
|
||||
let pair_mut = self.raw.pair as *mut (K, V);
|
||||
ptr::drop_in_place(&mut (*pair_mut).0); // only drop key
|
||||
*self.raw.hash() = EMPTY_BUCKET;
|
||||
let pair_ptr = self.raw.pair();
|
||||
ptr::drop_in_place(&mut (*pair_ptr).0); // only drop key
|
||||
}
|
||||
}
|
||||
|
||||
@ -617,8 +596,8 @@ impl<K, V, M> FullBucket<K, V, M>
|
||||
{
|
||||
pub fn replace(&mut self, h: SafeHash, k: K, v: V) -> (SafeHash, K, V) {
|
||||
unsafe {
|
||||
let old_hash = ptr::replace(self.raw.hash as *mut SafeHash, h);
|
||||
let (old_key, old_val) = ptr::replace(self.raw.pair as *mut (K, V), (k, v));
|
||||
let old_hash = ptr::replace(self.raw.hash() as *mut SafeHash, h);
|
||||
let (old_key, old_val) = ptr::replace(self.raw.pair(), (k, v));
|
||||
|
||||
(old_hash, old_key, old_val)
|
||||
}
|
||||
@ -630,8 +609,10 @@ impl<K, V, M> FullBucket<K, V, M>
|
||||
{
|
||||
/// Gets mutable references to the key and value at a given index.
|
||||
pub fn read_mut(&mut self) -> (&mut K, &mut V) {
|
||||
let pair_mut = self.raw.pair as *mut (K, V);
|
||||
unsafe { (&mut (*pair_mut).0, &mut (*pair_mut).1) }
|
||||
unsafe {
|
||||
let pair_ptr = self.raw.pair();
|
||||
(&mut (*pair_ptr).0, &mut (*pair_ptr).1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -644,7 +625,10 @@ impl<'t, K, V, M> FullBucket<K, V, M>
|
||||
/// in exchange for this, the returned references have a longer lifetime
|
||||
/// than the references returned by `read()`.
|
||||
pub fn into_refs(self) -> (&'t K, &'t V) {
|
||||
unsafe { (&(*self.raw.pair).0, &(*self.raw.pair).1) }
|
||||
unsafe {
|
||||
let pair_ptr = self.raw.pair();
|
||||
(&(*pair_ptr).0, &(*pair_ptr).1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -654,8 +638,10 @@ impl<'t, K, V, M> FullBucket<K, V, M>
|
||||
/// This works similarly to `into_refs`, exchanging a bucket state
|
||||
/// for mutable references into the table.
|
||||
pub fn into_mut_refs(self) -> (&'t mut K, &'t mut V) {
|
||||
let pair_mut = self.raw.pair as *mut (K, V);
|
||||
unsafe { (&mut (*pair_mut).0, &mut (*pair_mut).1) }
|
||||
unsafe {
|
||||
let pair_ptr = self.raw.pair();
|
||||
(&mut (*pair_ptr).0, &mut (*pair_ptr).1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -667,22 +653,23 @@ pub fn full(&self) -> &FullBucket<K, V, M> {
|
||||
&self.full
|
||||
}
|
||||
|
||||
pub fn into_bucket(self) -> Bucket<K, V, M> {
|
||||
self.full.into_bucket()
|
||||
pub fn into_table(self) -> M {
|
||||
self.full.into_table()
|
||||
}
|
||||
|
||||
pub fn shift(mut self) -> Result<GapThenFull<K, V, M>, Bucket<K, V, M>> {
|
||||
unsafe {
|
||||
*self.gap.raw.hash = mem::replace(&mut *self.full.raw.hash, EMPTY_BUCKET);
|
||||
ptr::copy_nonoverlapping(self.full.raw.pair, self.gap.raw.pair as *mut (K, V), 1);
|
||||
let (gap_hash, gap_pair) = self.gap.raw.hash_pair();
|
||||
let (full_hash, full_pair) = self.full.raw.hash_pair();
|
||||
*gap_hash = mem::replace(&mut *full_hash, EMPTY_BUCKET);
|
||||
ptr::copy_nonoverlapping(full_pair, gap_pair, 1);
|
||||
}
|
||||
|
||||
let FullBucket { raw: prev_raw, idx: prev_idx, .. } = self.full;
|
||||
let FullBucket { raw: prev_raw, .. } = self.full;
|
||||
|
||||
match self.full.next().peek() {
|
||||
Full(bucket) => {
|
||||
self.gap.raw = prev_raw;
|
||||
self.gap.idx = prev_idx;
|
||||
|
||||
self.full = bucket;
|
||||
|
||||
@ -761,7 +748,7 @@ unsafe fn new_uninitialized(capacity: usize) -> RawTable<K, V> {
|
||||
if capacity == 0 {
|
||||
return RawTable {
|
||||
size: 0,
|
||||
capacity: 0,
|
||||
capacity_mask: capacity.wrapping_sub(1),
|
||||
hashes: TaggedHashUintPtr::new(EMPTY as *mut HashUint),
|
||||
marker: marker::PhantomData,
|
||||
};
|
||||
@ -801,25 +788,27 @@ unsafe fn new_uninitialized(capacity: usize) -> RawTable<K, V> {
|
||||
let hashes = buffer.offset(hash_offset as isize) as *mut HashUint;
|
||||
|
||||
RawTable {
|
||||
capacity: capacity,
|
||||
capacity_mask: capacity.wrapping_sub(1),
|
||||
size: 0,
|
||||
hashes: TaggedHashUintPtr::new(hashes),
|
||||
marker: marker::PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
fn first_bucket_raw(&self) -> RawBucket<K, V> {
|
||||
let hashes_size = self.capacity * size_of::<HashUint>();
|
||||
let pairs_size = self.capacity * size_of::<(K, V)>();
|
||||
fn raw_bucket_at(&self, index: usize) -> RawBucket<K, V> {
|
||||
let hashes_size = self.capacity() * size_of::<HashUint>();
|
||||
let pairs_size = self.capacity() * size_of::<(K, V)>();
|
||||
|
||||
let buffer = self.hashes.ptr() as *mut u8;
|
||||
let (pairs_offset, _, oflo) =
|
||||
calculate_offsets(hashes_size, pairs_size, align_of::<(K, V)>());
|
||||
debug_assert!(!oflo, "capacity overflow");
|
||||
|
||||
let buffer = self.hashes.ptr() as *mut u8;
|
||||
unsafe {
|
||||
RawBucket {
|
||||
hash: self.hashes.ptr(),
|
||||
pair: buffer.offset(pairs_offset as isize) as *const _,
|
||||
hash_start: buffer as *mut HashUint,
|
||||
pair_start: buffer.offset(pairs_offset as isize) as *const (K, V),
|
||||
idx: index,
|
||||
_marker: marker::PhantomData,
|
||||
}
|
||||
}
|
||||
@ -837,7 +826,7 @@ pub fn new(capacity: usize) -> RawTable<K, V> {
|
||||
|
||||
/// The hashtable's capacity, similar to a vector's.
|
||||
pub fn capacity(&self) -> usize {
|
||||
self.capacity
|
||||
self.capacity_mask.wrapping_add(1)
|
||||
}
|
||||
|
||||
/// The number of elements ever `put` in the hashtable, minus the number
|
||||
@ -848,8 +837,8 @@ pub fn size(&self) -> usize {
|
||||
|
||||
fn raw_buckets(&self) -> RawBuckets<K, V> {
|
||||
RawBuckets {
|
||||
raw: self.first_bucket_raw(),
|
||||
hashes_end: unsafe { self.hashes.ptr().offset(self.capacity as isize) },
|
||||
raw: self.raw_bucket_at(0),
|
||||
elems_left: self.size,
|
||||
marker: marker::PhantomData,
|
||||
}
|
||||
}
|
||||
@ -857,25 +846,23 @@ fn raw_buckets(&self) -> RawBuckets<K, V> {
|
||||
pub fn iter(&self) -> Iter<K, V> {
|
||||
Iter {
|
||||
iter: self.raw_buckets(),
|
||||
elems_left: self.size(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter_mut(&mut self) -> IterMut<K, V> {
|
||||
IterMut {
|
||||
iter: self.raw_buckets(),
|
||||
elems_left: self.size(),
|
||||
_marker: marker::PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_iter(self) -> IntoIter<K, V> {
|
||||
let RawBuckets { raw, hashes_end, .. } = self.raw_buckets();
|
||||
let RawBuckets { raw, elems_left, .. } = self.raw_buckets();
|
||||
// Replace the marker regardless of lifetime bounds on parameters.
|
||||
IntoIter {
|
||||
iter: RawBuckets {
|
||||
raw: raw,
|
||||
hashes_end: hashes_end,
|
||||
elems_left: elems_left,
|
||||
marker: marker::PhantomData,
|
||||
},
|
||||
table: self,
|
||||
@ -883,12 +870,12 @@ pub fn into_iter(self) -> IntoIter<K, V> {
|
||||
}
|
||||
|
||||
pub fn drain(&mut self) -> Drain<K, V> {
|
||||
let RawBuckets { raw, hashes_end, .. } = self.raw_buckets();
|
||||
let RawBuckets { raw, elems_left, .. } = self.raw_buckets();
|
||||
// Replace the marker regardless of lifetime bounds on parameters.
|
||||
Drain {
|
||||
iter: RawBuckets {
|
||||
raw: raw,
|
||||
hashes_end: hashes_end,
|
||||
elems_left: elems_left,
|
||||
marker: marker::PhantomData,
|
||||
},
|
||||
table: unsafe { Shared::new(self) },
|
||||
@ -900,18 +887,16 @@ pub fn drain(&mut self) -> Drain<K, V> {
|
||||
/// state and should only be used for dropping the table's remaining
|
||||
/// entries. It's used in the implementation of Drop.
|
||||
unsafe fn rev_drop_buckets(&mut self) {
|
||||
let first_raw = self.first_bucket_raw();
|
||||
let mut raw = first_raw.offset(self.capacity as isize);
|
||||
// initialize the raw bucket past the end of the table
|
||||
let mut raw = self.raw_bucket_at(self.capacity());
|
||||
let mut elems_left = self.size;
|
||||
|
||||
while elems_left != 0 {
|
||||
debug_assert!(raw.hash != first_raw.hash);
|
||||
raw.idx -= 1;
|
||||
|
||||
raw = raw.offset(-1);
|
||||
|
||||
if *raw.hash != EMPTY_BUCKET {
|
||||
if *raw.hash() != EMPTY_BUCKET {
|
||||
elems_left -= 1;
|
||||
ptr::drop_in_place(raw.pair as *mut (K, V));
|
||||
ptr::drop_in_place(raw.pair());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -931,7 +916,7 @@ pub fn tag(&self) -> bool {
|
||||
/// this interface is safe, it's not used outside this module.
|
||||
struct RawBuckets<'a, K, V> {
|
||||
raw: RawBucket<K, V>,
|
||||
hashes_end: *mut HashUint,
|
||||
elems_left: usize,
|
||||
|
||||
// Strictly speaking, this should be &'a (K,V), but that would
|
||||
// require that K:'a, and we often use RawBuckets<'static...> for
|
||||
@ -946,7 +931,7 @@ impl<'a, K, V> Clone for RawBuckets<'a, K, V> {
|
||||
fn clone(&self) -> RawBuckets<'a, K, V> {
|
||||
RawBuckets {
|
||||
raw: self.raw,
|
||||
hashes_end: self.hashes_end,
|
||||
elems_left: self.elems_left,
|
||||
marker: marker::PhantomData,
|
||||
}
|
||||
}
|
||||
@ -957,25 +942,36 @@ impl<'a, K, V> Iterator for RawBuckets<'a, K, V> {
|
||||
type Item = RawBucket<K, V>;
|
||||
|
||||
fn next(&mut self) -> Option<RawBucket<K, V>> {
|
||||
while self.raw.hash != self.hashes_end {
|
||||
if self.elems_left == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
loop {
|
||||
unsafe {
|
||||
// We are swapping out the pointer to a bucket and replacing
|
||||
// it with the pointer to the next one.
|
||||
let prev = ptr::replace(&mut self.raw, self.raw.offset(1));
|
||||
if *prev.hash != EMPTY_BUCKET {
|
||||
return Some(prev);
|
||||
let item = self.raw;
|
||||
self.raw.idx += 1;
|
||||
if *item.hash() != EMPTY_BUCKET {
|
||||
self.elems_left -= 1;
|
||||
return Some(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
(self.elems_left, Some(self.elems_left))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V> ExactSizeIterator for RawBuckets<'a, K, V> {
|
||||
fn len(&self) -> usize {
|
||||
self.elems_left
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterator over shared references to entries in a table.
|
||||
pub struct Iter<'a, K: 'a, V: 'a> {
|
||||
iter: RawBuckets<'a, K, V>,
|
||||
elems_left: usize,
|
||||
}
|
||||
|
||||
unsafe impl<'a, K: Sync, V: Sync> Sync for Iter<'a, K, V> {}
|
||||
@ -986,16 +982,13 @@ impl<'a, K, V> Clone for Iter<'a, K, V> {
|
||||
fn clone(&self) -> Iter<'a, K, V> {
|
||||
Iter {
|
||||
iter: self.iter.clone(),
|
||||
elems_left: self.elems_left,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Iterator over mutable references to entries in a table.
|
||||
pub struct IterMut<'a, K: 'a, V: 'a> {
|
||||
iter: RawBuckets<'a, K, V>,
|
||||
elems_left: usize,
|
||||
// To ensure invariance with respect to V
|
||||
_marker: marker::PhantomData<&'a mut V>,
|
||||
}
|
||||
@ -1009,7 +1002,6 @@ impl<'a, K: 'a, V: 'a> IterMut<'a, K, V> {
|
||||
pub fn iter(&self) -> Iter<K, V> {
|
||||
Iter {
|
||||
iter: self.iter.clone(),
|
||||
elems_left: self.elems_left,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1027,7 +1019,6 @@ impl<K, V> IntoIter<K, V> {
|
||||
pub fn iter(&self) -> Iter<K, V> {
|
||||
Iter {
|
||||
iter: self.iter.clone(),
|
||||
elems_left: self.table.size,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1044,11 +1035,8 @@ unsafe impl<'a, K: Send, V: Send> Send for Drain<'a, K, V> {}
|
||||
|
||||
impl<'a, K, V> Drain<'a, K, V> {
|
||||
pub fn iter(&self) -> Iter<K, V> {
|
||||
unsafe {
|
||||
Iter {
|
||||
iter: self.iter.clone(),
|
||||
elems_left: (**self.table).size,
|
||||
}
|
||||
Iter {
|
||||
iter: self.iter.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1057,19 +1045,20 @@ impl<'a, K, V> Iterator for Iter<'a, K, V> {
|
||||
type Item = (&'a K, &'a V);
|
||||
|
||||
fn next(&mut self) -> Option<(&'a K, &'a V)> {
|
||||
self.iter.next().map(|bucket| {
|
||||
self.elems_left -= 1;
|
||||
unsafe { (&(*bucket.pair).0, &(*bucket.pair).1) }
|
||||
self.iter.next().map(|raw| unsafe {
|
||||
let pair_ptr = raw.pair();
|
||||
(&(*pair_ptr).0, &(*pair_ptr).1)
|
||||
})
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
(self.elems_left, Some(self.elems_left))
|
||||
self.iter.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V> ExactSizeIterator for Iter<'a, K, V> {
|
||||
fn len(&self) -> usize {
|
||||
self.elems_left
|
||||
self.iter.len()
|
||||
}
|
||||
}
|
||||
|
||||
@ -1077,20 +1066,20 @@ impl<'a, K, V> Iterator for IterMut<'a, K, V> {
|
||||
type Item = (&'a K, &'a mut V);
|
||||
|
||||
fn next(&mut self) -> Option<(&'a K, &'a mut V)> {
|
||||
self.iter.next().map(|bucket| {
|
||||
self.elems_left -= 1;
|
||||
let pair_mut = bucket.pair as *mut (K, V);
|
||||
unsafe { (&(*pair_mut).0, &mut (*pair_mut).1) }
|
||||
self.iter.next().map(|raw| unsafe {
|
||||
let pair_ptr = raw.pair();
|
||||
(&(*pair_ptr).0, &mut (*pair_ptr).1)
|
||||
})
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
(self.elems_left, Some(self.elems_left))
|
||||
self.iter.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V> ExactSizeIterator for IterMut<'a, K, V> {
|
||||
fn len(&self) -> usize {
|
||||
self.elems_left
|
||||
self.iter.len()
|
||||
}
|
||||
}
|
||||
|
||||
@ -1098,23 +1087,23 @@ impl<K, V> Iterator for IntoIter<K, V> {
|
||||
type Item = (SafeHash, K, V);
|
||||
|
||||
fn next(&mut self) -> Option<(SafeHash, K, V)> {
|
||||
self.iter.next().map(|bucket| {
|
||||
self.iter.next().map(|raw| {
|
||||
self.table.size -= 1;
|
||||
unsafe {
|
||||
let (k, v) = ptr::read(bucket.pair);
|
||||
(SafeHash { hash: *bucket.hash }, k, v)
|
||||
let (k, v) = ptr::read(raw.pair());
|
||||
(SafeHash { hash: *raw.hash() }, k, v)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let size = self.table.size();
|
||||
(size, Some(size))
|
||||
self.iter.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> ExactSizeIterator for IntoIter<K, V> {
|
||||
fn len(&self) -> usize {
|
||||
self.table.size()
|
||||
self.iter().len()
|
||||
}
|
||||
}
|
||||
|
||||
@ -1123,23 +1112,21 @@ impl<'a, K, V> Iterator for Drain<'a, K, V> {
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<(SafeHash, K, V)> {
|
||||
self.iter.next().map(|bucket| {
|
||||
unsafe {
|
||||
(*self.table.as_mut_ptr()).size -= 1;
|
||||
let (k, v) = ptr::read(bucket.pair);
|
||||
(SafeHash { hash: ptr::replace(bucket.hash, EMPTY_BUCKET) }, k, v)
|
||||
}
|
||||
self.iter.next().map(|raw| unsafe {
|
||||
(*self.table.as_mut_ptr()).size -= 1;
|
||||
let (k, v) = ptr::read(raw.pair());
|
||||
(SafeHash { hash: ptr::replace(&mut *raw.hash(), EMPTY_BUCKET) }, k, v)
|
||||
})
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let size = unsafe { (**self.table).size() };
|
||||
(size, Some(size))
|
||||
self.iter.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V> ExactSizeIterator for Drain<'a, K, V> {
|
||||
fn len(&self) -> usize {
|
||||
unsafe { (**self.table).size() }
|
||||
self.iter.len()
|
||||
}
|
||||
}
|
||||
|
||||
@ -1152,30 +1139,21 @@ fn drop(&mut self) {
|
||||
impl<K: Clone, V: Clone> Clone for RawTable<K, V> {
|
||||
fn clone(&self) -> RawTable<K, V> {
|
||||
unsafe {
|
||||
let mut new_ht = RawTable::new_uninitialized(self.capacity());
|
||||
let cap = self.capacity();
|
||||
let mut new_ht = RawTable::new_uninitialized(cap);
|
||||
|
||||
{
|
||||
let cap = self.capacity();
|
||||
let mut new_buckets = Bucket::first(&mut new_ht);
|
||||
let mut buckets = Bucket::first(self);
|
||||
while buckets.index() != cap {
|
||||
match buckets.peek() {
|
||||
Full(full) => {
|
||||
let (h, k, v) = {
|
||||
let (k, v) = full.read();
|
||||
(full.hash(), k.clone(), v.clone())
|
||||
};
|
||||
*new_buckets.raw.hash = h.inspect();
|
||||
ptr::write(new_buckets.raw.pair as *mut (K, V), (k, v));
|
||||
}
|
||||
Empty(..) => {
|
||||
*new_buckets.raw.hash = EMPTY_BUCKET;
|
||||
}
|
||||
}
|
||||
new_buckets.next();
|
||||
buckets.next();
|
||||
let mut new_buckets = new_ht.raw_bucket_at(0);
|
||||
let mut buckets = self.raw_bucket_at(0);
|
||||
while buckets.idx < cap {
|
||||
*new_buckets.hash() = *buckets.hash();
|
||||
if *new_buckets.hash() != EMPTY_BUCKET {
|
||||
let pair_ptr = buckets.pair();
|
||||
let kv = ((*pair_ptr).0.clone(), (*pair_ptr).1.clone());
|
||||
ptr::write(new_buckets.pair(), kv);
|
||||
}
|
||||
};
|
||||
buckets.idx += 1;
|
||||
new_buckets.idx += 1;
|
||||
}
|
||||
|
||||
new_ht.size = self.size();
|
||||
|
||||
@ -1186,7 +1164,7 @@ fn clone(&self) -> RawTable<K, V> {
|
||||
|
||||
unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable<K, V> {
|
||||
fn drop(&mut self) {
|
||||
if self.capacity == 0 {
|
||||
if self.capacity() == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1202,8 +1180,8 @@ fn drop(&mut self) {
|
||||
}
|
||||
}
|
||||
|
||||
let hashes_size = self.capacity * size_of::<HashUint>();
|
||||
let pairs_size = self.capacity * size_of::<(K, V)>();
|
||||
let hashes_size = self.capacity() * size_of::<HashUint>();
|
||||
let pairs_size = self.capacity() * size_of::<(K, V)>();
|
||||
let (align, _, size, oflo) = calculate_allocation(hashes_size,
|
||||
align_of::<HashUint>(),
|
||||
pairs_size,
|
||||
|
@ -92,7 +92,7 @@ fn oom_handler() -> ! {
|
||||
|
||||
#[cfg(not(any(target_os = "nacl", target_os = "emscripten", target_os="fuchsia")))]
|
||||
unsafe fn reset_sigpipe() {
|
||||
assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != !0);
|
||||
assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR);
|
||||
}
|
||||
#[cfg(any(target_os = "nacl", target_os = "emscripten", target_os="fuchsia"))]
|
||||
unsafe fn reset_sigpipe() {}
|
||||
|
@ -4657,25 +4657,30 @@ pub fn parse_impl_item(&mut self) -> PResult<'a, ImplItem> {
|
||||
})
|
||||
}
|
||||
|
||||
fn complain_if_pub_macro(&mut self, visa: &Visibility, span: Span) {
|
||||
match *visa {
|
||||
Visibility::Inherited => (),
|
||||
fn complain_if_pub_macro(&mut self, vis: &Visibility, sp: Span) {
|
||||
if let Err(mut err) = self.complain_if_pub_macro_diag(vis, sp) {
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
|
||||
fn complain_if_pub_macro_diag(&mut self, vis: &Visibility, sp: Span) -> PResult<'a, ()> {
|
||||
match *vis {
|
||||
Visibility::Inherited => Ok(()),
|
||||
_ => {
|
||||
let is_macro_rules: bool = match self.token {
|
||||
token::Ident(sid) => sid.name == Symbol::intern("macro_rules"),
|
||||
_ => false,
|
||||
};
|
||||
if is_macro_rules {
|
||||
self.diagnostic().struct_span_err(span, "can't qualify macro_rules \
|
||||
invocation with `pub`")
|
||||
.help("did you mean #[macro_export]?")
|
||||
.emit();
|
||||
let mut err = self.diagnostic()
|
||||
.struct_span_err(sp, "can't qualify macro_rules invocation with `pub`");
|
||||
err.help("did you mean #[macro_export]?");
|
||||
Err(err)
|
||||
} else {
|
||||
self.diagnostic().struct_span_err(span, "can't qualify macro \
|
||||
invocation with `pub`")
|
||||
.help("try adjusting the macro to put `pub` \
|
||||
inside the invocation")
|
||||
.emit();
|
||||
let mut err = self.diagnostic()
|
||||
.struct_span_err(sp, "can't qualify macro invocation with `pub`");
|
||||
err.help("try adjusting the macro to put `pub` inside the invocation");
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4686,14 +4691,36 @@ fn parse_impl_method(&mut self, vis: &Visibility)
|
||||
-> PResult<'a, (Ident, Vec<ast::Attribute>, ast::ImplItemKind)> {
|
||||
// code copied from parse_macro_use_or_failure... abstraction!
|
||||
if self.token.is_path_start() {
|
||||
// method macro.
|
||||
// Method macro.
|
||||
|
||||
let prev_span = self.prev_span;
|
||||
self.complain_if_pub_macro(&vis, prev_span);
|
||||
// Before complaining about trying to set a macro as `pub`,
|
||||
// check if `!` comes after the path.
|
||||
let err = self.complain_if_pub_macro_diag(&vis, prev_span);
|
||||
|
||||
let lo = self.span;
|
||||
let pth = self.parse_path(PathStyle::Mod)?;
|
||||
self.expect(&token::Not)?;
|
||||
let bang_err = self.expect(&token::Not);
|
||||
if let Err(mut err) = err {
|
||||
if let Err(mut bang_err) = bang_err {
|
||||
// Given this code `pub path(`, it seems like this is not setting the
|
||||
// visibility of a macro invocation, but rather a mistyped method declaration.
|
||||
// Create a diagnostic pointing out that `fn` is missing.
|
||||
//
|
||||
// x | pub path(&self) {
|
||||
// | ^ missing `fn` for method declaration
|
||||
|
||||
err.cancel();
|
||||
bang_err.cancel();
|
||||
// pub path(
|
||||
// ^^ `sp` below will point to this
|
||||
let sp = prev_span.between(self.prev_span);
|
||||
err = self.diagnostic()
|
||||
.struct_span_err(sp, "missing `fn` for method declaration");
|
||||
err.span_label(sp, &"missing `fn`");
|
||||
}
|
||||
return Err(err);
|
||||
}
|
||||
|
||||
// eat a matched-delimiter token tree:
|
||||
let (delim, tts) = self.expect_delimited_token_tree()?;
|
||||
|
@ -189,6 +189,30 @@ pub fn to(self, end: Span) -> Span {
|
||||
Span { hi: end.hi, ..self }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn between(self, end: Span) -> Span {
|
||||
Span {
|
||||
lo: self.hi,
|
||||
hi: end.lo,
|
||||
ctxt: if end.ctxt == SyntaxContext::empty() {
|
||||
end.ctxt
|
||||
} else {
|
||||
self.ctxt
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn until(self, end: Span) -> Span {
|
||||
Span {
|
||||
lo: self.lo,
|
||||
hi: end.lo,
|
||||
ctxt: if end.ctxt == SyntaxContext::empty() {
|
||||
end.ctxt
|
||||
} else {
|
||||
self.ctxt
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
@ -11,6 +11,6 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
trait C {}
|
||||
impl C { fn f() {} } //~ ERROR duplicate definitions with name `f`
|
||||
impl C { fn f() {} }
|
||||
impl C { fn f() {} }
|
||||
fn main() { }
|
@ -0,0 +1,10 @@
|
||||
error[E0592]: duplicate definitions with name `f`
|
||||
--> $DIR/coherence-overlapping-inherent-impl-trait.rs:14:10
|
||||
|
|
||||
14 | impl C { fn f() {} }
|
||||
| ^^^^^^^^^ duplicate definitions for `f`
|
||||
15 | impl C { fn f() {} }
|
||||
| --------- other definition for `f`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -16,7 +16,7 @@
|
||||
struct Foo;
|
||||
|
||||
impl Foo {
|
||||
fn id() {} //~ ERROR duplicate definitions
|
||||
fn id() {}
|
||||
}
|
||||
|
||||
impl Foo {
|
||||
@ -26,7 +26,7 @@ fn id() {}
|
||||
struct Bar<T>(T);
|
||||
|
||||
impl<T> Bar<T> {
|
||||
fn bar(&self) {} //~ ERROR duplicate definitions
|
||||
fn bar(&self) {}
|
||||
}
|
||||
|
||||
impl Bar<u32> {
|
||||
@ -36,7 +36,7 @@ fn bar(&self) {}
|
||||
struct Baz<T>(T);
|
||||
|
||||
impl<T: Copy> Baz<T> {
|
||||
fn baz(&self) {} //~ ERROR duplicate definitions
|
||||
fn baz(&self) {}
|
||||
}
|
||||
|
||||
impl<T> Baz<Vec<T>> {
|
29
src/test/ui/codemap_tests/overlapping_inherent_impls.stderr
Normal file
29
src/test/ui/codemap_tests/overlapping_inherent_impls.stderr
Normal file
@ -0,0 +1,29 @@
|
||||
error[E0592]: duplicate definitions with name `id`
|
||||
--> $DIR/overlapping_inherent_impls.rs:19:5
|
||||
|
|
||||
19 | fn id() {}
|
||||
| ^^^^^^^^^^ duplicate definitions for `id`
|
||||
...
|
||||
23 | fn id() {}
|
||||
| ---------- other definition for `id`
|
||||
|
||||
error[E0592]: duplicate definitions with name `bar`
|
||||
--> $DIR/overlapping_inherent_impls.rs:29:5
|
||||
|
|
||||
29 | fn bar(&self) {}
|
||||
| ^^^^^^^^^^^^^^^^ duplicate definitions for `bar`
|
||||
...
|
||||
33 | fn bar(&self) {}
|
||||
| ---------------- other definition for `bar`
|
||||
|
||||
error[E0592]: duplicate definitions with name `baz`
|
||||
--> $DIR/overlapping_inherent_impls.rs:39:5
|
||||
|
|
||||
39 | fn baz(&self) {}
|
||||
| ^^^^^^^^^^^^^^^^ duplicate definitions for `baz`
|
||||
...
|
||||
43 | fn baz(&self) {}
|
||||
| ---------------- other definition for `baz`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
21
src/test/ui/did_you_mean/issue-40006.rs
Normal file
21
src/test/ui/did_you_mean/issue-40006.rs
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
struct S;
|
||||
|
||||
impl S {
|
||||
pub hello_method(&self) {
|
||||
println!("Hello");
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
S.hello_method();
|
||||
}
|
8
src/test/ui/did_you_mean/issue-40006.stderr
Normal file
8
src/test/ui/did_you_mean/issue-40006.stderr
Normal file
@ -0,0 +1,8 @@
|
||||
error: missing `fn` for method declaration
|
||||
--> $DIR/issue-40006.rs:14:8
|
||||
|
|
||||
14 | pub hello_method(&self) {
|
||||
| ^ missing `fn`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
Loading…
Reference in New Issue
Block a user