├── .gitignore ├── .travis.yml ├── Cargo.lock ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── benches └── bench.rs └── src ├── lib.rs └── tests.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | **/*.rs.bk 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: 3 | - nightly 4 | - beta 5 | - stable 6 | - 1.36.0 7 | script: | 8 | cargo build --verbose && 9 | cargo test --verbose && 10 | ([ $TRAVIS_RUST_VERSION != nightly ] || cargo bench --verbose bench) 11 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "bit-vec" 7 | version = "0.6.3" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" 10 | 11 | [[package]] 12 | name = "cfg-if" 13 | version = "1.0.0" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 16 | 17 | [[package]] 18 | name = "getrandom" 19 | version = "0.2.12" 20 | source = "registry+https://github.com/rust-lang/crates.io-index" 21 | checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" 22 | dependencies = [ 23 | "cfg-if", 24 | "libc", 25 | "wasi", 26 | ] 27 | 28 | [[package]] 29 | name = "libc" 30 | version = "0.2.153" 31 | source = "registry+https://github.com/rust-lang/crates.io-index" 32 | checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" 33 | 34 | [[package]] 35 | name = "malloc_size_of" 36 | version = "0.1.0" 37 | source = "registry+https://github.com/rust-lang/crates.io-index" 38 | checksum = "46fd9b382a64a1424df42ce69cd84485336cfeca66795a210ea9bd2fe388a0af" 39 | 40 | [[package]] 41 | name = "ppv-lite86" 42 | version = "0.2.17" 43 | source = "registry+https://github.com/rust-lang/crates.io-index" 44 | checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" 45 | 46 | [[package]] 47 | name = "rand" 48 | version = "0.8.5" 49 | source = "registry+https://github.com/rust-lang/crates.io-index" 50 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 51 | dependencies = [ 52 | "libc", 53 | "rand_chacha", 54 | "rand_core", 55 | ] 56 | 57 | [[package]] 58 | name = "rand_chacha" 59 | version = "0.3.1" 60 | source = "registry+https://github.com/rust-lang/crates.io-index" 61 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 62 | dependencies = [ 63 | "ppv-lite86", 64 | "rand_core", 65 | ] 66 | 67 | [[package]] 68 | name = "rand_core" 69 | version = "0.6.4" 70 | source = "registry+https://github.com/rust-lang/crates.io-index" 71 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 72 | dependencies = [ 73 | "getrandom", 74 | ] 75 | 76 | [[package]] 77 | name = "smallbitvec" 78 | version = "2.5.4" 79 | dependencies = [ 80 | "bit-vec", 81 | "malloc_size_of", 82 | "rand", 83 | ] 84 | 85 | [[package]] 86 | name = "wasi" 87 | version = "0.11.0+wasi-snapshot-preview1" 88 | source = "registry+https://github.com/rust-lang/crates.io-index" 89 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 90 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "smallbitvec" 3 | version = "2.5.4" 4 | authors = ["Matt Brubeck "] 5 | license = "MIT OR Apache-2.0" 6 | description = "A bit vector optimized for size and inline storage" 7 | repository = "https://github.com/servo/smallbitvec" 8 | documentation = "https://docs.rs/smallbitvec" 9 | keywords = ["bitvec", "bitmap", "vec", "data-structures"] 10 | categories = ["data-structures"] 11 | readme = "README.md" 12 | edition = "2021" 13 | rust-version = "1.56" 14 | 15 | [dependencies] 16 | malloc_size_of = { version = "0.1", default-features = false, optional = true } 17 | 18 | [dev-dependencies] 19 | rand = { version = "0.8.5", features = ["small_rng"] } 20 | bit-vec = "0.6.3" 21 | -------------------------------------------------------------------------------- /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) 2017 Matt Brubeck 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 | # smallbitvec 2 | 3 | A bit vector that is the size of a pointer, and can store data either inline or 4 | on the heap. Like the `bit-vec` crate but optimized for small inline size and 5 | reduced allocations. 6 | 7 | * [Documentation](https://docs.rs/smallbitvec) 8 | * [crates.io](https://crates.io/crates/smallbitvec) 9 | * [Release notes](https://github.com/servo/smallbitvec/releases) 10 | -------------------------------------------------------------------------------- /benches/bench.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2012-2014 The Rust Project Developers. 2 | // 3 | // Copyright 2017 Matt Brubeck. 4 | // See the COPYRIGHT file at the top-level directory of this distribution and at 5 | // http://rust-lang.org/COPYRIGHT. 6 | // 7 | // Licensed under the Apache License, Version 2.0 or the MIT license 9 | // , at your 10 | // option. This file may not be copied, modified, or distributed 11 | // except according to those terms. 12 | 13 | #![feature(test)] 14 | 15 | extern crate bit_vec; 16 | extern crate rand; 17 | extern crate smallbitvec; 18 | extern crate test; 19 | 20 | use std::hash::{Hash, Hasher}; 21 | 22 | use bit_vec::BitVec; 23 | use rand::{Rng, RngCore, SeedableRng}; 24 | use smallbitvec::SmallBitVec; 25 | use test::{black_box, Bencher}; 26 | 27 | const BENCH_BITS: usize = 1 << 14; 28 | const USIZE_BITS: usize = ::std::mem::size_of::() * 8; 29 | 30 | fn rng() -> impl Rng { 31 | rand::rngs::SmallRng::seed_from_u64(0) 32 | } 33 | 34 | #[bench] 35 | fn bench_bit_set_big_fixed_bv(b: &mut Bencher) { 36 | let mut r = rng(); 37 | let mut bit_vec = BitVec::from_elem(BENCH_BITS, false); 38 | b.iter(|| { 39 | for _ in 0..100 { 40 | bit_vec.set((r.next_u64() as usize) % BENCH_BITS, true); 41 | } 42 | black_box(&bit_vec); 43 | }); 44 | } 45 | 46 | #[bench] 47 | fn bench_bit_set_big_fixed_sbv(b: &mut Bencher) { 48 | let mut r = rng(); 49 | let mut bit_vec = SmallBitVec::from_elem(BENCH_BITS, false); 50 | b.iter(|| { 51 | for _ in 0..100 { 52 | bit_vec.set(r.next_u64() as usize % BENCH_BITS, true); 53 | } 54 | black_box(&bit_vec); 55 | }); 56 | } 57 | 58 | #[bench] 59 | fn bench_big_set_big_variable_bv(b: &mut Bencher) { 60 | let mut r = rng(); 61 | let mut bit_vec = BitVec::from_elem(BENCH_BITS, false); 62 | b.iter(|| { 63 | for _ in 0..100 { 64 | bit_vec.set((r.next_u64() as usize) % BENCH_BITS, r.gen()); 65 | } 66 | black_box(&bit_vec); 67 | }); 68 | } 69 | 70 | #[bench] 71 | fn bench_bit_set_big_variable_sbv(b: &mut Bencher) { 72 | let mut r = rng(); 73 | let mut bit_vec = SmallBitVec::from_elem(BENCH_BITS, false); 74 | b.iter(|| { 75 | for _ in 0..100 { 76 | bit_vec.set(r.next_u64() as usize % BENCH_BITS, r.gen()); 77 | } 78 | black_box(&bit_vec); 79 | }); 80 | } 81 | 82 | #[bench] 83 | fn bench_bit_set_small_bv(b: &mut Bencher) { 84 | let mut r = rng(); 85 | let mut bit_vec = BitVec::from_elem(USIZE_BITS, false); 86 | b.iter(|| { 87 | for _ in 0..100 { 88 | bit_vec.set((r.next_u64() as usize) % USIZE_BITS, true); 89 | } 90 | black_box(&bit_vec); 91 | }); 92 | } 93 | 94 | #[bench] 95 | fn bench_bit_set_small_sbv(b: &mut Bencher) { 96 | let mut r = rng(); 97 | let mut bit_vec = SmallBitVec::from_elem(USIZE_BITS, false); 98 | b.iter(|| { 99 | for _ in 0..100 { 100 | bit_vec.set(r.next_u64() as usize % USIZE_BITS, true); 101 | } 102 | black_box(&bit_vec); 103 | }); 104 | } 105 | 106 | #[bench] 107 | fn bench_bit_vec_small_eq_bv(b: &mut Bencher) { 108 | let x = BitVec::from_elem(USIZE_BITS, false); 109 | let y = BitVec::from_elem(USIZE_BITS, false); 110 | b.iter(|| x == y); 111 | } 112 | 113 | #[bench] 114 | fn bench_bit_vec_small_eq_sbv(b: &mut Bencher) { 115 | let x = SmallBitVec::from_elem(USIZE_BITS, false); 116 | let y = SmallBitVec::from_elem(USIZE_BITS, false); 117 | b.iter(|| x == y); 118 | } 119 | 120 | #[bench] 121 | fn bench_bit_vec_big_eq_bv(b: &mut Bencher) { 122 | let x = BitVec::from_elem(BENCH_BITS, false); 123 | let y = BitVec::from_elem(BENCH_BITS, false); 124 | b.iter(|| x == y); 125 | } 126 | 127 | #[bench] 128 | fn bench_bit_vec_big_eq_sbv(b: &mut Bencher) { 129 | let x = SmallBitVec::from_elem(BENCH_BITS, false); 130 | let y = SmallBitVec::from_elem(BENCH_BITS, false); 131 | b.iter(|| x == y); 132 | } 133 | 134 | #[bench] 135 | fn bench_bit_vec_small_iter_bv(b: &mut Bencher) { 136 | let bit_vec = BitVec::from_elem(USIZE_BITS, false); 137 | b.iter(|| { 138 | let mut sum = 0; 139 | for _ in 0..10 { 140 | for pres in &bit_vec { 141 | sum += pres as usize; 142 | } 143 | } 144 | sum 145 | }) 146 | } 147 | 148 | #[bench] 149 | fn bench_bit_vec_small_iter_sbv(b: &mut Bencher) { 150 | let bit_vec = SmallBitVec::from_elem(USIZE_BITS, false); 151 | b.iter(|| { 152 | let mut sum = 0; 153 | for _ in 0..10 { 154 | for pres in &bit_vec { 155 | sum += pres as usize; 156 | } 157 | } 158 | sum 159 | }) 160 | } 161 | 162 | #[bench] 163 | fn bench_bit_vec_big_iter_bv(b: &mut Bencher) { 164 | let bit_vec = BitVec::from_elem(BENCH_BITS, false); 165 | b.iter(|| { 166 | let mut sum = 0; 167 | for pres in &bit_vec { 168 | sum += pres as usize; 169 | } 170 | sum 171 | }) 172 | } 173 | 174 | #[bench] 175 | fn bench_bit_vec_big_iter_sbv(b: &mut Bencher) { 176 | let bit_vec = SmallBitVec::from_elem(BENCH_BITS, false); 177 | b.iter(|| { 178 | let mut sum = 0; 179 | for pres in &bit_vec { 180 | sum += pres as usize; 181 | } 182 | sum 183 | }) 184 | } 185 | 186 | #[bench] 187 | fn bench_from_elem_bv(b: &mut Bencher) { 188 | let cap = black_box(BENCH_BITS); 189 | let bit = black_box(true); 190 | b.iter(|| BitVec::from_elem(cap, bit)); 191 | b.bytes = cap as u64 / 8; 192 | } 193 | 194 | #[bench] 195 | fn bench_from_elem_sbv(b: &mut Bencher) { 196 | let cap = black_box(BENCH_BITS); 197 | let bit = black_box(true); 198 | b.iter(|| SmallBitVec::from_elem(cap, bit)); 199 | b.bytes = cap as u64 / 8; 200 | } 201 | 202 | #[bench] 203 | fn bench_remove_small(b: &mut Bencher) { 204 | b.iter(|| { 205 | let mut v = SmallBitVec::from_elem(USIZE_BITS, false); 206 | for _ in 0..USIZE_BITS { 207 | v.remove(0); 208 | } 209 | }); 210 | } 211 | 212 | #[bench] 213 | fn bench_remove_big(b: &mut Bencher) { 214 | b.iter(|| { 215 | let mut v = SmallBitVec::from_elem(BENCH_BITS, false); 216 | for _ in 0..200 { 217 | v.remove(0); 218 | } 219 | }); 220 | } 221 | 222 | #[bench] 223 | fn bench_hash_small(b: &mut Bencher) { 224 | let mut hasher = std::collections::hash_map::DefaultHasher::new(); 225 | let v = SmallBitVec::from_elem(USIZE_BITS, false); 226 | b.iter(|| { 227 | v.hash(&mut hasher); 228 | }); 229 | black_box(hasher.finish()); 230 | } 231 | 232 | #[bench] 233 | fn bench_hash_big(b: &mut Bencher) { 234 | let mut hasher = std::collections::hash_map::DefaultHasher::new(); 235 | let v = SmallBitVec::from_elem(BENCH_BITS, false); 236 | b.iter(|| { 237 | v.hash(&mut hasher); 238 | }); 239 | black_box(hasher.finish()); 240 | } 241 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Matt Brubeck. See the COPYRIGHT file at the top-level 2 | // directory of this distribution and at http://rust-lang.org/COPYRIGHT. 3 | // 4 | // Licensed under the Apache License, Version 2.0 or the MIT license 6 | // , at your 7 | // option. This file may not be copied, modified, or distributed 8 | // except according to those terms. 9 | 10 | //! [`SmallBitVec`] is a bit vector, a vector of single-bit values stored compactly in memory. 11 | //! 12 | //! SmallBitVec grows dynamically, like the standard `Vec` type. It can hold up to about one 13 | //! word of bits inline (without a separate heap allocation). If the number of bits exceeds this 14 | //! inline capacity, it will allocate a buffer on the heap. 15 | //! 16 | //! [`SmallBitVec`]: struct.SmallBitVec.html 17 | //! 18 | //! # Example 19 | //! 20 | //! ``` 21 | //! use smallbitvec::SmallBitVec; 22 | //! 23 | //! let mut v = SmallBitVec::new(); 24 | //! v.push(true); 25 | //! v.push(false); 26 | //! 27 | //! assert_eq!(v[0], true); 28 | //! assert_eq!(v[1], false); 29 | //! ``` 30 | 31 | #![no_std] 32 | 33 | extern crate alloc; 34 | 35 | use alloc::{boxed::Box, vec, vec::Vec}; 36 | 37 | use core::cmp::max; 38 | use core::fmt; 39 | use core::hash; 40 | use core::mem::{forget, replace, size_of}; 41 | use core::ops::{Index, Range}; 42 | use core::slice; 43 | 44 | /// Creates a [`SmallBitVec`] containing the arguments. 45 | /// 46 | /// `sbvec!` allows `SmallBitVec`s to be defined with the same syntax as array expressions. 47 | /// There are two forms of this macro: 48 | /// 49 | /// - Create a [`SmallBitVec`] containing a given list of elements: 50 | /// 51 | /// ``` 52 | /// # #[macro_use] extern crate smallbitvec; 53 | /// # use smallbitvec::SmallBitVec; 54 | /// # fn main() { 55 | /// let v = sbvec![true, false, true]; 56 | /// assert_eq!(v[0], true); 57 | /// assert_eq!(v[1], false); 58 | /// assert_eq!(v[2], true); 59 | /// # } 60 | /// ``` 61 | /// 62 | /// - Create a [`SmallBitVec`] from a given element and size: 63 | /// 64 | /// ``` 65 | /// # #[macro_use] extern crate smallbitvec; 66 | /// # use smallbitvec::SmallBitVec; 67 | /// # fn main() { 68 | /// let v = sbvec![true; 3]; 69 | /// assert!(v.into_iter().eq(vec![true, true, true].into_iter())); 70 | /// # } 71 | /// ``` 72 | 73 | #[macro_export] 74 | macro_rules! sbvec { 75 | ($elem:expr; $n:expr) => ( 76 | $crate::SmallBitVec::from_elem($n, $elem) 77 | ); 78 | ($($x:expr),*) => ( 79 | [$($x),*].iter().cloned().collect::<$crate::SmallBitVec>() 80 | ); 81 | ($($x:expr,)*) => ( 82 | sbvec![$($x),*] 83 | ); 84 | } 85 | 86 | // FIXME: replace this with `debug_assert!` when it’s usable in `const`: 87 | // * https://github.com/rust-lang/rust/issues/49146 88 | // * https://github.com/rust-lang/rust/issues/51999 89 | macro_rules! const_debug_assert_le { 90 | ($left: ident <= $right: expr) => { 91 | #[cfg(debug_assertions)] 92 | // Causes an `index out of bounds` panic if `$left` is too large 93 | [(); $right + 1][$left]; 94 | }; 95 | } 96 | 97 | #[cfg(test)] 98 | mod tests; 99 | 100 | /// A resizable bit vector, optimized for size and inline storage. 101 | /// 102 | /// `SmallBitVec` is exactly one word wide. Depending on the required capacity, this word 103 | /// either stores the bits inline, or it stores a pointer to a separate buffer on the heap. 104 | pub struct SmallBitVec { 105 | data: usize, 106 | } 107 | 108 | /// Total number of bits per word. 109 | #[inline(always)] 110 | const fn inline_bits() -> usize { 111 | size_of::() * 8 112 | } 113 | 114 | /// For an inline vector, all bits except two can be used as storage capacity: 115 | /// 116 | /// - The rightmost bit is set to zero to signal an inline vector. 117 | /// - The position of the rightmost nonzero bit encodes the length. 118 | #[inline(always)] 119 | const fn inline_capacity() -> usize { 120 | inline_bits() - 2 121 | } 122 | 123 | /// Left shift amount to access the nth bit 124 | #[inline(always)] 125 | const fn inline_shift(n: usize) -> usize { 126 | const_debug_assert_le!(n <= inline_capacity()); 127 | // The storage starts at the leftmost bit. 128 | inline_bits() - 1 - n 129 | } 130 | 131 | /// An inline vector with the nth bit set. 132 | #[inline(always)] 133 | const fn inline_index(n: usize) -> usize { 134 | 1 << inline_shift(n) 135 | } 136 | 137 | /// An inline vector with the leftmost `n` bits set. 138 | #[inline(always)] 139 | fn inline_ones(n: usize) -> usize { 140 | if n == 0 { 141 | 0 142 | } else { 143 | !0 << (inline_bits() - n) 144 | } 145 | } 146 | 147 | /// If the rightmost bit of `data` is set, then the remaining bits of `data` 148 | /// are a pointer to a heap allocation. 149 | const HEAP_FLAG: usize = 1; 150 | 151 | /// The allocation will contain a `Header` followed by a [Storage] buffer. 152 | type Storage = usize; 153 | 154 | /// The number of bits in one `Storage`. 155 | #[inline(always)] 156 | fn bits_per_storage() -> usize { 157 | size_of::() * 8 158 | } 159 | 160 | /// Data stored at the start of the heap allocation. 161 | /// 162 | /// `Header` must have the same alignment as `Storage`. 163 | struct Header { 164 | /// The number of bits in this bit vector. 165 | len: Storage, 166 | 167 | /// The number of elements in the [usize] buffer that follows this header. 168 | buffer_len: Storage, 169 | } 170 | 171 | impl Header { 172 | /// Create a heap allocation with enough space for a header, 173 | /// plus a buffer of at least `cap` bits, each initialized to `val`. 174 | fn new(cap: usize, len: usize, val: bool) -> *mut Header { 175 | let alloc_len = header_len() + buffer_len(cap); 176 | let init = if val { !0 } else { 0 }; 177 | 178 | let v: Vec = vec![init; alloc_len]; 179 | 180 | let buffer_len = v.capacity() - header_len(); 181 | let header_ptr = v.as_ptr() as *mut Header; 182 | 183 | forget(v); 184 | 185 | unsafe { 186 | (*header_ptr).len = len; 187 | (*header_ptr).buffer_len = buffer_len; 188 | } 189 | header_ptr 190 | } 191 | } 192 | 193 | /// The number of `Storage` elements to allocate to hold a header. 194 | #[inline(always)] 195 | fn header_len() -> usize { 196 | size_of::
() / size_of::() 197 | } 198 | 199 | /// The minimum number of `Storage` elements to hold at least `cap` bits. 200 | #[inline(always)] 201 | fn buffer_len(cap: usize) -> usize { 202 | (cap + bits_per_storage() - 1) / bits_per_storage() 203 | } 204 | 205 | /// A typed representation of a `SmallBitVec`'s internal storage. 206 | /// 207 | /// The layout of the data inside both enum variants is a private implementation detail. 208 | pub enum InternalStorage { 209 | /// The internal representation of a `SmallBitVec` that has not spilled to a 210 | /// heap allocation. 211 | Inline(usize), 212 | 213 | /// The contents of the heap allocation of a spilled `SmallBitVec`. 214 | Spilled(Box<[usize]>), 215 | } 216 | 217 | impl SmallBitVec { 218 | /// Create an empty vector. 219 | #[inline] 220 | pub const fn new() -> SmallBitVec { 221 | SmallBitVec { 222 | data: inline_index(0), 223 | } 224 | } 225 | 226 | /// Create a vector containing `len` bits, each set to `val`. 227 | #[inline] 228 | pub fn from_elem(len: usize, val: bool) -> SmallBitVec { 229 | if len <= inline_capacity() { 230 | return SmallBitVec { 231 | data: if val { 232 | inline_ones(len + 1) 233 | } else { 234 | inline_index(len) 235 | }, 236 | }; 237 | } 238 | let header_ptr = Header::new(len, len, val); 239 | SmallBitVec { 240 | data: (header_ptr as usize) | HEAP_FLAG, 241 | } 242 | } 243 | 244 | /// Create an empty vector with enough storage pre-allocated to store at least `cap` bits 245 | /// without resizing. 246 | #[inline] 247 | pub fn with_capacity(cap: usize) -> SmallBitVec { 248 | // Use inline storage if possible. 249 | if cap <= inline_capacity() { 250 | return SmallBitVec::new(); 251 | } 252 | 253 | // Otherwise, allocate on the heap. 254 | let header_ptr = Header::new(cap, 0, false); 255 | SmallBitVec { 256 | data: (header_ptr as usize) | HEAP_FLAG, 257 | } 258 | } 259 | 260 | /// The number of bits stored in this bit vector. 261 | #[inline] 262 | pub fn len(&self) -> usize { 263 | if self.is_inline() { 264 | // The rightmost nonzero bit is a sentinel. All bits to the left of 265 | // the sentinel bit are the elements of the bit vector. 266 | inline_bits() - self.data.trailing_zeros() as usize - 1 267 | } else { 268 | self.header().len 269 | } 270 | } 271 | 272 | /// Returns `true` if this vector contains no bits. 273 | #[inline] 274 | pub fn is_empty(&self) -> bool { 275 | self.len() == 0 276 | } 277 | 278 | /// The number of bits that can be stored in this bit vector without re-allocating. 279 | #[inline] 280 | pub fn capacity(&self) -> usize { 281 | if self.is_inline() { 282 | inline_capacity() 283 | } else { 284 | self.header().buffer_len * bits_per_storage() 285 | } 286 | } 287 | 288 | /// Get the nth bit in this bit vector. 289 | #[inline] 290 | pub fn get(&self, n: usize) -> Option { 291 | if n < self.len() { 292 | Some(unsafe { self.get_unchecked(n) }) 293 | } else { 294 | None 295 | } 296 | } 297 | 298 | /// Get the last bit in this bit vector. 299 | #[inline] 300 | pub fn last(&self) -> Option { 301 | self.len() 302 | .checked_sub(1) 303 | .map(|n| unsafe { self.get_unchecked(n) }) 304 | } 305 | 306 | /// Get the nth bit in this bit vector, without bounds checks. 307 | #[inline] 308 | pub unsafe fn get_unchecked(&self, n: usize) -> bool { 309 | if self.is_inline() { 310 | self.data & inline_index(n) != 0 311 | } else { 312 | let buffer = self.buffer(); 313 | let i = n / bits_per_storage(); 314 | let offset = n % bits_per_storage(); 315 | *buffer.get_unchecked(i) & (1 << offset) != 0 316 | } 317 | } 318 | 319 | /// Set the nth bit in this bit vector to `val`. Panics if the index is out of bounds. 320 | #[inline] 321 | pub fn set(&mut self, n: usize, val: bool) { 322 | assert!(n < self.len(), "Index {} out of bounds", n); 323 | unsafe { 324 | self.set_unchecked(n, val); 325 | } 326 | } 327 | 328 | /// Set the nth bit in this bit vector to `val`, without bounds checks. 329 | #[inline] 330 | pub unsafe fn set_unchecked(&mut self, n: usize, val: bool) { 331 | if self.is_inline() { 332 | if val { 333 | self.data |= inline_index(n); 334 | } else { 335 | self.data &= !inline_index(n); 336 | } 337 | } else { 338 | let buffer = self.buffer_mut(); 339 | let i = n / bits_per_storage(); 340 | let offset = n % bits_per_storage(); 341 | if val { 342 | *buffer.get_unchecked_mut(i) |= 1 << offset; 343 | } else { 344 | *buffer.get_unchecked_mut(i) &= !(1 << offset); 345 | } 346 | } 347 | } 348 | 349 | /// Append a bit to the end of the vector. 350 | /// 351 | /// ``` 352 | /// use smallbitvec::SmallBitVec; 353 | /// let mut v = SmallBitVec::new(); 354 | /// v.push(true); 355 | /// 356 | /// assert_eq!(v.len(), 1); 357 | /// assert_eq!(v.get(0), Some(true)); 358 | /// ``` 359 | #[inline] 360 | pub fn push(&mut self, val: bool) { 361 | let idx = self.len(); 362 | if idx == self.capacity() { 363 | self.reserve(1); 364 | } 365 | unsafe { 366 | self.set_len(idx + 1); 367 | self.set_unchecked(idx, val); 368 | } 369 | } 370 | 371 | /// Remove the last bit from the vector and return it, if there is one. 372 | /// 373 | /// ``` 374 | /// use smallbitvec::SmallBitVec; 375 | /// let mut v = SmallBitVec::new(); 376 | /// v.push(false); 377 | /// 378 | /// assert_eq!(v.pop(), Some(false)); 379 | /// assert_eq!(v.len(), 0); 380 | /// assert_eq!(v.pop(), None); 381 | /// ``` 382 | #[inline] 383 | pub fn pop(&mut self) -> Option { 384 | self.len().checked_sub(1).map(|last| unsafe { 385 | let val = self.get_unchecked(last); 386 | self.set_len(last); 387 | val 388 | }) 389 | } 390 | 391 | /// Remove and return the bit at index `idx`, shifting all later bits toward the front. 392 | /// 393 | /// Panics if the index is out of bounds. 394 | #[inline] 395 | pub fn remove(&mut self, idx: usize) -> bool { 396 | let len = self.len(); 397 | let val = self[idx]; 398 | 399 | if self.is_inline() { 400 | // Shift later bits, including the length bit, toward the front. 401 | let mask = !inline_ones(idx); 402 | let new_vals = (self.data & mask) << 1; 403 | self.data = (self.data & !mask) | (new_vals & mask); 404 | } else { 405 | let first = idx / bits_per_storage(); 406 | let offset = idx % bits_per_storage(); 407 | let count = buffer_len(len); 408 | { 409 | // Shift bits within the first storage block. 410 | let buf = self.buffer_mut(); 411 | let mask = !0 << offset; 412 | let new_vals = (buf[first] & mask) >> 1; 413 | buf[first] = (buf[first] & !mask) | (new_vals & mask); 414 | } 415 | // Shift bits in subsequent storage blocks. 416 | for i in (first + 1)..count { 417 | // Move the first bit into the previous block. 418 | let bit_idx = i * bits_per_storage(); 419 | unsafe { 420 | let first_bit = self.get_unchecked(bit_idx); 421 | self.set_unchecked(bit_idx - 1, first_bit); 422 | } 423 | // Shift the remaining bits. 424 | self.buffer_mut()[i] >>= 1; 425 | } 426 | // Decrement the length. 427 | unsafe { 428 | self.set_len(len - 1); 429 | } 430 | } 431 | val 432 | } 433 | 434 | /// Remove all elements from the vector, without deallocating its buffer. 435 | #[inline] 436 | pub fn clear(&mut self) { 437 | unsafe { 438 | self.set_len(0); 439 | } 440 | } 441 | 442 | /// Reserve capacity for at least `additional` more elements to be inserted. 443 | /// 444 | /// May reserve more space than requested, to avoid frequent reallocations. 445 | /// 446 | /// Panics if the new capacity overflows `usize`. 447 | /// 448 | /// Re-allocates only if `self.capacity() < self.len() + additional`. 449 | #[inline] 450 | pub fn reserve(&mut self, additional: usize) { 451 | let old_cap = self.capacity(); 452 | let new_cap = self 453 | .len() 454 | .checked_add(additional) 455 | .expect("capacity overflow"); 456 | if new_cap <= old_cap { 457 | return; 458 | } 459 | // Ensure the new capacity is at least double, to guarantee exponential growth. 460 | let double_cap = old_cap.saturating_mul(2); 461 | self.reallocate(max(new_cap, double_cap)); 462 | } 463 | 464 | /// Set the length of the vector. The length must not exceed the capacity. 465 | /// 466 | /// If this makes the vector longer, then the values of its new elements 467 | /// are not specified. 468 | #[inline] 469 | unsafe fn set_len(&mut self, len: usize) { 470 | debug_assert!(len <= self.capacity()); 471 | if self.is_inline() { 472 | let sentinel = inline_index(len); 473 | let mask = !(sentinel - 1); 474 | self.data |= sentinel; 475 | self.data &= mask; 476 | } else { 477 | self.header_mut().len = len; 478 | } 479 | } 480 | 481 | /// Returns an iterator that yields the bits of the vector in order, as `bool` values. 482 | #[inline] 483 | pub fn iter(&self) -> Iter { 484 | Iter { 485 | vec: self, 486 | range: 0..self.len(), 487 | } 488 | } 489 | 490 | /// Returns an immutable view of a range of bits from this vec. 491 | /// ``` 492 | /// #[macro_use] extern crate smallbitvec; 493 | /// let v = sbvec![true, false, true]; 494 | /// let r = v.range(1..3); 495 | /// assert_eq!(r[1], true); 496 | /// ``` 497 | #[inline] 498 | pub fn range(&self, range: Range) -> VecRange { 499 | assert!(range.end <= self.len(), "range out of bounds"); 500 | VecRange { vec: &self, range } 501 | } 502 | 503 | /// Returns true if all the bits in the vec are set to zero/false. 504 | /// 505 | /// On an empty vector, returns true. 506 | #[inline] 507 | pub fn all_false(&self) -> bool { 508 | let mut len = self.len(); 509 | if len == 0 { 510 | return true; 511 | } 512 | 513 | if self.is_inline() { 514 | let mask = inline_ones(len); 515 | self.data & mask == 0 516 | } else { 517 | for &storage in self.buffer() { 518 | if len >= bits_per_storage() { 519 | if storage != 0 { 520 | return false; 521 | } 522 | len -= bits_per_storage(); 523 | } else { 524 | let mask = (1 << len) - 1; 525 | if storage & mask != 0 { 526 | return false; 527 | } 528 | break; 529 | } 530 | } 531 | true 532 | } 533 | } 534 | 535 | /// Returns true if all the bits in the vec are set to one/true. 536 | /// 537 | /// On an empty vector, returns true. 538 | #[inline] 539 | pub fn all_true(&self) -> bool { 540 | let mut len = self.len(); 541 | if len == 0 { 542 | return true; 543 | } 544 | 545 | if self.is_inline() { 546 | let mask = inline_ones(len); 547 | self.data & mask == mask 548 | } else { 549 | for &storage in self.buffer() { 550 | if len >= bits_per_storage() { 551 | if storage != !0 { 552 | return false; 553 | } 554 | len -= bits_per_storage(); 555 | } else { 556 | let mask = (1 << len) - 1; 557 | if storage & mask != mask { 558 | return false; 559 | } 560 | break; 561 | } 562 | } 563 | true 564 | } 565 | } 566 | 567 | /// Shorten the vector, keeping the first `len` elements and dropping the rest. 568 | /// 569 | /// If `len` is greater than or equal to the vector's current length, this has no 570 | /// effect. 571 | /// 572 | /// This does not re-allocate. 573 | pub fn truncate(&mut self, len: usize) { 574 | unsafe { 575 | if len < self.len() { 576 | self.set_len(len); 577 | } 578 | } 579 | } 580 | 581 | /// Resizes the vector so that its length is equal to `len`. 582 | /// 583 | /// If `len` is less than the current length, the vector simply truncated. 584 | /// 585 | /// If `len` is greater than the current length, `value` is appended to the 586 | /// vector until its length equals `len`. 587 | pub fn resize(&mut self, len: usize, value: bool) { 588 | let old_len = self.len(); 589 | 590 | if len > old_len { 591 | unsafe { 592 | self.reallocate(len); 593 | self.set_len(len); 594 | for i in old_len..len { 595 | self.set(i, value); 596 | } 597 | } 598 | } else { 599 | self.truncate(len); 600 | } 601 | } 602 | 603 | /// Resize the vector to have capacity for at least `cap` bits. 604 | /// 605 | /// `cap` must be at least as large as the length of the vector. 606 | fn reallocate(&mut self, cap: usize) { 607 | let old_cap = self.capacity(); 608 | if cap <= old_cap { 609 | return; 610 | } 611 | assert!(self.len() <= cap); 612 | 613 | if self.is_heap() { 614 | let old_buffer_len = self.header().buffer_len; 615 | let new_buffer_len = buffer_len(cap); 616 | 617 | let old_alloc_len = header_len() + old_buffer_len; 618 | let new_alloc_len = header_len() + new_buffer_len; 619 | 620 | let old_ptr = self.header_raw() as *mut Storage; 621 | let mut v = unsafe { Vec::from_raw_parts(old_ptr, old_alloc_len, old_alloc_len) }; 622 | v.resize(new_alloc_len, 0); 623 | v.shrink_to_fit(); 624 | self.data = v.as_ptr() as usize | HEAP_FLAG; 625 | forget(v); 626 | 627 | self.header_mut().buffer_len = new_buffer_len; 628 | } else { 629 | let old_self = replace(self, SmallBitVec::with_capacity(cap)); 630 | unsafe { 631 | self.set_len(old_self.len()); 632 | for i in 0..old_self.len() { 633 | self.set_unchecked(i, old_self.get_unchecked(i)); 634 | } 635 | } 636 | } 637 | } 638 | 639 | /// If the vector owns a heap allocation, returns a pointer to the start of the allocation. 640 | /// 641 | /// The layout of the data at this allocation is a private implementation detail. 642 | #[inline] 643 | pub fn heap_ptr(&self) -> Option<*const usize> { 644 | if self.is_heap() { 645 | Some((self.data & !HEAP_FLAG) as *const Storage) 646 | } else { 647 | None 648 | } 649 | } 650 | 651 | /// Converts this `SmallBitVec` into its internal representation. 652 | /// 653 | /// The layout of the data inside both enum variants is a private implementation detail. 654 | #[inline] 655 | pub fn into_storage(self) -> InternalStorage { 656 | if self.is_heap() { 657 | let alloc_len = header_len() + self.header().buffer_len; 658 | let ptr = self.header_raw() as *mut Storage; 659 | let slice = unsafe { Box::from_raw(slice::from_raw_parts_mut(ptr, alloc_len)) }; 660 | forget(self); 661 | InternalStorage::Spilled(slice) 662 | } else { 663 | InternalStorage::Inline(self.data) 664 | } 665 | } 666 | 667 | /// Creates a `SmallBitVec` directly from the internal storage of another 668 | /// `SmallBitVec`. 669 | /// 670 | /// # Safety 671 | /// 672 | /// This is highly unsafe. `storage` needs to have been previously generated 673 | /// via `SmallBitVec::into_storage` (at least, it's highly likely to be 674 | /// incorrect if it wasn't.) Violating this may cause problems like corrupting the 675 | /// allocator's internal data structures. 676 | /// 677 | /// # Examples 678 | /// 679 | /// ``` 680 | /// # use smallbitvec::{InternalStorage, SmallBitVec}; 681 | /// 682 | /// fn main() { 683 | /// let v = SmallBitVec::from_elem(200, false); 684 | /// 685 | /// // Get the internal representation of the SmallBitVec. 686 | /// // unless we transfer its ownership somewhere else. 687 | /// let storage = v.into_storage(); 688 | /// 689 | /// /// Make a copy of the SmallBitVec's data. 690 | /// let cloned_storage = match storage { 691 | /// InternalStorage::Spilled(vs) => InternalStorage::Spilled(vs.clone()), 692 | /// inline => inline, 693 | /// }; 694 | /// 695 | /// /// Create a new SmallBitVec from the coped storage. 696 | /// let v = unsafe { SmallBitVec::from_storage(cloned_storage) }; 697 | /// } 698 | /// ``` 699 | pub unsafe fn from_storage(storage: InternalStorage) -> SmallBitVec { 700 | match storage { 701 | InternalStorage::Inline(data) => SmallBitVec { data }, 702 | InternalStorage::Spilled(vs) => { 703 | let ptr = Box::into_raw(vs); 704 | SmallBitVec { 705 | data: (ptr as *mut usize as usize) | HEAP_FLAG, 706 | } 707 | } 708 | } 709 | } 710 | 711 | /// If the rightmost bit is unset, then we treat it as inline storage. 712 | #[inline] 713 | fn is_inline(&self) -> bool { 714 | self.data & HEAP_FLAG == 0 715 | } 716 | 717 | /// Otherwise, `data` is a pointer to a heap allocation. 718 | #[inline] 719 | fn is_heap(&self) -> bool { 720 | !self.is_inline() 721 | } 722 | 723 | /// Get the header of a heap-allocated vector. 724 | #[inline] 725 | fn header_raw(&self) -> *mut Header { 726 | assert!(self.is_heap()); 727 | (self.data & !HEAP_FLAG) as *mut Header 728 | } 729 | 730 | #[inline] 731 | fn header_mut(&mut self) -> &mut Header { 732 | unsafe { &mut *self.header_raw() } 733 | } 734 | 735 | #[inline] 736 | fn header(&self) -> &Header { 737 | unsafe { &*self.header_raw() } 738 | } 739 | 740 | /// Get the buffer of a heap-allocated vector. 741 | #[inline] 742 | fn buffer_raw(&self) -> *mut [Storage] { 743 | unsafe { 744 | let header_ptr = self.header_raw(); 745 | let buffer_len = (*header_ptr).buffer_len; 746 | let buffer_ptr = (header_ptr as *mut Storage) 747 | .offset((size_of::
() / size_of::()) as isize); 748 | slice::from_raw_parts_mut(buffer_ptr, buffer_len) 749 | } 750 | } 751 | 752 | #[inline] 753 | fn buffer_mut(&mut self) -> &mut [Storage] { 754 | unsafe { &mut *self.buffer_raw() } 755 | } 756 | 757 | #[inline] 758 | fn buffer(&self) -> &[Storage] { 759 | unsafe { &*self.buffer_raw() } 760 | } 761 | } 762 | 763 | // Trait implementations: 764 | 765 | impl fmt::Debug for SmallBitVec { 766 | #[inline] 767 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 768 | fmt.debug_list() 769 | .entries(self.iter().map(|b| b as u8)) 770 | .finish() 771 | } 772 | } 773 | 774 | impl Default for SmallBitVec { 775 | #[inline] 776 | fn default() -> Self { 777 | Self::new() 778 | } 779 | } 780 | 781 | impl PartialEq for SmallBitVec { 782 | fn eq(&self, other: &Self) -> bool { 783 | // Compare by inline representation 784 | if self.is_inline() && other.is_inline() { 785 | return self.data == other.data; 786 | } 787 | 788 | let len = self.len(); 789 | if len != other.len() { 790 | return false; 791 | } 792 | 793 | // Compare by heap representation 794 | if self.is_heap() && other.is_heap() { 795 | let buf0 = self.buffer(); 796 | let buf1 = other.buffer(); 797 | 798 | let full_blocks = len / bits_per_storage(); 799 | let remainder = len % bits_per_storage(); 800 | 801 | if buf0[..full_blocks] != buf1[..full_blocks] { 802 | return false; 803 | } 804 | 805 | if remainder != 0 { 806 | let mask = (1 << remainder) - 1; 807 | if buf0[full_blocks] & mask != buf1[full_blocks] & mask { 808 | return false; 809 | } 810 | } 811 | return true; 812 | } 813 | 814 | // Representations differ; fall back to bit-by-bit comparison 815 | Iterator::eq(self.iter(), other.iter()) 816 | } 817 | } 818 | 819 | impl Eq for SmallBitVec {} 820 | 821 | impl Drop for SmallBitVec { 822 | fn drop(&mut self) { 823 | if self.is_heap() { 824 | unsafe { 825 | let header_ptr = self.header_raw(); 826 | let alloc_ptr = header_ptr as *mut Storage; 827 | let alloc_len = header_len() + (*header_ptr).buffer_len; 828 | Vec::from_raw_parts(alloc_ptr, alloc_len, alloc_len); 829 | } 830 | } 831 | } 832 | } 833 | 834 | impl Clone for SmallBitVec { 835 | fn clone(&self) -> Self { 836 | if self.is_inline() { 837 | return SmallBitVec { data: self.data }; 838 | } 839 | 840 | let buffer_len = self.header().buffer_len; 841 | let alloc_len = header_len() + buffer_len; 842 | let ptr = self.header_raw() as *mut Storage; 843 | let raw_allocation = unsafe { slice::from_raw_parts(ptr, alloc_len) }; 844 | 845 | let v = raw_allocation.to_vec(); 846 | let header_ptr = v.as_ptr() as *mut Header; 847 | forget(v); 848 | SmallBitVec { 849 | data: (header_ptr as usize) | HEAP_FLAG, 850 | } 851 | } 852 | } 853 | 854 | impl Index for SmallBitVec { 855 | type Output = bool; 856 | 857 | #[inline(always)] 858 | fn index(&self, i: usize) -> &bool { 859 | assert!(i < self.len(), "index out of range"); 860 | if self.get(i).unwrap() { 861 | &true 862 | } else { 863 | &false 864 | } 865 | } 866 | } 867 | 868 | #[cfg(feature = "malloc_size_of")] 869 | impl malloc_size_of::MallocSizeOf for SmallBitVec { 870 | fn size_of(&self, ops: &mut malloc_size_of::MallocSizeOfOps) -> usize { 871 | if let Some(ptr) = self.heap_ptr() { 872 | unsafe { ops.malloc_size_of(ptr) } 873 | } else { 874 | 0 875 | } 876 | } 877 | } 878 | 879 | impl hash::Hash for SmallBitVec { 880 | #[inline] 881 | fn hash(&self, state: &mut H) { 882 | let len = self.len(); 883 | len.hash(state); 884 | if self.is_inline() { 885 | (self.data & inline_ones(len)).reverse_bits().hash(state); 886 | } else { 887 | let full_blocks = len / bits_per_storage(); 888 | let remainder = len % bits_per_storage(); 889 | let buffer = self.buffer(); 890 | if full_blocks != 0 { 891 | buffer[..full_blocks].hash(state); 892 | } 893 | if remainder != 0 { 894 | let mask = (1 << remainder) - 1; 895 | (buffer[full_blocks] & mask).hash(state); 896 | } 897 | } 898 | } 899 | } 900 | 901 | impl Extend for SmallBitVec { 902 | #[inline] 903 | fn extend>(&mut self, iter: I) { 904 | let iter = iter.into_iter(); 905 | 906 | let (min, _) = iter.size_hint(); 907 | assert!(min <= usize::max_value(), "capacity overflow"); 908 | self.reserve(min); 909 | 910 | for element in iter { 911 | self.push(element) 912 | } 913 | } 914 | } 915 | 916 | impl FromIterator for SmallBitVec { 917 | #[inline] 918 | fn from_iter>(iter: I) -> Self { 919 | let mut v = SmallBitVec::new(); 920 | v.extend(iter); 921 | v 922 | } 923 | } 924 | 925 | impl IntoIterator for SmallBitVec { 926 | type Item = bool; 927 | type IntoIter = IntoIter; 928 | 929 | #[inline] 930 | fn into_iter(self) -> IntoIter { 931 | IntoIter { 932 | range: 0..self.len(), 933 | vec: self, 934 | } 935 | } 936 | } 937 | 938 | impl<'a> IntoIterator for &'a SmallBitVec { 939 | type Item = bool; 940 | type IntoIter = Iter<'a>; 941 | 942 | #[inline] 943 | fn into_iter(self) -> Iter<'a> { 944 | self.iter() 945 | } 946 | } 947 | 948 | /// An iterator that owns a SmallBitVec and yields its bits as `bool` values. 949 | /// 950 | /// Returned from [`SmallBitVec::into_iter`][1]. 951 | /// 952 | /// [1]: struct.SmallBitVec.html#method.into_iter 953 | pub struct IntoIter { 954 | vec: SmallBitVec, 955 | range: Range, 956 | } 957 | 958 | impl Iterator for IntoIter { 959 | type Item = bool; 960 | 961 | #[inline] 962 | fn next(&mut self) -> Option { 963 | self.range 964 | .next() 965 | .map(|i| unsafe { self.vec.get_unchecked(i) }) 966 | } 967 | 968 | #[inline] 969 | fn size_hint(&self) -> (usize, Option) { 970 | self.range.size_hint() 971 | } 972 | } 973 | 974 | impl DoubleEndedIterator for IntoIter { 975 | #[inline] 976 | fn next_back(&mut self) -> Option { 977 | self.range 978 | .next_back() 979 | .map(|i| unsafe { self.vec.get_unchecked(i) }) 980 | } 981 | } 982 | 983 | impl ExactSizeIterator for IntoIter {} 984 | 985 | /// An iterator that borrows a SmallBitVec and yields its bits as `bool` values. 986 | /// 987 | /// Returned from [`SmallBitVec::iter`][1]. 988 | /// 989 | /// [1]: struct.SmallBitVec.html#method.iter 990 | pub struct Iter<'a> { 991 | vec: &'a SmallBitVec, 992 | range: Range, 993 | } 994 | 995 | impl<'a> Default for Iter<'a> { 996 | #[inline] 997 | fn default() -> Self { 998 | const EMPTY: &'static SmallBitVec = &SmallBitVec::new(); 999 | Self { 1000 | vec: EMPTY, 1001 | range: 0..0, 1002 | } 1003 | } 1004 | } 1005 | 1006 | impl<'a> Iterator for Iter<'a> { 1007 | type Item = bool; 1008 | 1009 | #[inline] 1010 | fn next(&mut self) -> Option { 1011 | self.range 1012 | .next() 1013 | .map(|i| unsafe { self.vec.get_unchecked(i) }) 1014 | } 1015 | 1016 | #[inline] 1017 | fn size_hint(&self) -> (usize, Option) { 1018 | self.range.size_hint() 1019 | } 1020 | } 1021 | 1022 | impl<'a> DoubleEndedIterator for Iter<'a> { 1023 | #[inline] 1024 | fn next_back(&mut self) -> Option { 1025 | self.range 1026 | .next_back() 1027 | .map(|i| unsafe { self.vec.get_unchecked(i) }) 1028 | } 1029 | } 1030 | 1031 | impl<'a> ExactSizeIterator for Iter<'a> {} 1032 | 1033 | /// An immutable view of a range of bits from a borrowed SmallBitVec. 1034 | /// 1035 | /// Returned from [`SmallBitVec::range`][1]. 1036 | /// 1037 | /// [1]: struct.SmallBitVec.html#method.range 1038 | #[derive(Debug, Clone)] 1039 | pub struct VecRange<'a> { 1040 | vec: &'a SmallBitVec, 1041 | range: Range, 1042 | } 1043 | 1044 | impl<'a> VecRange<'a> { 1045 | #[inline] 1046 | pub fn iter(&self) -> Iter<'a> { 1047 | Iter { 1048 | vec: self.vec, 1049 | range: self.range.clone(), 1050 | } 1051 | } 1052 | } 1053 | 1054 | impl<'a> Index for VecRange<'a> { 1055 | type Output = bool; 1056 | 1057 | #[inline] 1058 | fn index(&self, i: usize) -> &bool { 1059 | let vec_i = i + self.range.start; 1060 | assert!(vec_i < self.range.end, "index out of range"); 1061 | &self.vec[vec_i] 1062 | } 1063 | } 1064 | -------------------------------------------------------------------------------- /src/tests.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Matt Brubeck. See the COPYRIGHT file at the top-level 2 | // directory of this distribution and at http://rust-lang.org/COPYRIGHT. 3 | // 4 | // Licensed under the Apache License, Version 2.0 or the MIT license 6 | // , at your 7 | // option. This file may not be copied, modified, or distributed 8 | // except according to those terms. 9 | 10 | use super::*; 11 | 12 | use alloc::format; 13 | 14 | #[cfg(target_pointer_width = "32")] 15 | #[test] 16 | fn test_inline_capacity() { 17 | assert_eq!(inline_capacity(), 30); 18 | } 19 | 20 | #[cfg(target_pointer_width = "64")] 21 | #[test] 22 | fn test_inline_capacity() { 23 | assert_eq!(inline_capacity(), 62); 24 | } 25 | 26 | #[test] 27 | fn new() { 28 | let v = SmallBitVec::new(); 29 | assert_eq!(v.len(), 0); 30 | assert_eq!(v.capacity(), inline_capacity()); 31 | assert!(v.is_empty()); 32 | assert!(v.is_inline()); 33 | } 34 | 35 | #[test] 36 | fn with_capacity_inline() { 37 | for cap in 0..(inline_capacity() + 1) { 38 | let v = SmallBitVec::with_capacity(cap); 39 | assert_eq!(v.len(), 0); 40 | assert_eq!(v.capacity(), inline_capacity()); 41 | assert!(v.is_inline()); 42 | } 43 | } 44 | 45 | #[test] 46 | fn with_capacity_heap() { 47 | let cap = inline_capacity() + 1; 48 | let v = SmallBitVec::with_capacity(cap); 49 | assert_eq!(v.len(), 0); 50 | assert!(v.capacity() > inline_capacity()); 51 | assert!(v.is_heap()); 52 | } 53 | 54 | #[test] 55 | fn set_len_inline() { 56 | let mut v = SmallBitVec::new(); 57 | for i in 0..(inline_capacity() + 1) { 58 | unsafe { 59 | v.set_len(i); 60 | } 61 | assert_eq!(v.len(), i); 62 | } 63 | for i in (0..(inline_capacity() + 1)).rev() { 64 | unsafe { 65 | v.set_len(i); 66 | } 67 | assert_eq!(v.len(), i); 68 | } 69 | } 70 | 71 | #[test] 72 | fn set_len_heap() { 73 | let mut v = SmallBitVec::with_capacity(500); 74 | unsafe { 75 | v.set_len(30); 76 | } 77 | assert_eq!(v.len(), 30); 78 | } 79 | 80 | #[test] 81 | fn push_many() { 82 | let mut v = SmallBitVec::new(); 83 | for i in 0..500 { 84 | v.push(i % 3 == 0); 85 | } 86 | assert_eq!(v.len(), 500); 87 | 88 | for i in 0..500 { 89 | assert_eq!(v.get(i).unwrap(), (i % 3 == 0), "{}", i); 90 | assert_eq!(v[i], v.get(i).unwrap()); 91 | } 92 | } 93 | 94 | #[test] 95 | #[should_panic(expected = "index out of range")] 96 | fn index_out_of_bounds() { 97 | let v = SmallBitVec::new(); 98 | v[0]; 99 | } 100 | 101 | #[test] 102 | #[should_panic(expected = "index out of range")] 103 | fn index_out_of_bounds_nonempty() { 104 | let mut v = SmallBitVec::new(); 105 | v.push(true); 106 | v[1 << 32]; 107 | } 108 | 109 | #[test] 110 | fn get_out_of_bounds() { 111 | let v = SmallBitVec::new(); 112 | assert!(v.get(0).is_none()); 113 | } 114 | 115 | #[test] 116 | #[should_panic] 117 | fn set_out_of_bounds() { 118 | let mut v = SmallBitVec::new(); 119 | v.set(2, false); 120 | } 121 | 122 | #[test] 123 | fn all_false() { 124 | let mut v = SmallBitVec::new(); 125 | assert!(v.all_false()); 126 | for _ in 0..100 { 127 | v.push(false); 128 | assert!(v.all_false()); 129 | 130 | let mut v2 = v.clone(); 131 | v2.push(true); 132 | assert!(!v2.all_false()); 133 | } 134 | } 135 | 136 | #[test] 137 | fn all_true() { 138 | let mut v = SmallBitVec::new(); 139 | assert!(v.all_true()); 140 | for _ in 0..100 { 141 | v.push(true); 142 | assert!(v.all_true()); 143 | 144 | let mut v2 = v.clone(); 145 | v2.push(false); 146 | assert!(!v2.all_true()); 147 | } 148 | } 149 | 150 | #[test] 151 | fn iter() { 152 | let mut v = SmallBitVec::new(); 153 | v.push(true); 154 | v.push(false); 155 | v.push(false); 156 | 157 | let mut i = v.iter(); 158 | assert_eq!(i.next(), Some(true)); 159 | assert_eq!(i.next(), Some(false)); 160 | assert_eq!(i.next(), Some(false)); 161 | assert_eq!(i.next(), None); 162 | } 163 | 164 | #[test] 165 | fn into_iter() { 166 | let mut v = SmallBitVec::new(); 167 | v.push(true); 168 | v.push(false); 169 | v.push(false); 170 | 171 | let mut i = v.into_iter(); 172 | assert_eq!(i.next(), Some(true)); 173 | assert_eq!(i.next(), Some(false)); 174 | assert_eq!(i.next(), Some(false)); 175 | assert_eq!(i.next(), None); 176 | } 177 | 178 | #[test] 179 | fn iter_back() { 180 | let mut v = SmallBitVec::new(); 181 | v.push(true); 182 | v.push(false); 183 | v.push(false); 184 | 185 | let mut i = v.iter(); 186 | assert_eq!(i.next_back(), Some(false)); 187 | assert_eq!(i.next_back(), Some(false)); 188 | assert_eq!(i.next_back(), Some(true)); 189 | assert_eq!(i.next(), None); 190 | } 191 | 192 | #[test] 193 | fn range() { 194 | let mut v = SmallBitVec::new(); 195 | v.push(true); 196 | v.push(false); 197 | v.push(false); 198 | v.push(true); 199 | 200 | let r = v.range(0..2); 201 | let mut ri = r.iter(); 202 | assert_eq!(ri.next(), Some(true)); 203 | assert_eq!(ri.next(), Some(false)); 204 | assert_eq!(ri.next(), None); 205 | assert_eq!(r[0], true); 206 | } 207 | 208 | #[test] 209 | #[should_panic(expected = "range out of bounds")] 210 | fn range_oob() { 211 | let mut v = SmallBitVec::new(); 212 | v.push(true); 213 | 214 | v.range(0..2); 215 | } 216 | 217 | #[test] 218 | #[should_panic(expected = "index out of range")] 219 | fn range_index_oob() { 220 | let mut v = SmallBitVec::new(); 221 | v.push(true); 222 | v.push(false); 223 | v.push(true); 224 | 225 | let r = v.range(1..2); 226 | r[1]; 227 | } 228 | 229 | #[test] 230 | fn debug() { 231 | let mut v = SmallBitVec::new(); 232 | v.push(true); 233 | v.push(false); 234 | v.push(false); 235 | 236 | assert_eq!(format!("{:?}", v), "[1, 0, 0]") 237 | } 238 | 239 | #[test] 240 | fn from_elem() { 241 | for len in 0..100 { 242 | let ones = SmallBitVec::from_elem(len, true); 243 | assert_eq!(ones.len(), len); 244 | assert!(ones.all_true()); 245 | 246 | let zeros = SmallBitVec::from_elem(len, false); 247 | assert_eq!(zeros.len(), len); 248 | assert!(zeros.all_false()); 249 | } 250 | } 251 | 252 | #[test] 253 | fn remove() { 254 | let mut v = SmallBitVec::new(); 255 | v.push(false); 256 | v.push(true); 257 | v.push(false); 258 | v.push(false); 259 | v.push(true); 260 | 261 | assert_eq!(v.remove(1), true); 262 | assert_eq!(format!("{:?}", v), "[0, 0, 0, 1]"); 263 | assert_eq!(v.remove(0), false); 264 | assert_eq!(format!("{:?}", v), "[0, 0, 1]"); 265 | v.remove(2); 266 | assert_eq!(format!("{:?}", v), "[0, 0]"); 267 | v.remove(1); 268 | assert_eq!(format!("{:?}", v), "[0]"); 269 | v.remove(0); 270 | assert_eq!(format!("{:?}", v), "[]"); 271 | } 272 | 273 | #[test] 274 | fn remove_big() { 275 | let mut v = SmallBitVec::from_elem(256, false); 276 | v.set(100, true); 277 | v.set(255, true); 278 | v.remove(0); 279 | assert_eq!(v.len(), 255); 280 | assert_eq!(v.get(0).unwrap(), false); 281 | assert_eq!(v.get(99).unwrap(), true); 282 | assert_eq!(v.get(100).unwrap(), false); 283 | assert_eq!(v.get(253).unwrap(), false); 284 | assert_eq!(v.get(254).unwrap(), true); 285 | 286 | v.remove(254); 287 | assert_eq!(v.len(), 254); 288 | assert_eq!(v.get(0).unwrap(), false); 289 | assert_eq!(v.get(99).unwrap(), true); 290 | assert_eq!(v.get(100).unwrap(), false); 291 | assert_eq!(v.get(253).unwrap(), false); 292 | 293 | v.remove(99); 294 | assert_eq!(v, SmallBitVec::from_elem(253, false)); 295 | } 296 | 297 | #[test] 298 | fn eq() { 299 | assert_eq!(sbvec![], sbvec![]); 300 | assert_eq!(sbvec![true], sbvec![true]); 301 | assert_eq!(sbvec![false], sbvec![false]); 302 | 303 | assert_ne!(sbvec![], sbvec![false]); 304 | assert_ne!(sbvec![true], sbvec![]); 305 | assert_ne!(sbvec![true], sbvec![false]); 306 | assert_ne!(sbvec![false], sbvec![true]); 307 | 308 | assert_eq!(sbvec![true, false], sbvec![true, false]); 309 | assert_eq!(sbvec![true; 400], sbvec![true; 400]); 310 | assert_eq!(sbvec![false; 400], sbvec![false; 400]); 311 | 312 | assert_ne!(sbvec![true, false], sbvec![true, true]); 313 | assert_ne!(sbvec![true; 400], sbvec![true; 401]); 314 | assert_ne!(sbvec![false; 401], sbvec![false; 400]); 315 | } 316 | 317 | #[test] 318 | fn truncate_inline() { 319 | let mut v = sbvec![false, true, false, false, true]; 320 | v.truncate(10); 321 | assert_eq!(v.len(), 5); 322 | v.truncate(3); 323 | assert_eq!(v, sbvec![false, true, false]); 324 | v.truncate(0); 325 | assert_eq!(v, sbvec![]); 326 | } 327 | 328 | #[test] 329 | fn truncate_large() { 330 | let mut v = SmallBitVec::from_elem(256, false); 331 | v.set(2, true); 332 | v.set(100, true); 333 | v.set(255, true); 334 | v.truncate(500); 335 | assert_eq!(v.len(), 256); 336 | v.truncate(150); 337 | assert_eq!(v.len(), 150); 338 | assert_eq!(v.get(0).unwrap(), false); 339 | assert_eq!(v.get(99).unwrap(), false); 340 | assert_eq!(v.get(100).unwrap(), true); 341 | assert_eq!(v.get(101).unwrap(), false); 342 | assert_eq!(v.get(149).unwrap(), false); 343 | v.truncate(5); 344 | assert_eq!(v.len(), 5); 345 | assert_eq!(v, sbvec![false, false, true, false, false]); 346 | } 347 | 348 | #[test] 349 | fn resize() { 350 | let mut v = sbvec![false, true, false, false, true]; 351 | v.resize(3, false); 352 | assert_eq!(v, sbvec![false, true, false]); 353 | v.resize(8, true); 354 | assert_eq!(v, sbvec![false, true, false, true, true, true, true, true]); 355 | v.resize(100, false); 356 | assert_eq!(v.len(), 100); 357 | assert_eq!(v.get(0).unwrap(), false); 358 | assert_eq!(v.get(1).unwrap(), true); 359 | assert_eq!(v.get(2).unwrap(), false); 360 | assert_eq!(v.get(3).unwrap(), true); 361 | assert_eq!(v.get(4).unwrap(), true); 362 | assert_eq!(v.get(7).unwrap(), true); 363 | assert_eq!(v.get(8).unwrap(), false); 364 | assert_eq!(v.get(9).unwrap(), false); 365 | assert_eq!(v.get(98).unwrap(), false); 366 | assert_eq!(v.get(99).unwrap(), false); 367 | } 368 | 369 | #[test] 370 | fn hash() { 371 | extern crate std; 372 | use core::hash::{Hash, Hasher}; 373 | 374 | let v1 = sbvec![true, false, true, false, true, true, true]; 375 | let mut v2 = v1.clone(); 376 | v2.reserve(100_000); 377 | assert_eq!(v1, v2); 378 | 379 | let hash = |v: &SmallBitVec| { 380 | let mut hasher = std::collections::hash_map::DefaultHasher::new(); 381 | v.hash(&mut hasher); 382 | hasher.finish() 383 | }; 384 | 385 | assert_eq!(hash(&v1), hash(&v2)); 386 | 387 | let mut v3 = v1.clone(); 388 | v3.push(false); 389 | assert_ne!(hash(&v1), hash(&v3)); 390 | 391 | let mut v4 = v2.clone(); 392 | v4.push(false); 393 | assert_ne!(hash(&v2), hash(&v4)); 394 | 395 | assert_eq!(v3, v4); 396 | assert_eq!(hash(&v3), hash(&v4)); 397 | } 398 | --------------------------------------------------------------------------------