├── .gitignore ├── .travis.yml ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── deploy-docs.sh └── src ├── bench.rs ├── immut_slist.rs ├── iter ├── mod.rs └── string_joiner.rs ├── lib.rs └── proto ├── linear_map.rs ├── mod.rs └── par_vec.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /Cargo.lock 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | 2 | language: rust 3 | sudo: false 4 | 5 | env: 6 | global: 7 | - secure: "PdLSLIwcxQynRSxfkZrhYPQu8goMpbO3BUoIvUohRzF2xYFB6sS/4+uxyzCuy85TV+2Q6TYdh/G3GDcRVU24G4mMIV2AH3PwiRmC/bzclqbj6CWtBlgHkKP4WYsIaqxuLl4X/7W8EbNjAqW3bD/WuzESGbY26v3pu+MLoQvxduA=" 8 | script: 9 | - cargo build 10 | - cargo test 11 | - cargo test --no-default-features --features "immut_slist" 12 | - cargo test --no-default-features --features "proto" 13 | - cargo test --no-default-features --features "string_joiner" 14 | - cargo doc 15 | 16 | after_success: 17 | - test "$TRAVIS_PULL_REQUEST" == false && test "$TRAVIS_BRANCH" == "master" && bash deploy-docs.sh 18 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | 3 | name = "collect" 4 | version = "0.0.26" 5 | license = "MIT/Apache-2.0" 6 | description = "An experimental extension of std::collections" 7 | authors = ["Alexis Beingessner ", 8 | "Sebastian Gesemann ", 9 | "Jonathan Reem "] 10 | 11 | repository = "https://github.com/Gankro/collect-rs" 12 | homepage = "https://github.com/Gankro/collect-rs" 13 | documentation = "http://Gankro.github.io/collect-rs/collect" 14 | keywords = ["data-structures"] 15 | readme = "README.md" 16 | 17 | [features] 18 | default = ["immut_slist", 19 | "proto", "string_joiner", "ordered_iter"] 20 | immut_slist = [] 21 | proto = [] 22 | string_joiner = [] 23 | 24 | [dependencies.compare] 25 | optional = true 26 | 27 | [dependencies.ordered_iter] 28 | optional = true 29 | 30 | [dev-dependencies] 31 | rand = "*" 32 | threadpool = "*" 33 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 The Rust Project Developers 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Collect-rs has been deprecated in favour of seperate crates hosted at contain-rs 3 | 4 | https://github.com/contain-rs/ 5 | 6 | 7 | 8 | # Old Readme 9 | 10 | collect-rs is intended as an experimental extension of the Rust standard library's 11 | libcollections. Ideas that are too niche, crazy, or experimental to land in libcollections 12 | can be gathered here where they can gain the maintenance and network-effect benefits that 13 | libcollections enjoys, but without worrying about such ivory tower concepts as 14 | "general usefulness" and "consistency". 15 | 16 | For the time being, we plan to be highly volatile with a low barrier of entry. We want to 17 | explore the space of data structuring in Rust. We want to prove out ideas and implementations 18 | that could one day make their way into the standard library. 19 | 20 | Got a concurrent, immutable, or persistent collection? Awesome! Crazy ideas for collection or 21 | iterator adapters? Heck yeah! 22 | 23 | Come on in! 24 | 25 | [Documentation](http://Gankro.github.io/collect-rs/collect) 26 | 27 | ----------- 28 | 29 | Note that anything included in collect-rs is theoretically a candidate for inclusion in 30 | libcollections. As such, this project is licensed under the same terms as Rust itself. 31 | -------------------------------------------------------------------------------- /deploy-docs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | rev=$(git rev-parse --short HEAD) 6 | 7 | cd target/doc 8 | 9 | git init 10 | git config --global user.name "doc bot" 11 | git config --global user.email "docbot@travis" 12 | git remote add upstream "https://$GH_TOKEN@github.com/Gankro/collect-rs.git" 13 | git fetch upstream 14 | git reset upstream/gh-pages 15 | 16 | touch . 17 | 18 | git add -A . 19 | git commit -m "rebuild pages at ${rev}" 20 | git push upstream HEAD:gh-pages 21 | -------------------------------------------------------------------------------- /src/bench.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | macro_rules! map_insert_rand_bench { 12 | ($name: ident, $n: expr, $map: ident) => ( 13 | #[bench] 14 | pub fn $name(b: &mut ::test::Bencher) { 15 | use rand::{self, Rng}; 16 | use test::black_box; 17 | 18 | let n: usize = $n; 19 | let mut map = $map::new(); 20 | // setup 21 | let mut rng = rand::weak_rng(); 22 | 23 | for _ in 0..n { 24 | let i = rng.gen() % n; 25 | map.insert(i, i); 26 | } 27 | 28 | // measure 29 | b.iter(|| { 30 | let k = rng.gen() % n; 31 | map.insert(k, k); 32 | map.remove(&k); 33 | }); 34 | black_box(map); 35 | } 36 | ) 37 | } 38 | 39 | macro_rules! map_insert_seq_bench { 40 | ($name: ident, $n: expr, $map: ident) => ( 41 | #[bench] 42 | pub fn $name(b: &mut ::test::Bencher) { 43 | use test::black_box; 44 | 45 | let mut map = $map::new(); 46 | let n: usize = $n; 47 | // setup 48 | for i in 0..n { 49 | map.insert(i * 2, i * 2); 50 | } 51 | 52 | // measure 53 | let mut i = 1; 54 | b.iter(|| { 55 | map.insert(i, i); 56 | map.remove(&i); 57 | i = (i + 2) % n; 58 | }); 59 | black_box(map); 60 | } 61 | ) 62 | } 63 | 64 | macro_rules! map_find_rand_bench { 65 | ($name: ident, $n: expr, $map: ident) => ( 66 | #[bench] 67 | pub fn $name(b: &mut ::test::Bencher) { 68 | use rand::{self, Rng}; 69 | use test::black_box; 70 | 71 | let mut map = $map::new(); 72 | let n: usize = $n; 73 | 74 | // setup 75 | let mut rng = rand::weak_rng(); 76 | let mut keys: Vec<_> = (0..n).map(|_| rng.gen() % n).collect(); 77 | 78 | for &k in &keys { 79 | map.insert(k, k); 80 | } 81 | 82 | rng.shuffle(&mut keys); 83 | 84 | // measure 85 | let mut i = 0; 86 | b.iter(|| { 87 | let t = map.get(&keys[i]); 88 | i = (i + 1) % n; 89 | black_box(t); 90 | }) 91 | } 92 | ) 93 | } 94 | 95 | macro_rules! map_find_seq_bench { 96 | ($name: ident, $n: expr, $map: ident) => ( 97 | #[bench] 98 | pub fn $name(b: &mut ::test::Bencher) { 99 | use test::black_box; 100 | 101 | let mut map = $map::new(); 102 | let n: usize = $n; 103 | 104 | // setup 105 | for i in 0..n { 106 | map.insert(i, i); 107 | } 108 | 109 | // measure 110 | let mut i = 0; 111 | b.iter(|| { 112 | let x = map.get(&i); 113 | i = (i + 1) % n; 114 | black_box(x); 115 | }) 116 | } 117 | ) 118 | } 119 | -------------------------------------------------------------------------------- /src/immut_slist.rs: -------------------------------------------------------------------------------- 1 | use std::cmp::Ordering; 2 | use std::iter::{self, IntoIterator}; 3 | use std::rc::{try_unwrap, Rc}; 4 | use std::hash::{Hash, Hasher}; 5 | use std; 6 | 7 | struct Node { 8 | elem: T, 9 | next: Option>>, 10 | } 11 | 12 | impl Node { 13 | fn new(elem: T) -> Node { 14 | Node { elem: elem, next: None } 15 | } 16 | } 17 | 18 | /// An iterator over the items of an ImmutSList 19 | #[derive(Clone)] 20 | pub struct Iter<'a, T: 'a> { 21 | head: Option<&'a Node>, 22 | nelem: usize, 23 | } 24 | 25 | /// An immutable singly-linked list, as seen in basically every functional language 26 | pub struct ImmutSList { 27 | front: Option>>, 28 | length: usize, 29 | } 30 | 31 | impl ImmutSList { 32 | /// Constructs a new, empty `ImmutSList` 33 | pub fn new () -> ImmutSList { 34 | ImmutSList{ front: None, length: 0 } 35 | } 36 | 37 | /// Returns a copy of the list, with `elem` appended to the front 38 | pub fn append (&self, elem: T) -> ImmutSList{ 39 | let mut new_node = Node::new(elem); 40 | new_node.next = self.front.clone(); 41 | 42 | ImmutSList{ 43 | front: Some(Rc::new(new_node)), 44 | length: self.len() + 1, 45 | } 46 | } 47 | 48 | /// Returns a reference to the first element in the list 49 | pub fn head (&self) -> Option<&T> { 50 | self.front.as_ref().map(|node| &node.elem) 51 | } 52 | 53 | /// Returns a copy of the list, with the first element removed 54 | pub fn tail (&self) -> ImmutSList { 55 | self.tailn(1) 56 | } 57 | 58 | /// Returns a copy of the list, with the first `n` elements removed 59 | pub fn tailn (&self, n: usize) -> ImmutSList { 60 | if self.len() <= n { 61 | ImmutSList::new() 62 | } else { 63 | let len = self.len() - n; 64 | let mut head = self.front.as_ref(); 65 | for _ in 0..n { 66 | head = head.unwrap().next.as_ref(); 67 | } 68 | ImmutSList { 69 | front: Some(head.unwrap().clone()), 70 | length: len, 71 | } 72 | } 73 | } 74 | 75 | /// Returns the last element in the list 76 | pub fn last (&self) -> Option<&T> { 77 | self.iter().last() 78 | } 79 | 80 | /// Returns a copy of the list, with only the last `n` elements remaining 81 | pub fn lastn (&self, n: usize) -> ImmutSList { 82 | if n >= self.length { 83 | self.clone() 84 | } else { 85 | self.tailn(self.length - n) 86 | } 87 | 88 | } 89 | 90 | /// Returns an iterator over references to the elements of the list in order 91 | pub fn iter <'a> (&'a self) -> Iter<'a, T> { 92 | Iter{ head: self.front.as_ref().map(|x| &**x), nelem: self.len() } 93 | } 94 | 95 | pub fn len (&self) -> usize { 96 | self.length 97 | } 98 | 99 | pub fn is_empty(&self) -> bool { 100 | return self.len() == 0 101 | } 102 | } 103 | 104 | #[unsafe_destructor] 105 | impl Drop for ImmutSList { 106 | fn drop (&mut self) { 107 | // don't want to blow the stack with destructors, 108 | // but also don't want to walk the whole list. 109 | // So walk the list until we find a non-uniquely owned item 110 | let mut head = self.front.take(); 111 | loop { 112 | let temp = head; 113 | match temp { 114 | Some(node) => match try_unwrap(node) { 115 | Ok(mut node) => { 116 | head = node.next.take(); 117 | } 118 | _ => return, 119 | }, 120 | _ => return, 121 | } 122 | } 123 | } 124 | } 125 | 126 | 127 | impl<'a, T> Iterator for Iter<'a, T> { 128 | type Item = &'a T; 129 | fn next(&mut self) -> Option<&'a T> { 130 | match self.head.take() { 131 | None => None, 132 | Some(head) => { 133 | self.nelem -= 1; 134 | self.head = head.next.as_ref().map(|next| &**next); 135 | Some(&head.elem) 136 | } 137 | } 138 | } 139 | 140 | fn size_hint(&self) -> (usize, Option) { 141 | (self.nelem, Some(self.nelem)) 142 | } 143 | } 144 | 145 | impl iter::FromIterator for ImmutSList { 146 | fn from_iter>(iter: I) -> ImmutSList { 147 | let mut list = ImmutSList::new(); 148 | for elem in iter { 149 | list = list.append(elem); 150 | } 151 | list 152 | } 153 | } 154 | 155 | impl PartialEq for ImmutSList { 156 | fn eq(&self, other: &ImmutSList) -> bool { 157 | self.len() == other.len() && 158 | std::iter::order::eq(self.iter(), other.iter()) 159 | } 160 | 161 | fn ne(&self, other: &ImmutSList) -> bool { 162 | self.len() != other.len() || 163 | std::iter::order::ne(self.iter(), other.iter()) 164 | } 165 | } 166 | 167 | impl PartialOrd for ImmutSList { 168 | fn partial_cmp(&self, other: &ImmutSList) -> Option { 169 | std::iter::order::partial_cmp(self.iter(), other.iter()) 170 | } 171 | } 172 | 173 | impl Clone for ImmutSList { 174 | fn clone(&self) -> ImmutSList { 175 | ImmutSList { 176 | front: self.front.clone(), 177 | length: self.length, 178 | } 179 | } 180 | } 181 | 182 | impl std::fmt::Debug for ImmutSList { 183 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 184 | try!(write!(f, "[")); 185 | 186 | for (i, e) in self.iter().enumerate() { 187 | if i != 0 { try!(write!(f, ", ")); } 188 | try!(write!(f, "{:?}", *e)); 189 | } 190 | 191 | write!(f, "]") 192 | } 193 | } 194 | 195 | impl Hash for ImmutSList { 196 | fn hash(&self, state: &mut H) { 197 | self.len().hash(state); 198 | for elt in self.iter() { 199 | elt.hash(state); 200 | } 201 | } 202 | } 203 | 204 | impl<'a, T> IntoIterator for &'a ImmutSList { 205 | type Item = &'a T; 206 | type IntoIter = Iter<'a, T>; 207 | fn into_iter(self) -> Iter<'a, T> { self.iter() } 208 | } 209 | 210 | #[cfg(test)] 211 | mod tests { 212 | use std::hash; 213 | use test::Bencher; 214 | use test; 215 | 216 | use super::ImmutSList; 217 | 218 | #[test] 219 | fn test_basic() { 220 | let mut m = ImmutSList::new(); 221 | assert_eq!(m.head(), None); 222 | assert_eq!(m.tail().head(), None); 223 | m = m.append(box 1); 224 | assert_eq!(m.head().unwrap(), & box 1); 225 | m = m.tail().append(box 2).append(box 3); 226 | assert_eq!(m.len(), 2); 227 | assert_eq!(m.head().unwrap(), & box 3); 228 | m = m.tail(); 229 | assert_eq!(m.head().unwrap(), & box 2); 230 | m = m.tail(); 231 | assert_eq!(m.len(), 0); 232 | assert_eq!(m.head(), None); 233 | m = m.append(box 7).append(box 5).append(box 3).append(box 1); 234 | assert_eq!(m.head().unwrap(), & box 1); 235 | } 236 | 237 | #[test] 238 | fn test_tailn() { 239 | let m = list_from(&[0,1,2,3,4,5]); 240 | assert_eq!(m.tailn(0), m); 241 | assert_eq!(m.tailn(3), m.tail().tail().tail()); 242 | } 243 | 244 | #[test] 245 | fn test_last() { 246 | let mut m = list_from(&[0,1,2,3,4,5]); 247 | assert_eq!(m.last().unwrap(), &5); 248 | 249 | m = ImmutSList::new(); 250 | assert_eq!(m.last(), None); 251 | } 252 | 253 | #[test] 254 | fn test_lastn() { 255 | let m = list_from(&[0,1,2,3,4,5]); 256 | assert_eq!(m.lastn(0).head(), None); 257 | assert_eq!(m.lastn(8), m); 258 | assert_eq!(m.lastn(4), m.tail().tail()); 259 | } 260 | 261 | #[cfg(test)] 262 | fn generate_test() -> ImmutSList { 263 | list_from(&[0,1,2,3,4,5,6]) 264 | } 265 | 266 | #[cfg(test)] 267 | fn list_from(v: &[T]) -> ImmutSList { 268 | v.iter().rev().map(|x| (*x).clone()).collect() 269 | } 270 | 271 | #[test] 272 | fn test_iterator() { 273 | let m = generate_test(); 274 | for (i, elt) in m.iter().enumerate() { 275 | assert_eq!(i as i32, *elt); 276 | } 277 | let mut n = ImmutSList::new(); 278 | assert_eq!(n.iter().next(), None); 279 | n = n.append(4); 280 | let mut it = n.iter(); 281 | assert_eq!(it.size_hint(), (1, Some(1))); 282 | assert_eq!(it.next().unwrap(), &4); 283 | assert_eq!(it.size_hint(), (0, Some(0))); 284 | assert_eq!(it.next(), None); 285 | } 286 | 287 | #[test] 288 | fn test_iterator_clone() { 289 | let mut n = ImmutSList::new(); 290 | n = n.append(1).append(2).append(3); 291 | let mut it = n.iter(); 292 | it.next(); 293 | let mut jt = it.clone(); 294 | assert_eq!(it.next(), jt.next()); 295 | assert_eq!(it.next(), jt.next()); 296 | } 297 | 298 | #[test] 299 | fn test_eq() { 300 | let mut n: ImmutSList = list_from(&[]); 301 | let mut m = list_from(&[]); 302 | assert!(n == m); 303 | n = n.append(1); 304 | assert!(n != m); 305 | m = m.append(1); 306 | assert!(n == m); 307 | 308 | let n = list_from(&[2,3,4]); 309 | let m = list_from(&[1,2,3]); 310 | assert!(n != m); 311 | } 312 | 313 | #[test] 314 | fn test_hash() { 315 | let mut x = ImmutSList::new(); 316 | let mut y = ImmutSList::new(); 317 | 318 | assert!(hash::hash::<_, hash::SipHasher>(&x) == hash::hash::<_, hash::SipHasher>(&y)); 319 | 320 | x = x.append(1).append(2).append(3); 321 | y = y.append(1).append(4).tail().append(2).append(3); 322 | 323 | assert!(hash::hash::<_, hash::SipHasher>(&x) == hash::hash::<_, hash::SipHasher>(&y)); 324 | } 325 | 326 | #[test] 327 | fn test_ord() { 328 | let n = list_from(&[]); 329 | let m = list_from(&[1,2,3]); 330 | assert!(n < m); 331 | assert!(m > n); 332 | assert!(n <= n); 333 | assert!(n >= n); 334 | } 335 | 336 | #[test] 337 | fn test_ord_nan() { 338 | let nan = 0.0f64/0.0; 339 | let n = list_from(&[nan]); 340 | let m = list_from(&[nan]); 341 | assert!(!(n < m)); 342 | assert!(!(n > m)); 343 | assert!(!(n <= m)); 344 | assert!(!(n >= m)); 345 | 346 | let n = list_from(&[nan]); 347 | let one = list_from(&[1.0f64]); 348 | assert!(!(n < one)); 349 | assert!(!(n > one)); 350 | assert!(!(n <= one)); 351 | assert!(!(n >= one)); 352 | 353 | let u = list_from(&[1.0f64,2.0,nan]); 354 | let v = list_from(&[1.0f64,2.0,3.0]); 355 | assert!(!(u < v)); 356 | assert!(!(u > v)); 357 | assert!(!(u <= v)); 358 | assert!(!(u >= v)); 359 | 360 | let s = list_from(&[1.0f64,2.0,4.0,2.0]); 361 | let t = list_from(&[1.0f64,2.0,3.0,2.0]); 362 | assert!(!(s < t)); 363 | assert!(s > one); 364 | assert!(!(s <= one)); 365 | assert!(s >= one); 366 | } 367 | 368 | #[test] 369 | fn test_debug() { 370 | let list: ImmutSList = (0..10).rev().collect(); 371 | assert_eq!(format!("{:?}", list), "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]"); 372 | 373 | let list: ImmutSList<&str> = vec!["just", "one", "test", "more"].iter() 374 | .rev() 375 | .map(|&s| s) 376 | .collect(); 377 | assert_eq!(format!("{:?}", list), r#"["just", "one", "test", "more"]"#); 378 | } 379 | 380 | #[bench] 381 | fn bench_collect_into(b: &mut test::Bencher) { 382 | let v = &[0i32; 64]; 383 | b.iter(|| { 384 | let _: ImmutSList = v.iter().map(|x| *x).collect(); 385 | }) 386 | } 387 | 388 | #[bench] 389 | fn bench_append(b: &mut test::Bencher) { 390 | let mut m: ImmutSList = ImmutSList::new(); 391 | b.iter(|| { 392 | m = m.append(0); 393 | }) 394 | } 395 | 396 | #[bench] 397 | fn bench_append_tail(b: &mut test::Bencher) { 398 | let mut m: ImmutSList = ImmutSList::new(); 399 | b.iter(|| { 400 | m = m.append(0).tail(); 401 | }) 402 | } 403 | 404 | #[bench] 405 | fn bench_iter(b: &mut test::Bencher) { 406 | let v = &[0; 128]; 407 | let m: ImmutSList = v.iter().map(|&x|x).collect(); 408 | b.iter(|| { 409 | assert!(m.iter().count() == 128); 410 | }) 411 | } 412 | } 413 | -------------------------------------------------------------------------------- /src/iter/mod.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature="string_joiner")] 2 | pub use self::string_joiner::StringJoiner; 3 | 4 | #[cfg(feature="string_joiner")] 5 | mod string_joiner; 6 | -------------------------------------------------------------------------------- /src/iter/string_joiner.rs: -------------------------------------------------------------------------------- 1 | /// An Iterator adapter that walks through all the elements in the Iterator, 2 | /// converts them to Strings and joins them to one big String, seperated by 3 | /// some seperator string slice. 4 | pub trait StringJoiner { 5 | /// Converts all elements the Iterator yields to Strings, 6 | /// then combines them all into one String, seperated by sep. 7 | /// 8 | /// # Example 9 | /// 10 | /// ```rust 11 | /// use collect::iter::StringJoiner; 12 | /// 13 | /// let vec = vec![1,2,3]; 14 | /// assert_eq!(&*vec.iter().join(", "), "1, 2, 3"); 15 | /// ``` 16 | fn join(&mut self, sep: &str) -> String; 17 | } 18 | 19 | // Implement it for all Iterators with Elements convertable into a String 20 | impl> StringJoiner for T { 21 | fn join(&mut self, sep: &str) -> String { 22 | match self.next() { 23 | Some(elem) => { 24 | let mut output = elem.to_string(); 25 | for elem in self.by_ref() { 26 | output.push_str(sep); 27 | output.push_str(&elem.to_string()); 28 | } 29 | output 30 | } 31 | None => String::new() 32 | } 33 | } 34 | } 35 | 36 | #[test] 37 | fn test_join() { 38 | let many = vec![1,2,3]; 39 | let one = vec![1]; 40 | let none: Vec = vec![]; 41 | 42 | assert_eq!(many.iter().join(", "), "1, 2, 3"); 43 | assert_eq!( one.iter().join(", "), "1"); 44 | assert_eq!(none.iter().join(", "), ""); 45 | } 46 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | 2 | //! collect-rs is intended as an experimental extension of the Rust standard library's 3 | //! libcollections. Ideas that are too niche, crazy, or experimental to land in libcollections 4 | //! can be gathered here where they can gain the maintenance and network-effect benefits that 5 | //! libcollections enjoys, but without worrying about such ivory tower concepts as 6 | //! "general usefulness" and "consistency". 7 | //! 8 | //! For the time being we plan to be highly volatile with a low barrier of entry. We want to 9 | //! explore the space of data structuring in Rust. We want to prove out ideas and implementations 10 | //! that could one day make their way into the standard library. 11 | //! 12 | //! Got a Concurrent, Immutable, or Persistent collection? Awesome! Crazy ideas for collection or 13 | //! iterator adapters? Heck yeah! 14 | //! 15 | //! Come on in! 16 | //! 17 | //! ----------- 18 | //! 19 | //! Note that anything include in collect-rs is theoretically a candidate for inclusion in 20 | //! libcollections. As such, this project is licensed under the same terms as Rust itself. 21 | 22 | // there's too many combinations to track this stuff properly 23 | #![allow(unused_features)] 24 | #![allow(raw_pointer_derive)] 25 | 26 | #![cfg_attr(test, feature(test))] 27 | 28 | #![feature(box_patterns, box_syntax)] 29 | #![feature(std_misc)] 30 | #![feature(unboxed_closures)] 31 | #![feature(unsafe_destructor)] 32 | 33 | #![feature(core, hash, alloc, step_by)] 34 | 35 | #[cfg(test)] extern crate rand; 36 | #[cfg(test)] extern crate test; 37 | extern crate core; 38 | 39 | #[cfg(feature="compare")] 40 | extern crate compare; 41 | 42 | #[cfg(feature="ordered_iter")] 43 | extern crate ordered_iter; 44 | 45 | #[cfg(test)] #[macro_use] mod bench; 46 | 47 | // Re-Exports 48 | #[cfg(feature="immut_slist")] pub use immut_slist::ImmutSList; 49 | 50 | // publics 51 | 52 | pub mod iter; 53 | 54 | #[cfg(feature="immut_slist")] pub mod immut_slist; 55 | 56 | #[cfg(feature="proto")] 57 | pub mod proto; 58 | 59 | -------------------------------------------------------------------------------- /src/proto/linear_map.rs: -------------------------------------------------------------------------------- 1 | //! A module providing a map implementation `LinearMap` backed by a vector. 2 | 3 | #![warn(missing_docs)] 4 | 5 | use std::fmt::{self, Debug}; 6 | use std::iter::{IntoIterator, Map}; 7 | use std::mem; 8 | use std::slice; 9 | 10 | // TODO: Unzip the vectors? 11 | // Consideration: When unzipped, the compiler will not be able to understand 12 | // that both of the `Vec`s have the same length, thus stuff like `iter` and so 13 | // on should probably be implemented in unsafe code. 14 | 15 | /// A very simple map implementation backed by a vector. 16 | /// 17 | /// Use it like any map, as long as the number of elements that it stores is 18 | /// very small. 19 | /// 20 | /// # Example (like std's HashMap) 21 | /// 22 | /// ``` 23 | /// use collect::proto::linear_map::LinearMap; 24 | /// 25 | /// // type inference lets us omit an explicit type signature (which 26 | /// // would be `LinearMap<&str, &str>` in this example). 27 | /// let mut book_reviews = LinearMap::new(); 28 | /// 29 | /// // review some books. 30 | /// book_reviews.insert("Adventures of Huckleberry Finn", "My favorite book."); 31 | /// book_reviews.insert("Grimms' Fairy Tales", "Masterpiece."); 32 | /// book_reviews.insert("Pride and Prejudice", "Very enjoyable."); 33 | /// book_reviews.insert("The Adventures of Sherlock Holmes", "Eye lyked it alot."); 34 | /// 35 | /// // check for a specific one. 36 | /// if !book_reviews.contains_key(&("Les Misérables")) { 37 | /// println!("We've got {} reviews, but Les Misérables ain't one.", 38 | /// book_reviews.len()); 39 | /// } 40 | /// 41 | /// // oops, this review has a lot of spelling mistakes, let's delete it. 42 | /// book_reviews.remove(&("The Adventures of Sherlock Holmes")); 43 | /// 44 | /// // look up the values associated with some keys. 45 | /// let to_find = ["Pride and Prejudice", "Alice's Adventure in Wonderland"]; 46 | /// for book in to_find.iter() { 47 | /// match book_reviews.get(book) { 48 | /// Some(review) => println!("{}: {}", *book, *review), 49 | /// None => println!("{} is unreviewed.", *book) 50 | /// } 51 | /// } 52 | /// 53 | /// // iterate over everything. 54 | /// for (book, review) in book_reviews.iter() { 55 | /// println!("{}: \"{}\"", *book, *review); 56 | /// } 57 | /// ``` 58 | #[derive(Clone, Default)] 59 | pub struct LinearMap { 60 | storage: Vec<(K,V)>, 61 | } 62 | 63 | impl LinearMap { 64 | /// Creates an empty map. This method does not allocate. 65 | pub fn new() -> LinearMap { 66 | LinearMap { 67 | storage: Vec::new(), 68 | } 69 | } 70 | 71 | /// Creates an empty map with the given initial capacity. 72 | pub fn with_capacity(capacity: usize) -> LinearMap { 73 | LinearMap { 74 | storage: Vec::with_capacity(capacity), 75 | } 76 | } 77 | 78 | /// Returns the number of elements the map can hold without reallocating. 79 | pub fn capacity(&self) -> usize { 80 | self.storage.capacity() 81 | } 82 | 83 | /// Reserves capacity for at least `additional` more to be inserted in the 84 | /// map. The collection may reserve more space to avoid frequent 85 | /// reallocations. 86 | /// 87 | /// # Panics 88 | /// 89 | /// Panics if the new allocation size overflows `usize`. 90 | pub fn reserve(&mut self, additional: usize) { 91 | self.storage.reserve(additional); 92 | } 93 | 94 | /// Reserves the minimum capacity for exactly `additional` more elemnnts to 95 | /// be inserted in the map. 96 | /// 97 | /// Note that the allocator may give the collection more space than it 98 | /// requests. Therefore capacity cannot be relied upon to be precisely 99 | /// minimal. Prefer `reserve` if future insertions are expected. 100 | /// 101 | /// # Panics 102 | /// 103 | /// Panics if the new capacity overflows `usize`. 104 | pub fn reserve_exact(&mut self, additional: usize) { 105 | self.storage.reserve_exact(additional); 106 | } 107 | 108 | /// Shrinks the capacity of the map as much as possible. 109 | /// 110 | /// It will drop down as close as possible to the current length but the 111 | /// allocator may still inform the map that there is more space than 112 | /// necessary. Therefore capacity cannot be relid upon to be minimal. 113 | pub fn shrink_to_fit(&mut self) { 114 | self.storage.shrink_to_fit(); 115 | } 116 | 117 | /// Returns the number of elements in the map. 118 | pub fn len(&self) -> usize { 119 | self.storage.len() 120 | } 121 | 122 | /// Returns true if the map contains no elements. 123 | pub fn is_empty(&self) -> bool { 124 | self.storage.is_empty() 125 | } 126 | 127 | /// Clears the map, removing all elements. Keeps the allocated memory for 128 | /// reuse. 129 | pub fn clear(&mut self) { 130 | self.storage.clear(); 131 | } 132 | 133 | /// An iterator visiting all key-value pairs in arbitrary order. Iterator 134 | /// element type is `(&'a K, &'a V)`. 135 | pub fn iter<'a>(&'a self) -> Iter<'a, K, V> { 136 | fn ref_(&(ref v1, ref v2): &(A, B)) -> (&A, &B) { (v1, v2) } 137 | Iter { iter: self.storage.iter().map(ref_) } 138 | } 139 | 140 | /// An iterator visiting all key-value pairs in arbitrary order with 141 | /// mutable references to the values. Iterator element type is `(&'a K, &'a 142 | /// mut V)`. 143 | pub fn iter_mut<'a>(&'a mut self) -> IterMut<'a, K, V> { 144 | fn ref_(&mut (ref v1, ref mut v2): &mut (A, B)) -> (&A, &mut B) { (v1, v2) } 145 | IterMut { iter: self.storage.iter_mut().map(ref_) } 146 | } 147 | 148 | /// An iterator visiting all keys in arbitrary order. Iterator element type 149 | /// is `&'a K`. 150 | pub fn keys<'a>(&'a self) -> Keys<'a, K, V> { 151 | fn first((v, _): (A, B)) -> A { v } 152 | Keys { iter: self.iter().map(first) } 153 | } 154 | 155 | /// An iterator visiting all values in arbitrary order. Iterator element 156 | /// type is `&'a V`. 157 | pub fn values<'a>(&'a self) -> Values<'a, K, V> { 158 | fn second((_, v): (A, B)) -> B { v } 159 | Values { iter: self.iter().map(second) } 160 | } 161 | 162 | /// Returns a reference to the value corresponding to the key. 163 | pub fn get<'a>(&'a self, key: &K) -> Option<&'a V> { 164 | for (k, v) in self.iter() { 165 | if key == k { 166 | return Some(v); 167 | } 168 | } 169 | None 170 | } 171 | 172 | /// Returns a mutable reference to the value corresponding to the key. 173 | pub fn get_mut<'a>(&'a mut self, key: &K) -> Option<&'a mut V> { 174 | for (k, v) in self.iter_mut() { 175 | if key == k { 176 | return Some(v); 177 | } 178 | } 179 | None 180 | } 181 | 182 | /// Returns true if the map contains a value to the specified key. 183 | pub fn contains_key(&self, key: &K) -> bool { 184 | self.get(key).is_some() 185 | } 186 | 187 | /// Inserts a key-value pair into the map. If the key already had a value 188 | /// present in the map, it is returned. Otherwise, `None` is returned. 189 | pub fn insert(&mut self, key: K, value: V) -> Option { 190 | for kv in self.storage.iter_mut() { 191 | let found; 192 | { 193 | let &mut (ref k, _) = kv; 194 | found = key == *k; 195 | } 196 | if found { 197 | let (_, v) = mem::replace(kv, (key, value)); 198 | return Some(v); 199 | } 200 | } 201 | self.storage.push((key, value)); 202 | None 203 | } 204 | 205 | /// Removes a key-value pair from the map. If the key had a value present 206 | /// in the map, it is returned. Otherwise, `None` is returned. 207 | pub fn remove(&mut self, key: &K) -> Option { 208 | for i in 0..self.storage.len() { 209 | let found; 210 | { 211 | let (ref k, _) = self.storage[i]; 212 | found = key == k; 213 | } 214 | if found { 215 | let (_, v) = self.storage.swap_remove(i); 216 | return Some(v); 217 | } 218 | } 219 | None 220 | } 221 | } 222 | 223 | /// The iterator returned by `LinearMap::iter`. 224 | pub struct Iter<'a, K:'a, V:'a> { 225 | iter: Map, 226 | fn(&'a (K, V)) -> (&'a K, &'a V)>, 227 | } 228 | 229 | /// The iterator returned by `LinearMap::iter_mut`. 230 | pub struct IterMut<'a, K:'a, V:'a> { 231 | iter: Map, 232 | fn(&'a mut (K, V)) -> (&'a K, &'a mut V)>, 233 | } 234 | 235 | /// The iterator returned by `LinearMap::keys`. 236 | pub struct Keys<'a, K:'a, V:'a> { 237 | iter: Map, fn((&'a K, &'a V)) -> &'a K>, 238 | } 239 | 240 | /// The iterator returned by `LinearMap::values`. 241 | pub struct Values<'a, K:'a, V:'a> { 242 | iter: Map, fn((&'a K, &'a V)) -> &'a V>, 243 | } 244 | 245 | impl<'a, K:'a, V:'a> Iterator for Iter<'a, K, V> { 246 | type Item = (&'a K, &'a V); 247 | fn next(&mut self) -> Option<(&'a K, &'a V)> { self.iter.next() } 248 | fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } 249 | } 250 | 251 | impl<'a, K:'a, V:'a> Iterator for IterMut<'a, K, V> { 252 | type Item = (&'a K, &'a mut V); 253 | fn next(&mut self) -> Option<(&'a K, &'a mut V)> { self.iter.next() } 254 | fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } 255 | } 256 | 257 | impl<'a, K:'a, V:'a> Iterator for Keys<'a, K, V> { 258 | type Item = &'a K; 259 | fn next(&mut self) -> Option<&'a K> { self.iter.next() } 260 | fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } 261 | } 262 | 263 | impl<'a, K:'a, V:'a> Iterator for Values<'a, K, V> { 264 | type Item = &'a V; 265 | fn next(&mut self) -> Option<&'a V> { self.iter.next() } 266 | fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } 267 | } 268 | 269 | impl<'a, K:'a, V:'a> Clone for Iter<'a, K, V> { 270 | fn clone(&self) -> Iter<'a, K, V> { Iter { iter: self.iter.clone() } } 271 | } 272 | 273 | impl<'a, K:'a, V:'a> Clone for Keys<'a, K, V> { 274 | fn clone(&self) -> Keys<'a, K, V> { Keys { iter: self.iter.clone() } } 275 | } 276 | 277 | impl<'a, K:'a, V:'a> Clone for Values<'a, K, V> { 278 | fn clone(&self) -> Values<'a, K, V> { Values { iter: self.iter.clone() } } 279 | } 280 | 281 | impl<'a, K:'a, V:'a> DoubleEndedIterator for Iter<'a, K, V> { 282 | fn next_back(&mut self) -> Option<(&'a K, &'a V)> { self.iter.next_back() } 283 | } 284 | 285 | impl<'a, K:'a, V:'a> DoubleEndedIterator for IterMut<'a, K, V> { 286 | fn next_back(&mut self) -> Option<(&'a K, &'a mut V)> { self.iter.next_back() } 287 | } 288 | 289 | impl<'a, K:'a, V:'a> DoubleEndedIterator for Keys<'a, K, V> { 290 | fn next_back(&mut self) -> Option<&'a K> { self.iter.next_back() } 291 | } 292 | 293 | impl<'a, K:'a, V:'a> DoubleEndedIterator for Values<'a, K, V> { 294 | fn next_back(&mut self) -> Option<&'a V> { self.iter.next_back() } 295 | } 296 | 297 | impl<'a, K:'a, V:'a> ExactSizeIterator for Iter <'a, K, V> { } 298 | impl<'a, K:'a, V:'a> ExactSizeIterator for IterMut<'a, K, V> { } 299 | impl<'a, K:'a, V:'a> ExactSizeIterator for Keys <'a, K, V> { } 300 | impl<'a, K:'a, V:'a> ExactSizeIterator for Values <'a, K, V> { } 301 | 302 | impl<'a, K:'a + Eq, V:'a> IntoIterator for &'a LinearMap { 303 | type Item = (&'a K, &'a V); 304 | type IntoIter = Iter<'a, K, V>; 305 | fn into_iter(self) -> Iter<'a, K, V> { self.iter() } 306 | } 307 | 308 | impl<'a, K:'a + Eq, V:'a> IntoIterator for &'a mut LinearMap { 309 | type Item = (&'a K, &'a mut V); 310 | type IntoIter = IterMut<'a, K, V>; 311 | fn into_iter(self) -> IterMut<'a, K, V> { self.iter_mut() } 312 | } 313 | 314 | impl Debug for LinearMap where K: Debug + Eq, V: Debug { 315 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 316 | try!(write!(f, "{{")); 317 | 318 | let mut it = self.iter(); 319 | 320 | if let Some((k, v)) = it.next() { 321 | try!(write!(f, "{:?}: {:?}", k, v)); 322 | for (k, v) in it { try!(write!(f, ", {:?}: {:?}", k, v)); } 323 | } 324 | 325 | write!(f, "}}") 326 | } 327 | } 328 | 329 | #[cfg(test)] 330 | mod test { 331 | use super::LinearMap; 332 | 333 | const TEST_CAPACITY: usize = 10; 334 | 335 | #[test] 336 | fn test_new() { 337 | let map: LinearMap = LinearMap::new(); 338 | assert_eq!(map.capacity(), 0); 339 | assert_eq!(map.len(), 0); 340 | assert!(map.is_empty()); 341 | } 342 | 343 | #[test] 344 | fn test_with_capacity() { 345 | let map: LinearMap = LinearMap::with_capacity(TEST_CAPACITY); 346 | assert!(map.capacity() >= TEST_CAPACITY); 347 | } 348 | 349 | #[test] 350 | fn test_capacity() { 351 | let mut map = LinearMap::new(); 352 | map.insert(1, 2); 353 | assert!(map.capacity() >= 1); 354 | map.remove(&1); 355 | assert!(map.capacity() >= 1); 356 | map.reserve(TEST_CAPACITY); 357 | let capacity = map.capacity(); 358 | assert!(capacity >= TEST_CAPACITY); 359 | for i in 0..TEST_CAPACITY as i32 { 360 | assert!(map.insert(i, i).is_none()); 361 | } 362 | assert_eq!(capacity, map.capacity()); 363 | } 364 | 365 | #[test] 366 | fn test_reserve() { 367 | let mut map = LinearMap::new(); 368 | map.reserve(TEST_CAPACITY); 369 | assert!(map.capacity() >= TEST_CAPACITY); 370 | for i in 0..TEST_CAPACITY as i32 { 371 | assert!(map.insert(i, i).is_none()); 372 | } 373 | map.reserve(TEST_CAPACITY); 374 | assert!(map.capacity() >= 2 * TEST_CAPACITY); 375 | 376 | let mut map = LinearMap::new(); 377 | map.reserve(TEST_CAPACITY); 378 | assert!(map.capacity() >= TEST_CAPACITY); 379 | for i in 0..TEST_CAPACITY as i32 { 380 | assert!(map.insert(i, i).is_none()); 381 | } 382 | map.reserve(TEST_CAPACITY); 383 | assert!(map.capacity() >= 2 * TEST_CAPACITY); 384 | } 385 | 386 | #[test] 387 | fn test_shrink_to_fit() { 388 | let mut map = LinearMap::new(); 389 | map.shrink_to_fit(); 390 | assert_eq!(map.capacity(), 0); 391 | map.reserve(TEST_CAPACITY); 392 | map.shrink_to_fit(); 393 | assert_eq!(map.capacity(), 0); 394 | for i in 0..TEST_CAPACITY as i32 { 395 | assert!(map.insert(i, i).is_none()); 396 | } 397 | map.shrink_to_fit(); 398 | assert_eq!(map.len(), TEST_CAPACITY); 399 | assert!(map.capacity() >= TEST_CAPACITY); 400 | } 401 | 402 | #[test] 403 | fn test_len_and_is_empty() { 404 | let mut map = LinearMap::new(); 405 | assert_eq!(map.len(), 0); 406 | assert!(map.is_empty()); 407 | map.insert(100, 100); 408 | assert_eq!(map.len(), 1); 409 | assert!(!map.is_empty()); 410 | for i in 0..TEST_CAPACITY as i32 { 411 | assert!(map.insert(i, i).is_none()); 412 | } 413 | assert_eq!(map.len(), 1 + TEST_CAPACITY); 414 | assert!(!map.is_empty()); 415 | assert!(map.remove(&100).is_some()); 416 | assert_eq!(map.len(), TEST_CAPACITY); 417 | assert!(!map.is_empty()); 418 | } 419 | 420 | #[test] 421 | fn test_clear() { 422 | let mut map = LinearMap::new(); 423 | map.clear(); 424 | assert_eq!(map.len(), 0); 425 | for i in 0..TEST_CAPACITY as i32 { 426 | assert!(map.insert(i, i).is_none()); 427 | } 428 | map.clear(); 429 | assert_eq!(map.len(), 0); 430 | assert!(map.capacity() > 0); 431 | } 432 | 433 | #[test] 434 | fn test_iterators() { 435 | const ONE: i32 = 0b0001; 436 | const TWO: i32 = 0b0010; 437 | const THREE: i32 = 0b0100; 438 | const FOUR: i32 = 0b1000; 439 | const ALL: i32 = 0b1111; 440 | let mut map = LinearMap::new(); 441 | assert!(map.insert(ONE, TWO).is_none()); 442 | assert!(map.insert(TWO, THREE).is_none()); 443 | assert!(map.insert(THREE, FOUR).is_none()); 444 | assert!(map.insert(FOUR, ONE).is_none()); 445 | 446 | { 447 | let mut result_k = 0; 448 | let mut result_v = 0; 449 | for (&k, &v) in map.iter() { 450 | result_k ^= k; 451 | result_v ^= v; 452 | assert_eq!(((k << 1) & ALL) | ((k >> 3) & ALL), v); 453 | } 454 | assert_eq!(result_k, ALL); 455 | assert_eq!(result_v, ALL); 456 | } 457 | { 458 | let mut result_k = 0; 459 | let mut result_v = 0; 460 | for (&k, &mut v) in map.iter_mut() { 461 | result_k ^= k; 462 | result_v ^= v; 463 | assert_eq!(((k << 1) & ALL) | ((k >> 3) & ALL), v); 464 | } 465 | assert_eq!(result_k, ALL); 466 | assert_eq!(result_v, ALL); 467 | } 468 | { 469 | let mut result = 0; 470 | for &k in map.keys() { 471 | result ^= k; 472 | } 473 | assert_eq!(result, ALL); 474 | } 475 | { 476 | let mut result = 0; 477 | for &v in map.values() { 478 | result ^= v; 479 | } 480 | assert_eq!(result, ALL); 481 | } 482 | } 483 | 484 | #[test] 485 | fn test_insert_remove_get() { 486 | let mut map = LinearMap::new(); 487 | assert!(map.insert(100, 101).is_none()); 488 | assert!(map.contains_key(&100)); 489 | assert_eq!(map.get(&100), Some(&101)); 490 | assert_eq!(map.get_mut(&100), Some(&mut 101)); 491 | for i in 0..TEST_CAPACITY as i32 { 492 | assert!(map.insert(i, i).is_none()); 493 | } 494 | assert_eq!(map.insert(100, 102), Some(101)); 495 | assert_eq!(map.remove(&100), Some(102)); 496 | assert_eq!(map.remove(&100), None); 497 | assert_eq!(map.remove(&1000), None); 498 | } 499 | } 500 | 501 | #[cfg(test)] 502 | mod bench { 503 | use super::LinearMap; 504 | use test; 505 | 506 | const SMALL: u32 = 10; 507 | const MEDIUM: u32 = 100; 508 | const BIG: u32 = 1000; 509 | 510 | fn insert(b: &mut test::Bencher, num: u32) { 511 | b.iter(|| { 512 | let mut map = LinearMap::new(); 513 | for i in 0..num { 514 | map.insert(i, i); 515 | } 516 | }) 517 | } 518 | 519 | fn remove_insert(b: &mut test::Bencher, num: u32) { 520 | b.iter(|| { 521 | let mut map = LinearMap::new(); 522 | for i in 0..num { 523 | map.insert(i, i); 524 | } 525 | for i in 0..num { 526 | map.remove(&i); 527 | } 528 | }) 529 | } 530 | 531 | fn remove_rev_insert(b: &mut test::Bencher, num: u32) { 532 | b.iter(|| { 533 | let mut map = LinearMap::new(); 534 | for i in 0..num { 535 | map.insert(i, i); 536 | } 537 | for i in 0..num { 538 | map.remove(&(num - i - 1)); 539 | } 540 | }) 541 | } 542 | 543 | fn get_middle(b: &mut test::Bencher, num: u32) { 544 | let mut map = LinearMap::new(); 545 | for i in 0..num { 546 | map.insert(i, i); 547 | } 548 | let middle = num / 2; 549 | b.iter(|| { 550 | test::black_box(map.get(&middle)); 551 | test::black_box(map.get_mut(&middle)); 552 | }) 553 | } 554 | 555 | fn get_none(b: &mut test::Bencher, num: u32) { 556 | let mut map = LinearMap::new(); 557 | for i in 0..num { 558 | map.insert(i, i); 559 | } 560 | let none = num + 1; 561 | b.iter(|| { 562 | test::black_box(map.get(&none)); 563 | test::black_box(map.get_mut(&none)); 564 | }) 565 | } 566 | 567 | #[bench] fn bench_insert_small (b: &mut test::Bencher) { insert(b, SMALL); } 568 | #[bench] fn bench_insert_medium(b: &mut test::Bencher) { insert(b, MEDIUM); } 569 | #[bench] fn bench_insert_big (b: &mut test::Bencher) { insert(b, BIG); } 570 | 571 | #[bench] fn bench_remove_insert_small (b: &mut test::Bencher) { remove_insert(b, SMALL); } 572 | #[bench] fn bench_remove_insert_medium(b: &mut test::Bencher) { remove_insert(b, MEDIUM); } 573 | #[bench] fn bench_remove_insert_big (b: &mut test::Bencher) { remove_insert(b, BIG); } 574 | 575 | #[bench] fn bench_remove_rev_insert_small (b: &mut test::Bencher) { remove_rev_insert(b, SMALL); } 576 | #[bench] fn bench_remove_rev_insert_medium(b: &mut test::Bencher) { remove_rev_insert(b, MEDIUM); } 577 | #[bench] fn bench_remove_rev_insert_big (b: &mut test::Bencher) { remove_rev_insert(b, BIG); } 578 | 579 | #[bench] fn bench_get_middle_small (b: &mut test::Bencher) { get_middle(b, SMALL); } 580 | #[bench] fn bench_get_middle_medium(b: &mut test::Bencher) { get_middle(b, MEDIUM); } 581 | #[bench] fn bench_get_middle_big (b: &mut test::Bencher) { get_middle(b, BIG); } 582 | 583 | #[bench] fn bench_get_none_small (b: &mut test::Bencher) { get_none(b, SMALL); } 584 | #[bench] fn bench_get_none_medium(b: &mut test::Bencher) { get_none(b, MEDIUM); } 585 | #[bench] fn bench_get_none_big (b: &mut test::Bencher) { get_none(b, BIG); } 586 | } 587 | -------------------------------------------------------------------------------- /src/proto/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod linear_map; 2 | pub mod par_vec; 3 | -------------------------------------------------------------------------------- /src/proto/par_vec.rs: -------------------------------------------------------------------------------- 1 | extern crate alloc; 2 | 3 | use self::alloc::arc; 4 | 5 | use std::cmp::min; 6 | use std::fmt::{Formatter, Debug}; 7 | use std::fmt::Error as FmtError; 8 | use std::iter::range_inclusive; 9 | use std::sync::Arc; 10 | use std::mem; 11 | use std::ops; 12 | 13 | /// A vector that can be operated on concurrently via non-overlapping slices. 14 | /// 15 | /// Get a `ParVec` and a vector of slices via `new()`, send the slices to other threads 16 | /// and mutate them, then get the mutated vector with `into_inner()` when finished. 17 | pub struct ParVec { 18 | data: Arc>, 19 | } 20 | 21 | impl ParVec { 22 | /// Create a new `ParVec`, returning it and a vector of slices that can be sent 23 | /// to other threads and mutated concurrently. 24 | pub fn new(vec: Vec, slices: usize) -> (ParVec, Vec>) { 25 | let data = Arc::new(vec); 26 | 27 | let par_slices = sub_slices(&data, slices).into_iter() 28 | .map(|slice| 29 | ParSlice { 30 | _vec: data.clone(), 31 | data: unsafe { mem::transmute(slice) }, 32 | } 33 | ).collect(); 34 | 35 | let par_vec = ParVec { 36 | data: data, 37 | }; 38 | 39 | (par_vec, par_slices) 40 | } 41 | 42 | /// Take the inner `Vec` if there are no slices remaining. 43 | /// Returns `Err(self)` if there are still slices out there. 44 | pub fn into_inner_opt(self) -> Result, ParVec> { 45 | // Unwrap if we hold a unique reference 46 | // (we don't use weak refs so ignore those) 47 | if arc::strong_count(&self.data) == 1 { 48 | let vec_ptr: &mut Vec = unsafe { mem::transmute(&*self.data) }; 49 | Ok(mem::replace(vec_ptr, Vec::new())) 50 | } else { 51 | Err(self) 52 | } 53 | } 54 | 55 | /// Take the inner `Vec`, waiting until all slices have been freed. 56 | pub fn into_inner(mut self) -> Vec { 57 | loop { 58 | match self.into_inner_opt() { 59 | Ok(vec) => return vec, 60 | Err(new_self) => self = new_self, 61 | } 62 | } 63 | } 64 | } 65 | 66 | fn sub_slices(parent: &[T], slice_count: usize) -> Vec<&[T]> { 67 | let mut slices = Vec::new(); 68 | 69 | let len = parent.len(); 70 | let mut start = 0; 71 | 72 | for curr in range_inclusive(1, slice_count).rev() { 73 | let slice_len = (len - start) / curr; 74 | let end = min(start + slice_len, len); 75 | 76 | slices.push(&parent[start..end]); 77 | start += slice_len; 78 | } 79 | 80 | slices 81 | } 82 | 83 | /// A slice of `ParVec` that can be sent to another task for processing. 84 | /// Automatically releases the slice on drop. 85 | pub struct ParSlice { 86 | // Just to keep the source vector alive while the slice is, 87 | // since the ParVec can die asynchronously. 88 | _vec: Arc>, 89 | // This isn't actually &'static but we're guarding it so it's safe. 90 | data: &'static mut [T], 91 | } 92 | 93 | impl ops::Deref for ParSlice { 94 | type Target = [T]; 95 | 96 | fn deref<'a>(&'a self) -> &'a [T] { 97 | self.data 98 | } 99 | } 100 | 101 | impl ops::DerefMut for ParSlice { 102 | fn deref_mut<'a>(&'a mut self) -> &'a mut [T] { 103 | self.data 104 | } 105 | } 106 | 107 | impl Debug for ParSlice where T: Debug { 108 | fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> { 109 | write!(f, "{:?}", self.data) 110 | } 111 | } 112 | 113 | #[cfg(test)] 114 | mod test { 115 | extern crate threadpool; 116 | extern crate test; 117 | use self::test::Bencher; 118 | use super::ParVec; 119 | use std::mem; 120 | use std::iter::range_inclusive; 121 | use rand::{thread_rng, Rng}; 122 | 123 | const TEST_SLICES: usize = 8; 124 | const TEST_MAX: u32 = 1000; 125 | 126 | #[test] 127 | fn test_unwrap_safely() { 128 | let (vec, slices) = ParVec::new([5; TEST_MAX as usize].to_vec(), TEST_SLICES); 129 | mem::drop(slices); 130 | 131 | let vec = vec.into_inner(); 132 | 133 | assert_eq!(vec, &[5; TEST_MAX as usize][..]); 134 | } 135 | 136 | #[test] 137 | fn test_slices() { 138 | let (_, slices) = ParVec::new((1u32..TEST_MAX).collect(), TEST_SLICES); 139 | 140 | assert_eq!(slices.len(), TEST_SLICES); 141 | } 142 | 143 | #[bench] 144 | fn seq_prime_factors_1000(b: &mut Bencher) { 145 | let vec: Vec = range_inclusive(1, TEST_MAX).collect(); 146 | 147 | b.iter(|| { 148 | let _: Vec<(u32, Vec)> = vec.iter() 149 | .map(|&x| (x, get_prime_factors(x))) 150 | .collect(); 151 | }); 152 | } 153 | 154 | #[bench] 155 | fn par_prime_factors_1000(b: &mut Bencher) { 156 | use self::threadpool::ThreadPool; 157 | 158 | let mut rng = thread_rng(); 159 | let pool = ThreadPool::new(TEST_SLICES); 160 | 161 | b.iter(|| { 162 | let mut vec: Vec<(u32, Vec)> = range_inclusive(1, TEST_MAX) 163 | .map(|x| (x, Vec::new())).collect(); 164 | 165 | // Shuffle so each thread gets an even distribution of work. 166 | // Otherwise, the lower threads will quit early. 167 | rng.shuffle(&mut *vec); 168 | 169 | let (par_vec, par_slices) = ParVec::new(vec, TEST_SLICES); 170 | 171 | for mut slice in par_slices.into_iter() { 172 | pool.execute(move || 173 | for pair in slice.iter_mut() { 174 | let (x, ref mut x_primes) = *pair; 175 | *x_primes = get_prime_factors(x); 176 | } 177 | ); 178 | } 179 | 180 | let mut vec = par_vec.into_inner(); 181 | // Sort so they're in the same order as sequential. 182 | vec.sort(); 183 | }); 184 | } 185 | 186 | fn get_prime_factors(x: u32) -> Vec { 187 | (1..x).filter(|&y| x % y == 0 && is_prime(y)).collect() 188 | } 189 | 190 | fn is_prime(x: u32) -> bool { 191 | if x < 3 { return true; } 192 | 193 | if x & 1 == 0 { return false; } 194 | 195 | for i in (3..x).step_by(2) { 196 | if x % i == 0 { return false; } 197 | } 198 | 199 | true 200 | } 201 | 202 | } 203 | --------------------------------------------------------------------------------