diff options
| author | bors <bors@rust-lang.org> | 2015-02-19 18:36:59 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2015-02-19 18:36:59 +0000 |
| commit | 522d09dfecbeca1595f25ac58c6d0178bbd21d7d (patch) | |
| tree | cc0252dd3413e5f890d0ebcfdaa096e5b002be0b /src/libstd | |
| parent | 0b664bb8436f2cfda7f13a6f302ab486f332816f (diff) | |
| parent | 49771bafa5fca16486bfd06741dac3de2c587adf (diff) | |
| download | rust-522d09dfecbeca1595f25ac58c6d0178bbd21d7d.tar.gz rust-522d09dfecbeca1595f25ac58c6d0178bbd21d7d.zip | |
Auto merge of #22541 - Manishearth:rollup, r=Gankro 1.0.0-alpha.2
Continued from #22520
Diffstat (limited to 'src/libstd')
50 files changed, 4875 insertions, 490 deletions
diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 1b9f8b99017..ade4f1f0533 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -14,12 +14,12 @@ use self::Entry::*; use self::SearchResult::*; use self::VacantEntryState::*; -use borrow::BorrowFrom; +use borrow::Borrow; use clone::Clone; use cmp::{max, Eq, PartialEq}; use default::Default; use fmt::{self, Debug}; -use hash::{self, Hash, SipHasher}; +use hash::{Hash, SipHasher}; use iter::{self, Iterator, ExactSizeIterator, IntoIterator, IteratorExt, FromIterator, Extend, Map}; use marker::Sized; use mem::{self, replace}; @@ -440,12 +440,10 @@ impl<K, V, M> SearchResult<K, V, M> { } } -impl<K, V, S, H> HashMap<K, V, S> - where K: Eq + Hash<H>, - S: HashState<Hasher=H>, - H: hash::Hasher<Output=u64> +impl<K, V, S> HashMap<K, V, S> + where K: Eq + Hash, S: HashState { - fn make_hash<X: ?Sized>(&self, x: &X) -> SafeHash where X: Hash<H> { + fn make_hash<X: ?Sized>(&self, x: &X) -> SafeHash where X: Hash { table::make_hash(&self.hash_state, x) } @@ -453,18 +451,18 @@ impl<K, V, S, H> HashMap<K, V, S> /// If you already have the hash for the key lying around, use /// search_hashed. fn search<'a, Q: ?Sized>(&'a self, q: &Q) -> Option<FullBucketImm<'a, K, V>> - where Q: BorrowFrom<K> + Eq + Hash<H> + where K: Borrow<Q>, Q: Eq + Hash { let hash = self.make_hash(q); - search_hashed(&self.table, hash, |k| q.eq(BorrowFrom::borrow_from(k))) + search_hashed(&self.table, hash, |k| q.eq(k.borrow())) .into_option() } fn search_mut<'a, Q: ?Sized>(&'a mut self, q: &Q) -> Option<FullBucketMut<'a, K, V>> - where Q: BorrowFrom<K> + Eq + Hash<H> + where K: Borrow<Q>, Q: Eq + Hash { let hash = self.make_hash(q); - search_hashed(&mut self.table, hash, |k| q.eq(BorrowFrom::borrow_from(k))) + search_hashed(&mut self.table, hash, |k| q.eq(k.borrow())) .into_option() } @@ -490,7 +488,7 @@ impl<K, V, S, H> HashMap<K, V, S> } } -impl<K: Hash<Hasher> + Eq, V> HashMap<K, V, RandomState> { +impl<K: Hash + Eq, V> HashMap<K, V, RandomState> { /// Create an empty HashMap. /// /// # Example @@ -520,10 +518,8 @@ impl<K: Hash<Hasher> + Eq, V> HashMap<K, V, RandomState> { } } -impl<K, V, S, H> HashMap<K, V, S> - where K: Eq + Hash<H>, - S: HashState<Hasher=H>, - H: hash::Hasher<Output=u64> +impl<K, V, S> HashMap<K, V, S> + where K: Eq + Hash, S: HashState { /// Creates an empty hashmap which will use the given hasher to hash keys. /// @@ -1037,7 +1033,7 @@ impl<K, V, S, H> HashMap<K, V, S> /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V> - where Q: Hash<H> + Eq + BorrowFrom<K> + where K: Borrow<Q>, Q: Hash + Eq { self.search(k).map(|bucket| bucket.into_refs().1) } @@ -1060,7 +1056,7 @@ impl<K, V, S, H> HashMap<K, V, S> /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool - where Q: Hash<H> + Eq + BorrowFrom<K> + where K: Borrow<Q>, Q: Hash + Eq { self.search(k).is_some() } @@ -1086,7 +1082,7 @@ impl<K, V, S, H> HashMap<K, V, S> /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V> - where Q: Hash<H> + Eq + BorrowFrom<K> + where K: Borrow<Q>, Q: Hash + Eq { self.search_mut(k).map(|bucket| bucket.into_mut_refs().1) } @@ -1138,7 +1134,7 @@ impl<K, V, S, H> HashMap<K, V, S> /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn remove<Q: ?Sized>(&mut self, k: &Q) -> Option<V> - where Q: Hash<H> + Eq + BorrowFrom<K> + where K: Borrow<Q>, Q: Hash + Eq { if self.table.size() == 0 { return None @@ -1195,10 +1191,8 @@ fn search_entry_hashed<'a, K: Eq, V>(table: &'a mut RawTable<K,V>, hash: SafeHas } } -impl<K, V, S, H> PartialEq for HashMap<K, V, S> - where K: Eq + Hash<H>, V: PartialEq, - S: HashState<Hasher=H>, - H: hash::Hasher<Output=u64> +impl<K, V, S> PartialEq for HashMap<K, V, S> + where K: Eq + Hash, V: PartialEq, S: HashState { fn eq(&self, other: &HashMap<K, V, S>) -> bool { if self.len() != other.len() { return false; } @@ -1210,17 +1204,13 @@ impl<K, V, S, H> PartialEq for HashMap<K, V, S> } #[stable(feature = "rust1", since = "1.0.0")] -impl<K, V, S, H> Eq for HashMap<K, V, S> - where K: Eq + Hash<H>, V: Eq, - S: HashState<Hasher=H>, - H: hash::Hasher<Output=u64> +impl<K, V, S> Eq for HashMap<K, V, S> + where K: Eq + Hash, V: Eq, S: HashState {} #[stable(feature = "rust1", since = "1.0.0")] -impl<K, V, S, H> Debug for HashMap<K, V, S> - where K: Eq + Hash<H> + Debug, V: Debug, - S: HashState<Hasher=H>, - H: hash::Hasher<Output=u64> +impl<K, V, S> Debug for HashMap<K, V, S> + where K: Eq + Hash + Debug, V: Debug, S: HashState { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { try!(write!(f, "HashMap {{")); @@ -1235,10 +1225,9 @@ impl<K, V, S, H> Debug for HashMap<K, V, S> } #[stable(feature = "rust1", since = "1.0.0")] -impl<K, V, S, H> Default for HashMap<K, V, S> - where K: Eq + Hash<H>, - S: HashState<Hasher=H> + Default, - H: hash::Hasher<Output=u64> +impl<K, V, S> Default for HashMap<K, V, S> + where K: Eq + Hash, + S: HashState + Default, { fn default() -> HashMap<K, V, S> { HashMap::with_hash_state(Default::default()) @@ -1246,11 +1235,10 @@ impl<K, V, S, H> Default for HashMap<K, V, S> } #[stable(feature = "rust1", since = "1.0.0")] -impl<K, Q: ?Sized, V, S, H> Index<Q> for HashMap<K, V, S> - where K: Eq + Hash<H>, - Q: Eq + Hash<H> + BorrowFrom<K>, - S: HashState<Hasher=H>, - H: hash::Hasher<Output=u64> +impl<K, Q: ?Sized, V, S> Index<Q> for HashMap<K, V, S> + where K: Eq + Hash + Borrow<Q>, + Q: Eq + Hash, + S: HashState, { type Output = V; @@ -1261,11 +1249,10 @@ impl<K, Q: ?Sized, V, S, H> Index<Q> for HashMap<K, V, S> } #[stable(feature = "rust1", since = "1.0.0")] -impl<K, V, S, H, Q: ?Sized> IndexMut<Q> for HashMap<K, V, S> - where K: Eq + Hash<H>, - Q: Eq + Hash<H> + BorrowFrom<K>, - S: HashState<Hasher=H>, - H: hash::Hasher<Output=u64> +impl<K, V, S, Q: ?Sized> IndexMut<Q> for HashMap<K, V, S> + where K: Eq + Hash + Borrow<Q>, + Q: Eq + Hash, + S: HashState, { #[inline] fn index_mut<'a>(&'a mut self, index: &Q) -> &'a mut V { @@ -1373,10 +1360,8 @@ enum VacantEntryState<K, V, M> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K, V, S, H> IntoIterator for &'a HashMap<K, V, S> - where K: Eq + Hash<H>, - S: HashState<Hasher=H>, - H: hash::Hasher<Output=u64> +impl<'a, K, V, S> IntoIterator for &'a HashMap<K, V, S> + where K: Eq + Hash, S: HashState { type Item = (&'a K, &'a V); type IntoIter = Iter<'a, K, V>; @@ -1387,10 +1372,8 @@ impl<'a, K, V, S, H> IntoIterator for &'a HashMap<K, V, S> } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K, V, S, H> IntoIterator for &'a mut HashMap<K, V, S> - where K: Eq + Hash<H>, - S: HashState<Hasher=H>, - H: hash::Hasher<Output=u64> +impl<'a, K, V, S> IntoIterator for &'a mut HashMap<K, V, S> + where K: Eq + Hash, S: HashState { type Item = (&'a K, &'a mut V); type IntoIter = IterMut<'a, K, V>; @@ -1401,10 +1384,8 @@ impl<'a, K, V, S, H> IntoIterator for &'a mut HashMap<K, V, S> } #[stable(feature = "rust1", since = "1.0.0")] -impl<K, V, S, H> IntoIterator for HashMap<K, V, S> - where K: Eq + Hash<H>, - S: HashState<Hasher=H>, - H: hash::Hasher<Output=u64> +impl<K, V, S> IntoIterator for HashMap<K, V, S> + where K: Eq + Hash, S: HashState { type Item = (K, V); type IntoIter = IntoIter<K, V>; @@ -1550,12 +1531,11 @@ impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<K, V, S, H> FromIterator<(K, V)> for HashMap<K, V, S> - where K: Eq + Hash<H>, - S: HashState<Hasher=H> + Default, - H: hash::Hasher<Output=u64> +impl<K, V, S> FromIterator<(K, V)> for HashMap<K, V, S> + where K: Eq + Hash, S: HashState + Default { - fn from_iter<T: Iterator<Item=(K, V)>>(iter: T) -> HashMap<K, V, S> { + fn from_iter<T: IntoIterator<Item=(K, V)>>(iterable: T) -> HashMap<K, V, S> { + let iter = iterable.into_iter(); let lower = iter.size_hint().0; let mut map = HashMap::with_capacity_and_hash_state(lower, Default::default()); @@ -1565,12 +1545,10 @@ impl<K, V, S, H> FromIterator<(K, V)> for HashMap<K, V, S> } #[stable(feature = "rust1", since = "1.0.0")] -impl<K, V, S, H> Extend<(K, V)> for HashMap<K, V, S> - where K: Eq + Hash<H>, - S: HashState<Hasher=H>, - H: hash::Hasher<Output=u64> +impl<K, V, S> Extend<(K, V)> for HashMap<K, V, S> + where K: Eq + Hash, S: HashState { - fn extend<T: Iterator<Item=(K, V)>>(&mut self, iter: T) { + fn extend<T: IntoIterator<Item=(K, V)>>(&mut self, iter: T) { for (k, v) in iter { self.insert(k, v); } @@ -1606,9 +1584,9 @@ impl RandomState { #[unstable(feature = "std_misc", reason = "hashing an hash maps may be altered")] impl HashState for RandomState { - type Hasher = Hasher; - fn hasher(&self) -> Hasher { - Hasher { inner: SipHasher::new_with_keys(self.k0, self.k1) } + type Hasher = SipHasher; + fn hasher(&self) -> SipHasher { + SipHasher::new_with_keys(self.k0, self.k1) } } @@ -1621,25 +1599,6 @@ impl Default for RandomState { } } -/// A hasher implementation which is generated from `RandomState` instances. -/// -/// This is the default hasher used in a `HashMap` to hash keys. Types do not -/// typically declare an ability to explicitly hash into this particular type, -/// but rather in a `H: hash::Writer` type parameter. -#[unstable(feature = "std_misc", - reason = "hashing an hash maps may be altered")] -pub struct Hasher { inner: SipHasher } - -impl hash::Writer for Hasher { - fn write(&mut self, data: &[u8]) { self.inner.write(data) } -} - -impl hash::Hasher for Hasher { - type Output = u64; - fn reset(&mut self) { self.inner.reset() } - fn finish(&self) -> u64 { self.inner.finish() } -} - #[cfg(test)] mod test_map { use prelude::v1::*; diff --git a/src/libstd/collections/hash/map_stage0.rs b/src/libstd/collections/hash/map_stage0.rs new file mode 100644 index 00000000000..f9e5044c597 --- /dev/null +++ b/src/libstd/collections/hash/map_stage0.rs @@ -0,0 +1,2330 @@ +// Copyright 2014-2015 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. +// +// ignore-lexer-test FIXME #15883 + +use self::Entry::*; +use self::SearchResult::*; +use self::VacantEntryState::*; + +use borrow::Borrow; +use clone::Clone; +use cmp::{max, Eq, PartialEq}; +use default::Default; +use fmt::{self, Debug}; +use hash::{self, Hash, SipHasher}; +use iter::{self, Iterator, ExactSizeIterator, IntoIterator, IteratorExt, FromIterator, Extend, Map}; +use marker::Sized; +use mem::{self, replace}; +use num::{Int, UnsignedInt}; +use ops::{Deref, FnMut, Index, IndexMut}; +use option::Option::{self, Some, None}; +use rand::{self, Rng}; +use result::Result::{self, Ok, Err}; + +use super::table::{ + self, + Bucket, + EmptyBucket, + FullBucket, + FullBucketImm, + FullBucketMut, + RawTable, + SafeHash +}; +use super::table::BucketState::{ + Empty, + Full, +}; +use super::state::HashState; + +const INITIAL_LOG2_CAP: usize = 5; +#[unstable(feature = "std_misc")] +pub const INITIAL_CAPACITY: usize = 1 << INITIAL_LOG2_CAP; // 2^5 + +/// The default behavior of HashMap implements a load factor of 90.9%. +/// This behavior is characterized by the following condition: +/// +/// - if size > 0.909 * capacity: grow the map +#[derive(Clone)] +struct DefaultResizePolicy; + +impl DefaultResizePolicy { + fn new() -> DefaultResizePolicy { + DefaultResizePolicy + } + + #[inline] + fn min_capacity(&self, usable_size: usize) -> usize { + // Here, we are rephrasing the logic by specifying the lower limit + // on capacity: + // + // - if `cap < size * 1.1`: grow the map + usable_size * 11 / 10 + } + + /// An inverse of `min_capacity`, approximately. + #[inline] + fn usable_capacity(&self, cap: usize) -> usize { + // As the number of entries approaches usable capacity, + // min_capacity(size) must be smaller than the internal capacity, + // so that the map is not resized: + // `min_capacity(usable_capacity(x)) <= x`. + // The left-hand side can only be smaller due to flooring by integer + // division. + // + // This doesn't have to be checked for overflow since allocation size + // in bytes will overflow earlier than multiplication by 10. + cap * 10 / 11 + } +} + +#[test] +fn test_resize_policy() { + use prelude::v1::*; + let rp = DefaultResizePolicy; + for n in 0..1000 { + assert!(rp.min_capacity(rp.usable_capacity(n)) <= n); + assert!(rp.usable_capacity(rp.min_capacity(n)) <= n); + } +} + +// The main performance trick in this hashmap is called Robin Hood Hashing. +// It gains its excellent performance from one essential operation: +// +// If an insertion collides with an existing element, and that element's +// "probe distance" (how far away the element is from its ideal location) +// is higher than how far we've already probed, swap the elements. +// +// This massively lowers variance in probe distance, and allows us to get very +// high load factors with good performance. The 90% load factor I use is rather +// conservative. +// +// > Why a load factor of approximately 90%? +// +// In general, all the distances to initial buckets will converge on the mean. +// At a load factor of α, the odds of finding the target bucket after k +// probes is approximately 1-α^k. If we set this equal to 50% (since we converge +// on the mean) and set k=8 (64-byte cache line / 8-byte hash), α=0.92. I round +// this down to make the math easier on the CPU and avoid its FPU. +// Since on average we start the probing in the middle of a cache line, this +// strategy pulls in two cache lines of hashes on every lookup. I think that's +// pretty good, but if you want to trade off some space, it could go down to one +// cache line on average with an α of 0.84. +// +// > Wait, what? Where did you get 1-α^k from? +// +// On the first probe, your odds of a collision with an existing element is α. +// The odds of doing this twice in a row is approximately α^2. For three times, +// α^3, etc. Therefore, the odds of colliding k times is α^k. The odds of NOT +// colliding after k tries is 1-α^k. +// +// The paper from 1986 cited below mentions an implementation which keeps track +// of the distance-to-initial-bucket histogram. This approach is not suitable +// for modern architectures because it requires maintaining an internal data +// structure. This allows very good first guesses, but we are most concerned +// with guessing entire cache lines, not individual indexes. Furthermore, array +// accesses are no longer linear and in one direction, as we have now. There +// is also memory and cache pressure that this would entail that would be very +// difficult to properly see in a microbenchmark. +// +// ## Future Improvements (FIXME!) +// +// Allow the load factor to be changed dynamically and/or at initialization. +// +// Also, would it be possible for us to reuse storage when growing the +// underlying table? This is exactly the use case for 'realloc', and may +// be worth exploring. +// +// ## Future Optimizations (FIXME!) +// +// Another possible design choice that I made without any real reason is +// parameterizing the raw table over keys and values. Technically, all we need +// is the size and alignment of keys and values, and the code should be just as +// efficient (well, we might need one for power-of-two size and one for not...). +// This has the potential to reduce code bloat in rust executables, without +// really losing anything except 4 words (key size, key alignment, val size, +// val alignment) which can be passed in to every call of a `RawTable` function. +// This would definitely be an avenue worth exploring if people start complaining +// about the size of rust executables. +// +// Annotate exceedingly likely branches in `table::make_hash` +// and `search_hashed` to reduce instruction cache pressure +// and mispredictions once it becomes possible (blocked on issue #11092). +// +// Shrinking the table could simply reallocate in place after moving buckets +// to the first half. +// +// The growth algorithm (fragment of the Proof of Correctness) +// -------------------- +// +// The growth algorithm is basically a fast path of the naive reinsertion- +// during-resize algorithm. Other paths should never be taken. +// +// Consider growing a robin hood hashtable of capacity n. Normally, we do this +// by allocating a new table of capacity `2n`, and then individually reinsert +// each element in the old table into the new one. This guarantees that the +// new table is a valid robin hood hashtable with all the desired statistical +// properties. Remark that the order we reinsert the elements in should not +// matter. For simplicity and efficiency, we will consider only linear +// reinsertions, which consist of reinserting all elements in the old table +// into the new one by increasing order of index. However we will not be +// starting our reinsertions from index 0 in general. If we start from index +// i, for the purpose of reinsertion we will consider all elements with real +// index j < i to have virtual index n + j. +// +// Our hash generation scheme consists of generating a 64-bit hash and +// truncating the most significant bits. When moving to the new table, we +// simply introduce a new bit to the front of the hash. Therefore, if an +// elements has ideal index i in the old table, it can have one of two ideal +// locations in the new table. If the new bit is 0, then the new ideal index +// is i. If the new bit is 1, then the new ideal index is n + i. Intuitively, +// we are producing two independent tables of size n, and for each element we +// independently choose which table to insert it into with equal probability. +// However the rather than wrapping around themselves on overflowing their +// indexes, the first table overflows into the first, and the first into the +// second. Visually, our new table will look something like: +// +// [yy_xxx_xxxx_xxx|xx_yyy_yyyy_yyy] +// +// Where x's are elements inserted into the first table, y's are elements +// inserted into the second, and _'s are empty sections. We now define a few +// key concepts that we will use later. Note that this is a very abstract +// perspective of the table. A real resized table would be at least half +// empty. +// +// Theorem: A linear robin hood reinsertion from the first ideal element +// produces identical results to a linear naive reinsertion from the same +// element. +// +// FIXME(Gankro, pczarn): review the proof and put it all in a separate doc.rs + +/// A hash map implementation which uses linear probing with Robin +/// Hood bucket stealing. +/// +/// The hashes are all keyed by the task-local random number generator +/// on creation by default. This means that the ordering of the keys is +/// randomized, but makes the tables more resistant to +/// denial-of-service attacks (Hash DoS). This behaviour can be +/// overridden with one of the constructors. +/// +/// It is required that the keys implement the `Eq` and `Hash` traits, although +/// this can frequently be achieved by using `#[derive(Eq, Hash)]`. +/// +/// Relevant papers/articles: +/// +/// 1. Pedro Celis. ["Robin Hood Hashing"](https://cs.uwaterloo.ca/research/tr/1986/CS-86-14.pdf) +/// 2. Emmanuel Goossaert. ["Robin Hood +/// hashing"](http://codecapsule.com/2013/11/11/robin-hood-hashing/) +/// 3. Emmanuel Goossaert. ["Robin Hood hashing: backward shift +/// deletion"](http://codecapsule.com/2013/11/17/robin-hood-hashing-backward-shift-deletion/) +/// +/// # Example +/// +/// ``` +/// use std::collections::HashMap; +/// +/// // type inference lets us omit an explicit type signature (which +/// // would be `HashMap<&str, &str>` in this example). +/// let mut book_reviews = HashMap::new(); +/// +/// // review some books. +/// book_reviews.insert("Adventures of Huckleberry Finn", "My favorite book."); +/// book_reviews.insert("Grimms' Fairy Tales", "Masterpiece."); +/// book_reviews.insert("Pride and Prejudice", "Very enjoyable."); +/// book_reviews.insert("The Adventures of Sherlock Holmes", "Eye lyked it alot."); +/// +/// // check for a specific one. +/// if !book_reviews.contains_key(&("Les Misérables")) { +/// println!("We've got {} reviews, but Les Misérables ain't one.", +/// book_reviews.len()); +/// } +/// +/// // oops, this review has a lot of spelling mistakes, let's delete it. +/// book_reviews.remove(&("The Adventures of Sherlock Holmes")); +/// +/// // look up the values associated with some keys. +/// let to_find = ["Pride and Prejudice", "Alice's Adventure in Wonderland"]; +/// for book in to_find.iter() { +/// match book_reviews.get(book) { +/// Some(review) => println!("{}: {}", *book, *review), +/// None => println!("{} is unreviewed.", *book) +/// } +/// } +/// +/// // iterate over everything. +/// for (book, review) in book_reviews.iter() { +/// println!("{}: \"{}\"", *book, *review); +/// } +/// ``` +/// +/// The easiest way to use `HashMap` with a custom type as key is to derive `Eq` and `Hash`. +/// We must also derive `PartialEq`. +/// +/// ``` +/// use std::collections::HashMap; +/// +/// #[derive(Hash, Eq, PartialEq, Debug)] +/// struct Viking { +/// name: String, +/// country: String, +/// } +/// +/// impl Viking { +/// /// Create a new Viking. +/// fn new(name: &str, country: &str) -> Viking { +/// Viking { name: name.to_string(), country: country.to_string() } +/// } +/// } +/// +/// // Use a HashMap to store the vikings' health points. +/// let mut vikings = HashMap::new(); +/// +/// vikings.insert(Viking::new("Einar", "Norway"), 25); +/// vikings.insert(Viking::new("Olaf", "Denmark"), 24); +/// vikings.insert(Viking::new("Harald", "Iceland"), 12); +/// +/// // Use derived implementation to print the status of the vikings. +/// for (viking, health) in vikings.iter() { +/// println!("{:?} has {} hp", viking, health); +/// } +/// ``` +#[derive(Clone)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct HashMap<K, V, S = RandomState> { + // All hashes are keyed on these values, to prevent hash collision attacks. + hash_state: S, + + table: RawTable<K, V>, + + resize_policy: DefaultResizePolicy, +} + +/// Search for a pre-hashed key. +fn search_hashed<K, V, M, F>(table: M, + hash: SafeHash, + mut is_match: F) + -> SearchResult<K, V, M> where + M: Deref<Target=RawTable<K, V>>, + F: FnMut(&K) -> bool, +{ + let size = table.size(); + let mut probe = Bucket::new(table, hash); + let ib = probe.index(); + + while probe.index() != ib + size { + let full = match probe.peek() { + Empty(b) => return TableRef(b.into_table()), // hit an empty bucket + Full(b) => b + }; + + if full.distance() + ib < full.index() { + // We can finish the search early if we hit any bucket + // with a lower distance to initial bucket than we've probed. + return TableRef(full.into_table()); + } + + // If the hash doesn't match, it can't be this one.. + if hash == full.hash() { + // If the key doesn't match, it can't be this one.. + if is_match(full.read().0) { + return FoundExisting(full); + } + } + + probe = full.next(); + } + + TableRef(probe.into_table()) +} + +fn pop_internal<K, V>(starting_bucket: FullBucketMut<K, V>) -> (K, V) { + let (empty, retkey, retval) = starting_bucket.take(); + let mut gap = match empty.gap_peek() { + Some(b) => b, + None => return (retkey, retval) + }; + + while gap.full().distance() != 0 { + gap = match gap.shift() { + Some(b) => b, + None => break + }; + } + + // Now we've done all our shifting. Return the value we grabbed earlier. + (retkey, retval) +} + +/// Perform robin hood bucket stealing at the given `bucket`. You must +/// also pass the position of that bucket's initial bucket so we don't have +/// to recalculate it. +/// +/// `hash`, `k`, and `v` are the elements to "robin hood" into the hashtable. +fn robin_hood<'a, K: 'a, V: 'a>(mut bucket: FullBucketMut<'a, K, V>, + mut ib: usize, + mut hash: SafeHash, + mut k: K, + mut v: V) + -> &'a mut V { + let starting_index = bucket.index(); + let size = { + let table = bucket.table(); // FIXME "lifetime too short". + table.size() + }; + // There can be at most `size - dib` buckets to displace, because + // in the worst case, there are `size` elements and we already are + // `distance` buckets away from the initial one. + let idx_end = starting_index + size - bucket.distance(); + + loop { + let (old_hash, old_key, old_val) = bucket.replace(hash, k, v); + loop { + let probe = bucket.next(); + assert!(probe.index() != idx_end); + + let full_bucket = match probe.peek() { + Empty(bucket) => { + // Found a hole! + let b = bucket.put(old_hash, old_key, old_val); + // Now that it's stolen, just read the value's pointer + // right out of the table! + return Bucket::at_index(b.into_table(), starting_index) + .peek() + .expect_full() + .into_mut_refs() + .1; + }, + Full(bucket) => bucket + }; + + let probe_ib = full_bucket.index() - full_bucket.distance(); + + bucket = full_bucket; + + // Robin hood! Steal the spot. + if ib < probe_ib { + ib = probe_ib; + hash = old_hash; + k = old_key; + v = old_val; + break; + } + } + } +} + +/// A result that works like Option<FullBucket<..>> but preserves +/// the reference that grants us access to the table in any case. +enum SearchResult<K, V, M> { + // This is an entry that holds the given key: + FoundExisting(FullBucket<K, V, M>), + + // There was no such entry. The reference is given back: + TableRef(M) +} + +impl<K, V, M> SearchResult<K, V, M> { + fn into_option(self) -> Option<FullBucket<K, V, M>> { + match self { + FoundExisting(bucket) => Some(bucket), + TableRef(_) => None + } + } +} + +impl<K, V, S, H> HashMap<K, V, S> + where K: Eq + Hash<H>, + S: HashState<Hasher=H>, + H: hash::Hasher<Output=u64> +{ + fn make_hash<X: ?Sized>(&self, x: &X) -> SafeHash where X: Hash<H> { + table::make_hash(&self.hash_state, x) + } + + /// Search for a key, yielding the index if it's found in the hashtable. + /// If you already have the hash for the key lying around, use + /// search_hashed. + fn search<'a, Q: ?Sized>(&'a self, q: &Q) -> Option<FullBucketImm<'a, K, V>> + where K: Borrow<Q>, Q: Eq + Hash<H> + { + let hash = self.make_hash(q); + search_hashed(&self.table, hash, |k| q.eq(k.borrow())) + .into_option() + } + + fn search_mut<'a, Q: ?Sized>(&'a mut self, q: &Q) -> Option<FullBucketMut<'a, K, V>> + where K: Borrow<Q>, Q: Eq + Hash<H> + { + let hash = self.make_hash(q); + search_hashed(&mut self.table, hash, |k| q.eq(k.borrow())) + .into_option() + } + + // The caller should ensure that invariants by Robin Hood Hashing hold. + fn insert_hashed_ordered(&mut self, hash: SafeHash, k: K, v: V) { + let cap = self.table.capacity(); + let mut buckets = Bucket::new(&mut self.table, hash); + let ib = buckets.index(); + + while buckets.index() != ib + cap { + // We don't need to compare hashes for value swap. + // Not even DIBs for Robin Hood. + buckets = match buckets.peek() { + Empty(empty) => { + empty.put(hash, k, v); + return; + } + Full(b) => b.into_bucket() + }; + buckets.next(); + } + panic!("Internal HashMap error: Out of space."); + } +} + +impl<K: Hash<Hasher> + Eq, V> HashMap<K, V, RandomState> { + /// Create an empty HashMap. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashMap; + /// let mut map: HashMap<&str, int> = HashMap::new(); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn new() -> HashMap<K, V, RandomState> { + Default::default() + } + + /// Creates an empty hash map with the given initial capacity. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashMap; + /// let mut map: HashMap<&str, int> = HashMap::with_capacity(10); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn with_capacity(capacity: usize) -> HashMap<K, V, RandomState> { + HashMap::with_capacity_and_hash_state(capacity, Default::default()) + } +} + +impl<K, V, S, H> HashMap<K, V, S> + where K: Eq + Hash<H>, + S: HashState<Hasher=H>, + H: hash::Hasher<Output=u64> +{ + /// Creates an empty hashmap which will use the given hasher to hash keys. + /// + /// The creates map has the default initial capacity. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashMap; + /// use std::collections::hash_map::RandomState; + /// + /// let s = RandomState::new(); + /// let mut map = HashMap::with_hash_state(s); + /// map.insert(1, 2); + /// ``` + #[inline] + #[unstable(feature = "std_misc", reason = "hasher stuff is unclear")] + pub fn with_hash_state(hash_state: S) -> HashMap<K, V, S> { + HashMap { + hash_state: hash_state, + resize_policy: DefaultResizePolicy::new(), + table: RawTable::new(0), + } + } + + /// Create an empty HashMap with space for at least `capacity` + /// elements, using `hasher` to hash the keys. + /// + /// Warning: `hasher` is normally randomly generated, and + /// is designed to allow HashMaps to be resistant to attacks that + /// cause many collisions and very poor performance. Setting it + /// manually using this function can expose a DoS attack vector. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashMap; + /// use std::collections::hash_map::RandomState; + /// + /// let s = RandomState::new(); + /// let mut map = HashMap::with_capacity_and_hash_state(10, s); + /// map.insert(1, 2); + /// ``` + #[inline] + #[unstable(feature = "std_misc", reason = "hasher stuff is unclear")] + pub fn with_capacity_and_hash_state(capacity: usize, hash_state: S) + -> HashMap<K, V, S> { + let resize_policy = DefaultResizePolicy::new(); + let min_cap = max(INITIAL_CAPACITY, resize_policy.min_capacity(capacity)); + let internal_cap = min_cap.checked_next_power_of_two().expect("capacity overflow"); + assert!(internal_cap >= capacity, "capacity overflow"); + HashMap { + hash_state: hash_state, + resize_policy: resize_policy, + table: RawTable::new(internal_cap), + } + } + + /// Returns the number of elements the map can hold without reallocating. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashMap; + /// let map: HashMap<int, int> = HashMap::with_capacity(100); + /// assert!(map.capacity() >= 100); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn capacity(&self) -> usize { + self.resize_policy.usable_capacity(self.table.capacity()) + } + + /// Reserves capacity for at least `additional` more elements to be inserted + /// in the `HashMap`. The collection may reserve more space to avoid + /// frequent reallocations. + /// + /// # Panics + /// + /// Panics if the new allocation size overflows `usize`. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashMap; + /// let mut map: HashMap<&str, int> = HashMap::new(); + /// map.reserve(10); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn reserve(&mut self, additional: usize) { + let new_size = self.len().checked_add(additional).expect("capacity overflow"); + let min_cap = self.resize_policy.min_capacity(new_size); + + // An invalid value shouldn't make us run out of space. This includes + // an overflow check. + assert!(new_size <= min_cap); + + if self.table.capacity() < min_cap { + let new_capacity = max(min_cap.next_power_of_two(), INITIAL_CAPACITY); + self.resize(new_capacity); + } + } + + /// Resizes the internal vectors to a new capacity. It's your responsibility to: + /// 1) Make sure the new capacity is enough for all the elements, accounting + /// for the load factor. + /// 2) Ensure new_capacity is a power of two or zero. + fn resize(&mut self, new_capacity: usize) { + assert!(self.table.size() <= new_capacity); + assert!(new_capacity.is_power_of_two() || new_capacity == 0); + + let mut old_table = replace(&mut self.table, RawTable::new(new_capacity)); + let old_size = old_table.size(); + + if old_table.capacity() == 0 || old_table.size() == 0 { + return; + } + + // Grow the table. + // Specialization of the other branch. + let mut bucket = Bucket::first(&mut old_table); + + // "So a few of the first shall be last: for many be called, + // but few chosen." + // + // We'll most likely encounter a few buckets at the beginning that + // have their initial buckets near the end of the table. They were + // placed at the beginning as the probe wrapped around the table + // during insertion. We must skip forward to a bucket that won't + // get reinserted too early and won't unfairly steal others spot. + // This eliminates the need for robin hood. + loop { + bucket = match bucket.peek() { + Full(full) => { + if full.distance() == 0 { + // This bucket occupies its ideal spot. + // It indicates the start of another "cluster". + bucket = full.into_bucket(); + break; + } + // Leaving this bucket in the last cluster for later. + full.into_bucket() + } + Empty(b) => { + // Encountered a hole between clusters. + b.into_bucket() + } + }; + bucket.next(); + } + + // This is how the buckets might be laid out in memory: + // ($ marks an initialized bucket) + // ________________ + // |$$$_$$$$$$_$$$$$| + // + // But we've skipped the entire initial cluster of buckets + // and will continue iteration in this order: + // ________________ + // |$$$$$$_$$$$$ + // ^ wrap around once end is reached + // ________________ + // $$$_____________| + // ^ exit once table.size == 0 + loop { + bucket = match bucket.peek() { + Full(bucket) => { + let h = bucket.hash(); + let (b, k, v) = bucket.take(); + self.insert_hashed_ordered(h, k, v); + { + let t = b.table(); // FIXME "lifetime too short". + if t.size() == 0 { break } + }; + b.into_bucket() + } + Empty(b) => b.into_bucket() + }; + bucket.next(); + } + + assert_eq!(self.table.size(), old_size); + } + + /// Shrinks the capacity of the map as much as possible. It will drop + /// down as much as possible while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map: HashMap<int, int> = HashMap::with_capacity(100); + /// map.insert(1, 2); + /// map.insert(3, 4); + /// assert!(map.capacity() >= 100); + /// map.shrink_to_fit(); + /// assert!(map.capacity() >= 2); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn shrink_to_fit(&mut self) { + let min_capacity = self.resize_policy.min_capacity(self.len()); + let min_capacity = max(min_capacity.next_power_of_two(), INITIAL_CAPACITY); + + // An invalid value shouldn't make us run out of space. + debug_assert!(self.len() <= min_capacity); + + if self.table.capacity() != min_capacity { + let old_table = replace(&mut self.table, RawTable::new(min_capacity)); + let old_size = old_table.size(); + + // Shrink the table. Naive algorithm for resizing: + for (h, k, v) in old_table.into_iter() { + self.insert_hashed_nocheck(h, k, v); + } + + debug_assert_eq!(self.table.size(), old_size); + } + } + + /// Insert a pre-hashed key-value pair, without first checking + /// that there's enough room in the buckets. Returns a reference to the + /// newly insert value. + /// + /// If the key already exists, the hashtable will be returned untouched + /// and a reference to the existing element will be returned. + fn insert_hashed_nocheck(&mut self, hash: SafeHash, k: K, v: V) -> &mut V { + self.insert_or_replace_with(hash, k, v, |_, _, _| ()) + } + + fn insert_or_replace_with<'a, F>(&'a mut self, + hash: SafeHash, + k: K, + v: V, + mut found_existing: F) + -> &'a mut V where + F: FnMut(&mut K, &mut V, V), + { + // Worst case, we'll find one empty bucket among `size + 1` buckets. + let size = self.table.size(); + let mut probe = Bucket::new(&mut self.table, hash); + let ib = probe.index(); + + loop { + let mut bucket = match probe.peek() { + Empty(bucket) => { + // Found a hole! + return bucket.put(hash, k, v).into_mut_refs().1; + } + Full(bucket) => bucket + }; + + // hash matches? + if bucket.hash() == hash { + // key matches? + if k == *bucket.read_mut().0 { + let (bucket_k, bucket_v) = bucket.into_mut_refs(); + debug_assert!(k == *bucket_k); + // Key already exists. Get its reference. + found_existing(bucket_k, bucket_v, v); + return bucket_v; + } + } + + let robin_ib = bucket.index() as int - bucket.distance() as int; + + if (ib as int) < robin_ib { + // Found a luckier bucket than me. Better steal his spot. + return robin_hood(bucket, robin_ib as usize, hash, k, v); + } + + probe = bucket.next(); + assert!(probe.index() != ib + size + 1); + } + } + + /// An iterator visiting all keys in arbitrary order. + /// Iterator element type is `&'a K`. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert("a", 1); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// + /// for key in map.keys() { + /// println!("{}", key); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn keys<'a>(&'a self) -> Keys<'a, K, V> { + fn first<A, B>((a, _): (A, B)) -> A { a } + let first: fn((&'a K,&'a V)) -> &'a K = first; // coerce to fn ptr + + Keys { inner: self.iter().map(first) } + } + + /// An iterator visiting all values in arbitrary order. + /// Iterator element type is `&'a V`. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert("a", 1); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// + /// for val in map.values() { + /// println!("{}", val); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn values<'a>(&'a self) -> Values<'a, K, V> { + fn second<A, B>((_, b): (A, B)) -> B { b } + let second: fn((&'a K,&'a V)) -> &'a V = second; // coerce to fn ptr + + Values { inner: self.iter().map(second) } + } + + /// An iterator visiting all key-value pairs in arbitrary order. + /// Iterator element type is `(&'a K, &'a V)`. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert("a", 1); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// + /// for (key, val) in map.iter() { + /// println!("key: {} val: {}", key, val); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn iter(&self) -> Iter<K, V> { + Iter { inner: self.table.iter() } + } + + /// An iterator visiting all key-value pairs in arbitrary order, + /// with mutable references to the values. + /// Iterator element type is `(&'a K, &'a mut V)`. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert("a", 1); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// + /// // Update all values + /// for (_, val) in map.iter_mut() { + /// *val *= 2; + /// } + /// + /// for (key, val) in map.iter() { + /// println!("key: {} val: {}", key, val); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn iter_mut(&mut self) -> IterMut<K, V> { + IterMut { inner: self.table.iter_mut() } + } + + /// Creates a consuming iterator, that is, one that moves each key-value + /// pair out of the map in arbitrary order. The map cannot be used after + /// calling this. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert("a", 1); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// + /// // Not possible with .iter() + /// let vec: Vec<(&str, int)> = map.into_iter().collect(); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn into_iter(self) -> IntoIter<K, V> { + fn last_two<A, B, C>((_, b, c): (A, B, C)) -> (B, C) { (b, c) } + let last_two: fn((SafeHash, K, V)) -> (K, V) = last_two; + + IntoIter { + inner: self.table.into_iter().map(last_two) + } + } + + /// Gets the given key's corresponding entry in the map for in-place manipulation. + #[stable(feature = "rust1", since = "1.0.0")] + pub fn entry(&mut self, key: K) -> Entry<K, V> { + // Gotta resize now. + self.reserve(1); + + let hash = self.make_hash(&key); + search_entry_hashed(&mut self.table, hash, key) + } + + /// Returns the number of elements in the map. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut a = HashMap::new(); + /// assert_eq!(a.len(), 0); + /// a.insert(1, "a"); + /// assert_eq!(a.len(), 1); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn len(&self) -> usize { self.table.size() } + + /// Returns true if the map contains no elements. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut a = HashMap::new(); + /// assert!(a.is_empty()); + /// a.insert(1, "a"); + /// assert!(!a.is_empty()); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn is_empty(&self) -> bool { self.len() == 0 } + + /// Clears the map, returning all key-value pairs as an iterator. Keeps the + /// allocated memory for reuse. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut a = HashMap::new(); + /// a.insert(1, "a"); + /// a.insert(2, "b"); + /// + /// for (k, v) in a.drain().take(1) { + /// assert!(k == 1 || k == 2); + /// assert!(v == "a" || v == "b"); + /// } + /// + /// assert!(a.is_empty()); + /// ``` + #[inline] + #[unstable(feature = "std_misc", + reason = "matches collection reform specification, waiting for dust to settle")] + pub fn drain(&mut self) -> Drain<K, V> { + fn last_two<A, B, C>((_, b, c): (A, B, C)) -> (B, C) { (b, c) } + let last_two: fn((SafeHash, K, V)) -> (K, V) = last_two; // coerce to fn pointer + + Drain { + inner: self.table.drain().map(last_two), + } + } + + /// Clears the map, removing all key-value pairs. Keeps the allocated memory + /// for reuse. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut a = HashMap::new(); + /// a.insert(1, "a"); + /// a.clear(); + /// assert!(a.is_empty()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn clear(&mut self) { + self.drain(); + } + + /// Returns a reference to the value corresponding to the key. + /// + /// The key may be any borrowed form of the map's key type, but + /// `Hash` and `Eq` on the borrowed form *must* match those for + /// the key type. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// assert_eq!(map.get(&1), Some(&"a")); + /// assert_eq!(map.get(&2), None); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V> + where K: Borrow<Q>, Q: Hash<H> + Eq + { + self.search(k).map(|bucket| bucket.into_refs().1) + } + + /// Returns true if the map contains a value for the specified key. + /// + /// The key may be any borrowed form of the map's key type, but + /// `Hash` and `Eq` on the borrowed form *must* match those for + /// the key type. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// assert_eq!(map.contains_key(&1), true); + /// assert_eq!(map.contains_key(&2), false); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool + where K: Borrow<Q>, Q: Hash<H> + Eq + { + self.search(k).is_some() + } + + /// Returns a mutable reference to the value corresponding to the key. + /// + /// The key may be any borrowed form of the map's key type, but + /// `Hash` and `Eq` on the borrowed form *must* match those for + /// the key type. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// match map.get_mut(&1) { + /// Some(x) => *x = "b", + /// None => (), + /// } + /// assert_eq!(map[1], "b"); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V> + where K: Borrow<Q>, Q: Hash<H> + Eq + { + self.search_mut(k).map(|bucket| bucket.into_mut_refs().1) + } + + /// Inserts a key-value pair from the map. If the key already had a value + /// present in the map, that value is returned. Otherwise, `None` is returned. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::new(); + /// assert_eq!(map.insert(37, "a"), None); + /// assert_eq!(map.is_empty(), false); + /// + /// map.insert(37, "b"); + /// assert_eq!(map.insert(37, "c"), Some("b")); + /// assert_eq!(map[37], "c"); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn insert(&mut self, k: K, v: V) -> Option<V> { + let hash = self.make_hash(&k); + self.reserve(1); + + let mut retval = None; + self.insert_or_replace_with(hash, k, v, |_, val_ref, val| { + retval = Some(replace(val_ref, val)); + }); + retval + } + + /// Removes a key from the map, returning the value at the key if the key + /// was previously in the map. + /// + /// The key may be any borrowed form of the map's key type, but + /// `Hash` and `Eq` on the borrowed form *must* match those for + /// the key type. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// assert_eq!(map.remove(&1), Some("a")); + /// assert_eq!(map.remove(&1), None); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn remove<Q: ?Sized>(&mut self, k: &Q) -> Option<V> + where K: Borrow<Q>, Q: Hash<H> + Eq + { + if self.table.size() == 0 { + return None + } + + self.search_mut(k).map(|bucket| pop_internal(bucket).1) + } +} + +fn search_entry_hashed<'a, K: Eq, V>(table: &'a mut RawTable<K,V>, hash: SafeHash, k: K) + -> Entry<'a, K, V> +{ + // Worst case, we'll find one empty bucket among `size + 1` buckets. + let size = table.size(); + let mut probe = Bucket::new(table, hash); + let ib = probe.index(); + + loop { + let bucket = match probe.peek() { + Empty(bucket) => { + // Found a hole! + return Vacant(VacantEntry { + hash: hash, + key: k, + elem: NoElem(bucket), + }); + }, + Full(bucket) => bucket + }; + + // hash matches? + if bucket.hash() == hash { + // key matches? + if k == *bucket.read().0 { + return Occupied(OccupiedEntry{ + elem: bucket, + }); + } + } + + let robin_ib = bucket.index() as int - bucket.distance() as int; + + if (ib as int) < robin_ib { + // Found a luckier bucket than me. Better steal his spot. + return Vacant(VacantEntry { + hash: hash, + key: k, + elem: NeqElem(bucket, robin_ib as usize), + }); + } + + probe = bucket.next(); + assert!(probe.index() != ib + size + 1); + } +} + +impl<K, V, S, H> PartialEq for HashMap<K, V, S> + where K: Eq + Hash<H>, V: PartialEq, + S: HashState<Hasher=H>, + H: hash::Hasher<Output=u64> +{ + fn eq(&self, other: &HashMap<K, V, S>) -> bool { + if self.len() != other.len() { return false; } + + self.iter().all(|(key, value)| + other.get(key).map_or(false, |v| *value == *v) + ) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<K, V, S, H> Eq for HashMap<K, V, S> + where K: Eq + Hash<H>, V: Eq, + S: HashState<Hasher=H>, + H: hash::Hasher<Output=u64> +{} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<K, V, S, H> Debug for HashMap<K, V, S> + where K: Eq + Hash<H> + Debug, V: Debug, + S: HashState<Hasher=H>, + H: hash::Hasher<Output=u64> +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + try!(write!(f, "HashMap {{")); + + for (i, (k, v)) in self.iter().enumerate() { + if i != 0 { try!(write!(f, ", ")); } + try!(write!(f, "{:?}: {:?}", *k, *v)); + } + + write!(f, "}}") + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<K, V, S, H> Default for HashMap<K, V, S> + where K: Eq + Hash<H>, + S: HashState<Hasher=H> + Default, + H: hash::Hasher<Output=u64> +{ + fn default() -> HashMap<K, V, S> { + HashMap::with_hash_state(Default::default()) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<K, Q: ?Sized, V, S, H> Index<Q> for HashMap<K, V, S> + where K: Eq + Hash<H> + Borrow<Q>, + Q: Eq + Hash<H>, + S: HashState<Hasher=H>, + H: hash::Hasher<Output=u64> +{ + type Output = V; + + #[inline] + fn index<'a>(&'a self, index: &Q) -> &'a V { + self.get(index).expect("no entry found for key") + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<K, V, S, H, Q: ?Sized> IndexMut<Q> for HashMap<K, V, S> + where K: Eq + Hash<H> + Borrow<Q>, + Q: Eq + Hash<H>, + S: HashState<Hasher=H>, + H: hash::Hasher<Output=u64> +{ + #[inline] + fn index_mut<'a>(&'a mut self, index: &Q) -> &'a mut V { + self.get_mut(index).expect("no entry found for key") + } +} + +/// HashMap iterator. +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Iter<'a, K: 'a, V: 'a> { + inner: table::Iter<'a, K, V> +} + +// FIXME(#19839) Remove in favor of `#[derive(Clone)]` +impl<'a, K, V> Clone for Iter<'a, K, V> { + fn clone(&self) -> Iter<'a, K, V> { + Iter { + inner: self.inner.clone() + } + } +} + +/// HashMap mutable values iterator. +#[stable(feature = "rust1", since = "1.0.0")] +pub struct IterMut<'a, K: 'a, V: 'a> { + inner: table::IterMut<'a, K, V> +} + +/// HashMap move iterator. +#[stable(feature = "rust1", since = "1.0.0")] +pub struct IntoIter<K, V> { + inner: iter::Map<table::IntoIter<K, V>, fn((SafeHash, K, V)) -> (K, V)> +} + +/// HashMap keys iterator. +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Keys<'a, K: 'a, V: 'a> { + inner: Map<Iter<'a, K, V>, fn((&'a K, &'a V)) -> &'a K> +} + +// FIXME(#19839) Remove in favor of `#[derive(Clone)]` +impl<'a, K, V> Clone for Keys<'a, K, V> { + fn clone(&self) -> Keys<'a, K, V> { + Keys { + inner: self.inner.clone() + } + } +} + +/// HashMap values iterator. +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Values<'a, K: 'a, V: 'a> { + inner: Map<Iter<'a, K, V>, fn((&'a K, &'a V)) -> &'a V> +} + +// FIXME(#19839) Remove in favor of `#[derive(Clone)]` +impl<'a, K, V> Clone for Values<'a, K, V> { + fn clone(&self) -> Values<'a, K, V> { + Values { + inner: self.inner.clone() + } + } +} + +/// HashMap drain iterator. +#[unstable(feature = "std_misc", + reason = "matches collection reform specification, waiting for dust to settle")] +pub struct Drain<'a, K: 'a, V: 'a> { + inner: iter::Map<table::Drain<'a, K, V>, fn((SafeHash, K, V)) -> (K, V)> +} + +/// A view into a single occupied location in a HashMap. +#[unstable(feature = "std_misc", + reason = "precise API still being fleshed out")] +pub struct OccupiedEntry<'a, K: 'a, V: 'a> { + elem: FullBucket<K, V, &'a mut RawTable<K, V>>, +} + +/// A view into a single empty location in a HashMap. +#[unstable(feature = "std_misc", + reason = "precise API still being fleshed out")] +pub struct VacantEntry<'a, K: 'a, V: 'a> { + hash: SafeHash, + key: K, + elem: VacantEntryState<K, V, &'a mut RawTable<K, V>>, +} + +/// A view into a single location in a map, which may be vacant or occupied. +#[unstable(feature = "std_misc", + reason = "precise API still being fleshed out")] +pub enum Entry<'a, K: 'a, V: 'a> { + /// An occupied Entry. + Occupied(OccupiedEntry<'a, K, V>), + /// A vacant Entry. + Vacant(VacantEntry<'a, K, V>), +} + +/// Possible states of a VacantEntry. +enum VacantEntryState<K, V, M> { + /// The index is occupied, but the key to insert has precedence, + /// and will kick the current one out on insertion. + NeqElem(FullBucket<K, V, M>, usize), + /// The index is genuinely vacant. + NoElem(EmptyBucket<K, V, M>), +} + +impl<'a, K, V, S, H> IntoIterator for &'a HashMap<K, V, S> + where K: Eq + Hash<H>, + S: HashState<Hasher=H>, + H: hash::Hasher<Output=u64> +{ + type Item = (&'a K, &'a V); + type IntoIter = Iter<'a, K, V>; + + fn into_iter(self) -> Iter<'a, K, V> { + self.iter() + } +} + +impl<'a, K, V, S, H> IntoIterator for &'a mut HashMap<K, V, S> + where K: Eq + Hash<H>, + S: HashState<Hasher=H>, + H: hash::Hasher<Output=u64> +{ + type Item = (&'a K, &'a mut V); + type IntoIter = IterMut<'a, K, V>; + + fn into_iter(mut self) -> IterMut<'a, K, V> { + self.iter_mut() + } +} + +impl<K, V, S, H> IntoIterator for HashMap<K, V, S> + where K: Eq + Hash<H>, + S: HashState<Hasher=H>, + H: hash::Hasher<Output=u64> +{ + type Item = (K, V); + type IntoIter = IntoIter<K, V>; + + fn into_iter(self) -> IntoIter<K, V> { + self.into_iter() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, K, V> Iterator for Iter<'a, K, V> { + type Item = (&'a K, &'a V); + + #[inline] fn next(&mut self) -> Option<(&'a K, &'a V)> { self.inner.next() } + #[inline] fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, K, V> ExactSizeIterator for Iter<'a, K, V> { + #[inline] fn len(&self) -> usize { self.inner.len() } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, K, V> Iterator for IterMut<'a, K, V> { + type Item = (&'a K, &'a mut V); + + #[inline] fn next(&mut self) -> Option<(&'a K, &'a mut V)> { self.inner.next() } + #[inline] fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, K, V> ExactSizeIterator for IterMut<'a, K, V> { + #[inline] fn len(&self) -> usize { self.inner.len() } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<K, V> Iterator for IntoIter<K, V> { + type Item = (K, V); + + #[inline] fn next(&mut self) -> Option<(K, V)> { self.inner.next() } + #[inline] fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl<K, V> ExactSizeIterator for IntoIter<K, V> { + #[inline] fn len(&self) -> usize { self.inner.len() } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, K, V> Iterator for Keys<'a, K, V> { + type Item = &'a K; + + #[inline] fn next(&mut self) -> Option<(&'a K)> { self.inner.next() } + #[inline] fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, K, V> ExactSizeIterator for Keys<'a, K, V> { + #[inline] fn len(&self) -> usize { self.inner.len() } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, K, V> Iterator for Values<'a, K, V> { + type Item = &'a V; + + #[inline] fn next(&mut self) -> Option<(&'a V)> { self.inner.next() } + #[inline] fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> { + #[inline] fn len(&self) -> usize { self.inner.len() } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, K, V> Iterator for Drain<'a, K, V> { + type Item = (K, V); + + #[inline] fn next(&mut self) -> Option<(K, V)> { self.inner.next() } + #[inline] fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, K, V> ExactSizeIterator for Drain<'a, K, V> { + #[inline] fn len(&self) -> usize { self.inner.len() } +} + +#[unstable(feature = "std_misc", + reason = "matches collection reform v2 specification, waiting for dust to settle")] +impl<'a, K, V> Entry<'a, K, V> { + /// Returns a mutable reference to the entry if occupied, or the VacantEntry if vacant. + pub fn get(self) -> Result<&'a mut V, VacantEntry<'a, K, V>> { + match self { + Occupied(entry) => Ok(entry.into_mut()), + Vacant(entry) => Err(entry), + } + } +} + +impl<'a, K, V> OccupiedEntry<'a, K, V> { + /// Gets a reference to the value in the entry. + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get(&self) -> &V { + self.elem.read().1 + } + + /// Gets a mutable reference to the value in the entry. + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get_mut(&mut self) -> &mut V { + self.elem.read_mut().1 + } + + /// Converts the OccupiedEntry into a mutable reference to the value in the entry + /// with a lifetime bound to the map itself + #[stable(feature = "rust1", since = "1.0.0")] + pub fn into_mut(self) -> &'a mut V { + self.elem.into_mut_refs().1 + } + + /// Sets the value of the entry, and returns the entry's old value + #[stable(feature = "rust1", since = "1.0.0")] + pub fn insert(&mut self, mut value: V) -> V { + let old_value = self.get_mut(); + mem::swap(&mut value, old_value); + value + } + + /// Takes the value out of the entry, and returns it + #[stable(feature = "rust1", since = "1.0.0")] + pub fn remove(self) -> V { + pop_internal(self.elem).1 + } +} + +impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> { + /// Sets the value of the entry with the VacantEntry's key, + /// and returns a mutable reference to it + #[stable(feature = "rust1", since = "1.0.0")] + pub fn insert(self, value: V) -> &'a mut V { + match self.elem { + NeqElem(bucket, ib) => { + robin_hood(bucket, ib, self.hash, self.key, value) + } + NoElem(bucket) => { + bucket.put(self.hash, self.key, value).into_mut_refs().1 + } + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<K, V, S, H> FromIterator<(K, V)> for HashMap<K, V, S> + where K: Eq + Hash<H>, + S: HashState<Hasher=H> + Default, + H: hash::Hasher<Output=u64> +{ + fn from_iter<T: IntoIterator<Item=(K, V)>>(iter: T) -> HashMap<K, V, S> { + let iter = iter.into_iter(); + let lower = iter.size_hint().0; + let mut map = HashMap::with_capacity_and_hash_state(lower, + Default::default()); + map.extend(iter); + map + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<K, V, S, H> Extend<(K, V)> for HashMap<K, V, S> + where K: Eq + Hash<H>, + S: HashState<Hasher=H>, + H: hash::Hasher<Output=u64> +{ + fn extend<T: IntoIterator<Item=(K, V)>>(&mut self, iter: T) { + for (k, v) in iter { + self.insert(k, v); + } + } +} + + +/// `RandomState` is the default state for `HashMap` types. +/// +/// A particular instance `RandomState` will create the same instances of +/// `Hasher`, but the hashers created by two different `RandomState` +/// instances are unlikely to produce the same result for the same values. +#[derive(Clone)] +#[unstable(feature = "std_misc", + reason = "hashing an hash maps may be altered")] +pub struct RandomState { + k0: u64, + k1: u64, +} + +#[unstable(feature = "std_misc", + reason = "hashing an hash maps may be altered")] +impl RandomState { + /// Construct a new `RandomState` that is initialized with random keys. + #[inline] + #[allow(deprecated)] + pub fn new() -> RandomState { + let mut r = rand::thread_rng(); + RandomState { k0: r.gen(), k1: r.gen() } + } +} + +#[unstable(feature = "std_misc", + reason = "hashing an hash maps may be altered")] +impl HashState for RandomState { + type Hasher = Hasher; + fn hasher(&self) -> Hasher { + Hasher { inner: SipHasher::new_with_keys(self.k0, self.k1) } + } +} + +#[unstable(feature = "std_misc", + reason = "hashing an hash maps may be altered")] +impl Default for RandomState { + #[inline] + fn default() -> RandomState { + RandomState::new() + } +} + +/// A hasher implementation which is generated from `RandomState` instances. +/// +/// This is the default hasher used in a `HashMap` to hash keys. Types do not +/// typically declare an ability to explicitly hash into this particular type, +/// but rather in a `H: hash::Writer` type parameter. +#[unstable(feature = "std_misc", + reason = "hashing an hash maps may be altered")] +pub struct Hasher { inner: SipHasher } + +impl hash::Writer for Hasher { + fn write(&mut self, data: &[u8]) { + hash::Writer::write(&mut self.inner, data) + } +} + +impl hash::Hasher for Hasher { + type Output = u64; + fn reset(&mut self) { hash::Hasher::reset(&mut self.inner) } + fn finish(&self) -> u64 { self.inner.finish() } +} + +#[cfg(test)] +mod test_map { + use prelude::v1::*; + + use super::HashMap; + use super::Entry::{Occupied, Vacant}; + use iter::{range_inclusive, range_step_inclusive, repeat}; + use cell::RefCell; + use rand::{weak_rng, Rng}; + + #[test] + fn test_create_capacity_zero() { + let mut m = HashMap::with_capacity(0); + + assert!(m.insert(1, 1).is_none()); + + assert!(m.contains_key(&1)); + assert!(!m.contains_key(&0)); + } + + #[test] + fn test_insert() { + let mut m = HashMap::new(); + assert_eq!(m.len(), 0); + assert!(m.insert(1, 2).is_none()); + assert_eq!(m.len(), 1); + assert!(m.insert(2, 4).is_none()); + assert_eq!(m.len(), 2); + assert_eq!(*m.get(&1).unwrap(), 2); + assert_eq!(*m.get(&2).unwrap(), 4); + } + + thread_local! { static DROP_VECTOR: RefCell<Vec<int>> = RefCell::new(Vec::new()) } + + #[derive(Hash, PartialEq, Eq)] + struct Dropable { + k: usize + } + + impl Dropable { + fn new(k: usize) -> Dropable { + DROP_VECTOR.with(|slot| { + slot.borrow_mut()[k] += 1; + }); + + Dropable { k: k } + } + } + + impl Drop for Dropable { + fn drop(&mut self) { + DROP_VECTOR.with(|slot| { + slot.borrow_mut()[self.k] -= 1; + }); + } + } + + impl Clone for Dropable { + fn clone(&self) -> Dropable { + Dropable::new(self.k) + } + } + + #[test] + fn test_drops() { + DROP_VECTOR.with(|slot| { + *slot.borrow_mut() = repeat(0).take(200).collect(); + }); + + { + let mut m = HashMap::new(); + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 0); + } + }); + + for i in 0..100 { + let d1 = Dropable::new(i); + let d2 = Dropable::new(i+100); + m.insert(d1, d2); + } + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 1); + } + }); + + for i in 0..50 { + let k = Dropable::new(i); + let v = m.remove(&k); + + assert!(v.is_some()); + + DROP_VECTOR.with(|v| { + assert_eq!(v.borrow()[i], 1); + assert_eq!(v.borrow()[i+100], 1); + }); + } + + DROP_VECTOR.with(|v| { + for i in 0..50 { + assert_eq!(v.borrow()[i], 0); + assert_eq!(v.borrow()[i+100], 0); + } + + for i in 50..100 { + assert_eq!(v.borrow()[i], 1); + assert_eq!(v.borrow()[i+100], 1); + } + }); + } + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 0); + } + }); + } + + #[test] + fn test_move_iter_drops() { + DROP_VECTOR.with(|v| { + *v.borrow_mut() = repeat(0).take(200).collect(); + }); + + let hm = { + let mut hm = HashMap::new(); + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 0); + } + }); + + for i in 0..100 { + let d1 = Dropable::new(i); + let d2 = Dropable::new(i+100); + hm.insert(d1, d2); + } + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 1); + } + }); + + hm + }; + + // By the way, ensure that cloning doesn't screw up the dropping. + drop(hm.clone()); + + { + let mut half = hm.into_iter().take(50); + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 1); + } + }); + + for _ in half.by_ref() {} + + DROP_VECTOR.with(|v| { + let nk = (0..100).filter(|&i| { + v.borrow()[i] == 1 + }).count(); + + let nv = (0..100).filter(|&i| { + v.borrow()[i+100] == 1 + }).count(); + + assert_eq!(nk, 50); + assert_eq!(nv, 50); + }); + }; + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 0); + } + }); + } + + #[test] + fn test_empty_pop() { + let mut m: HashMap<int, bool> = HashMap::new(); + assert_eq!(m.remove(&0), None); + } + + #[test] + fn test_lots_of_insertions() { + let mut m = HashMap::new(); + + // Try this a few times to make sure we never screw up the hashmap's + // internal state. + for _ in 0..10 { + assert!(m.is_empty()); + + for i in range_inclusive(1, 1000) { + assert!(m.insert(i, i).is_none()); + + for j in range_inclusive(1, i) { + let r = m.get(&j); + assert_eq!(r, Some(&j)); + } + + for j in range_inclusive(i+1, 1000) { + let r = m.get(&j); + assert_eq!(r, None); + } + } + + for i in range_inclusive(1001, 2000) { + assert!(!m.contains_key(&i)); + } + + // remove forwards + for i in range_inclusive(1, 1000) { + assert!(m.remove(&i).is_some()); + + for j in range_inclusive(1, i) { + assert!(!m.contains_key(&j)); + } + + for j in range_inclusive(i+1, 1000) { + assert!(m.contains_key(&j)); + } + } + + for i in range_inclusive(1, 1000) { + assert!(!m.contains_key(&i)); + } + + for i in range_inclusive(1, 1000) { + assert!(m.insert(i, i).is_none()); + } + + // remove backwards + for i in range_step_inclusive(1000, 1, -1) { + assert!(m.remove(&i).is_some()); + + for j in range_inclusive(i, 1000) { + assert!(!m.contains_key(&j)); + } + + for j in range_inclusive(1, i-1) { + assert!(m.contains_key(&j)); + } + } + } + } + + #[test] + fn test_find_mut() { + let mut m = HashMap::new(); + assert!(m.insert(1, 12).is_none()); + assert!(m.insert(2, 8).is_none()); + assert!(m.insert(5, 14).is_none()); + let new = 100; + match m.get_mut(&5) { + None => panic!(), Some(x) => *x = new + } + assert_eq!(m.get(&5), Some(&new)); + } + + #[test] + fn test_insert_overwrite() { + let mut m = HashMap::new(); + assert!(m.insert(1, 2).is_none()); + assert_eq!(*m.get(&1).unwrap(), 2); + assert!(!m.insert(1, 3).is_none()); + assert_eq!(*m.get(&1).unwrap(), 3); + } + + #[test] + fn test_insert_conflicts() { + let mut m = HashMap::with_capacity(4); + assert!(m.insert(1, 2).is_none()); + assert!(m.insert(5, 3).is_none()); + assert!(m.insert(9, 4).is_none()); + assert_eq!(*m.get(&9).unwrap(), 4); + assert_eq!(*m.get(&5).unwrap(), 3); + assert_eq!(*m.get(&1).unwrap(), 2); + } + + #[test] + fn test_conflict_remove() { + let mut m = HashMap::with_capacity(4); + assert!(m.insert(1, 2).is_none()); + assert_eq!(*m.get(&1).unwrap(), 2); + assert!(m.insert(5, 3).is_none()); + assert_eq!(*m.get(&1).unwrap(), 2); + assert_eq!(*m.get(&5).unwrap(), 3); + assert!(m.insert(9, 4).is_none()); + assert_eq!(*m.get(&1).unwrap(), 2); + assert_eq!(*m.get(&5).unwrap(), 3); + assert_eq!(*m.get(&9).unwrap(), 4); + assert!(m.remove(&1).is_some()); + assert_eq!(*m.get(&9).unwrap(), 4); + assert_eq!(*m.get(&5).unwrap(), 3); + } + + #[test] + fn test_is_empty() { + let mut m = HashMap::with_capacity(4); + assert!(m.insert(1, 2).is_none()); + assert!(!m.is_empty()); + assert!(m.remove(&1).is_some()); + assert!(m.is_empty()); + } + + #[test] + fn test_pop() { + let mut m = HashMap::new(); + m.insert(1, 2); + assert_eq!(m.remove(&1), Some(2)); + assert_eq!(m.remove(&1), None); + } + + #[test] + fn test_iterate() { + let mut m = HashMap::with_capacity(4); + for i in 0..32 { + assert!(m.insert(i, i*2).is_none()); + } + assert_eq!(m.len(), 32); + + let mut observed: u32 = 0; + + for (k, v) in &m { + assert_eq!(*v, *k * 2); + observed |= 1 << *k; + } + assert_eq!(observed, 0xFFFF_FFFF); + } + + #[test] + fn test_keys() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: HashMap<_, _> = vec.into_iter().collect(); + let keys: Vec<_> = map.keys().cloned().collect(); + assert_eq!(keys.len(), 3); + assert!(keys.contains(&1)); + assert!(keys.contains(&2)); + assert!(keys.contains(&3)); + } + + #[test] + fn test_values() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: HashMap<_, _> = vec.into_iter().collect(); + let values: Vec<_> = map.values().cloned().collect(); + assert_eq!(values.len(), 3); + assert!(values.contains(&'a')); + assert!(values.contains(&'b')); + assert!(values.contains(&'c')); + } + + #[test] + fn test_find() { + let mut m = HashMap::new(); + assert!(m.get(&1).is_none()); + m.insert(1, 2); + match m.get(&1) { + None => panic!(), + Some(v) => assert_eq!(*v, 2) + } + } + + #[test] + fn test_eq() { + let mut m1 = HashMap::new(); + m1.insert(1, 2); + m1.insert(2, 3); + m1.insert(3, 4); + + let mut m2 = HashMap::new(); + m2.insert(1, 2); + m2.insert(2, 3); + + assert!(m1 != m2); + + m2.insert(3, 4); + + assert_eq!(m1, m2); + } + + #[test] + fn test_show() { + let mut map = HashMap::new(); + let empty: HashMap<i32, i32> = HashMap::new(); + + map.insert(1, 2); + map.insert(3, 4); + + let map_str = format!("{:?}", map); + + assert!(map_str == "HashMap {1: 2, 3: 4}" || + map_str == "HashMap {3: 4, 1: 2}"); + assert_eq!(format!("{:?}", empty), "HashMap {}"); + } + + #[test] + fn test_expand() { + let mut m = HashMap::new(); + + assert_eq!(m.len(), 0); + assert!(m.is_empty()); + + let mut i = 0; + let old_cap = m.table.capacity(); + while old_cap == m.table.capacity() { + m.insert(i, i); + i += 1; + } + + assert_eq!(m.len(), i); + assert!(!m.is_empty()); + } + + #[test] + fn test_behavior_resize_policy() { + let mut m = HashMap::new(); + + assert_eq!(m.len(), 0); + assert_eq!(m.table.capacity(), 0); + assert!(m.is_empty()); + + m.insert(0, 0); + m.remove(&0); + assert!(m.is_empty()); + let initial_cap = m.table.capacity(); + m.reserve(initial_cap); + let cap = m.table.capacity(); + + assert_eq!(cap, initial_cap * 2); + + let mut i = 0; + for _ in 0..cap * 3 / 4 { + m.insert(i, i); + i += 1; + } + // three quarters full + + assert_eq!(m.len(), i); + assert_eq!(m.table.capacity(), cap); + + for _ in 0..cap / 4 { + m.insert(i, i); + i += 1; + } + // half full + + let new_cap = m.table.capacity(); + assert_eq!(new_cap, cap * 2); + + for _ in 0..cap / 2 - 1 { + i -= 1; + m.remove(&i); + assert_eq!(m.table.capacity(), new_cap); + } + // A little more than one quarter full. + m.shrink_to_fit(); + assert_eq!(m.table.capacity(), cap); + // again, a little more than half full + for _ in 0..cap / 2 - 1 { + i -= 1; + m.remove(&i); + } + m.shrink_to_fit(); + + assert_eq!(m.len(), i); + assert!(!m.is_empty()); + assert_eq!(m.table.capacity(), initial_cap); + } + + #[test] + fn test_reserve_shrink_to_fit() { + let mut m = HashMap::new(); + m.insert(0, 0); + m.remove(&0); + assert!(m.capacity() >= m.len()); + for i in 0..128 { + m.insert(i, i); + } + m.reserve(256); + + let usable_cap = m.capacity(); + for i in 128..(128 + 256) { + m.insert(i, i); + assert_eq!(m.capacity(), usable_cap); + } + + for i in 100..(128 + 256) { + assert_eq!(m.remove(&i), Some(i)); + } + m.shrink_to_fit(); + + assert_eq!(m.len(), 100); + assert!(!m.is_empty()); + assert!(m.capacity() >= m.len()); + + for i in 0..100 { + assert_eq!(m.remove(&i), Some(i)); + } + m.shrink_to_fit(); + m.insert(0, 0); + + assert_eq!(m.len(), 1); + assert!(m.capacity() >= m.len()); + assert_eq!(m.remove(&0), Some(0)); + } + + #[test] + fn test_from_iter() { + let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let map: HashMap<_, _> = xs.iter().cloned().collect(); + + for &(k, v) in &xs { + assert_eq!(map.get(&k), Some(&v)); + } + } + + #[test] + fn test_size_hint() { + let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let map: HashMap<_, _> = xs.iter().cloned().collect(); + + let mut iter = map.iter(); + + for _ in iter.by_ref().take(3) {} + + assert_eq!(iter.size_hint(), (3, Some(3))); + } + + #[test] + fn test_iter_len() { + let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let map: HashMap<_, _> = xs.iter().cloned().collect(); + + let mut iter = map.iter(); + + for _ in iter.by_ref().take(3) {} + + assert_eq!(iter.len(), 3); + } + + #[test] + fn test_mut_size_hint() { + let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let mut map: HashMap<_, _> = xs.iter().cloned().collect(); + + let mut iter = map.iter_mut(); + + for _ in iter.by_ref().take(3) {} + + assert_eq!(iter.size_hint(), (3, Some(3))); + } + + #[test] + fn test_iter_mut_len() { + let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let mut map: HashMap<_, _> = xs.iter().cloned().collect(); + + let mut iter = map.iter_mut(); + + for _ in iter.by_ref().take(3) {} + + assert_eq!(iter.len(), 3); + } + + #[test] + fn test_index() { + let mut map = HashMap::new(); + + map.insert(1, 2); + map.insert(2, 1); + map.insert(3, 4); + + assert_eq!(map[2], 1); + } + + #[test] + #[should_fail] + fn test_index_nonexistent() { + let mut map = HashMap::new(); + + map.insert(1, 2); + map.insert(2, 1); + map.insert(3, 4); + + map[4]; + } + + #[test] + fn test_entry(){ + let xs = [(1, 10), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)]; + + let mut map: HashMap<_, _> = xs.iter().cloned().collect(); + + // Existing key (insert) + match map.entry(1) { + Vacant(_) => unreachable!(), + Occupied(mut view) => { + assert_eq!(view.get(), &10); + assert_eq!(view.insert(100), 10); + } + } + assert_eq!(map.get(&1).unwrap(), &100); + assert_eq!(map.len(), 6); + + + // Existing key (update) + match map.entry(2) { + Vacant(_) => unreachable!(), + Occupied(mut view) => { + let v = view.get_mut(); + let new_v = (*v) * 10; + *v = new_v; + } + } + assert_eq!(map.get(&2).unwrap(), &200); + assert_eq!(map.len(), 6); + + // Existing key (take) + match map.entry(3) { + Vacant(_) => unreachable!(), + Occupied(view) => { + assert_eq!(view.remove(), 30); + } + } + assert_eq!(map.get(&3), None); + assert_eq!(map.len(), 5); + + + // Inexistent key (insert) + match map.entry(10) { + Occupied(_) => unreachable!(), + Vacant(view) => { + assert_eq!(*view.insert(1000), 1000); + } + } + assert_eq!(map.get(&10).unwrap(), &1000); + assert_eq!(map.len(), 6); + } + + #[test] + fn test_entry_take_doesnt_corrupt() { + // Test for #19292 + fn check(m: &HashMap<isize, ()>) { + for k in m.keys() { + assert!(m.contains_key(k), + "{} is in keys() but not in the map?", k); + } + } + + let mut m = HashMap::new(); + let mut rng = weak_rng(); + + // Populate the map with some items. + for _ in 0..50 { + let x = rng.gen_range(-10, 10); + m.insert(x, ()); + } + + for i in 0..1000 { + let x = rng.gen_range(-10, 10); + match m.entry(x) { + Vacant(_) => {}, + Occupied(e) => { + println!("{}: remove {}", i, x); + e.remove(); + }, + } + + check(&m); + } + } +} diff --git a/src/libstd/collections/hash/mod.rs b/src/libstd/collections/hash/mod.rs index 47e300af269..39c1458b720 100644 --- a/src/libstd/collections/hash/mod.rs +++ b/src/libstd/collections/hash/mod.rs @@ -12,6 +12,14 @@ mod bench; mod table; +#[cfg(stage0)] +#[path = "map_stage0.rs"] pub mod map; +#[cfg(not(stage0))] +pub mod map; +#[cfg(stage0)] +#[path = "set_stage0.rs"] +pub mod set; +#[cfg(not(stage0))] pub mod set; pub mod state; diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index 5fbbcb3b347..e0631a64d44 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -10,21 +10,21 @@ // // ignore-lexer-test FIXME #15883 -use borrow::BorrowFrom; +use borrow::Borrow; use clone::Clone; use cmp::{Eq, PartialEq}; use core::marker::Sized; use default::Default; use fmt::Debug; use fmt; -use hash::{self, Hash}; +use hash::Hash; use iter::{ Iterator, IntoIterator, ExactSizeIterator, IteratorExt, FromIterator, Map, Chain, Extend, }; use ops::{BitOr, BitAnd, BitXor, Sub}; use option::Option::{Some, None, self}; -use super::map::{self, HashMap, Keys, INITIAL_CAPACITY, RandomState, Hasher}; +use super::map::{self, HashMap, Keys, INITIAL_CAPACITY, RandomState}; use super::state::HashState; // Future Optimization (FIXME!) @@ -97,7 +97,7 @@ pub struct HashSet<T, S = RandomState> { map: HashMap<T, (), S> } -impl<T: Hash<Hasher> + Eq> HashSet<T, RandomState> { +impl<T: Hash + Eq> HashSet<T, RandomState> { /// Create an empty HashSet. /// /// # Example @@ -128,10 +128,8 @@ impl<T: Hash<Hasher> + Eq> HashSet<T, RandomState> { } } -impl<T, S, H> HashSet<T, S> - where T: Eq + Hash<H>, - S: HashState<Hasher=H>, - H: hash::Hasher<Output=u64> +impl<T, S> HashSet<T, S> + where T: Eq + Hash, S: HashState { /// Creates a new empty hash set which will use the given hasher to hash /// keys. @@ -462,7 +460,7 @@ impl<T, S, H> HashSet<T, S> /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn contains<Q: ?Sized>(&self, value: &Q) -> bool - where Q: BorrowFrom<T> + Hash<H> + Eq + where T: Borrow<Q>, Q: Hash + Eq { self.map.contains_key(value) } @@ -572,17 +570,15 @@ impl<T, S, H> HashSet<T, S> /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn remove<Q: ?Sized>(&mut self, value: &Q) -> bool - where Q: BorrowFrom<T> + Hash<H> + Eq + where T: Borrow<Q>, Q: Hash + Eq { self.map.remove(value).is_some() } } #[stable(feature = "rust1", since = "1.0.0")] -impl<T, S, H> PartialEq for HashSet<T, S> - where T: Eq + Hash<H>, - S: HashState<Hasher=H>, - H: hash::Hasher<Output=u64> +impl<T, S> PartialEq for HashSet<T, S> + where T: Eq + Hash, S: HashState { fn eq(&self, other: &HashSet<T, S>) -> bool { if self.len() != other.len() { return false; } @@ -592,17 +588,14 @@ impl<T, S, H> PartialEq for HashSet<T, S> } #[stable(feature = "rust1", since = "1.0.0")] -impl<T, S, H> Eq for HashSet<T, S> - where T: Eq + Hash<H>, - S: HashState<Hasher=H>, - H: hash::Hasher<Output=u64> +impl<T, S> Eq for HashSet<T, S> + where T: Eq + Hash, S: HashState {} #[stable(feature = "rust1", since = "1.0.0")] -impl<T, S, H> fmt::Debug for HashSet<T, S> - where T: Eq + Hash<H> + fmt::Debug, - S: HashState<Hasher=H>, - H: hash::Hasher<Output=u64> +impl<T, S> fmt::Debug for HashSet<T, S> + where T: Eq + Hash + fmt::Debug, + S: HashState { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { try!(write!(f, "HashSet {{")); @@ -617,12 +610,12 @@ impl<T, S, H> fmt::Debug for HashSet<T, S> } #[stable(feature = "rust1", since = "1.0.0")] -impl<T, S, H> FromIterator<T> for HashSet<T, S> - where T: Eq + Hash<H>, - S: HashState<Hasher=H> + Default, - H: hash::Hasher<Output=u64> +impl<T, S> FromIterator<T> for HashSet<T, S> + where T: Eq + Hash, + S: HashState + Default, { - fn from_iter<I: Iterator<Item=T>>(iter: I) -> HashSet<T, S> { + fn from_iter<I: IntoIterator<Item=T>>(iterable: I) -> HashSet<T, S> { + let iter = iterable.into_iter(); let lower = iter.size_hint().0; let mut set = HashSet::with_capacity_and_hash_state(lower, Default::default()); set.extend(iter); @@ -631,12 +624,11 @@ impl<T, S, H> FromIterator<T> for HashSet<T, S> } #[stable(feature = "rust1", since = "1.0.0")] -impl<T, S, H> Extend<T> for HashSet<T, S> - where T: Eq + Hash<H>, - S: HashState<Hasher=H>, - H: hash::Hasher<Output=u64> +impl<T, S> Extend<T> for HashSet<T, S> + where T: Eq + Hash, + S: HashState, { - fn extend<I: Iterator<Item=T>>(&mut self, iter: I) { + fn extend<I: IntoIterator<Item=T>>(&mut self, iter: I) { for k in iter { self.insert(k); } @@ -644,10 +636,9 @@ impl<T, S, H> Extend<T> for HashSet<T, S> } #[stable(feature = "rust1", since = "1.0.0")] -impl<T, S, H> Default for HashSet<T, S> - where T: Eq + Hash<H>, - S: HashState<Hasher=H> + Default, - H: hash::Hasher<Output=u64> +impl<T, S> Default for HashSet<T, S> + where T: Eq + Hash, + S: HashState + Default, { #[stable(feature = "rust1", since = "1.0.0")] fn default() -> HashSet<T, S> { @@ -656,10 +647,9 @@ impl<T, S, H> Default for HashSet<T, S> } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, 'b, T, S, H> BitOr<&'b HashSet<T, S>> for &'a HashSet<T, S> - where T: Eq + Hash<H> + Clone, - S: HashState<Hasher=H> + Default, - H: hash::Hasher<Output=u64> +impl<'a, 'b, T, S> BitOr<&'b HashSet<T, S>> for &'a HashSet<T, S> + where T: Eq + Hash + Clone, + S: HashState + Default, { type Output = HashSet<T, S>; @@ -689,10 +679,9 @@ impl<'a, 'b, T, S, H> BitOr<&'b HashSet<T, S>> for &'a HashSet<T, S> } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, 'b, T, S, H> BitAnd<&'b HashSet<T, S>> for &'a HashSet<T, S> - where T: Eq + Hash<H> + Clone, - S: HashState<Hasher=H> + Default, - H: hash::Hasher<Output=u64> +impl<'a, 'b, T, S> BitAnd<&'b HashSet<T, S>> for &'a HashSet<T, S> + where T: Eq + Hash + Clone, + S: HashState + Default, { type Output = HashSet<T, S>; @@ -722,10 +711,9 @@ impl<'a, 'b, T, S, H> BitAnd<&'b HashSet<T, S>> for &'a HashSet<T, S> } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, 'b, T, S, H> BitXor<&'b HashSet<T, S>> for &'a HashSet<T, S> - where T: Eq + Hash<H> + Clone, - S: HashState<Hasher=H> + Default, - H: hash::Hasher<Output=u64> +impl<'a, 'b, T, S> BitXor<&'b HashSet<T, S>> for &'a HashSet<T, S> + where T: Eq + Hash + Clone, + S: HashState + Default, { type Output = HashSet<T, S>; @@ -755,10 +743,9 @@ impl<'a, 'b, T, S, H> BitXor<&'b HashSet<T, S>> for &'a HashSet<T, S> } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, 'b, T, S, H> Sub<&'b HashSet<T, S>> for &'a HashSet<T, S> - where T: Eq + Hash<H> + Clone, - S: HashState<Hasher=H> + Default, - H: hash::Hasher<Output=u64> +impl<'a, 'b, T, S> Sub<&'b HashSet<T, S>> for &'a HashSet<T, S> + where T: Eq + Hash + Clone, + S: HashState + Default, { type Output = HashSet<T, S>; @@ -836,10 +823,8 @@ pub struct Union<'a, T: 'a, S: 'a> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, S, H> IntoIterator for &'a HashSet<T, S> - where T: Eq + Hash<H>, - S: HashState<Hasher=H>, - H: hash::Hasher<Output=u64> +impl<'a, T, S> IntoIterator for &'a HashSet<T, S> + where T: Eq + Hash, S: HashState { type Item = &'a T; type IntoIter = Iter<'a, T>; @@ -850,10 +835,9 @@ impl<'a, T, S, H> IntoIterator for &'a HashSet<T, S> } #[stable(feature = "rust1", since = "1.0.0")] -impl<T, S, H> IntoIterator for HashSet<T, S> - where T: Eq + Hash<H>, - S: HashState<Hasher=H>, - H: hash::Hasher<Output=u64> +impl<T, S> IntoIterator for HashSet<T, S> + where T: Eq + Hash, + S: HashState { type Item = T; type IntoIter = IntoIter<T>; @@ -900,10 +884,8 @@ impl<'a, K> ExactSizeIterator for Drain<'a, K> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, S, H> Iterator for Intersection<'a, T, S> - where T: Eq + Hash<H>, - S: HashState<Hasher=H>, - H: hash::Hasher<Output=u64> +impl<'a, T, S> Iterator for Intersection<'a, T, S> + where T: Eq + Hash, S: HashState { type Item = &'a T; @@ -925,10 +907,8 @@ impl<'a, T, S, H> Iterator for Intersection<'a, T, S> } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, S, H> Iterator for Difference<'a, T, S> - where T: Eq + Hash<H>, - S: HashState<Hasher=H>, - H: hash::Hasher<Output=u64> +impl<'a, T, S> Iterator for Difference<'a, T, S> + where T: Eq + Hash, S: HashState { type Item = &'a T; @@ -950,10 +930,8 @@ impl<'a, T, S, H> Iterator for Difference<'a, T, S> } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, S, H> Iterator for SymmetricDifference<'a, T, S> - where T: Eq + Hash<H>, - S: HashState<Hasher=H>, - H: hash::Hasher<Output=u64> +impl<'a, T, S> Iterator for SymmetricDifference<'a, T, S> + where T: Eq + Hash, S: HashState { type Item = &'a T; @@ -962,10 +940,8 @@ impl<'a, T, S, H> Iterator for SymmetricDifference<'a, T, S> } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, S, H> Iterator for Union<'a, T, S> - where T: Eq + Hash<H>, - S: HashState<Hasher=H>, - H: hash::Hasher<Output=u64> +impl<'a, T, S> Iterator for Union<'a, T, S> + where T: Eq + Hash, S: HashState { type Item = &'a T; diff --git a/src/libstd/collections/hash/set_stage0.rs b/src/libstd/collections/hash/set_stage0.rs new file mode 100644 index 00000000000..68c9e02d8ad --- /dev/null +++ b/src/libstd/collections/hash/set_stage0.rs @@ -0,0 +1,1252 @@ +// Copyright 2014 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. +// +// ignore-lexer-test FIXME #15883 + +use borrow::Borrow; +use clone::Clone; +use cmp::{Eq, PartialEq}; +use core::marker::Sized; +use default::Default; +use fmt::Debug; +use fmt; +use hash::{self, Hash}; +use iter::{ + Iterator, IntoIterator, ExactSizeIterator, IteratorExt, FromIterator, Map, Chain, Extend, +}; +use ops::{BitOr, BitAnd, BitXor, Sub}; +use option::Option::{Some, None, self}; + +use super::map::{self, HashMap, Keys, INITIAL_CAPACITY, RandomState, Hasher}; +use super::state::HashState; + +// Future Optimization (FIXME!) +// ============================= +// +// Iteration over zero sized values is a noop. There is no need +// for `bucket.val` in the case of HashSet. I suppose we would need HKT +// to get rid of it properly. + +/// An implementation of a hash set using the underlying representation of a +/// HashMap where the value is (). As with the `HashMap` type, a `HashSet` +/// requires that the elements implement the `Eq` and `Hash` traits. +/// +/// # Example +/// +/// ``` +/// use std::collections::HashSet; +/// // Type inference lets us omit an explicit type signature (which +/// // would be `HashSet<&str>` in this example). +/// let mut books = HashSet::new(); +/// +/// // Add some books. +/// books.insert("A Dance With Dragons"); +/// books.insert("To Kill a Mockingbird"); +/// books.insert("The Odyssey"); +/// books.insert("The Great Gatsby"); +/// +/// // Check for a specific one. +/// if !books.contains(&("The Winds of Winter")) { +/// println!("We have {} books, but The Winds of Winter ain't one.", +/// books.len()); +/// } +/// +/// // Remove a book. +/// books.remove(&"The Odyssey"); +/// +/// // Iterate over everything. +/// for book in books.iter() { +/// println!("{}", *book); +/// } +/// ``` +/// +/// The easiest way to use `HashSet` with a custom type is to derive +/// `Eq` and `Hash`. We must also derive `PartialEq`, this will in the +/// future be implied by `Eq`. +/// +/// ``` +/// use std::collections::HashSet; +/// #[derive(Hash, Eq, PartialEq, Debug)] +/// struct Viking<'a> { +/// name: &'a str, +/// power: usize, +/// } +/// +/// let mut vikings = HashSet::new(); +/// +/// vikings.insert(Viking { name: "Einar", power: 9 }); +/// vikings.insert(Viking { name: "Einar", power: 9 }); +/// vikings.insert(Viking { name: "Olaf", power: 4 }); +/// vikings.insert(Viking { name: "Harald", power: 8 }); +/// +/// // Use derived implementation to print the vikings. +/// for x in vikings.iter() { +/// println!("{:?}", x); +/// } +/// ``` +#[derive(Clone)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct HashSet<T, S = RandomState> { + map: HashMap<T, (), S> +} + +impl<T: Hash<Hasher> + Eq> HashSet<T, RandomState> { + /// Create an empty HashSet. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashSet; + /// let mut set: HashSet<int> = HashSet::new(); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn new() -> HashSet<T, RandomState> { + HashSet::with_capacity(INITIAL_CAPACITY) + } + + /// Create an empty HashSet with space for at least `n` elements in + /// the hash table. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashSet; + /// let mut set: HashSet<int> = HashSet::with_capacity(10); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn with_capacity(capacity: usize) -> HashSet<T, RandomState> { + HashSet { map: HashMap::with_capacity(capacity) } + } +} + +impl<T, S, H> HashSet<T, S> + where T: Eq + Hash<H>, + S: HashState<Hasher=H>, + H: hash::Hasher<Output=u64> +{ + /// Creates a new empty hash set which will use the given hasher to hash + /// keys. + /// + /// The hash set is also created with the default initial capacity. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashSet; + /// use std::collections::hash_map::RandomState; + /// + /// let s = RandomState::new(); + /// let mut set = HashSet::with_hash_state(s); + /// set.insert(2); + /// ``` + #[inline] + #[unstable(feature = "std_misc", reason = "hasher stuff is unclear")] + pub fn with_hash_state(hash_state: S) -> HashSet<T, S> { + HashSet::with_capacity_and_hash_state(INITIAL_CAPACITY, hash_state) + } + + /// Create an empty HashSet with space for at least `capacity` + /// elements in the hash table, using `hasher` to hash the keys. + /// + /// Warning: `hasher` is normally randomly generated, and + /// is designed to allow `HashSet`s to be resistant to attacks that + /// cause many collisions and very poor performance. Setting it + /// manually using this function can expose a DoS attack vector. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashSet; + /// use std::collections::hash_map::RandomState; + /// + /// let s = RandomState::new(); + /// let mut set = HashSet::with_capacity_and_hash_state(10, s); + /// set.insert(1); + /// ``` + #[inline] + #[unstable(feature = "std_misc", reason = "hasher stuff is unclear")] + pub fn with_capacity_and_hash_state(capacity: usize, hash_state: S) + -> HashSet<T, S> { + HashSet { + map: HashMap::with_capacity_and_hash_state(capacity, hash_state), + } + } + + /// Returns the number of elements the set can hold without reallocating. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashSet; + /// let set: HashSet<int> = HashSet::with_capacity(100); + /// assert!(set.capacity() >= 100); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn capacity(&self) -> usize { + self.map.capacity() + } + + /// Reserves capacity for at least `additional` more elements to be inserted + /// in the `HashSet`. The collection may reserve more space to avoid + /// frequent reallocations. + /// + /// # Panics + /// + /// Panics if the new allocation size overflows `usize`. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashSet; + /// let mut set: HashSet<int> = HashSet::new(); + /// set.reserve(10); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn reserve(&mut self, additional: usize) { + self.map.reserve(additional) + } + + /// Shrinks the capacity of the set as much as possible. It will drop + /// down as much as possible while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let mut set: HashSet<int> = HashSet::with_capacity(100); + /// set.insert(1); + /// set.insert(2); + /// assert!(set.capacity() >= 100); + /// set.shrink_to_fit(); + /// assert!(set.capacity() >= 2); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn shrink_to_fit(&mut self) { + self.map.shrink_to_fit() + } + + /// An iterator visiting all elements in arbitrary order. + /// Iterator element type is &'a T. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashSet; + /// let mut set = HashSet::new(); + /// set.insert("a"); + /// set.insert("b"); + /// + /// // Will print in an arbitrary order. + /// for x in set.iter() { + /// println!("{}", x); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn iter(&self) -> Iter<T> { + Iter { iter: self.map.keys() } + } + + /// Creates a consuming iterator, that is, one that moves each value out + /// of the set in arbitrary order. The set cannot be used after calling + /// this. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashSet; + /// let mut set = HashSet::new(); + /// set.insert("a".to_string()); + /// set.insert("b".to_string()); + /// + /// // Not possible to collect to a Vec<String> with a regular `.iter()`. + /// let v: Vec<String> = set.into_iter().collect(); + /// + /// // Will print in an arbitrary order. + /// for x in v.iter() { + /// println!("{}", x); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn into_iter(self) -> IntoIter<T> { + fn first<A, B>((a, _): (A, B)) -> A { a } + let first: fn((T, ())) -> T = first; + + IntoIter { iter: self.map.into_iter().map(first) } + } + + /// Visit the values representing the difference. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashSet; + /// let a: HashSet<int> = [1, 2, 3].iter().map(|&x| x).collect(); + /// let b: HashSet<int> = [4, 2, 3, 4].iter().map(|&x| x).collect(); + /// + /// // Can be seen as `a - b`. + /// for x in a.difference(&b) { + /// println!("{}", x); // Print 1 + /// } + /// + /// let diff: HashSet<int> = a.difference(&b).map(|&x| x).collect(); + /// assert_eq!(diff, [1].iter().map(|&x| x).collect()); + /// + /// // Note that difference is not symmetric, + /// // and `b - a` means something else: + /// let diff: HashSet<int> = b.difference(&a).map(|&x| x).collect(); + /// assert_eq!(diff, [4].iter().map(|&x| x).collect()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn difference<'a>(&'a self, other: &'a HashSet<T, S>) -> Difference<'a, T, S> { + Difference { + iter: self.iter(), + other: other, + } + } + + /// Visit the values representing the symmetric difference. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashSet; + /// let a: HashSet<int> = [1, 2, 3].iter().map(|&x| x).collect(); + /// let b: HashSet<int> = [4, 2, 3, 4].iter().map(|&x| x).collect(); + /// + /// // Print 1, 4 in arbitrary order. + /// for x in a.symmetric_difference(&b) { + /// println!("{}", x); + /// } + /// + /// let diff1: HashSet<int> = a.symmetric_difference(&b).map(|&x| x).collect(); + /// let diff2: HashSet<int> = b.symmetric_difference(&a).map(|&x| x).collect(); + /// + /// assert_eq!(diff1, diff2); + /// assert_eq!(diff1, [1, 4].iter().map(|&x| x).collect()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn symmetric_difference<'a>(&'a self, other: &'a HashSet<T, S>) + -> SymmetricDifference<'a, T, S> { + SymmetricDifference { iter: self.difference(other).chain(other.difference(self)) } + } + + /// Visit the values representing the intersection. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashSet; + /// let a: HashSet<int> = [1, 2, 3].iter().map(|&x| x).collect(); + /// let b: HashSet<int> = [4, 2, 3, 4].iter().map(|&x| x).collect(); + /// + /// // Print 2, 3 in arbitrary order. + /// for x in a.intersection(&b) { + /// println!("{}", x); + /// } + /// + /// let diff: HashSet<int> = a.intersection(&b).map(|&x| x).collect(); + /// assert_eq!(diff, [2, 3].iter().map(|&x| x).collect()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn intersection<'a>(&'a self, other: &'a HashSet<T, S>) -> Intersection<'a, T, S> { + Intersection { + iter: self.iter(), + other: other, + } + } + + /// Visit the values representing the union. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashSet; + /// let a: HashSet<int> = [1, 2, 3].iter().map(|&x| x).collect(); + /// let b: HashSet<int> = [4, 2, 3, 4].iter().map(|&x| x).collect(); + /// + /// // Print 1, 2, 3, 4 in arbitrary order. + /// for x in a.union(&b) { + /// println!("{}", x); + /// } + /// + /// let diff: HashSet<int> = a.union(&b).map(|&x| x).collect(); + /// assert_eq!(diff, [1, 2, 3, 4].iter().map(|&x| x).collect()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn union<'a>(&'a self, other: &'a HashSet<T, S>) -> Union<'a, T, S> { + Union { iter: self.iter().chain(other.difference(self)) } + } + + /// Return the number of elements in the set + /// + /// # Example + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let mut v = HashSet::new(); + /// assert_eq!(v.len(), 0); + /// v.insert(1); + /// assert_eq!(v.len(), 1); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn len(&self) -> usize { self.map.len() } + + /// Returns true if the set contains no elements + /// + /// # Example + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let mut v = HashSet::new(); + /// assert!(v.is_empty()); + /// v.insert(1); + /// assert!(!v.is_empty()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn is_empty(&self) -> bool { self.map.len() == 0 } + + /// Clears the set, returning all elements in an iterator. + #[inline] + #[unstable(feature = "std_misc", + reason = "matches collection reform specification, waiting for dust to settle")] + pub fn drain(&mut self) -> Drain<T> { + fn first<A, B>((a, _): (A, B)) -> A { a } + let first: fn((T, ())) -> T = first; // coerce to fn pointer + + Drain { iter: self.map.drain().map(first) } + } + + /// Clears the set, removing all values. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let mut v = HashSet::new(); + /// v.insert(1); + /// v.clear(); + /// assert!(v.is_empty()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn clear(&mut self) { self.map.clear() } + + /// Returns `true` if the set contains a value. + /// + /// The value may be any borrowed form of the set's value type, but + /// `Hash` and `Eq` on the borrowed form *must* match those for + /// the value type. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let set: HashSet<_> = [1, 2, 3].iter().cloned().collect(); + /// assert_eq!(set.contains(&1), true); + /// assert_eq!(set.contains(&4), false); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn contains<Q: ?Sized>(&self, value: &Q) -> bool + where T: Borrow<Q>, Q: Hash<H> + Eq + { + self.map.contains_key(value) + } + + /// Returns `true` if the set has no elements in common with `other`. + /// This is equivalent to checking for an empty intersection. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect(); + /// let mut b = HashSet::new(); + /// + /// assert_eq!(a.is_disjoint(&b), true); + /// b.insert(4); + /// assert_eq!(a.is_disjoint(&b), true); + /// b.insert(1); + /// assert_eq!(a.is_disjoint(&b), false); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn is_disjoint(&self, other: &HashSet<T, S>) -> bool { + self.iter().all(|v| !other.contains(v)) + } + + /// Returns `true` if the set is a subset of another. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let sup: HashSet<_> = [1, 2, 3].iter().cloned().collect(); + /// let mut set = HashSet::new(); + /// + /// assert_eq!(set.is_subset(&sup), true); + /// set.insert(2); + /// assert_eq!(set.is_subset(&sup), true); + /// set.insert(4); + /// assert_eq!(set.is_subset(&sup), false); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn is_subset(&self, other: &HashSet<T, S>) -> bool { + self.iter().all(|v| other.contains(v)) + } + + /// Returns `true` if the set is a superset of another. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let sub: HashSet<_> = [1, 2].iter().cloned().collect(); + /// let mut set = HashSet::new(); + /// + /// assert_eq!(set.is_superset(&sub), false); + /// + /// set.insert(0); + /// set.insert(1); + /// assert_eq!(set.is_superset(&sub), false); + /// + /// set.insert(2); + /// assert_eq!(set.is_superset(&sub), true); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn is_superset(&self, other: &HashSet<T, S>) -> bool { + other.is_subset(self) + } + + /// Adds a value to the set. Returns `true` if the value was not already + /// present in the set. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let mut set = HashSet::new(); + /// + /// assert_eq!(set.insert(2), true); + /// assert_eq!(set.insert(2), false); + /// assert_eq!(set.len(), 1); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn insert(&mut self, value: T) -> bool { self.map.insert(value, ()).is_none() } + + /// Removes a value from the set. Returns `true` if the value was + /// present in the set. + /// + /// The value may be any borrowed form of the set's value type, but + /// `Hash` and `Eq` on the borrowed form *must* match those for + /// the value type. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let mut set = HashSet::new(); + /// + /// set.insert(2); + /// assert_eq!(set.remove(&2), true); + /// assert_eq!(set.remove(&2), false); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn remove<Q: ?Sized>(&mut self, value: &Q) -> bool + where T: Borrow<Q>, Q: Hash<H> + Eq + { + self.map.remove(value).is_some() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<T, S, H> PartialEq for HashSet<T, S> + where T: Eq + Hash<H>, + S: HashState<Hasher=H>, + H: hash::Hasher<Output=u64> +{ + fn eq(&self, other: &HashSet<T, S>) -> bool { + if self.len() != other.len() { return false; } + + self.iter().all(|key| other.contains(key)) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<T, S, H> Eq for HashSet<T, S> + where T: Eq + Hash<H>, + S: HashState<Hasher=H>, + H: hash::Hasher<Output=u64> +{} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<T, S, H> fmt::Debug for HashSet<T, S> + where T: Eq + Hash<H> + fmt::Debug, + S: HashState<Hasher=H>, + H: hash::Hasher<Output=u64> +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + try!(write!(f, "HashSet {{")); + + for (i, x) in self.iter().enumerate() { + if i != 0 { try!(write!(f, ", ")); } + try!(write!(f, "{:?}", *x)); + } + + write!(f, "}}") + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<T, S, H> FromIterator<T> for HashSet<T, S> + where T: Eq + Hash<H>, + S: HashState<Hasher=H> + Default, + H: hash::Hasher<Output=u64> +{ + fn from_iter<I: IntoIterator<Item=T>>(iter: I) -> HashSet<T, S> { + let iter = iter.into_iter(); + let lower = iter.size_hint().0; + let mut set = HashSet::with_capacity_and_hash_state(lower, Default::default()); + set.extend(iter); + set + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<T, S, H> Extend<T> for HashSet<T, S> + where T: Eq + Hash<H>, + S: HashState<Hasher=H>, + H: hash::Hasher<Output=u64> +{ + fn extend<I: IntoIterator<Item=T>>(&mut self, iter: I) { + for k in iter { + self.insert(k); + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<T, S, H> Default for HashSet<T, S> + where T: Eq + Hash<H>, + S: HashState<Hasher=H> + Default, + H: hash::Hasher<Output=u64> +{ + #[stable(feature = "rust1", since = "1.0.0")] + fn default() -> HashSet<T, S> { + HashSet::with_hash_state(Default::default()) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, 'b, T, S, H> BitOr<&'b HashSet<T, S>> for &'a HashSet<T, S> + where T: Eq + Hash<H> + Clone, + S: HashState<Hasher=H> + Default, + H: hash::Hasher<Output=u64> +{ + type Output = HashSet<T, S>; + + /// Returns the union of `self` and `rhs` as a new `HashSet<T, S>`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = vec![3, 4, 5].into_iter().collect(); + /// + /// let set = &a | &b; + /// + /// let mut i = 0; + /// let expected = [1, 2, 3, 4, 5]; + /// for x in set.iter() { + /// assert!(expected.contains(x)); + /// i += 1; + /// } + /// assert_eq!(i, expected.len()); + /// ``` + fn bitor(self, rhs: &HashSet<T, S>) -> HashSet<T, S> { + self.union(rhs).cloned().collect() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, 'b, T, S, H> BitAnd<&'b HashSet<T, S>> for &'a HashSet<T, S> + where T: Eq + Hash<H> + Clone, + S: HashState<Hasher=H> + Default, + H: hash::Hasher<Output=u64> +{ + type Output = HashSet<T, S>; + + /// Returns the intersection of `self` and `rhs` as a new `HashSet<T, S>`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = vec![2, 3, 4].into_iter().collect(); + /// + /// let set = &a & &b; + /// + /// let mut i = 0; + /// let expected = [2, 3]; + /// for x in set.iter() { + /// assert!(expected.contains(x)); + /// i += 1; + /// } + /// assert_eq!(i, expected.len()); + /// ``` + fn bitand(self, rhs: &HashSet<T, S>) -> HashSet<T, S> { + self.intersection(rhs).cloned().collect() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, 'b, T, S, H> BitXor<&'b HashSet<T, S>> for &'a HashSet<T, S> + where T: Eq + Hash<H> + Clone, + S: HashState<Hasher=H> + Default, + H: hash::Hasher<Output=u64> +{ + type Output = HashSet<T, S>; + + /// Returns the symmetric difference of `self` and `rhs` as a new `HashSet<T, S>`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = vec![3, 4, 5].into_iter().collect(); + /// + /// let set = &a ^ &b; + /// + /// let mut i = 0; + /// let expected = [1, 2, 4, 5]; + /// for x in set.iter() { + /// assert!(expected.contains(x)); + /// i += 1; + /// } + /// assert_eq!(i, expected.len()); + /// ``` + fn bitxor(self, rhs: &HashSet<T, S>) -> HashSet<T, S> { + self.symmetric_difference(rhs).cloned().collect() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, 'b, T, S, H> Sub<&'b HashSet<T, S>> for &'a HashSet<T, S> + where T: Eq + Hash<H> + Clone, + S: HashState<Hasher=H> + Default, + H: hash::Hasher<Output=u64> +{ + type Output = HashSet<T, S>; + + /// Returns the difference of `self` and `rhs` as a new `HashSet<T, S>`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = vec![3, 4, 5].into_iter().collect(); + /// + /// let set = &a - &b; + /// + /// let mut i = 0; + /// let expected = [1, 2]; + /// for x in set.iter() { + /// assert!(expected.contains(x)); + /// i += 1; + /// } + /// assert_eq!(i, expected.len()); + /// ``` + fn sub(self, rhs: &HashSet<T, S>) -> HashSet<T, S> { + self.difference(rhs).cloned().collect() + } +} + +/// HashSet iterator +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Iter<'a, K: 'a> { + iter: Keys<'a, K, ()> +} + +/// HashSet move iterator +#[stable(feature = "rust1", since = "1.0.0")] +pub struct IntoIter<K> { + iter: Map<map::IntoIter<K, ()>, fn((K, ())) -> K> +} + +/// HashSet drain iterator +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Drain<'a, K: 'a> { + iter: Map<map::Drain<'a, K, ()>, fn((K, ())) -> K>, +} + +/// Intersection iterator +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Intersection<'a, T: 'a, S: 'a> { + // iterator of the first set + iter: Iter<'a, T>, + // the second set + other: &'a HashSet<T, S>, +} + +/// Difference iterator +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Difference<'a, T: 'a, S: 'a> { + // iterator of the first set + iter: Iter<'a, T>, + // the second set + other: &'a HashSet<T, S>, +} + +/// Symmetric difference iterator. +#[stable(feature = "rust1", since = "1.0.0")] +pub struct SymmetricDifference<'a, T: 'a, S: 'a> { + iter: Chain<Difference<'a, T, S>, Difference<'a, T, S>> +} + +/// Set union iterator. +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Union<'a, T: 'a, S: 'a> { + iter: Chain<Iter<'a, T>, Difference<'a, T, S>> +} + +impl<'a, T, S, H> IntoIterator for &'a HashSet<T, S> + where T: Eq + Hash<H>, + S: HashState<Hasher=H>, + H: hash::Hasher<Output=u64> +{ + type Item = &'a T; + type IntoIter = Iter<'a, T>; + + fn into_iter(self) -> Iter<'a, T> { + self.iter() + } +} + +impl<T, S, H> IntoIterator for HashSet<T, S> + where T: Eq + Hash<H>, + S: HashState<Hasher=H>, + H: hash::Hasher<Output=u64> +{ + type Item = T; + type IntoIter = IntoIter<T>; + + fn into_iter(self) -> IntoIter<T> { + self.into_iter() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, K> Iterator for Iter<'a, K> { + type Item = &'a K; + + fn next(&mut self) -> Option<&'a K> { self.iter.next() } + fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, K> ExactSizeIterator for Iter<'a, K> { + fn len(&self) -> usize { self.iter.len() } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<K> Iterator for IntoIter<K> { + type Item = K; + + fn next(&mut self) -> Option<K> { self.iter.next() } + fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl<K> ExactSizeIterator for IntoIter<K> { + fn len(&self) -> usize { self.iter.len() } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, K> Iterator for Drain<'a, K> { + type Item = K; + + fn next(&mut self) -> Option<K> { self.iter.next() } + fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, K> ExactSizeIterator for Drain<'a, K> { + fn len(&self) -> usize { self.iter.len() } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T, S, H> Iterator for Intersection<'a, T, S> + where T: Eq + Hash<H>, + S: HashState<Hasher=H>, + H: hash::Hasher<Output=u64> +{ + type Item = &'a T; + + fn next(&mut self) -> Option<&'a T> { + loop { + match self.iter.next() { + None => return None, + Some(elt) => if self.other.contains(elt) { + return Some(elt) + }, + } + } + } + + fn size_hint(&self) -> (usize, Option<usize>) { + let (_, upper) = self.iter.size_hint(); + (0, upper) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T, S, H> Iterator for Difference<'a, T, S> + where T: Eq + Hash<H>, + S: HashState<Hasher=H>, + H: hash::Hasher<Output=u64> +{ + type Item = &'a T; + + fn next(&mut self) -> Option<&'a T> { + loop { + match self.iter.next() { + None => return None, + Some(elt) => if !self.other.contains(elt) { + return Some(elt) + }, + } + } + } + + fn size_hint(&self) -> (usize, Option<usize>) { + let (_, upper) = self.iter.size_hint(); + (0, upper) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T, S, H> Iterator for SymmetricDifference<'a, T, S> + where T: Eq + Hash<H>, + S: HashState<Hasher=H>, + H: hash::Hasher<Output=u64> +{ + type Item = &'a T; + + fn next(&mut self) -> Option<&'a T> { self.iter.next() } + fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T, S, H> Iterator for Union<'a, T, S> + where T: Eq + Hash<H>, + S: HashState<Hasher=H>, + H: hash::Hasher<Output=u64> +{ + type Item = &'a T; + + fn next(&mut self) -> Option<&'a T> { self.iter.next() } + fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() } +} + +#[cfg(test)] +mod test_set { + use prelude::v1::*; + + use super::HashSet; + + #[test] + fn test_disjoint() { + let mut xs = HashSet::new(); + let mut ys = HashSet::new(); + assert!(xs.is_disjoint(&ys)); + assert!(ys.is_disjoint(&xs)); + assert!(xs.insert(5)); + assert!(ys.insert(11)); + assert!(xs.is_disjoint(&ys)); + assert!(ys.is_disjoint(&xs)); + assert!(xs.insert(7)); + assert!(xs.insert(19)); + assert!(xs.insert(4)); + assert!(ys.insert(2)); + assert!(ys.insert(-11)); + assert!(xs.is_disjoint(&ys)); + assert!(ys.is_disjoint(&xs)); + assert!(ys.insert(7)); + assert!(!xs.is_disjoint(&ys)); + assert!(!ys.is_disjoint(&xs)); + } + + #[test] + fn test_subset_and_superset() { + let mut a = HashSet::new(); + assert!(a.insert(0)); + assert!(a.insert(5)); + assert!(a.insert(11)); + assert!(a.insert(7)); + + let mut b = HashSet::new(); + assert!(b.insert(0)); + assert!(b.insert(7)); + assert!(b.insert(19)); + assert!(b.insert(250)); + assert!(b.insert(11)); + assert!(b.insert(200)); + + assert!(!a.is_subset(&b)); + assert!(!a.is_superset(&b)); + assert!(!b.is_subset(&a)); + assert!(!b.is_superset(&a)); + + assert!(b.insert(5)); + + assert!(a.is_subset(&b)); + assert!(!a.is_superset(&b)); + assert!(!b.is_subset(&a)); + assert!(b.is_superset(&a)); + } + + #[test] + fn test_iterate() { + let mut a = HashSet::new(); + for i in 0..32 { + assert!(a.insert(i)); + } + let mut observed: u32 = 0; + for k in &a { + observed |= 1 << *k; + } + assert_eq!(observed, 0xFFFF_FFFF); + } + + #[test] + fn test_intersection() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(11)); + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(77)); + assert!(a.insert(103)); + assert!(a.insert(5)); + assert!(a.insert(-5)); + + assert!(b.insert(2)); + assert!(b.insert(11)); + assert!(b.insert(77)); + assert!(b.insert(-9)); + assert!(b.insert(-42)); + assert!(b.insert(5)); + assert!(b.insert(3)); + + let mut i = 0; + let expected = [3, 5, 11, 77]; + for x in a.intersection(&b) { + assert!(expected.contains(x)); + i += 1 + } + assert_eq!(i, expected.len()); + } + + #[test] + fn test_difference() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + + assert!(b.insert(3)); + assert!(b.insert(9)); + + let mut i = 0; + let expected = [1, 5, 11]; + for x in a.difference(&b) { + assert!(expected.contains(x)); + i += 1 + } + assert_eq!(i, expected.len()); + } + + #[test] + fn test_symmetric_difference() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + + assert!(b.insert(-2)); + assert!(b.insert(3)); + assert!(b.insert(9)); + assert!(b.insert(14)); + assert!(b.insert(22)); + + let mut i = 0; + let expected = [-2, 1, 5, 11, 14, 22]; + for x in a.symmetric_difference(&b) { + assert!(expected.contains(x)); + i += 1 + } + assert_eq!(i, expected.len()); + } + + #[test] + fn test_union() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + assert!(a.insert(16)); + assert!(a.insert(19)); + assert!(a.insert(24)); + + assert!(b.insert(-2)); + assert!(b.insert(1)); + assert!(b.insert(5)); + assert!(b.insert(9)); + assert!(b.insert(13)); + assert!(b.insert(19)); + + let mut i = 0; + let expected = [-2, 1, 3, 5, 9, 11, 13, 16, 19, 24]; + for x in a.union(&b) { + assert!(expected.contains(x)); + i += 1 + } + assert_eq!(i, expected.len()); + } + + #[test] + fn test_from_iter() { + let xs = [1, 2, 3, 4, 5, 6, 7, 8, 9]; + + let set: HashSet<_> = xs.iter().cloned().collect(); + + for x in &xs { + assert!(set.contains(x)); + } + } + + #[test] + fn test_move_iter() { + let hs = { + let mut hs = HashSet::new(); + + hs.insert('a'); + hs.insert('b'); + + hs + }; + + let v = hs.into_iter().collect::<Vec<char>>(); + assert!(['a', 'b'] == v || ['b', 'a'] == v); + } + + #[test] + fn test_eq() { + // These constants once happened to expose a bug in insert(). + // I'm keeping them around to prevent a regression. + let mut s1 = HashSet::new(); + + s1.insert(1); + s1.insert(2); + s1.insert(3); + + let mut s2 = HashSet::new(); + + s2.insert(1); + s2.insert(2); + + assert!(s1 != s2); + + s2.insert(3); + + assert_eq!(s1, s2); + } + + #[test] + fn test_show() { + let mut set = HashSet::new(); + let empty = HashSet::<i32>::new(); + + set.insert(1); + set.insert(2); + + let set_str = format!("{:?}", set); + + assert!(set_str == "HashSet {1, 2}" || set_str == "HashSet {2, 1}"); + assert_eq!(format!("{:?}", empty), "HashSet {}"); + } + + #[test] + fn test_trivial_drain() { + let mut s = HashSet::<i32>::new(); + for _ in s.drain() {} + assert!(s.is_empty()); + drop(s); + + let mut s = HashSet::<i32>::new(); + drop(s.drain()); + assert!(s.is_empty()); + } + + #[test] + fn test_drain() { + let mut s: HashSet<_> = (1..100).collect(); + + // try this a bunch of times to make sure we don't screw up internal state. + for _ in 0..20 { + assert_eq!(s.len(), 99); + + { + let mut last_i = 0; + let mut d = s.drain(); + for (i, x) in d.by_ref().take(50).enumerate() { + last_i = i; + assert!(x != 0); + } + assert_eq!(last_i, 49); + } + + for _ in &s { panic!("s should be empty!"); } + + // reset to try again. + s.extend(1..100); + } + } +} diff --git a/src/libstd/collections/hash/state.rs b/src/libstd/collections/hash/state.rs index 79e01304fb8..7e6dd45b51e 100644 --- a/src/libstd/collections/hash/state.rs +++ b/src/libstd/collections/hash/state.rs @@ -11,6 +11,7 @@ use clone::Clone; use default::Default; use hash; +use marker; /// A trait representing stateful hashes which can be used to hash keys in a /// `HashMap`. @@ -37,7 +38,7 @@ pub trait HashState { /// /// This struct has is 0-sized and does not need construction. #[unstable(feature = "std_misc", reason = "hasher stuff is unclear")] -pub struct DefaultState<H>; +pub struct DefaultState<H>(marker::PhantomData<H>); impl<H: Default + hash::Hasher> HashState for DefaultState<H> { type Hasher = H; @@ -45,9 +46,9 @@ impl<H: Default + hash::Hasher> HashState for DefaultState<H> { } impl<H> Clone for DefaultState<H> { - fn clone(&self) -> DefaultState<H> { DefaultState } + fn clone(&self) -> DefaultState<H> { DefaultState(marker::PhantomData) } } impl<H> Default for DefaultState<H> { - fn default() -> DefaultState<H> { DefaultState } + fn default() -> DefaultState<H> { DefaultState(marker::PhantomData) } } diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 0bb6bd4cf35..f301f6db92f 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -23,8 +23,8 @@ use num::{Int, UnsignedInt}; use ops::{Deref, DerefMut, Drop}; use option::Option; use option::Option::{Some, None}; -use ptr::{self, PtrExt, copy_nonoverlapping_memory, zero_memory}; -use rt::heap::{allocate, deallocate}; +use ptr::{self, PtrExt, copy_nonoverlapping_memory, Unique, zero_memory}; +use rt::heap::{allocate, deallocate, EMPTY}; use collections::hash_state::HashState; const EMPTY_BUCKET: u64 = 0u64; @@ -69,10 +69,11 @@ const EMPTY_BUCKET: u64 = 0u64; pub struct RawTable<K, V> { capacity: usize, size: usize, - hashes: *mut u64, + hashes: Unique<u64>, + // Because K/V do not appear directly in any of the types in the struct, // inform rustc that in fact instances of K and V are reachable from here. - marker: marker::CovariantType<(K,V)>, + marker: marker::PhantomData<(K,V)>, } unsafe impl<K: Send, V: Send> Send for RawTable<K, V> {} @@ -81,7 +82,8 @@ unsafe impl<K: Sync, V: Sync> Sync for RawTable<K, V> {} struct RawBucket<K, V> { hash: *mut u64, key: *mut K, - val: *mut V + val: *mut V, + _marker: marker::PhantomData<(K,V)>, } impl<K,V> Copy for RawBucket<K,V> {} @@ -141,6 +143,7 @@ impl SafeHash { /// We need to remove hashes of 0. That's reserved for empty buckets. /// This function wraps up `hash_keyed` to be the only way outside this /// module to generate a SafeHash. +#[cfg(stage0)] pub fn make_hash<T: ?Sized, S, H>(hash_state: &S, t: &T) -> SafeHash where T: Hash<H>, S: HashState<Hasher=H>, @@ -155,6 +158,22 @@ pub fn make_hash<T: ?Sized, S, H>(hash_state: &S, t: &T) -> SafeHash SafeHash { hash: 0x8000_0000_0000_0000 | state.finish() } } +/// We need to remove hashes of 0. That's reserved for empty buckets. +/// This function wraps up `hash_keyed` to be the only way outside this +/// module to generate a SafeHash. +#[cfg(not(stage0))] +pub fn make_hash<T: ?Sized, S>(hash_state: &S, t: &T) -> SafeHash + where T: Hash, S: HashState +{ + let mut state = hash_state.hasher(); + t.hash(&mut state); + // We need to avoid 0u64 in order to prevent collisions with + // EMPTY_HASH. We can maintain our precious uniform distribution + // of initial indexes by unconditionally setting the MSB, + // effectively reducing 64-bits hashes to 63 bits. + SafeHash { hash: 0x8000_0000_0000_0000 | state.finish() } +} + // `replace` casts a `*u64` to a `*SafeHash`. Since we statically // ensure that a `FullBucket` points to an index with a non-zero hash, // and a `SafeHash` is just a `u64` with a different name, this is @@ -170,11 +189,12 @@ fn can_alias_safehash_as_u64() { } impl<K, V> RawBucket<K, V> { - unsafe fn offset(self, count: int) -> RawBucket<K, V> { + unsafe fn offset(self, count: isize) -> RawBucket<K, V> { RawBucket { hash: self.hash.offset(count), key: self.key.offset(count), val: self.val.offset(count), + _marker: marker::PhantomData, } } } @@ -567,10 +587,11 @@ impl<K, V> RawTable<K, V> { return RawTable { size: 0, capacity: 0, - hashes: ptr::null_mut(), - marker: marker::CovariantType, + hashes: Unique::new(EMPTY as *mut u64), + marker: marker::PhantomData, }; } + // No need for `checked_mul` before a more restrictive check performed // later in this method. let hashes_size = capacity * size_of::<u64>(); @@ -606,8 +627,8 @@ impl<K, V> RawTable<K, V> { RawTable { capacity: capacity, size: 0, - hashes: hashes, - marker: marker::CovariantType, + hashes: Unique::new(hashes), + marker: marker::PhantomData, } } @@ -615,16 +636,17 @@ impl<K, V> RawTable<K, V> { let hashes_size = self.capacity * size_of::<u64>(); let keys_size = self.capacity * size_of::<K>(); - let buffer = self.hashes as *mut u8; + let buffer = *self.hashes as *mut u8; let (keys_offset, vals_offset) = calculate_offsets(hashes_size, keys_size, min_align_of::<K>(), min_align_of::<V>()); unsafe { RawBucket { - hash: self.hashes, + hash: *self.hashes, key: buffer.offset(keys_offset as isize) as *mut K, - val: buffer.offset(vals_offset as isize) as *mut V + val: buffer.offset(vals_offset as isize) as *mut V, + _marker: marker::PhantomData, } } } @@ -634,7 +656,7 @@ impl<K, V> RawTable<K, V> { pub fn new(capacity: usize) -> RawTable<K, V> { unsafe { let ret = RawTable::new_uninitialized(capacity); - zero_memory(ret.hashes, capacity); + zero_memory(*ret.hashes, capacity); ret } } @@ -656,7 +678,7 @@ impl<K, V> RawTable<K, V> { hashes_end: unsafe { self.hashes.offset(self.capacity as isize) }, - marker: marker::ContravariantLifetime, + marker: marker::PhantomData, } } @@ -681,7 +703,7 @@ impl<K, V> RawTable<K, V> { iter: RawBuckets { raw: raw, hashes_end: hashes_end, - marker: marker::ContravariantLifetime, + marker: marker::PhantomData, }, table: self, } @@ -694,7 +716,7 @@ impl<K, V> RawTable<K, V> { iter: RawBuckets { raw: raw, hashes_end: hashes_end, - marker: marker::ContravariantLifetime::<'static>, + marker: marker::PhantomData, }, table: self, } @@ -708,7 +730,7 @@ impl<K, V> RawTable<K, V> { raw: raw_bucket.offset(self.capacity as isize), hashes_end: raw_bucket.hash, elems_left: self.size, - marker: marker::ContravariantLifetime, + marker: marker::PhantomData, } } } @@ -718,7 +740,13 @@ impl<K, V> RawTable<K, V> { struct RawBuckets<'a, K, V> { raw: RawBucket<K, V>, hashes_end: *mut u64, - marker: marker::ContravariantLifetime<'a>, + + // Strictly speaking, this should be &'a (K,V), but that would + // require that K:'a, and we often use RawBuckets<'static...> for + // move iterations, so that messes up a lot of other things. So + // just use `&'a (K,V)` as this is not a publicly exposed type + // anyway. + marker: marker::PhantomData<&'a ()>, } // FIXME(#19839) Remove in favor of `#[derive(Clone)]` @@ -727,7 +755,7 @@ impl<'a, K, V> Clone for RawBuckets<'a, K, V> { RawBuckets { raw: self.raw, hashes_end: self.hashes_end, - marker: marker::ContravariantLifetime, + marker: marker::PhantomData, } } } @@ -759,7 +787,11 @@ struct RevMoveBuckets<'a, K, V> { raw: RawBucket<K, V>, hashes_end: *mut u64, elems_left: usize, - marker: marker::ContravariantLifetime<'a>, + + // As above, `&'a (K,V)` would seem better, but we often use + // 'static for the lifetime, and this is not a publicly exposed + // type. + marker: marker::PhantomData<&'a ()>, } impl<'a, K, V> Iterator for RevMoveBuckets<'a, K, V> { @@ -966,9 +998,10 @@ impl<K: Clone, V: Clone> Clone for RawTable<K, V> { #[unsafe_destructor] impl<K, V> Drop for RawTable<K, V> { fn drop(&mut self) { - if self.hashes.is_null() { + if self.capacity == 0 { return; } + // This is done in reverse because we've likely partially taken // some elements out with `.into_iter()` from the front. // Check if the size is 0, so we don't do a useless scan when @@ -986,7 +1019,7 @@ impl<K, V> Drop for RawTable<K, V> { vals_size, min_align_of::<V>()); unsafe { - deallocate(self.hashes as *mut u8, size, align); + deallocate(*self.hashes as *mut u8, size, align); // Remember how everything was allocated out of one buffer // during initialization? We only need one call to free here. } diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs index be441bfec88..0e64370df60 100644 --- a/src/libstd/collections/mod.rs +++ b/src/libstd/collections/mod.rs @@ -23,7 +23,7 @@ //! //! Rust's collections can be grouped into four major categories: //! -//! * Sequences: `Vec`, `RingBuf`, `DList`, `BitV` +//! * Sequences: `Vec`, `VecDeque`, `LinkedList`, `BitV` //! * Maps: `HashMap`, `BTreeMap`, `VecMap` //! * Sets: `HashSet`, `BTreeSet`, `BitVSet` //! * Misc: `BinaryHeap` @@ -43,13 +43,13 @@ //! * You want a resizable array. //! * You want a heap-allocated array. //! -//! ### Use a `RingBuf` when: +//! ### Use a `VecDeque` when: //! * You want a `Vec` that supports efficient insertion at both ends of the sequence. //! * You want a queue. //! * You want a double-ended queue (deque). //! -//! ### Use a `DList` when: -//! * You want a `Vec` or `RingBuf` of unknown size, and can't tolerate amortization. +//! ### Use a `LinkedList` when: +//! * You want a `Vec` or `VecDeque` of unknown size, and can't tolerate amortization. //! * You want to efficiently split and append lists. //! * You are *absolutely* certain you *really*, *truly*, want a doubly linked list. //! @@ -75,7 +75,7 @@ //! //! ### Use a `BitV` when: //! * You want to store an unbounded number of booleans in a small space. -//! * You want a bitvector. +//! * You want a bit vector. //! //! ### Use a `BitVSet` when: //! * You want a `VecSet`. @@ -106,20 +106,20 @@ //! //! ## Sequences //! -//! | | get(i) | insert(i) | remove(i) | append | split_off(i) | -//! |---------|----------------|-----------------|----------------|--------|----------------| -//! | Vec | O(1) | O(n-i)* | O(n-i) | O(m)* | O(n-i) | -//! | RingBuf | O(1) | O(min(i, n-i))* | O(min(i, n-i)) | O(m)* | O(min(i, n-i)) | -//! | DList | O(min(i, n-i)) | O(min(i, n-i)) | O(min(i, n-i)) | O(1) | O(min(i, n-i)) | -//! | Bitv | O(1) | O(n-i)* | O(n-i) | O(m)* | O(n-i) | +//! | | get(i) | insert(i) | remove(i) | append | split_off(i) | +//! |--------------|----------------|-----------------|----------------|--------|----------------| +//! | Vec | O(1) | O(n-i)* | O(n-i) | O(m)* | O(n-i) | +//! | VecDeque | O(1) | O(min(i, n-i))* | O(min(i, n-i)) | O(m)* | O(min(i, n-i)) | +//! | LinkedList | O(min(i, n-i)) | O(min(i, n-i)) | O(min(i, n-i)) | O(1) | O(min(i, n-i)) | +//! | BitVec | O(1) | O(n-i)* | O(n-i) | O(m)* | O(n-i) | //! -//! Note that where ties occur, Vec is generally going to be faster than RingBuf, and RingBuf -//! is generally going to be faster than DList. Bitv is not a general purpose collection, and +//! Note that where ties occur, Vec is generally going to be faster than VecDeque, and VecDeque +//! is generally going to be faster than LinkedList. BitVec is not a general purpose collection, and //! therefore cannot reasonably be compared. //! //! ## Maps //! -//! For Sets, all operations have the cost of the equivalent Map operation. For BitvSet, +//! For Sets, all operations have the cost of the equivalent Map operation. For BitSet, //! refer to VecMap. //! //! | | get | insert | remove | predecessor | @@ -166,7 +166,7 @@ //! //! Any `with_capacity` constructor will instruct the collection to allocate enough space //! for the specified number of elements. Ideally this will be for exactly that many -//! elements, but some implementation details may prevent this. `Vec` and `RingBuf` can +//! elements, but some implementation details may prevent this. `Vec` and `VecDeque` can //! be relied on to allocate exactly the requested amount, though. Use `with_capacity` //! when you know exactly how many elements will be inserted, or at least have a //! reasonable upper-bound on that number. @@ -240,10 +240,10 @@ //! ``` //! //! ``` -//! use std::collections::RingBuf; +//! use std::collections::VecDeque; //! //! let vec = vec![1, 2, 3, 4]; -//! let buf: RingBuf<_> = vec.into_iter().collect(); +//! let buf: VecDeque<_> = vec.into_iter().collect(); //! ``` //! //! Iterators also provide a series of *adapter* methods for performing common tasks to @@ -362,11 +362,11 @@ #![stable(feature = "rust1", since = "1.0.0")] pub use core_collections::Bound; -pub use core_collections::{BinaryHeap, Bitv, BitvSet, BTreeMap, BTreeSet}; -pub use core_collections::{DList, RingBuf, VecMap}; +pub use core_collections::{BinaryHeap, BitVec, BitSet, BTreeMap, BTreeSet}; +pub use core_collections::{LinkedList, VecDeque, VecMap}; -pub use core_collections::{binary_heap, bitv, bitv_set, btree_map, btree_set}; -pub use core_collections::{dlist, ring_buf, vec_map}; +pub use core_collections::{binary_heap, bit_vec, bit_set, btree_map, btree_set}; +pub use core_collections::{linked_list, vec_deque, vec_map}; pub use self::hash_map::HashMap; pub use self::hash_set::HashSet; diff --git a/src/libstd/dynamic_lib.rs b/src/libstd/dynamic_lib.rs index c5dd66630b4..b0fb9c29403 100644 --- a/src/libstd/dynamic_lib.rs +++ b/src/libstd/dynamic_lib.rs @@ -112,7 +112,7 @@ impl DynamicLibrary { // This function should have a lifetime constraint of 'a on // T but that feature is still unimplemented - let raw_string = CString::from_slice(symbol.as_bytes()); + let raw_string = CString::new(symbol).unwrap(); let maybe_symbol_value = dl::check_for_errors_in(|| { dl::symbol(self.handle, raw_string.as_ptr()) }); @@ -187,7 +187,7 @@ mod test { mod dl { use prelude::v1::*; - use ffi::{self, CString}; + use ffi::{CString, CStr}; use str; use libc; use ptr; @@ -206,7 +206,7 @@ mod dl { const LAZY: libc::c_int = 1; unsafe fn open_external(filename: &[u8]) -> *mut u8 { - let s = CString::from_slice(filename); + let s = CString::new(filename).unwrap(); dlopen(s.as_ptr(), LAZY) as *mut u8 } @@ -231,7 +231,7 @@ mod dl { let ret = if ptr::null() == last_error { Ok(result) } else { - let s = ffi::c_str_to_bytes(&last_error); + let s = CStr::from_ptr(last_error).to_bytes(); Err(str::from_utf8(s).unwrap().to_string()) }; diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 93dc3efe2c4..8676586e7dc 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -926,7 +926,7 @@ mod tests { #[cfg(unix)] fn join_paths_unix() { fn test_eq(input: &[&str], output: &str) -> bool { - &*join_paths(input.iter().map(|s| *s)).unwrap() == + &*join_paths(input.iter().cloned()).unwrap() == OsStr::from_str(output) } @@ -935,14 +935,14 @@ mod tests { "/bin:/usr/bin:/usr/local/bin")); assert!(test_eq(&["", "/bin", "", "", "/usr/bin", ""], ":/bin:::/usr/bin:")); - assert!(join_paths(["/te:st"].iter().map(|s| *s)).is_err()); + assert!(join_paths(["/te:st"].iter().cloned()).is_err()); } #[test] #[cfg(windows)] fn join_paths_windows() { fn test_eq(input: &[&str], output: &str) -> bool { - &*join_paths(input.iter().map(|s| *s)).unwrap() == + &*join_paths(input.iter().cloned()).unwrap() == OsStr::from_str(output) } @@ -953,6 +953,6 @@ mod tests { r";c:\windows;;;c:\;")); assert!(test_eq(&[r"c:\te;st", r"c:\"], r#""c:\te;st";c:\"#)); - assert!(join_paths([r#"c:\te"st"#].iter().map(|s| *s)).is_err()); + assert!(join_paths([r#"c:\te"st"#].iter().cloned()).is_err()); } } diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 45089176cba..8976813d3f9 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -8,18 +8,25 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering}; +use error::{Error, FromError}; use fmt; +use io; use iter::IteratorExt; use libc; use mem; +use old_io; use ops::Deref; +use option::Option::{self, Some, None}; +use result::Result::{self, Ok, Err}; use slice::{self, SliceExt}; +use str::StrExt; use string::String; use vec::Vec; -/// A type representing a C-compatible string +/// A type representing an owned C-compatible string /// -/// This type serves the primary purpose of being able to generate a +/// This type serves the primary purpose of being able to safely generate a /// C-compatible string from a Rust byte slice or vector. An instance of this /// type is a static guarantee that the underlying bytes contain no interior 0 /// bytes and the final byte is 0. @@ -44,8 +51,8 @@ use vec::Vec; /// fn my_printer(s: *const libc::c_char); /// } /// -/// let to_print = "Hello, world!"; -/// let c_to_print = CString::from_slice(to_print.as_bytes()); +/// let to_print = b"Hello, world!"; +/// let c_to_print = CString::new(to_print).unwrap(); /// unsafe { /// my_printer(c_to_print.as_ptr()); /// } @@ -53,19 +60,135 @@ use vec::Vec; /// ``` #[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] pub struct CString { - inner: Vec<libc::c_char>, + inner: Vec<u8>, +} + +/// Representation of a borrowed C string. +/// +/// This dynamically sized type is only safely constructed via a borrowed +/// version of an instance of `CString`. This type can be constructed from a raw +/// C string as well and represents a C string borrowed from another location. +/// +/// Note that this structure is **not** `repr(C)` and is not recommended to be +/// placed in the signatures of FFI functions. Instead safe wrappers of FFI +/// functions may leverage the unsafe `from_ptr` constructor to provide a safe +/// interface to other consumers. +/// +/// # Examples +/// +/// Inspecting a foreign C string +/// +/// ```no_run +/// extern crate libc; +/// use std::ffi::CStr; +/// +/// extern { fn my_string() -> *const libc::c_char; } +/// +/// fn main() { +/// unsafe { +/// let slice = CStr::from_ptr(my_string()); +/// println!("string length: {}", slice.to_bytes().len()); +/// } +/// } +/// ``` +/// +/// Passing a Rust-originating C string +/// +/// ```no_run +/// extern crate libc; +/// use std::ffi::{CString, CStr}; +/// +/// fn work(data: &CStr) { +/// extern { fn work_with(data: *const libc::c_char); } +/// +/// unsafe { work_with(data.as_ptr()) } +/// } +/// +/// fn main() { +/// let s = CString::new("data data data data").unwrap(); +/// work(&s); +/// } +/// ``` +#[derive(Hash)] +pub struct CStr { + inner: [libc::c_char] +} + +/// An error returned from `CString::new` to indicate that a nul byte was found +/// in the vector provided. +#[derive(Clone, PartialEq, Debug)] +pub struct NulError(usize, Vec<u8>); + +/// A conversion trait used by the constructor of `CString` for types that can +/// be converted to a vector of bytes. +pub trait IntoBytes { + /// Consumes this container, returning a vector of bytes. + fn into_bytes(self) -> Vec<u8>; } impl CString { + /// Create a new C-compatible string from a container of bytes. + /// + /// This method will consume the provided data and use the underlying bytes + /// to construct a new string, ensuring that there is a trailing 0 byte. + /// + /// # Examples + /// + /// ```no_run + /// extern crate libc; + /// use std::ffi::CString; + /// + /// extern { fn puts(s: *const libc::c_char); } + /// + /// fn main() { + /// let to_print = CString::new("Hello!").unwrap(); + /// unsafe { + /// puts(to_print.as_ptr()); + /// } + /// } + /// ``` + /// + /// # Errors + /// + /// This function will return an error if the bytes yielded contain an + /// internal 0 byte. The error returned will contain the bytes as well as + /// the position of the nul byte. + pub fn new<T: IntoBytes>(t: T) -> Result<CString, NulError> { + let bytes = t.into_bytes(); + match bytes.iter().position(|x| *x == 0) { + Some(i) => Err(NulError(i, bytes)), + None => Ok(unsafe { CString::from_vec_unchecked(bytes) }), + } + } + /// Create a new C-compatible string from a byte slice. /// /// This method will copy the data of the slice provided into a new /// allocation, ensuring that there is a trailing 0 byte. /// + /// # Examples + /// + /// ```no_run + /// extern crate libc; + /// use std::ffi::CString; + /// + /// extern { fn puts(s: *const libc::c_char); } + /// + /// fn main() { + /// let to_print = CString::new("Hello!").unwrap(); + /// unsafe { + /// puts(to_print.as_ptr()); + /// } + /// } + /// ``` + /// /// # Panics /// - /// This function will panic if there are any 0 bytes already in the slice - /// provided. + /// This function will panic if the provided slice contains any + /// interior nul bytes. + #[unstable(feature = "std_misc")] + #[deprecated(since = "1.0.0", reason = "use CString::new instead")] + #[allow(deprecated)] pub fn from_slice(v: &[u8]) -> CString { CString::from_vec(v.to_vec()) } @@ -77,11 +200,15 @@ impl CString { /// /// # Panics /// - /// This function will panic if there are any 0 bytes already in the vector - /// provided. + /// This function will panic if the provided slice contains any + /// interior nul bytes. + #[unstable(feature = "std_misc")] + #[deprecated(since = "1.0.0", reason = "use CString::new instead")] pub fn from_vec(v: Vec<u8>) -> CString { - assert!(!v.iter().any(|&x| x == 0)); - unsafe { CString::from_vec_unchecked(v) } + match v.iter().position(|x| *x == 0) { + Some(i) => panic!("null byte found in slice at: {}", i), + None => unsafe { CString::from_vec_unchecked(v) }, + } } /// Create a C-compatible string from a byte vector without checking for @@ -91,31 +218,29 @@ impl CString { /// is made that `v` contains no 0 bytes. pub unsafe fn from_vec_unchecked(mut v: Vec<u8>) -> CString { v.push(0); - CString { inner: mem::transmute(v) } + CString { inner: v } } - /// Create a view into this C string which includes the trailing nul - /// terminator at the end of the string. - pub fn as_slice_with_nul(&self) -> &[libc::c_char] { &self.inner } - - /// Similar to the `as_slice` method, but returns a `u8` slice instead of a - /// `libc::c_char` slice. + /// Returns the contents of this `CString` as a slice of bytes. + /// + /// The returned slice does **not** contain the trailing nul separator and + /// it is guaranteet to not have any interior nul bytes. pub fn as_bytes(&self) -> &[u8] { - unsafe { mem::transmute(&**self) } + &self.inner[..self.inner.len() - 1] } - /// Equivalent to `as_slice_with_nul` except that the type returned is a - /// `u8` slice instead of a `libc::c_char` slice. + /// Equivalent to the `as_bytes` function except that the returned slice + /// includes the trailing nul byte. pub fn as_bytes_with_nul(&self) -> &[u8] { - unsafe { mem::transmute(self.as_slice_with_nul()) } + &self.inner } } impl Deref for CString { - type Target = [libc::c_char]; + type Target = CStr; - fn deref(&self) -> &[libc::c_char] { - &self.inner[..(self.inner.len() - 1)] + fn deref(&self) -> &CStr { + unsafe { mem::transmute(self.as_bytes_with_nul()) } } } @@ -126,54 +251,172 @@ impl fmt::Debug for CString { } } -/// Interpret a C string as a byte slice. -/// -/// This function will calculate the length of the C string provided, and it -/// will then return a corresponding slice for the contents of the C string not -/// including the nul terminator. -/// -/// This function will tie the lifetime of the returned slice to the lifetime of -/// the pointer provided. This is done to help prevent the slice from escaping -/// the lifetime of the pointer itself. If a longer lifetime is needed, then -/// `mem::copy_lifetime` should be used. -/// -/// This function is unsafe because there is no guarantee of the validity of the -/// pointer `raw` or a guarantee that a nul terminator will be found. -/// -/// # Example -/// -/// ```no_run -/// # extern crate libc; -/// # fn main() { -/// use std::ffi; -/// use std::str; -/// use libc; -/// -/// extern { -/// fn my_string() -> *const libc::c_char; -/// } -/// -/// unsafe { -/// let to_print = my_string(); -/// let slice = ffi::c_str_to_bytes(&to_print); -/// println!("string returned: {}", str::from_utf8(slice).unwrap()); -/// } -/// # } -/// ``` +impl NulError { + /// Returns the position of the nul byte in the slice that was provided to + /// `CString::from_vec`. + pub fn nul_position(&self) -> usize { self.0 } + + /// Consumes this error, returning the underlying vector of bytes which + /// generated the error in the first place. + pub fn into_vec(self) -> Vec<u8> { self.1 } +} + +impl Error for NulError { + fn description(&self) -> &str { "nul byte found in data" } +} + +impl fmt::Display for NulError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "nul byte found in provided data at position: {}", self.0) + } +} + +impl FromError<NulError> for io::Error { + fn from_error(_: NulError) -> io::Error { + io::Error::new(io::ErrorKind::InvalidInput, + "data provided contains a nul byte", None) + } +} + +impl FromError<NulError> for old_io::IoError { + fn from_error(_: NulError) -> old_io::IoError { + old_io::IoError { + kind: old_io::IoErrorKind::InvalidInput, + desc: "data provided contains a nul byte", + detail: None + } + } +} + +impl CStr { + /// Cast a raw C string to a safe C string wrapper. + /// + /// This function will cast the provided `ptr` to the `CStr` wrapper which + /// allows inspection and interoperation of non-owned C strings. This method + /// is unsafe for a number of reasons: + /// + /// * There is no guarantee to the validity of `ptr` + /// * The returned lifetime is not guaranteed to be the actual lifetime of + /// `ptr` + /// * There is no guarantee that the memory pointed to by `ptr` contains a + /// valid nul terminator byte at the end of the string. + /// + /// > **Note**: This operation is intended to be a 0-cost cast but it is + /// > currently implemented with an up-front calculation of the length of + /// > the string. This is not guaranteed to always be the case. + /// + /// # Example + /// + /// ```no_run + /// # extern crate libc; + /// # fn main() { + /// use std::ffi::CStr; + /// use std::str; + /// use libc; + /// + /// extern { + /// fn my_string() -> *const libc::c_char; + /// } + /// + /// unsafe { + /// let slice = CStr::from_ptr(my_string()); + /// println!("string returned: {}", + /// str::from_utf8(slice.to_bytes()).unwrap()); + /// } + /// # } + /// ``` + pub unsafe fn from_ptr<'a>(ptr: *const libc::c_char) -> &'a CStr { + let len = libc::strlen(ptr); + mem::transmute(slice::from_raw_parts(ptr, len as usize + 1)) + } + + /// Return the inner pointer to this C string. + /// + /// The returned pointer will be valid for as long as `self` is and points + /// to a continguous region of memory terminated with a 0 byte to represent + /// the end of the string. + pub fn as_ptr(&self) -> *const libc::c_char { + self.inner.as_ptr() + } + + /// Convert this C string to a byte slice. + /// + /// This function will calculate the length of this string (which normally + /// requires a linear amount of work to be done) and then return the + /// resulting slice of `u8` elements. + /// + /// The returned slice will **not** contain the trailing nul that this C + /// string has. + /// + /// > **Note**: This method is currently implemented as a 0-cost cast, but + /// > it is planned to alter its definition in the future to perform the + /// > length calculation whenever this method is called. + pub fn to_bytes(&self) -> &[u8] { + let bytes = self.to_bytes_with_nul(); + &bytes[..bytes.len() - 1] + } + + /// Convert this C string to a byte slice containing the trailing 0 byte. + /// + /// This function is the equivalent of `to_bytes` except that it will retain + /// the trailing nul instead of chopping it off. + /// + /// > **Note**: This method is currently implemented as a 0-cost cast, but + /// > it is planned to alter its definition in the future to perform the + /// > length calculation whenever this method is called. + pub fn to_bytes_with_nul(&self) -> &[u8] { + unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.inner) } + } +} + +impl PartialEq for CStr { + fn eq(&self, other: &CStr) -> bool { + self.to_bytes().eq(&other.to_bytes()) + } +} +impl Eq for CStr {} +impl PartialOrd for CStr { + fn partial_cmp(&self, other: &CStr) -> Option<Ordering> { + self.to_bytes().partial_cmp(&other.to_bytes()) + } +} +impl Ord for CStr { + fn cmp(&self, other: &CStr) -> Ordering { + self.to_bytes().cmp(&other.to_bytes()) + } +} + +/// Deprecated in favor of `CStr` +#[unstable(feature = "std_misc")] +#[deprecated(since = "1.0.0", reason = "use CStr::from_ptr(p).to_bytes() instead")] pub unsafe fn c_str_to_bytes<'a>(raw: &'a *const libc::c_char) -> &'a [u8] { let len = libc::strlen(*raw); slice::from_raw_parts(*(raw as *const _ as *const *const u8), len as usize) } -/// Interpret a C string as a byte slice with the nul terminator. -/// -/// This function is identical to `from_raw_buf` except that the returned slice -/// will include the nul terminator of the string. -pub unsafe fn c_str_to_bytes_with_nul<'a>(raw: &'a *const libc::c_char) -> &'a [u8] { +/// Deprecated in favor of `CStr` +#[unstable(feature = "std_misc")] +#[deprecated(since = "1.0.0", + reason = "use CStr::from_ptr(p).to_bytes_with_nul() instead")] +pub unsafe fn c_str_to_bytes_with_nul<'a>(raw: &'a *const libc::c_char) + -> &'a [u8] { let len = libc::strlen(*raw) + 1; slice::from_raw_parts(*(raw as *const _ as *const *const u8), len as usize) } +impl<'a> IntoBytes for &'a str { + fn into_bytes(self) -> Vec<u8> { self.as_bytes().to_vec() } +} +impl<'a> IntoBytes for &'a [u8] { + fn into_bytes(self) -> Vec<u8> { self.to_vec() } +} +impl IntoBytes for String { + fn into_bytes(self) -> Vec<u8> { self.into_bytes() } +} +impl IntoBytes for Vec<u8> { + fn into_bytes(self) -> Vec<u8> { self } +} + #[cfg(test)] mod tests { use prelude::v1::*; @@ -193,21 +436,19 @@ mod tests { #[test] fn simple() { - let s = CString::from_slice(b"1234"); + let s = CString::new(b"1234").unwrap(); assert_eq!(s.as_bytes(), b"1234"); assert_eq!(s.as_bytes_with_nul(), b"1234\0"); - unsafe { - assert_eq!(&*s, - mem::transmute::<_, &[libc::c_char]>(b"1234")); - assert_eq!(s.as_slice_with_nul(), - mem::transmute::<_, &[libc::c_char]>(b"1234\0")); - } } - #[should_fail] #[test] - fn build_with_zero1() { CString::from_slice(b"\0"); } - #[should_fail] #[test] - fn build_with_zero2() { CString::from_vec(vec![0]); } + #[test] + fn build_with_zero1() { + assert!(CString::new(b"\0").is_err()); + } + #[test] + fn build_with_zero2() { + assert!(CString::new(vec![0]).is_err()); + } #[test] fn build_with_zero3() { @@ -219,7 +460,16 @@ mod tests { #[test] fn formatted() { - let s = CString::from_slice(b"12"); + let s = CString::new(b"12").unwrap(); assert_eq!(format!("{:?}", s), "\"12\""); } + + #[test] + fn borrowed() { + unsafe { + let s = CStr::from_ptr(b"12\0".as_ptr() as *const _); + assert_eq!(s.to_bytes(), b"12"); + assert_eq!(s.to_bytes_with_nul(), b"12\0"); + } + } } diff --git a/src/libstd/ffi/mod.rs b/src/libstd/ffi/mod.rs index 07a4f17796c..1bff6afb776 100644 --- a/src/libstd/ffi/mod.rs +++ b/src/libstd/ffi/mod.rs @@ -14,8 +14,10 @@ reason = "module just underwent fairly large reorganization and the dust \ still needs to settle")] -pub use self::c_str::CString; +pub use self::c_str::{CString, CStr, NulError, IntoBytes}; +#[allow(deprecated)] pub use self::c_str::c_str_to_bytes; +#[allow(deprecated)] pub use self::c_str::c_str_to_bytes_with_nul; pub use self::os_str::OsString; diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 1d14b141778..84149a2eb8e 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -34,13 +34,14 @@ use core::prelude::*; -use core::borrow::{BorrowFrom, ToOwned}; +use borrow::{Borrow, ToOwned}; use fmt::{self, Debug}; use mem; use string::{String, CowString}; use ops; use cmp; -use hash::{Hash, Hasher, Writer}; +use hash::{Hash, Hasher}; +#[cfg(stage0)] use hash::Writer; use old_path::{Path, GenericPath}; use sys::os_str::{Buf, Slice}; @@ -103,7 +104,7 @@ impl ops::Deref for OsString { #[inline] fn deref(&self) -> &OsStr { - &self[] + &self[..] } } @@ -162,12 +163,21 @@ impl Ord for OsString { } } +#[cfg(stage0)] impl<'a, S: Hasher + Writer> Hash<S> for OsString { #[inline] fn hash(&self, state: &mut S) { (&**self).hash(state) } } +#[cfg(not(stage0))] +#[stable(feature = "rust1", since = "1.0.0")] +impl Hash for OsString { + #[inline] + fn hash<H: Hasher>(&self, state: &mut H) { + (&**self).hash(state) + } +} impl OsStr { /// Coerce directly from a `&str` slice to a `&OsStr` slice. @@ -253,12 +263,21 @@ impl Ord for OsStr { fn cmp(&self, other: &OsStr) -> cmp::Ordering { self.bytes().cmp(other.bytes()) } } +#[cfg(stage0)] impl<'a, S: Hasher + Writer> Hash<S> for OsStr { #[inline] fn hash(&self, state: &mut S) { self.bytes().hash(state) } } +#[cfg(not(stage0))] +#[stable(feature = "rust1", since = "1.0.0")] +impl Hash for OsStr { + #[inline] + fn hash<H: Hasher>(&self, state: &mut H) { + self.bytes().hash(state) + } +} impl Debug for OsStr { fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { @@ -266,11 +285,12 @@ impl Debug for OsStr { } } -impl BorrowFrom<OsString> for OsStr { - fn borrow_from(owned: &OsString) -> &OsStr { &owned[] } +impl Borrow<OsStr> for OsString { + fn borrow(&self) -> &OsStr { &self[..] } } -impl ToOwned<OsString> for OsStr { +impl ToOwned for OsStr { + type Owned = OsString; fn to_owned(&self) -> OsString { self.to_os_string() } } @@ -288,7 +308,7 @@ impl AsOsStr for OsStr { impl AsOsStr for OsString { fn as_os_str(&self) -> &OsStr { - &self[] + &self[..] } } @@ -300,7 +320,7 @@ impl AsOsStr for str { impl AsOsStr for String { fn as_os_str(&self) -> &OsStr { - OsStr::from_str(&self[]) + OsStr::from_str(&self[..]) } } diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index 2fd6631ecc4..e9a8dbb4098 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -618,14 +618,14 @@ mod tests { #[test] fn read_char_buffered() { let buf = [195u8, 159u8]; - let mut reader = BufReader::with_capacity(1, &buf[]); + let mut reader = BufReader::with_capacity(1, &buf[..]); assert_eq!(reader.chars().next(), Some(Ok('ß'))); } #[test] fn test_chars() { let buf = [195u8, 159u8, b'a']; - let mut reader = BufReader::with_capacity(1, &buf[]); + let mut reader = BufReader::with_capacity(1, &buf[..]); let mut it = reader.chars(); assert_eq!(it.next(), Some(Ok('ß'))); assert_eq!(it.next(), Some(Ok('a'))); diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs index 9f3655de20f..f6cb4a8c9f3 100644 --- a/src/libstd/io/cursor.rs +++ b/src/libstd/io/cursor.rs @@ -180,7 +180,7 @@ mod tests { fn test_buf_writer() { let mut buf = [0 as u8; 9]; { - let mut writer = Cursor::new(&mut buf[]); + let mut writer = Cursor::new(&mut buf[..]); assert_eq!(writer.position(), 0); assert_eq!(writer.write(&[0]), Ok(1)); assert_eq!(writer.position(), 1); @@ -201,7 +201,7 @@ mod tests { fn test_buf_writer_seek() { let mut buf = [0 as u8; 8]; { - let mut writer = Cursor::new(&mut buf[]); + let mut writer = Cursor::new(&mut buf[..]); assert_eq!(writer.position(), 0); assert_eq!(writer.write(&[1]), Ok(1)); assert_eq!(writer.position(), 1); @@ -229,7 +229,7 @@ mod tests { #[test] fn test_buf_writer_error() { let mut buf = [0 as u8; 2]; - let mut writer = Cursor::new(&mut buf[]); + let mut writer = Cursor::new(&mut buf[..]); assert_eq!(writer.write(&[0]), Ok(1)); assert_eq!(writer.write(&[0, 0]), Ok(1)); assert_eq!(writer.write(&[0, 0]), Ok(0)); @@ -331,7 +331,7 @@ mod tests { #[test] fn seek_past_end() { let buf = [0xff]; - let mut r = Cursor::new(&buf[]); + let mut r = Cursor::new(&buf[..]); assert_eq!(r.seek(SeekFrom::Start(10)), Ok(10)); assert_eq!(r.read(&mut [0]), Ok(0)); @@ -340,7 +340,7 @@ mod tests { assert_eq!(r.read(&mut [0]), Ok(0)); let mut buf = [0]; - let mut r = Cursor::new(&mut buf[]); + let mut r = Cursor::new(&mut buf[..]); assert_eq!(r.seek(SeekFrom::Start(10)), Ok(10)); assert_eq!(r.write(&[3]), Ok(0)); } @@ -348,14 +348,14 @@ mod tests { #[test] fn seek_before_0() { let buf = [0xff_u8]; - let mut r = Cursor::new(&buf[]); + let mut r = Cursor::new(&buf[..]); assert!(r.seek(SeekFrom::End(-2)).is_err()); let mut r = Cursor::new(vec!(10u8)); assert!(r.seek(SeekFrom::End(-2)).is_err()); let mut buf = [0]; - let mut r = Cursor::new(&mut buf[]); + let mut r = Cursor::new(&mut buf[..]); assert!(r.seek(SeekFrom::End(-2)).is_err()); } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 7c9a8a7b4b5..fbd403ea593 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -161,7 +161,6 @@ extern crate libc; // NB: These reexports are in the order they should be listed in rustdoc pub use core::any; -pub use core::borrow; pub use core::cell; pub use core::clone; #[cfg(not(test))] pub use core::cmp; @@ -184,6 +183,7 @@ pub use core::error; #[cfg(not(test))] pub use alloc::boxed; pub use alloc::rc; +pub use core_collections::borrow; pub use core_collections::fmt; pub use core_collections::slice; pub use core_collections::str; diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index 66d4d34f8eb..51944adf3b4 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -147,6 +147,7 @@ impl PartialEq for Repr { } impl Eq for Repr {} +#[cfg(stage0)] impl<S: hash::Hasher + hash::Writer> hash::Hash<S> for Repr { fn hash(&self, s: &mut S) { match *self { @@ -160,6 +161,21 @@ impl<S: hash::Hasher + hash::Writer> hash::Hash<S> for Repr { } } } +#[cfg(not(stage0))] +#[stable(feature = "rust1", since = "1.0.0")] +impl hash::Hash for Repr { + fn hash<H: hash::Hasher>(&self, s: &mut H) { + match *self { + Repr::V4(ref a) => { + (a.sin_family, a.sin_port, a.sin_addr.s_addr).hash(s) + } + Repr::V6(ref a) => { + (a.sin6_family, a.sin6_port, &a.sin6_addr.s6_addr, + a.sin6_flowinfo, a.sin6_scope_id).hash(s) + } + } + } +} /// A trait for objects which can be converted or resolved to one or more /// `SocketAddr` values. diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 08f7a6e2e96..571a1b03ef0 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -189,11 +189,19 @@ impl PartialEq for Ipv4Addr { } impl Eq for Ipv4Addr {} +#[cfg(stage0)] impl<S: hash::Hasher + hash::Writer> hash::Hash<S> for Ipv4Addr { fn hash(&self, s: &mut S) { self.inner.s_addr.hash(s) } } +#[cfg(not(stage0))] +#[stable(feature = "rust1", since = "1.0.0")] +impl hash::Hash for Ipv4Addr { + fn hash<H: hash::Hasher>(&self, s: &mut H) { + self.inner.s_addr.hash(s) + } +} impl PartialOrd for Ipv4Addr { fn partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering> { @@ -421,11 +429,19 @@ impl PartialEq for Ipv6Addr { } impl Eq for Ipv6Addr {} +#[cfg(stage0)] impl<S: hash::Hasher + hash::Writer> hash::Hash<S> for Ipv6Addr { fn hash(&self, s: &mut S) { self.inner.s6_addr.hash(s) } } +#[cfg(not(stage0))] +#[stable(feature = "rust1", since = "1.0.0")] +impl hash::Hash for Ipv6Addr { + fn hash<H: hash::Hasher>(&self, s: &mut H) { + self.inner.s6_addr.hash(s) + } +} impl PartialOrd for Ipv6Addr { fn partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering> { diff --git a/src/libstd/old_io/buffered.rs b/src/libstd/old_io/buffered.rs index 59a437ad916..2d2d0d8b33a 100644 --- a/src/libstd/old_io/buffered.rs +++ b/src/libstd/old_io/buffered.rs @@ -546,7 +546,7 @@ mod test { assert_eq!(a, &w.get_ref()[]); let w = w.into_inner(); let a: &[_] = &[0, 1]; - assert_eq!(a, &w[]); + assert_eq!(a, &w[..]); } // This is just here to make sure that we don't infinite loop in the @@ -643,14 +643,14 @@ mod test { #[test] fn read_char_buffered() { let buf = [195u8, 159u8]; - let mut reader = BufferedReader::with_capacity(1, &buf[]); + let mut reader = BufferedReader::with_capacity(1, &buf[..]); assert_eq!(reader.read_char(), Ok('ß')); } #[test] fn test_chars() { let buf = [195u8, 159u8, b'a']; - let mut reader = BufferedReader::with_capacity(1, &buf[]); + let mut reader = BufferedReader::with_capacity(1, &buf[..]); let mut it = reader.chars(); assert_eq!(it.next(), Some(Ok('ß'))); assert_eq!(it.next(), Some(Ok('a'))); diff --git a/src/libstd/old_io/mod.rs b/src/libstd/old_io/mod.rs index 21282a0c28a..fc3deb67f41 100644 --- a/src/libstd/old_io/mod.rs +++ b/src/libstd/old_io/mod.rs @@ -252,7 +252,7 @@ use error::Error; use fmt; use isize; use iter::{Iterator, IteratorExt}; -use marker::Sized; +use marker::{PhantomFn, Sized}; use mem::transmute; use ops::FnOnce; use option::Option; @@ -433,7 +433,7 @@ pub enum IoErrorKind { } /// A trait that lets you add a `detail` to an IoError easily -trait UpdateIoError<T> { +trait UpdateIoError { /// Returns an IoError with updated description and detail fn update_err<D>(self, desc: &'static str, detail: D) -> Self where D: FnOnce(&IoError) -> String; @@ -446,7 +446,7 @@ trait UpdateIoError<T> { fn update_desc(self, desc: &'static str) -> Self; } -impl<T> UpdateIoError<T> for IoResult<T> { +impl<T> UpdateIoError for IoResult<T> { fn update_err<D>(self, desc: &'static str, detail: D) -> IoResult<T> where D: FnOnce(&IoError) -> String, { @@ -1572,7 +1572,9 @@ pub trait Seek { /// connections. /// /// Doing so produces some sort of Acceptor. -pub trait Listener<T, A: Acceptor<T>> { +pub trait Listener<T, A: Acceptor<T>> + : PhantomFn<T,T> // FIXME should be an assoc type anyhow +{ /// Spin up the listener and start queuing incoming connections /// /// # Error diff --git a/src/libstd/old_io/net/pipe.rs b/src/libstd/old_io/net/pipe.rs index 8a4e8668b10..d05669d32b8 100644 --- a/src/libstd/old_io/net/pipe.rs +++ b/src/libstd/old_io/net/pipe.rs @@ -55,7 +55,7 @@ impl UnixStream { /// stream.write(&[1, 2, 3]); /// ``` pub fn connect<P: BytesContainer>(path: P) -> IoResult<UnixStream> { - let path = CString::from_slice(path.container_as_bytes()); + let path = try!(CString::new(path.container_as_bytes())); UnixStreamImp::connect(&path, None) .map(|inner| UnixStream { inner: inner }) } @@ -77,7 +77,7 @@ impl UnixStream { return Err(standard_error(TimedOut)); } - let path = CString::from_slice(path.container_as_bytes()); + let path = try!(CString::new(path.container_as_bytes())); UnixStreamImp::connect(&path, Some(timeout.num_milliseconds() as u64)) .map(|inner| UnixStream { inner: inner }) } @@ -184,7 +184,7 @@ impl UnixListener { /// # } /// ``` pub fn bind<P: BytesContainer>(path: P) -> IoResult<UnixListener> { - let path = CString::from_slice(path.container_as_bytes()); + let path = try!(CString::new(path.container_as_bytes())); UnixListenerImp::bind(&path) .map(|inner| UnixListener { inner: inner }) } diff --git a/src/libstd/old_io/process.rs b/src/libstd/old_io/process.rs index ea6510c61b7..c803cfbcb7d 100644 --- a/src/libstd/old_io/process.rs +++ b/src/libstd/old_io/process.rs @@ -104,7 +104,7 @@ struct EnvKey(CString); #[derive(Eq, Clone, Debug)] struct EnvKey(CString); -#[cfg(windows)] +#[cfg(all(windows, stage0))] impl<H: hash::Writer + hash::Hasher> hash::Hash<H> for EnvKey { fn hash(&self, state: &mut H) { let &EnvKey(ref x) = self; @@ -116,6 +116,18 @@ impl<H: hash::Writer + hash::Hasher> hash::Hash<H> for EnvKey { } } } +#[cfg(all(windows, not(stage0)))] +impl hash::Hash for EnvKey { + fn hash<H: hash::Hasher>(&self, state: &mut H) { + let &EnvKey(ref x) = self; + match str::from_utf8(x.as_bytes()) { + Ok(s) => for ch in s.chars() { + (ch as u8 as char).to_lowercase().hash(state); + }, + Err(..) => x.hash(state) + } + } +} #[cfg(windows)] impl PartialEq for EnvKey { @@ -204,7 +216,7 @@ impl Command { /// otherwise configure the process. pub fn new<T: BytesContainer>(program: T) -> Command { Command { - program: CString::from_slice(program.container_as_bytes()), + program: CString::new(program.container_as_bytes()).unwrap(), args: Vec::new(), env: None, cwd: None, @@ -219,14 +231,14 @@ impl Command { /// Add an argument to pass to the program. pub fn arg<'a, T: BytesContainer>(&'a mut self, arg: T) -> &'a mut Command { - self.args.push(CString::from_slice(arg.container_as_bytes())); + self.args.push(CString::new(arg.container_as_bytes()).unwrap()); self } /// Add multiple arguments to pass to the program. pub fn args<'a, T: BytesContainer>(&'a mut self, args: &[T]) -> &'a mut Command { self.args.extend(args.iter().map(|arg| { - CString::from_slice(arg.container_as_bytes()) + CString::new(arg.container_as_bytes()).unwrap() })); self } @@ -239,8 +251,8 @@ impl Command { // if the env is currently just inheriting from the parent's, // materialize the parent's env into a hashtable. self.env = Some(os::env_as_bytes().into_iter().map(|(k, v)| { - (EnvKey(CString::from_slice(&k)), - CString::from_slice(&v)) + (EnvKey(CString::new(k).unwrap()), + CString::new(v).unwrap()) }).collect()); self.env.as_mut().unwrap() } @@ -254,8 +266,8 @@ impl Command { pub fn env<'a, T, U>(&'a mut self, key: T, val: U) -> &'a mut Command where T: BytesContainer, U: BytesContainer { - let key = EnvKey(CString::from_slice(key.container_as_bytes())); - let val = CString::from_slice(val.container_as_bytes()); + let key = EnvKey(CString::new(key.container_as_bytes()).unwrap()); + let val = CString::new(val.container_as_bytes()).unwrap(); self.get_env_map().insert(key, val); self } @@ -263,7 +275,7 @@ impl Command { /// Removes an environment variable mapping. pub fn env_remove<'a, T>(&'a mut self, key: T) -> &'a mut Command where T: BytesContainer { - let key = EnvKey(CString::from_slice(key.container_as_bytes())); + let key = EnvKey(CString::new(key.container_as_bytes()).unwrap()); self.get_env_map().remove(&key); self } @@ -276,15 +288,15 @@ impl Command { -> &'a mut Command where T: BytesContainer, U: BytesContainer { self.env = Some(env.iter().map(|&(ref k, ref v)| { - (EnvKey(CString::from_slice(k.container_as_bytes())), - CString::from_slice(v.container_as_bytes())) + (EnvKey(CString::new(k.container_as_bytes()).unwrap()), + CString::new(v.container_as_bytes()).unwrap()) }).collect()); self } /// Set the working directory for the child process. pub fn cwd<'a>(&'a mut self, dir: &Path) -> &'a mut Command { - self.cwd = Some(CString::from_slice(dir.as_vec())); + self.cwd = Some(CString::new(dir.as_vec()).unwrap()); self } @@ -1226,7 +1238,7 @@ mod tests { cmd.env("path", "foo"); cmd.env("Path", "bar"); let env = &cmd.env.unwrap(); - let val = env.get(&EnvKey(CString::from_slice(b"PATH"))); - assert!(val.unwrap() == &CString::from_slice(b"bar")); + let val = env.get(&EnvKey(CString::new(b"PATH").unwrap())); + assert!(val.unwrap() == &CString::new(b"bar").unwrap()); } } diff --git a/src/libstd/old_path/mod.rs b/src/libstd/old_path/mod.rs index 37de2993c4d..e9005aa22bc 100644 --- a/src/libstd/old_path/mod.rs +++ b/src/libstd/old_path/mod.rs @@ -877,7 +877,7 @@ impl BytesContainer for String { } #[inline] fn container_as_str(&self) -> Option<&str> { - Some(&self[]) + Some(&self[..]) } #[inline] fn is_str(_: Option<&String>) -> bool { true } @@ -893,7 +893,7 @@ impl BytesContainer for [u8] { impl BytesContainer for Vec<u8> { #[inline] fn container_as_bytes(&self) -> &[u8] { - &self[] + &self[..] } } diff --git a/src/libstd/old_path/posix.rs b/src/libstd/old_path/posix.rs index 0a184a01a1d..15eee9e4a0c 100644 --- a/src/libstd/old_path/posix.rs +++ b/src/libstd/old_path/posix.rs @@ -100,12 +100,21 @@ impl FromStr for Path { #[derive(Debug, Clone, PartialEq, Copy)] pub struct ParsePathError; +#[cfg(stage0)] impl<S: hash::Writer + hash::Hasher> hash::Hash<S> for Path { #[inline] fn hash(&self, state: &mut S) { self.repr.hash(state) } } +#[cfg(not(stage0))] +#[stable(feature = "rust1", since = "1.0.0")] +impl hash::Hash for Path { + #[inline] + fn hash<H: hash::Hasher>(&self, state: &mut H) { + self.repr.hash(state) + } +} impl BytesContainer for Path { #[inline] @@ -1172,7 +1181,7 @@ mod tests { let exp: &[&[u8]] = &[$($exp),*]; assert_eq!(comps, exp); let comps = path.components().rev().collect::<Vec<&[u8]>>(); - let exp = exp.iter().rev().map(|&x|x).collect::<Vec<&[u8]>>(); + let exp = exp.iter().rev().cloned().collect::<Vec<&[u8]>>(); assert_eq!(comps, exp) } ) @@ -1204,7 +1213,7 @@ mod tests { let exp: &[Option<&str>] = &$exp; assert_eq!(comps, exp); let comps = path.str_components().rev().collect::<Vec<Option<&str>>>(); - let exp = exp.iter().rev().map(|&x|x).collect::<Vec<Option<&str>>>(); + let exp = exp.iter().rev().cloned().collect::<Vec<Option<&str>>>(); assert_eq!(comps, exp); } ) diff --git a/src/libstd/old_path/windows.rs b/src/libstd/old_path/windows.rs index 02a21321c4c..887dc804c7a 100644 --- a/src/libstd/old_path/windows.rs +++ b/src/libstd/old_path/windows.rs @@ -127,6 +127,7 @@ impl FromStr for Path { #[derive(Debug, Clone, PartialEq, Copy)] pub struct ParsePathError; +#[cfg(stage0)] impl<S: hash::Writer + hash::Hasher> hash::Hash<S> for Path { #[cfg(not(test))] #[inline] @@ -140,6 +141,21 @@ impl<S: hash::Writer + hash::Hasher> hash::Hash<S> for Path { // No-op because the `hash` implementation will be wrong. } } +#[cfg(not(stage0))] +#[stable(feature = "rust1", since = "1.0.0")] +impl hash::Hash for Path { + #[cfg(not(test))] + #[inline] + fn hash<H: hash::Hasher>(&self, state: &mut H) { + self.repr.hash(state) + } + + #[cfg(test)] + #[inline] + fn hash<H: hash::Hasher>(&self, _: &mut H) { + // No-op because the `hash` implementation will be wrong. + } +} impl BytesContainer for Path { #[inline] @@ -182,7 +198,7 @@ impl GenericPathUnsafe for Path { s.push_str(".."); s.push(SEP); s.push_str(filename); - self.update_normalized(&s[]); + self.update_normalized(&s[..]); } None => { self.update_normalized(filename); @@ -192,20 +208,20 @@ impl GenericPathUnsafe for Path { s.push_str(&self.repr[..end]); s.push(SEP); s.push_str(filename); - self.update_normalized(&s[]); + self.update_normalized(&s[..]); } Some((idxb,idxa,_)) if self.prefix == Some(DiskPrefix) && idxa == self.prefix_len() => { let mut s = String::with_capacity(idxb + filename.len()); s.push_str(&self.repr[..idxb]); s.push_str(filename); - self.update_normalized(&s[]); + self.update_normalized(&s[..]); } Some((idxb,_,_)) => { let mut s = String::with_capacity(idxb + 1 + filename.len()); s.push_str(&self.repr[..idxb]); s.push(SEP); s.push_str(filename); - self.update_normalized(&s[]); + self.update_normalized(&s[..]); } } } @@ -229,7 +245,7 @@ impl GenericPathUnsafe for Path { } fn shares_volume(me: &Path, path: &str) -> bool { // path is assumed to have a prefix of Some(DiskPrefix) - let repr = &me.repr[]; + let repr = &me.repr[..]; match me.prefix { Some(DiskPrefix) => { repr.as_bytes()[0] == path.as_bytes()[0].to_ascii_uppercase() @@ -261,7 +277,7 @@ impl GenericPathUnsafe for Path { else { None }; let pathlen = path_.as_ref().map_or(path.len(), |p| p.len()); let mut s = String::with_capacity(me.repr.len() + 1 + pathlen); - s.push_str(&me.repr[]); + s.push_str(&me.repr[..]); let plen = me.prefix_len(); // if me is "C:" we don't want to add a path separator match me.prefix { @@ -273,9 +289,9 @@ impl GenericPathUnsafe for Path { } match path_ { None => s.push_str(path), - Some(p) => s.push_str(&p[]), + Some(p) => s.push_str(&p[..]), }; - me.update_normalized(&s[]) + me.update_normalized(&s[..]) } if !path.is_empty() { @@ -329,7 +345,7 @@ impl GenericPath for Path { /// Always returns a `Some` value. #[inline] fn as_str<'a>(&'a self) -> Option<&'a str> { - Some(&self.repr[]) + Some(&self.repr[..]) } #[inline] @@ -351,13 +367,13 @@ impl GenericPath for Path { /// Always returns a `Some` value. fn dirname_str<'a>(&'a self) -> Option<&'a str> { Some(match self.sepidx_or_prefix_len() { - None if ".." == self.repr => &self.repr[], + None if ".." == self.repr => &self.repr[..], None => ".", Some((_,idxa,end)) if &self.repr[idxa..end] == ".." => { - &self.repr[] + &self.repr[..] } Some((idxb,_,end)) if &self.repr[idxb..end] == "\\" => { - &self.repr[] + &self.repr[..] } Some((0,idxa,_)) => &self.repr[..idxa], Some((idxb,idxa,_)) => { @@ -379,7 +395,7 @@ impl GenericPath for Path { /// See `GenericPath::filename_str` for info. /// Always returns a `Some` value if `filename` returns a `Some` value. fn filename_str<'a>(&'a self) -> Option<&'a str> { - let repr = &self.repr[]; + let repr = &self.repr[..]; match self.sepidx_or_prefix_len() { None if "." == repr || ".." == repr => None, None => Some(repr), @@ -639,7 +655,7 @@ impl Path { /// Does not distinguish between absolute and cwd-relative paths, e.g. /// C:\foo and C:foo. pub fn str_components<'a>(&'a self) -> StrComponents<'a> { - let repr = &self.repr[]; + let repr = &self.repr[..]; let s = match self.prefix { Some(_) => { let plen = self.prefix_len(); @@ -667,8 +683,8 @@ impl Path { } fn equiv_prefix(&self, other: &Path) -> bool { - let s_repr = &self.repr[]; - let o_repr = &other.repr[]; + let s_repr = &self.repr[..]; + let o_repr = &other.repr[..]; match (self.prefix, other.prefix) { (Some(DiskPrefix), Some(VerbatimDiskPrefix)) => { self.is_absolute() && @@ -823,7 +839,7 @@ impl Path { fn update_sepidx(&mut self) { let s = if self.has_nonsemantic_trailing_slash() { &self.repr[..self.repr.len()-1] - } else { &self.repr[] }; + } else { &self.repr[..] }; let sep_test: fn(char) -> bool = if !prefix_is_verbatim(self.prefix) { is_sep } else { @@ -902,7 +918,7 @@ pub fn is_verbatim(path: &Path) -> bool { /// non-verbatim, the non-verbatim version is returned. /// Otherwise, None is returned. pub fn make_non_verbatim(path: &Path) -> Option<Path> { - let repr = &path.repr[]; + let repr = &path.repr[..]; let new_path = match path.prefix { Some(VerbatimPrefix(_)) | Some(DeviceNSPrefix(_)) => return None, Some(UNCPrefix(_,_)) | Some(DiskPrefix) | None => return Some(path.clone()), @@ -2226,7 +2242,7 @@ mod tests { assert_eq!(comps, exp); let comps = path.str_components().rev().map(|x|x.unwrap()) .collect::<Vec<&str>>(); - let exp = exp.iter().rev().map(|&x|x).collect::<Vec<&str>>(); + let exp = exp.iter().rev().cloned().collect::<Vec<&str>>(); assert_eq!(comps, exp); } ); @@ -2282,7 +2298,7 @@ mod tests { let exp: &[&[u8]] = &$exp; assert_eq!(comps, exp); let comps = path.components().rev().collect::<Vec<&[u8]>>(); - let exp = exp.iter().rev().map(|&x|x).collect::<Vec<&[u8]>>(); + let exp = exp.iter().rev().cloned().collect::<Vec<&[u8]>>(); assert_eq!(comps, exp); } ) diff --git a/src/libstd/os.rs b/src/libstd/os.rs index a4213e7373b..f181fc5df57 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -561,10 +561,11 @@ pub fn get_exit_status() -> int { #[cfg(target_os = "macos")] unsafe fn load_argc_and_argv(argc: int, argv: *const *const c_char) -> Vec<Vec<u8>> { + use ffi::CStr; use iter::range; - (0..argc as uint).map(|i| { - ffi::c_str_to_bytes(&*argv.offset(i as int)).to_vec() + (0..argc).map(|i| { + CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec() }).collect() } diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 35221a7e647..2e05f6d974e 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -37,7 +37,7 @@ pub fn on_panic(obj: &(Any+Send), file: &'static str, line: uint) { let msg = match obj.downcast_ref::<&'static str>() { Some(s) => *s, None => match obj.downcast_ref::<String>() { - Some(s) => &s[], + Some(s) => &s[..], None => "Box<Any>", } }; diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 1d992668900..49a5efec7c2 100755 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -108,12 +108,11 @@ use core::prelude::*; use ascii::*; -use borrow::BorrowFrom; +use borrow::{Borrow, ToOwned, Cow}; use cmp; -use iter; +use iter::{self, IntoIterator}; use mem; use ops::{self, Deref}; -use string::CowString; use vec::Vec; use fmt; @@ -953,7 +952,7 @@ impl PathBuf { } impl<'a, P: ?Sized + 'a> iter::FromIterator<&'a P> for PathBuf where P: AsPath { - fn from_iter<I: Iterator<Item = &'a P>>(iter: I) -> PathBuf { + fn from_iter<I: IntoIterator<Item = &'a P>>(iter: I) -> PathBuf { let mut buf = PathBuf::new(""); buf.extend(iter); buf @@ -961,7 +960,7 @@ impl<'a, P: ?Sized + 'a> iter::FromIterator<&'a P> for PathBuf where P: AsPath { } impl<'a, P: ?Sized + 'a> iter::Extend<&'a P> for PathBuf where P: AsPath { - fn extend<I: Iterator<Item = &'a P>>(&mut self, iter: I) { + fn extend<I: IntoIterator<Item = &'a P>>(&mut self, iter: I) { for p in iter { self.push(p) } @@ -978,16 +977,21 @@ impl ops::Deref for PathBuf { type Target = Path; fn deref(&self) -> &Path { - unsafe { mem::transmute(&self.inner[]) } + unsafe { mem::transmute(&self.inner[..]) } } } -impl BorrowFrom<PathBuf> for Path { - fn borrow_from(owned: &PathBuf) -> &Path { - owned.deref() +impl Borrow<Path> for PathBuf { + fn borrow(&self) -> &Path { + self.deref() } } +impl ToOwned for Path { + type Owned = PathBuf; + fn to_owned(&self) -> PathBuf { self.to_path_buf() } +} + impl cmp::PartialEq for PathBuf { fn eq(&self, other: &PathBuf) -> bool { self.components() == other.components() @@ -1010,7 +1014,7 @@ impl cmp::Ord for PathBuf { impl AsOsStr for PathBuf { fn as_os_str(&self) -> &OsStr { - &self.inner[] + &self.inner[..] } } @@ -1066,10 +1070,10 @@ impl Path { self.inner.to_str() } - /// Convert a `Path` to a `CowString`. + /// Convert a `Path` to a `Cow<str>`. /// /// Any non-Unicode sequences are replaced with U+FFFD REPLACEMENT CHARACTER. - pub fn to_string_lossy(&self) -> CowString { + pub fn to_string_lossy(&self) -> Cow<str> { self.inner.to_string_lossy() } diff --git a/src/libstd/rand/mod.rs b/src/libstd/rand/mod.rs index 25d372b406f..5c891441198 100644 --- a/src/libstd/rand/mod.rs +++ b/src/libstd/rand/mod.rs @@ -547,7 +547,7 @@ mod test { #[test] fn test_choose() { let mut r = thread_rng(); - assert_eq!(r.choose(&[1, 1, 1]).map(|&x|x), Some(1)); + assert_eq!(r.choose(&[1, 1, 1]).cloned(), Some(1)); let v: &[int] = &[]; assert_eq!(r.choose(v), None); diff --git a/src/libstd/rt/args.rs b/src/libstd/rt/args.rs index c2f5133eaf3..61f5bd0f013 100644 --- a/src/libstd/rt/args.rs +++ b/src/libstd/rt/args.rs @@ -49,7 +49,7 @@ mod imp { use libc; use mem; - use ffi; + use ffi::CStr; use sync::{StaticMutex, MUTEX_INIT}; @@ -96,10 +96,11 @@ mod imp { unsafe { mem::transmute(&GLOBAL_ARGS_PTR) } } - unsafe fn load_argc_and_argv(argc: int, argv: *const *const u8) -> Vec<Vec<u8>> { + unsafe fn load_argc_and_argv(argc: isize, + argv: *const *const u8) -> Vec<Vec<u8>> { let argv = argv as *const *const libc::c_char; - (0..argc as uint).map(|i| { - ffi::c_str_to_bytes(&*argv.offset(i as int)).to_vec() + (0..argc).map(|i| { + CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec() }).collect() } diff --git a/src/libstd/sys/common/net.rs b/src/libstd/sys/common/net.rs index 7325e0a5ac8..e2ac5ac24f8 100644 --- a/src/libstd/sys/common/net.rs +++ b/src/libstd/sys/common/net.rs @@ -12,8 +12,7 @@ use prelude::v1::*; use self::SocketStatus::*; use self::InAddr::*; -use ffi::CString; -use ffi; +use ffi::{CString, CStr}; use old_io::net::addrinfo; use old_io::net::ip::{SocketAddr, IpAddr, Ipv4Addr, Ipv6Addr}; use old_io::{IoResult, IoError}; @@ -235,9 +234,15 @@ pub fn get_host_addresses(host: Option<&str>, servname: Option<&str>, assert!(host.is_some() || servname.is_some()); - let c_host = host.map(|x| CString::from_slice(x.as_bytes())); + let c_host = match host { + Some(x) => Some(try!(CString::new(x))), + None => None, + }; let c_host = c_host.as_ref().map(|x| x.as_ptr()).unwrap_or(null()); - let c_serv = servname.map(|x| CString::from_slice(x.as_bytes())); + let c_serv = match servname { + Some(x) => Some(try!(CString::new(x))), + None => None, + }; let c_serv = c_serv.as_ref().map(|x| x.as_ptr()).unwrap_or(null()); let hint = hint.map(|hint| { @@ -325,8 +330,8 @@ pub fn get_address_name(addr: IpAddr) -> Result<String, IoError> { } unsafe { - Ok(str::from_utf8(ffi::c_str_to_bytes(&hostbuf.as_ptr())) - .unwrap().to_string()) + let data = CStr::from_ptr(hostbuf.as_ptr()); + Ok(str::from_utf8(data.to_bytes()).unwrap().to_string()) } } diff --git a/src/libstd/sys/common/net2.rs b/src/libstd/sys/common/net2.rs index 5af59ec6d2b..713f79c5d08 100644 --- a/src/libstd/sys/common/net2.rs +++ b/src/libstd/sys/common/net2.rs @@ -121,7 +121,7 @@ impl Drop for LookupHost { pub fn lookup_host(host: &str) -> io::Result<LookupHost> { init(); - let c_host = CString::from_slice(host.as_bytes()); + let c_host = try!(CString::new(host)); let mut res = 0 as *mut _; unsafe { try!(cvt_gai(getaddrinfo(c_host.as_ptr(), 0 as *const _, 0 as *const _, diff --git a/src/libstd/sys/common/wtf8.rs b/src/libstd/sys/common/wtf8.rs index b610f6c370b..ca3ae1a7a34 100644 --- a/src/libstd/sys/common/wtf8.rs +++ b/src/libstd/sys/common/wtf8.rs @@ -31,8 +31,9 @@ use ascii::*; use borrow::Cow; use cmp; use fmt; -use hash::{Hash, Writer, Hasher}; -use iter::FromIterator; +use hash::{Hash, Hasher}; +#[cfg(stage0)] use hash::Writer; +use iter::{FromIterator, IntoIterator}; use mem; use num::Int; use ops; @@ -356,9 +357,9 @@ impl Wtf8Buf { /// This replaces surrogate code point pairs with supplementary code points, /// like concatenating ill-formed UTF-16 strings effectively would. impl FromIterator<CodePoint> for Wtf8Buf { - fn from_iter<T: Iterator<Item=CodePoint>>(iterator: T) -> Wtf8Buf { + fn from_iter<T: IntoIterator<Item=CodePoint>>(iter: T) -> Wtf8Buf { let mut string = Wtf8Buf::new(); - string.extend(iterator); + string.extend(iter); string } } @@ -368,7 +369,8 @@ impl FromIterator<CodePoint> for Wtf8Buf { /// This replaces surrogate code point pairs with supplementary code points, /// like concatenating ill-formed UTF-16 strings effectively would. impl Extend<CodePoint> for Wtf8Buf { - fn extend<T: Iterator<Item=CodePoint>>(&mut self, iterator: T) { + fn extend<T: IntoIterator<Item=CodePoint>>(&mut self, iterable: T) { + let iterator = iterable.into_iter(); let (low, _high) = iterator.size_hint(); // Lower bound of one byte per code point (ASCII only) self.bytes.reserve(low); @@ -794,13 +796,22 @@ impl<'a> Iterator for EncodeWide<'a> { } } +#[cfg(stage0)] impl<S: Writer + Hasher> Hash<S> for CodePoint { #[inline] fn hash(&self, state: &mut S) { self.value.hash(state) } } +#[cfg(not(stage0))] +impl Hash for CodePoint { + #[inline] + fn hash<H: Hasher>(&self, state: &mut H) { + self.value.hash(state) + } +} +#[cfg(stage0)] impl<S: Writer + Hasher> Hash<S> for Wtf8Buf { #[inline] fn hash(&self, state: &mut S) { @@ -808,7 +819,16 @@ impl<S: Writer + Hasher> Hash<S> for Wtf8Buf { 0xfeu8.hash(state) } } +#[cfg(not(stage0))] +impl Hash for Wtf8Buf { + #[inline] + fn hash<H: Hasher>(&self, state: &mut H) { + state.write(&self.bytes); + 0xfeu8.hash(state) + } +} +#[cfg(stage0)] impl<'a, S: Writer + Hasher> Hash<S> for Wtf8 { #[inline] fn hash(&self, state: &mut S) { @@ -816,6 +836,14 @@ impl<'a, S: Writer + Hasher> Hash<S> for Wtf8 { 0xfeu8.hash(state) } } +#[cfg(not(stage0))] +impl Hash for Wtf8 { + #[inline] + fn hash<H: Hasher>(&self, state: &mut H) { + state.write(&self.bytes); + 0xfeu8.hash(state) + } +} impl AsciiExt for Wtf8 { type Owned = Wtf8Buf; diff --git a/src/libstd/sys/unix/backtrace.rs b/src/libstd/sys/unix/backtrace.rs index 5e512e9261b..8b560339f30 100644 --- a/src/libstd/sys/unix/backtrace.rs +++ b/src/libstd/sys/unix/backtrace.rs @@ -85,7 +85,7 @@ use prelude::v1::*; -use ffi; +use ffi::CStr; use old_io::IoResult; use libc; use mem; @@ -233,7 +233,7 @@ fn print(w: &mut Writer, idx: int, addr: *mut libc::c_void) -> IoResult<()> { output(w, idx,addr, None) } else { output(w, idx, addr, Some(unsafe { - ffi::c_str_to_bytes(&info.dli_sname) + CStr::from_ptr(info.dli_sname).to_bytes() })) } } @@ -364,7 +364,7 @@ fn print(w: &mut Writer, idx: int, addr: *mut libc::c_void) -> IoResult<()> { if ret == 0 || data.is_null() { output(w, idx, addr, None) } else { - output(w, idx, addr, Some(unsafe { ffi::c_str_to_bytes(&data) })) + output(w, idx, addr, Some(unsafe { CStr::from_ptr(data).to_bytes() })) } } diff --git a/src/libstd/sys/unix/ext.rs b/src/libstd/sys/unix/ext.rs index bbbe022fbaf..b8b9dcfb3c6 100644 --- a/src/libstd/sys/unix/ext.rs +++ b/src/libstd/sys/unix/ext.rs @@ -33,7 +33,7 @@ use prelude::v1::*; -use ffi::{CString, OsStr, OsString}; +use ffi::{CString, NulError, OsStr, OsString}; use fs::{self, Permissions, OpenOptions}; use net; use mem; @@ -155,7 +155,7 @@ pub trait OsStrExt { fn as_bytes(&self) -> &[u8]; /// Convert the `OsStr` slice into a `CString`. - fn to_cstring(&self) -> CString; + fn to_cstring(&self) -> Result<CString, NulError>; } impl OsStrExt for OsStr { @@ -166,8 +166,8 @@ impl OsStrExt for OsStr { &self.as_inner().inner } - fn to_cstring(&self) -> CString { - CString::from_slice(self.as_bytes()) + fn to_cstring(&self) -> Result<CString, NulError> { + CString::new(self.as_bytes()) } } @@ -249,5 +249,7 @@ impl ExitStatusExt for process::ExitStatus { /// Includes all extension traits, and some important type definitions. pub mod prelude { #[doc(no_inline)] - pub use super::{Fd, AsRawFd, OsStrExt, OsStringExt, PermissionsExt, CommandExt, ExitStatusExt}; + pub use super::{Fd, AsRawFd, OsStrExt, OsStringExt, PermissionsExt}; + #[doc(no_inline)] + pub use super::{CommandExt, ExitStatusExt}; } diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 0ee2b5b6809..5c847002d23 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -12,7 +12,7 @@ use prelude::v1::*; -use ffi::{self, CString}; +use ffi::{CString, CStr}; use old_io::{FilePermission, Write, UnstableFileStat, Open, FileAccess, FileMode}; use old_io::{IoResult, FileStat, SeekStyle}; use old_io::{Read, Truncate, SeekCur, SeekSet, ReadWrite, SeekEnd, Append}; @@ -151,8 +151,8 @@ impl Drop for FileDesc { } } -fn cstr(path: &Path) -> CString { - CString::from_slice(path.as_vec()) +fn cstr(path: &Path) -> IoResult<CString> { + Ok(try!(CString::new(path.as_vec()))) } pub fn open(path: &Path, fm: FileMode, fa: FileAccess) -> IoResult<FileDesc> { @@ -170,7 +170,7 @@ pub fn open(path: &Path, fm: FileMode, fa: FileAccess) -> IoResult<FileDesc> { libc::S_IRUSR | libc::S_IWUSR), }; - let path = cstr(path); + let path = try!(cstr(path)); match retry(|| unsafe { libc::open(path.as_ptr(), flags, mode) }) { -1 => Err(super::last_error()), fd => Ok(FileDesc::new(fd, true)), @@ -178,7 +178,7 @@ pub fn open(path: &Path, fm: FileMode, fa: FileAccess) -> IoResult<FileDesc> { } pub fn mkdir(p: &Path, mode: uint) -> IoResult<()> { - let p = cstr(p); + let p = try!(cstr(p)); mkerr_libc(unsafe { libc::mkdir(p.as_ptr(), mode as libc::mode_t) }) } @@ -203,7 +203,7 @@ pub fn readdir(p: &Path) -> IoResult<Vec<Path>> { let mut buf = Vec::<u8>::with_capacity(size as uint); let ptr = buf.as_mut_ptr() as *mut dirent_t; - let p = CString::from_slice(p.as_vec()); + let p = try!(CString::new(p.as_vec())); let dir_ptr = unsafe {opendir(p.as_ptr())}; if dir_ptr as uint != 0 { @@ -212,7 +212,7 @@ pub fn readdir(p: &Path) -> IoResult<Vec<Path>> { while unsafe { readdir_r(dir_ptr, ptr, &mut entry_ptr) == 0 } { if entry_ptr.is_null() { break } paths.push(unsafe { - Path::new(ffi::c_str_to_bytes(&rust_list_dir_val(entry_ptr))) + Path::new(CStr::from_ptr(rust_list_dir_val(entry_ptr)).to_bytes()) }); } assert_eq!(unsafe { closedir(dir_ptr) }, 0); @@ -223,39 +223,39 @@ pub fn readdir(p: &Path) -> IoResult<Vec<Path>> { } pub fn unlink(p: &Path) -> IoResult<()> { - let p = cstr(p); + let p = try!(cstr(p)); mkerr_libc(unsafe { libc::unlink(p.as_ptr()) }) } pub fn rename(old: &Path, new: &Path) -> IoResult<()> { - let old = cstr(old); - let new = cstr(new); + let old = try!(cstr(old)); + let new = try!(cstr(new)); mkerr_libc(unsafe { libc::rename(old.as_ptr(), new.as_ptr()) }) } pub fn chmod(p: &Path, mode: uint) -> IoResult<()> { - let p = cstr(p); + let p = try!(cstr(p)); mkerr_libc(retry(|| unsafe { libc::chmod(p.as_ptr(), mode as libc::mode_t) })) } pub fn rmdir(p: &Path) -> IoResult<()> { - let p = cstr(p); + let p = try!(cstr(p)); mkerr_libc(unsafe { libc::rmdir(p.as_ptr()) }) } pub fn chown(p: &Path, uid: int, gid: int) -> IoResult<()> { - let p = cstr(p); + let p = try!(cstr(p)); mkerr_libc(retry(|| unsafe { libc::chown(p.as_ptr(), uid as libc::uid_t, gid as libc::gid_t) })) } pub fn readlink(p: &Path) -> IoResult<Path> { - let c_path = cstr(p); + let c_path = try!(cstr(p)); let p = c_path.as_ptr(); let mut len = unsafe { libc::pathconf(p as *mut _, libc::_PC_NAME_MAX) }; if len == -1 { @@ -276,14 +276,14 @@ pub fn readlink(p: &Path) -> IoResult<Path> { } pub fn symlink(src: &Path, dst: &Path) -> IoResult<()> { - let src = cstr(src); - let dst = cstr(dst); + let src = try!(cstr(src)); + let dst = try!(cstr(dst)); mkerr_libc(unsafe { libc::symlink(src.as_ptr(), dst.as_ptr()) }) } pub fn link(src: &Path, dst: &Path) -> IoResult<()> { - let src = cstr(src); - let dst = cstr(dst); + let src = try!(cstr(src)); + let dst = try!(cstr(dst)); mkerr_libc(unsafe { libc::link(src.as_ptr(), dst.as_ptr()) }) } @@ -331,7 +331,7 @@ fn mkstat(stat: &libc::stat) -> FileStat { } pub fn stat(p: &Path) -> IoResult<FileStat> { - let p = cstr(p); + let p = try!(cstr(p)); let mut stat: libc::stat = unsafe { mem::zeroed() }; match unsafe { libc::stat(p.as_ptr(), &mut stat) } { 0 => Ok(mkstat(&stat)), @@ -340,7 +340,7 @@ pub fn stat(p: &Path) -> IoResult<FileStat> { } pub fn lstat(p: &Path) -> IoResult<FileStat> { - let p = cstr(p); + let p = try!(cstr(p)); let mut stat: libc::stat = unsafe { mem::zeroed() }; match unsafe { libc::lstat(p.as_ptr(), &mut stat) } { 0 => Ok(mkstat(&stat)), @@ -349,7 +349,7 @@ pub fn lstat(p: &Path) -> IoResult<FileStat> { } pub fn utime(p: &Path, atime: u64, mtime: u64) -> IoResult<()> { - let p = cstr(p); + let p = try!(cstr(p)); let buf = libc::utimbuf { actime: (atime / 1000) as libc::time_t, modtime: (mtime / 1000) as libc::time_t, diff --git a/src/libstd/sys/unix/fs2.rs b/src/libstd/sys/unix/fs2.rs index e5904b074bc..92a47c6c385 100644 --- a/src/libstd/sys/unix/fs2.rs +++ b/src/libstd/sys/unix/fs2.rs @@ -12,7 +12,7 @@ use core::prelude::*; use io::prelude::*; use os::unix::prelude::*; -use ffi::{self, CString, OsString, AsOsStr, OsStr}; +use ffi::{CString, CStr, OsString, AsOsStr, OsStr}; use io::{self, Error, Seek, SeekFrom}; use libc::{self, c_int, c_void, size_t, off_t, c_char, mode_t}; use mem; @@ -147,8 +147,7 @@ impl DirEntry { fn rust_list_dir_val(ptr: *mut libc::dirent_t) -> *const c_char; } unsafe { - let ptr = rust_list_dir_val(self.dirent); - ffi::c_str_to_bytes(mem::copy_lifetime(self, &ptr)) + CStr::from_ptr(rust_list_dir_val(self.dirent)).to_bytes() } } } @@ -204,7 +203,7 @@ impl File { (true, false) | (false, false) => libc::O_RDONLY, }; - let path = cstr(path); + let path = try!(cstr(path)); let fd = try!(cvt_r(|| unsafe { libc::open(path.as_ptr(), flags, opts.mode) })); @@ -268,19 +267,20 @@ impl File { pub fn fd(&self) -> &FileDesc { &self.0 } } -fn cstr(path: &Path) -> CString { - CString::from_slice(path.as_os_str().as_bytes()) +fn cstr(path: &Path) -> io::Result<CString> { + let cstring = try!(path.as_os_str().to_cstring()); + Ok(cstring) } pub fn mkdir(p: &Path) -> io::Result<()> { - let p = cstr(p); + let p = try!(cstr(p)); try!(cvt(unsafe { libc::mkdir(p.as_ptr(), 0o777) })); Ok(()) } pub fn readdir(p: &Path) -> io::Result<ReadDir> { let root = Rc::new(p.to_path_buf()); - let p = cstr(p); + let p = try!(cstr(p)); unsafe { let ptr = libc::opendir(p.as_ptr()); if ptr.is_null() { @@ -292,32 +292,32 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> { } pub fn unlink(p: &Path) -> io::Result<()> { - let p = cstr(p); + let p = try!(cstr(p)); try!(cvt(unsafe { libc::unlink(p.as_ptr()) })); Ok(()) } pub fn rename(old: &Path, new: &Path) -> io::Result<()> { - let old = cstr(old); - let new = cstr(new); + let old = try!(cstr(old)); + let new = try!(cstr(new)); try!(cvt(unsafe { libc::rename(old.as_ptr(), new.as_ptr()) })); Ok(()) } pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> { - let p = cstr(p); + let p = try!(cstr(p)); try!(cvt_r(|| unsafe { libc::chmod(p.as_ptr(), perm.mode) })); Ok(()) } pub fn rmdir(p: &Path) -> io::Result<()> { - let p = cstr(p); + let p = try!(cstr(p)); try!(cvt(unsafe { libc::rmdir(p.as_ptr()) })); Ok(()) } pub fn chown(p: &Path, uid: isize, gid: isize) -> io::Result<()> { - let p = cstr(p); + let p = try!(cstr(p)); try!(cvt_r(|| unsafe { libc::chown(p.as_ptr(), uid as libc::uid_t, gid as libc::gid_t) })); @@ -325,7 +325,7 @@ pub fn chown(p: &Path, uid: isize, gid: isize) -> io::Result<()> { } pub fn readlink(p: &Path) -> io::Result<PathBuf> { - let c_path = cstr(p); + let c_path = try!(cstr(p)); let p = c_path.as_ptr(); let mut len = unsafe { libc::pathconf(p as *mut _, libc::_PC_NAME_MAX) }; if len < 0 { @@ -343,35 +343,35 @@ pub fn readlink(p: &Path) -> io::Result<PathBuf> { } pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> { - let src = cstr(src); - let dst = cstr(dst); + let src = try!(cstr(src)); + let dst = try!(cstr(dst)); try!(cvt(unsafe { libc::symlink(src.as_ptr(), dst.as_ptr()) })); Ok(()) } pub fn link(src: &Path, dst: &Path) -> io::Result<()> { - let src = cstr(src); - let dst = cstr(dst); + let src = try!(cstr(src)); + let dst = try!(cstr(dst)); try!(cvt(unsafe { libc::link(src.as_ptr(), dst.as_ptr()) })); Ok(()) } pub fn stat(p: &Path) -> io::Result<FileAttr> { - let p = cstr(p); + let p = try!(cstr(p)); let mut stat: libc::stat = unsafe { mem::zeroed() }; try!(cvt(unsafe { libc::stat(p.as_ptr(), &mut stat) })); Ok(FileAttr { stat: stat }) } pub fn lstat(p: &Path) -> io::Result<FileAttr> { - let p = cstr(p); + let p = try!(cstr(p)); let mut stat: libc::stat = unsafe { mem::zeroed() }; try!(cvt(unsafe { libc::lstat(p.as_ptr(), &mut stat) })); Ok(FileAttr { stat: stat }) } pub fn utimes(p: &Path, atime: u64, mtime: u64) -> io::Result<()> { - let p = cstr(p); + let p = try!(cstr(p)); let buf = [super::ms_to_timeval(atime), super::ms_to_timeval(mtime)]; try!(cvt(unsafe { c::utimes(p.as_ptr(), buf.as_ptr()) })); Ok(()) diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index 850189140d1..b79ad7031fa 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -17,7 +17,7 @@ use prelude::v1::*; -use ffi; +use ffi::CStr; use io::{self, ErrorKind}; use libc; use num::{Int, SignedInt}; @@ -91,7 +91,8 @@ pub fn last_gai_error(s: libc::c_int) -> IoError { let mut err = decode_error(s); err.detail = Some(unsafe { - str::from_utf8(ffi::c_str_to_bytes(&gai_strerror(s))).unwrap().to_string() + let data = CStr::from_ptr(gai_strerror(s)); + str::from_utf8(data.to_bytes()).unwrap().to_string() }); err } diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs index 54aec7cf4b1..83b6a14b78d 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -10,7 +10,7 @@ use prelude::v1::*; -use ffi; +use ffi::CStr; use io; use libc::{self, c_int, size_t}; use str; @@ -31,7 +31,7 @@ pub fn cvt_gai(err: c_int) -> io::Result<()> { if err == 0 { return Ok(()) } let detail = unsafe { - str::from_utf8(ffi::c_str_to_bytes(&c::gai_strerror(err))).unwrap() + str::from_utf8(CStr::from_ptr(c::gai_strerror(err)).to_bytes()).unwrap() .to_string() }; Err(io::Error::new(io::ErrorKind::Other, diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index 5fe84cafb71..3d1ef3a2c37 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -14,7 +14,7 @@ use prelude::v1::*; use os::unix::*; use error::Error as StdError; -use ffi::{self, CString, OsString, OsStr, AsOsStr}; +use ffi::{CString, CStr, OsString, OsStr, AsOsStr}; use fmt; use iter; use libc::{self, c_int, c_char, c_void}; @@ -88,7 +88,7 @@ pub fn error_string(errno: i32) -> String { } let p = p as *const _; - str::from_utf8(ffi::c_str_to_bytes(&p)).unwrap().to_string() + str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap().to_string() } } @@ -98,13 +98,13 @@ pub fn getcwd() -> IoResult<Path> { if libc::getcwd(buf.as_mut_ptr(), buf.len() as libc::size_t).is_null() { Err(IoError::last_error()) } else { - Ok(Path::new(ffi::c_str_to_bytes(&buf.as_ptr()))) + Ok(Path::new(CStr::from_ptr(buf.as_ptr()).to_bytes())) } } } pub fn chdir(p: &Path) -> IoResult<()> { - let p = CString::from_slice(p.as_vec()); + let p = CString::new(p.as_vec()).unwrap(); unsafe { match libc::chdir(p.as_ptr()) == (0 as c_int) { true => Ok(()), @@ -211,7 +211,7 @@ pub fn current_exe() -> IoResult<Path> { if v.is_null() { Err(IoError::last_error()) } else { - Ok(Path::new(ffi::c_str_to_bytes(&v).to_vec())) + Ok(Path::new(CStr::from_ptr(&v).to_bytes().to_vec())) } } } @@ -266,7 +266,7 @@ pub fn args() -> Args { let (argc, argv) = (*_NSGetArgc() as isize, *_NSGetArgv() as *const *const c_char); range(0, argc as isize).map(|i| { - let bytes = ffi::c_str_to_bytes(&*argv.offset(i)).to_vec(); + let bytes = CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec(); OsStringExt::from_vec(bytes) }).collect::<Vec<_>>() }; @@ -324,7 +324,7 @@ pub fn args() -> Args { let tmp = objc_msgSend(args, object_at_sel, i); let utf_c_str: *const libc::c_char = mem::transmute(objc_msgSend(tmp, utf8_sel)); - let bytes = ffi::c_str_to_bytes(&utf_c_str); + let bytes = CStr::from_ptr(utf_c_str).to_bytes(); res.push(OsString::from_str(str::from_utf8(bytes).unwrap())) } } @@ -380,7 +380,7 @@ pub fn env() -> Env { } let mut result = Vec::new(); while *environ != ptr::null() { - result.push(parse(ffi::c_str_to_bytes(&*environ))); + result.push(parse(CStr::from_ptr(*environ).to_bytes())); environ = environ.offset(1); } Env { iter: result.into_iter(), _dont_send_or_sync_me: 0 as *mut _ } @@ -397,20 +397,20 @@ pub fn env() -> Env { pub fn getenv(k: &OsStr) -> Option<OsString> { unsafe { - let s = CString::from_slice(k.as_bytes()); + let s = k.to_cstring().unwrap(); let s = libc::getenv(s.as_ptr()) as *const _; if s.is_null() { None } else { - Some(OsStringExt::from_vec(ffi::c_str_to_bytes(&s).to_vec())) + Some(OsStringExt::from_vec(CStr::from_ptr(s).to_bytes().to_vec())) } } } pub fn setenv(k: &OsStr, v: &OsStr) { unsafe { - let k = CString::from_slice(k.as_bytes()); - let v = CString::from_slice(v.as_bytes()); + let k = k.to_cstring().unwrap(); + let v = v.to_cstring().unwrap(); if libc::funcs::posix01::unistd::setenv(k.as_ptr(), v.as_ptr(), 1) != 0 { panic!("failed setenv: {}", IoError::last_error()); } @@ -419,7 +419,7 @@ pub fn setenv(k: &OsStr, v: &OsStr) { pub fn unsetenv(n: &OsStr) { unsafe { - let nbuf = CString::from_slice(n.as_bytes()); + let nbuf = n.to_cstring().unwrap(); if libc::funcs::posix01::unistd::unsetenv(nbuf.as_ptr()) != 0 { panic!("failed unsetenv: {}", IoError::last_error()); } @@ -480,7 +480,7 @@ pub fn home_dir() -> Option<Path> { _ => return None } let ptr = passwd.pw_dir as *const _; - let bytes = ffi::c_str_to_bytes(&ptr).to_vec(); + let bytes = CStr::from_ptr(ptr).to_bytes().to_vec(); return Some(OsStringExt::from_vec(bytes)) } } diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs index 45d5b1506c3..3c9cdc65975 100644 --- a/src/libstd/sys/unix/pipe.rs +++ b/src/libstd/sys/unix/pipe.rs @@ -38,7 +38,7 @@ fn addr_to_sockaddr_un(addr: &CString, mem::size_of::<libc::sockaddr_un>()); let s = unsafe { &mut *(storage as *mut _ as *mut libc::sockaddr_un) }; - let len = addr.len(); + let len = addr.as_bytes().len(); if len > s.sun_path.len() - 1 { return Err(IoError { kind: old_io::InvalidInput, @@ -47,8 +47,8 @@ fn addr_to_sockaddr_un(addr: &CString, }) } s.sun_family = libc::AF_UNIX as libc::sa_family_t; - for (slot, value) in s.sun_path.iter_mut().zip(addr.iter()) { - *slot = *value; + for (slot, value) in s.sun_path.iter_mut().zip(addr.as_bytes().iter()) { + *slot = *value as libc::c_char; } // count the null terminator diff --git a/src/libstd/sys/unix/process.rs b/src/libstd/sys/unix/process.rs index f954024b0e9..b30ac889120 100644 --- a/src/libstd/sys/unix/process.rs +++ b/src/libstd/sys/unix/process.rs @@ -12,6 +12,7 @@ use prelude::v1::*; use self::Req::*; use collections::HashMap; +#[cfg(stage0)] use collections::hash_map::Hasher; use ffi::CString; use hash::Hash; @@ -63,6 +64,7 @@ impl Process { mkerr_libc(r) } + #[cfg(stage0)] pub fn spawn<K, V, C, P>(cfg: &C, in_fd: Option<P>, out_fd: Option<P>, err_fd: Option<P>) -> IoResult<Process> @@ -278,6 +280,214 @@ impl Process { }) }) } + #[cfg(not(stage0))] + pub fn spawn<K, V, C, P>(cfg: &C, in_fd: Option<P>, + out_fd: Option<P>, err_fd: Option<P>) + -> IoResult<Process> + where C: ProcessConfig<K, V>, P: AsInner<FileDesc>, + K: BytesContainer + Eq + Hash, V: BytesContainer + { + use libc::funcs::posix88::unistd::{fork, dup2, close, chdir, execvp}; + use libc::funcs::bsd44::getdtablesize; + + mod rustrt { + extern { + pub fn rust_unset_sigprocmask(); + } + } + + unsafe fn set_cloexec(fd: c_int) { + let ret = c::ioctl(fd, c::FIOCLEX); + assert_eq!(ret, 0); + } + + let dirp = cfg.cwd().map(|c| c.as_ptr()).unwrap_or(ptr::null()); + + // temporary until unboxed closures land + let cfg = unsafe { + mem::transmute::<&ProcessConfig<K,V>,&'static ProcessConfig<K,V>>(cfg) + }; + + with_envp(cfg.env(), move|envp: *const c_void| { + with_argv(cfg.program(), cfg.args(), move|argv: *const *const libc::c_char| unsafe { + let (input, mut output) = try!(sys::os::pipe()); + + // We may use this in the child, so perform allocations before the + // fork + let devnull = b"/dev/null\0"; + + set_cloexec(output.fd()); + + let pid = fork(); + if pid < 0 { + return Err(super::last_error()) + } else if pid > 0 { + #[inline] + fn combine(arr: &[u8]) -> i32 { + let a = arr[0] as u32; + let b = arr[1] as u32; + let c = arr[2] as u32; + let d = arr[3] as u32; + + ((a << 24) | (b << 16) | (c << 8) | (d << 0)) as i32 + } + + let p = Process{ pid: pid }; + drop(output); + let mut bytes = [0; 8]; + return match input.read(&mut bytes) { + Ok(8) => { + assert!(combine(CLOEXEC_MSG_FOOTER) == combine(&bytes[4.. 8]), + "Validation on the CLOEXEC pipe failed: {:?}", bytes); + let errno = combine(&bytes[0.. 4]); + assert!(p.wait(0).is_ok(), "wait(0) should either return Ok or panic"); + Err(super::decode_error(errno)) + } + Err(ref e) if e.kind == EndOfFile => Ok(p), + Err(e) => { + assert!(p.wait(0).is_ok(), "wait(0) should either return Ok or panic"); + panic!("the CLOEXEC pipe failed: {:?}", e) + }, + Ok(..) => { // pipe I/O up to PIPE_BUF bytes should be atomic + assert!(p.wait(0).is_ok(), "wait(0) should either return Ok or panic"); + panic!("short read on the CLOEXEC pipe") + } + }; + } + + // And at this point we've reached a special time in the life of the + // child. The child must now be considered hamstrung and unable to + // do anything other than syscalls really. Consider the following + // scenario: + // + // 1. Thread A of process 1 grabs the malloc() mutex + // 2. Thread B of process 1 forks(), creating thread C + // 3. Thread C of process 2 then attempts to malloc() + // 4. The memory of process 2 is the same as the memory of + // process 1, so the mutex is locked. + // + // This situation looks a lot like deadlock, right? It turns out + // that this is what pthread_atfork() takes care of, which is + // presumably implemented across platforms. The first thing that + // threads to *before* forking is to do things like grab the malloc + // mutex, and then after the fork they unlock it. + // + // Despite this information, libnative's spawn has been witnessed to + // deadlock on both OSX and FreeBSD. I'm not entirely sure why, but + // all collected backtraces point at malloc/free traffic in the + // child spawned process. + // + // For this reason, the block of code below should contain 0 + // invocations of either malloc of free (or their related friends). + // + // As an example of not having malloc/free traffic, we don't close + // this file descriptor by dropping the FileDesc (which contains an + // allocation). Instead we just close it manually. This will never + // have the drop glue anyway because this code never returns (the + // child will either exec() or invoke libc::exit) + let _ = libc::close(input.fd()); + + fn fail(output: &mut FileDesc) -> ! { + let errno = sys::os::errno() as u32; + let bytes = [ + (errno >> 24) as u8, + (errno >> 16) as u8, + (errno >> 8) as u8, + (errno >> 0) as u8, + CLOEXEC_MSG_FOOTER[0], CLOEXEC_MSG_FOOTER[1], + CLOEXEC_MSG_FOOTER[2], CLOEXEC_MSG_FOOTER[3] + ]; + // pipe I/O up to PIPE_BUF bytes should be atomic + assert!(output.write(&bytes).is_ok()); + unsafe { libc::_exit(1) } + } + + rustrt::rust_unset_sigprocmask(); + + // If a stdio file descriptor is set to be ignored (via a -1 file + // descriptor), then we don't actually close it, but rather open + // up /dev/null into that file descriptor. Otherwise, the first file + // descriptor opened up in the child would be numbered as one of the + // stdio file descriptors, which is likely to wreak havoc. + let setup = |src: Option<P>, dst: c_int| { + let src = match src { + None => { + let flags = if dst == libc::STDIN_FILENO { + libc::O_RDONLY + } else { + libc::O_RDWR + }; + libc::open(devnull.as_ptr() as *const _, flags, 0) + } + Some(obj) => { + let fd = obj.as_inner().fd(); + // Leak the memory and the file descriptor. We're in the + // child now an all our resources are going to be + // cleaned up very soon + mem::forget(obj); + fd + } + }; + src != -1 && retry(|| dup2(src, dst)) != -1 + }; + + if !setup(in_fd, libc::STDIN_FILENO) { fail(&mut output) } + if !setup(out_fd, libc::STDOUT_FILENO) { fail(&mut output) } + if !setup(err_fd, libc::STDERR_FILENO) { fail(&mut output) } + + // close all other fds + for fd in (3..getdtablesize()).rev() { + if fd != output.fd() { + let _ = close(fd as c_int); + } + } + + match cfg.gid() { + Some(u) => { + if libc::setgid(u as libc::gid_t) != 0 { + fail(&mut output); + } + } + None => {} + } + match cfg.uid() { + Some(u) => { + // When dropping privileges from root, the `setgroups` call + // will remove any extraneous groups. If we don't call this, + // then even though our uid has dropped, we may still have + // groups that enable us to do super-user things. This will + // fail if we aren't root, so don't bother checking the + // return value, this is just done as an optimistic + // privilege dropping function. + extern { + fn setgroups(ngroups: libc::c_int, + ptr: *const libc::c_void) -> libc::c_int; + } + let _ = setgroups(0, ptr::null()); + + if libc::setuid(u as libc::uid_t) != 0 { + fail(&mut output); + } + } + None => {} + } + if cfg.detach() { + // Don't check the error of setsid because it fails if we're the + // process leader already. We just forked so it shouldn't return + // error, but ignore it anyway. + let _ = libc::setsid(); + } + if !dirp.is_null() && chdir(dirp) == -1 { + fail(&mut output); + } + if !envp.is_null() { + *sys::os::environ() = envp as *const _; + } + let _ = execvp(*argv, argv as *mut _); + fail(&mut output); + }) + }) + } pub fn wait(&self, deadline: u64) -> IoResult<ProcessExit> { use cmp; @@ -556,6 +766,7 @@ fn with_argv<T,F>(prog: &CString, args: &[CString], cb(ptrs.as_ptr()) } +#[cfg(stage0)] fn with_envp<K,V,T,F>(env: Option<&HashMap<K, V>>, cb: F) -> T @@ -593,6 +804,44 @@ fn with_envp<K,V,T,F>(env: Option<&HashMap<K, V>>, _ => cb(ptr::null()) } } +#[cfg(not(stage0))] +fn with_envp<K,V,T,F>(env: Option<&HashMap<K, V>>, + cb: F) + -> T + where F : FnOnce(*const c_void) -> T, + K : BytesContainer + Eq + Hash, + V : BytesContainer +{ + // On posixy systems we can pass a char** for envp, which is a + // null-terminated array of "k=v\0" strings. Since we must create + // these strings locally, yet expose a raw pointer to them, we + // create a temporary vector to own the CStrings that outlives the + // call to cb. + match env { + Some(env) => { + let mut tmps = Vec::with_capacity(env.len()); + + for pair in env { + let mut kv = Vec::new(); + kv.push_all(pair.0.container_as_bytes()); + kv.push('=' as u8); + kv.push_all(pair.1.container_as_bytes()); + kv.push(0); // terminating null + tmps.push(kv); + } + + // As with `with_argv`, this is unsafe, since cb could leak the pointers. + let mut ptrs: Vec<*const libc::c_char> = + tmps.iter() + .map(|tmp| tmp.as_ptr() as *const libc::c_char) + .collect(); + ptrs.push(ptr::null()); + + cb(ptrs.as_ptr() as *const c_void) + } + _ => cb(ptr::null()) + } +} fn translate_status(status: c_int) -> ProcessExit { #![allow(non_snake_case)] diff --git a/src/libstd/sys/unix/process2.rs b/src/libstd/sys/unix/process2.rs index 5e2c207f375..06fa5c4bba7 100644 --- a/src/libstd/sys/unix/process2.rs +++ b/src/libstd/sys/unix/process2.rs @@ -11,7 +11,6 @@ use prelude::v1::*; use collections::HashMap; -use collections::hash_map::Hasher; use env; use ffi::{OsString, OsStr, CString}; use fmt; @@ -46,7 +45,7 @@ pub struct Command { impl Command { pub fn new(program: &OsStr) -> Command { Command { - program: program.to_cstring(), + program: program.to_cstring().unwrap(), args: Vec::new(), env: None, cwd: None, @@ -57,10 +56,10 @@ impl Command { } pub fn arg(&mut self, arg: &OsStr) { - self.args.push(arg.to_cstring()) + self.args.push(arg.to_cstring().unwrap()) } pub fn args<'a, I: Iterator<Item = &'a OsStr>>(&mut self, args: I) { - self.args.extend(args.map(OsStrExt::to_cstring)) + self.args.extend(args.map(|s| OsStrExt::to_cstring(s).unwrap())) } fn init_env_map(&mut self) { if self.env.is_none() { @@ -79,7 +78,7 @@ impl Command { self.env = Some(HashMap::new()) } pub fn cwd(&mut self, dir: &OsStr) { - self.cwd = Some(dir.to_cstring()) + self.cwd = Some(dir.to_cstring().unwrap()) } } diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index 82c52471d10..c90ba7645fe 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -237,7 +237,7 @@ pub unsafe fn create(stack: uint, p: Thunk) -> io::Result<rust_thread> { pub unsafe fn set_name(name: &str) { // pthread_setname_np() since glibc 2.12 // availability autodetected via weak linkage - let cname = CString::from_slice(name.as_bytes()); + let cname = CString::new(name).unwrap(); type F = unsafe extern "C" fn(libc::pthread_t, *const libc::c_char) -> libc::c_int; extern { #[linkage = "extern_weak"] @@ -255,14 +255,14 @@ pub unsafe fn set_name(name: &str) { target_os = "openbsd"))] pub unsafe fn set_name(name: &str) { // pthread_set_name_np() since almost forever on all BSDs - let cname = CString::from_slice(name.as_bytes()); + let cname = CString::new(name).unwrap(); pthread_set_name_np(pthread_self(), cname.as_ptr()); } #[cfg(any(target_os = "macos", target_os = "ios"))] pub unsafe fn set_name(name: &str) { // pthread_setname_np() since OS X 10.6 and iOS 3.2 - let cname = CString::from_slice(name.as_bytes()); + let cname = CString::new(name).unwrap(); pthread_setname_np(cname.as_ptr()); } diff --git a/src/libstd/sys/windows/backtrace.rs b/src/libstd/sys/windows/backtrace.rs index 92e309da34b..51cf3032423 100644 --- a/src/libstd/sys/windows/backtrace.rs +++ b/src/libstd/sys/windows/backtrace.rs @@ -25,7 +25,7 @@ #![allow(dead_code)] use dynamic_lib::DynamicLibrary; -use ffi; +use ffi::CStr; use intrinsics; use old_io::{IoResult, Writer}; use libc; @@ -362,7 +362,7 @@ pub fn write(w: &mut Writer) -> IoResult<()> { if ret == libc::TRUE { try!(write!(w, " - ")); let ptr = info.Name.as_ptr() as *const libc::c_char; - let bytes = unsafe { ffi::c_str_to_bytes(&ptr) }; + let bytes = unsafe { CStr::from_ptr(ptr).to_bytes() }; match str::from_utf8(bytes) { Ok(s) => try!(demangle(w, s)), Err(..) => try!(w.write_all(&bytes[..bytes.len()-1])), diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index f861255a00a..2d1a5e10bd6 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -283,7 +283,7 @@ pub mod compat { fallback: usize) -> usize { let mut module: Vec<u16> = module.utf16_units().collect(); module.push(0); - let symbol = CString::from_slice(symbol.as_bytes()); + let symbol = CString::new(symbol).unwrap(); let func = unsafe { let handle = GetModuleHandleW(module.as_ptr()); GetProcAddress(handle, symbol.as_ptr()) as usize diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index 4d6d033deee..a756fb29f81 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -265,12 +265,12 @@ fn fill_utf16_buf_base<F1, F2, T>(mut f1: F1, f2: F2) -> Result<T, ()> let mut n = stack_buf.len(); loop { let buf = if n <= stack_buf.len() { - &mut stack_buf[] + &mut stack_buf[..] } else { let extra = n - heap_buf.len(); heap_buf.reserve(extra); heap_buf.set_len(n); - &mut heap_buf[] + &mut heap_buf[..] }; // This function is typically called on windows API functions which diff --git a/src/libstd/sys/windows/os.rs b/src/libstd/sys/windows/os.rs index 502d70d4e1a..6520d30487c 100644 --- a/src/libstd/sys/windows/os.rs +++ b/src/libstd/sys/windows/os.rs @@ -114,7 +114,7 @@ impl Iterator for Env { let (k, v) = match s.iter().position(|&b| b == '=' as u16) { Some(n) => (&s[..n], &s[n+1..]), - None => (s, &[][]), + None => (s, &[][..]), }; Some((OsStringExt::from_wide(k), OsStringExt::from_wide(v))) } @@ -186,7 +186,7 @@ impl<'a> Iterator for SplitPaths<'a> { if !must_yield && in_progress.is_empty() { None } else { - Some(super::os2path(&in_progress[])) + Some(super::os2path(&in_progress[..])) } } } @@ -208,14 +208,14 @@ pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError> return Err(JoinPathsError) } else if v.contains(&sep) { joined.push(b'"' as u16); - joined.push_all(&v[]); + joined.push_all(&v[..]); joined.push(b'"' as u16); } else { - joined.push_all(&v[]); + joined.push_all(&v[..]); } } - Ok(OsStringExt::from_wide(&joined[])) + Ok(OsStringExt::from_wide(&joined[..])) } impl fmt::Display for JoinPathsError { diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index 96ffc4daddd..60d24e6174f 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -10,7 +10,7 @@ use prelude::v1::*; -use collections::hash_map::Hasher; +#[cfg(stage0)] use collections::hash_map::Hasher; use collections; use env; use ffi::CString; @@ -106,6 +106,7 @@ impl Process { } #[allow(deprecated)] + #[cfg(stage0)] pub fn spawn<K, V, C, P>(cfg: &C, in_fd: Option<P>, out_fd: Option<P>, err_fd: Option<P>) -> IoResult<Process> @@ -267,6 +268,169 @@ impl Process { }) } } + #[allow(deprecated)] + #[cfg(not(stage0))] + pub fn spawn<K, V, C, P>(cfg: &C, in_fd: Option<P>, + out_fd: Option<P>, err_fd: Option<P>) + -> IoResult<Process> + where C: ProcessConfig<K, V>, P: AsInner<FileDesc>, + K: BytesContainer + Eq + Hash, V: BytesContainer + { + use libc::types::os::arch::extra::{DWORD, HANDLE, STARTUPINFO}; + use libc::consts::os::extra::{ + TRUE, FALSE, + STARTF_USESTDHANDLES, + INVALID_HANDLE_VALUE, + DUPLICATE_SAME_ACCESS + }; + use libc::funcs::extra::kernel32::{ + GetCurrentProcess, + DuplicateHandle, + CloseHandle, + CreateProcessW + }; + use libc::funcs::extra::msvcrt::get_osfhandle; + + use mem; + use iter::IteratorExt; + use str::StrExt; + + if cfg.gid().is_some() || cfg.uid().is_some() { + return Err(IoError { + kind: old_io::IoUnavailable, + desc: "unsupported gid/uid requested on windows", + detail: None, + }) + } + + // To have the spawning semantics of unix/windows stay the same, we need to + // read the *child's* PATH if one is provided. See #15149 for more details. + let program = cfg.env().and_then(|env| { + for (key, v) in env { + if b"PATH" != key.container_as_bytes() { continue } + + // Split the value and test each path to see if the + // program exists. + for path in os::split_paths(v.container_as_bytes()) { + let path = path.join(cfg.program().as_bytes()) + .with_extension(env::consts::EXE_EXTENSION); + if path.exists() { + return Some(CString::from_slice(path.as_vec())) + } + } + break + } + None + }); + + unsafe { + let mut si = zeroed_startupinfo(); + si.cb = mem::size_of::<STARTUPINFO>() as DWORD; + si.dwFlags = STARTF_USESTDHANDLES; + + let cur_proc = GetCurrentProcess(); + + // Similarly to unix, we don't actually leave holes for the stdio file + // descriptors, but rather open up /dev/null equivalents. These + // equivalents are drawn from libuv's windows process spawning. + let set_fd = |fd: &Option<P>, slot: &mut HANDLE, + is_stdin: bool| { + match *fd { + None => { + let access = if is_stdin { + libc::FILE_GENERIC_READ + } else { + libc::FILE_GENERIC_WRITE | libc::FILE_READ_ATTRIBUTES + }; + let size = mem::size_of::<libc::SECURITY_ATTRIBUTES>(); + let mut sa = libc::SECURITY_ATTRIBUTES { + nLength: size as libc::DWORD, + lpSecurityDescriptor: ptr::null_mut(), + bInheritHandle: 1, + }; + let mut filename: Vec<u16> = "NUL".utf16_units().collect(); + filename.push(0); + *slot = libc::CreateFileW(filename.as_ptr(), + access, + libc::FILE_SHARE_READ | + libc::FILE_SHARE_WRITE, + &mut sa, + libc::OPEN_EXISTING, + 0, + ptr::null_mut()); + if *slot == INVALID_HANDLE_VALUE { + return Err(super::last_error()) + } + } + Some(ref fd) => { + let orig = get_osfhandle(fd.as_inner().fd()) as HANDLE; + if orig == INVALID_HANDLE_VALUE { + return Err(super::last_error()) + } + if DuplicateHandle(cur_proc, orig, cur_proc, slot, + 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE { + return Err(super::last_error()) + } + } + } + Ok(()) + }; + + try!(set_fd(&in_fd, &mut si.hStdInput, true)); + try!(set_fd(&out_fd, &mut si.hStdOutput, false)); + try!(set_fd(&err_fd, &mut si.hStdError, false)); + + let cmd_str = make_command_line(program.as_ref().unwrap_or(cfg.program()), + cfg.args()); + let mut pi = zeroed_process_information(); + let mut create_err = None; + + // stolen from the libuv code. + let mut flags = libc::CREATE_UNICODE_ENVIRONMENT; + if cfg.detach() { + flags |= libc::DETACHED_PROCESS | libc::CREATE_NEW_PROCESS_GROUP; + } + + with_envp(cfg.env(), |envp| { + with_dirp(cfg.cwd(), |dirp| { + let mut cmd_str: Vec<u16> = cmd_str.utf16_units().collect(); + cmd_str.push(0); + let _lock = CREATE_PROCESS_LOCK.lock().unwrap(); + let created = CreateProcessW(ptr::null(), + cmd_str.as_mut_ptr(), + ptr::null_mut(), + ptr::null_mut(), + TRUE, + flags, envp, dirp, + &mut si, &mut pi); + if created == FALSE { + create_err = Some(super::last_error()); + } + }) + }); + + assert!(CloseHandle(si.hStdInput) != 0); + assert!(CloseHandle(si.hStdOutput) != 0); + assert!(CloseHandle(si.hStdError) != 0); + + match create_err { + Some(err) => return Err(err), + None => {} + } + + // We close the thread handle because we don't care about keeping the + // thread id valid, and we aren't keeping the thread handle around to be + // able to close it later. We don't close the process handle however + // because std::we want the process id to stay valid at least until the + // calling code closes the process handle. + assert!(CloseHandle(pi.hThread) != 0); + + Ok(Process { + pid: pi.dwProcessId as pid_t, + handle: pi.hProcess as *mut () + }) + } + } /// Waits for a process to exit and returns the exit code, failing /// if there is no process with the specified id. @@ -425,6 +589,7 @@ fn make_command_line(prog: &CString, args: &[CString]) -> String { } } +#[cfg(stage0)] fn with_envp<K, V, T, F>(env: Option<&collections::HashMap<K, V>>, cb: F) -> T where K: BytesContainer + Eq + Hash<Hasher>, V: BytesContainer, @@ -452,6 +617,34 @@ fn with_envp<K, V, T, F>(env: Option<&collections::HashMap<K, V>>, cb: F) -> T _ => cb(ptr::null_mut()) } } +#[cfg(not(stage0))] +fn with_envp<K, V, T, F>(env: Option<&collections::HashMap<K, V>>, cb: F) -> T + where K: BytesContainer + Eq + Hash, + V: BytesContainer, + F: FnOnce(*mut c_void) -> T, +{ + // On Windows we pass an "environment block" which is not a char**, but + // rather a concatenation of null-terminated k=v\0 sequences, with a final + // \0 to terminate. + match env { + Some(env) => { + let mut blk = Vec::new(); + + for pair in env { + let kv = format!("{}={}", + pair.0.container_as_str().unwrap(), + pair.1.container_as_str().unwrap()); + blk.extend(kv.utf16_units()); + blk.push(0); + } + + blk.push(0); + + cb(blk.as_mut_ptr() as *mut c_void) + } + _ => cb(ptr::null_mut()) + } +} fn with_dirp<T, F>(d: Option<&CString>, cb: F) -> T where F: FnOnce(*const u16) -> T, diff --git a/src/libstd/thread.rs b/src/libstd/thread.rs index 3137d779c40..3653e7e31d5 100644 --- a/src/libstd/thread.rs +++ b/src/libstd/thread.rs @@ -153,7 +153,7 @@ use any::Any; use cell::UnsafeCell; use fmt; use io; -use marker; +use marker::PhantomData; use old_io::stdio; use rt::{self, unwind}; use sync::{Mutex, Condvar, Arc}; @@ -260,7 +260,7 @@ impl Builder { T: Send + 'a, F: FnOnce() -> T, F: Send + 'a { self.spawn_inner(Thunk::new(f)).map(|inner| { - JoinGuard { inner: inner, _marker: marker::CovariantType } + JoinGuard { inner: inner, _marker: PhantomData } }) } @@ -642,7 +642,7 @@ impl Drop for JoinHandle { #[stable(feature = "rust1", since = "1.0.0")] pub struct JoinGuard<'a, T: 'a> { inner: JoinInner<T>, - _marker: marker::CovariantType<&'a T>, + _marker: PhantomData<&'a T>, } #[stable(feature = "rust1", since = "1.0.0")] |
