timsort-0.1.2/.cargo_vcs_info.json0000644000000001121373474317700126050ustar { "git": { "sha1": "704215c05906ac7627f46458035f6ef18cc5b284" } } timsort-0.1.2/.github/workflows/ci.yaml010064400017500001750000000011741372155532400162620ustar 00000000000000on: pull_request: push: branches: [master] jobs: build_test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Test (debug) uses: actions-rs/cargo@v1 with: command: test - name: Test (release) uses: actions-rs/cargo@v1 with: command: test args: --release - name: Check rustfmt uses: actions-rs/cargo@v1 with: command: fmt args: -- --check - name: Check clippy uses: actions-rs/cargo@v1 with: command: clippy args: --tests -- -Dwarnings timsort-0.1.2/.gitignore010064400017500001750000000000221372150060500133550ustar 00000000000000target Cargo.lock timsort-0.1.2/Cargo.toml0000644000000015771373474317700106230ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] edition = "2018" name = "timsort" version = "0.1.2" authors = ["Michael Howell ", "RustPython Team"] description = "Rust implementation of the modified MergeSort used in Python and Java" license = "MIT/Apache-2.0" repository = "https://github.com/RustPython/rust-timsort" [dev-dependencies.rand] version = "0.7" features = ["small_rng"] timsort-0.1.2/Cargo.toml.orig010064400017500001750000000005731373474317500143060ustar 00000000000000[package] name = "timsort" version = "0.1.2" description = "Rust implementation of the modified MergeSort used in Python and Java" repository = "https://github.com/RustPython/rust-timsort" authors = ["Michael Howell ", "RustPython Team"] license = "MIT/Apache-2.0" edition = "2018" [dev-dependencies] rand = { version = "0.7", features = ["small_rng"] } timsort-0.1.2/LICENSE-APACHE010064400017500001750000000261361372155502700133370ustar 00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright {yyyy} {name of copyright owner} Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. timsort-0.1.2/LICENSE-MIT010064400017500001750000000021041372161650700130350ustar 00000000000000Copyright (c) 2015 Michael Howell Portions (c) 2020 RustPython Team Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. timsort-0.1.2/README.md010064400017500001750000000074421372155502700126710ustar 00000000000000A modified merge sort that's faster on almost-sorted data ========================================================= This is an implementation of TimSort, the default sorting algorithm used in Python and newer versions of Java. [Full documentation here.](https://www.notriddle.com/rustdoc/timsort/) [![Build Status](https://travis-ci.org/notriddle/rust-timsort.svg)](https://travis-ci.org/notriddle/rust-timsort) Performance ----------- This is still an extreme work-in-progress, and performance has vast room for improvement. The benchmarks are the only part that doesn't work in pure stable rust. `benches/bench.rs` is for rust-TimSort, `benches/bench_default.rs` is for the default MergeSort that comes with Rust. ``` Running target/release/bench-dae501bb89de0c02 running 16 tests test sort_big_random_large ... bench: 3,310,775 ns/iter (+/- 232,896) = 96 MB/s test sort_big_random_medium ... bench: 7,755 ns/iter (+/- 118) = 412 MB/s test sort_big_random_small ... bench: 297 ns/iter (+/- 19) = 538 MB/s test sort_big_sorted ... bench: 18,038 ns/iter (+/- 251) = 17740 MB/s test sort_equals ... bench: 1,342 ns/iter (+/- 93) = 5961 MB/s test sort_few_unique ... bench: 66,582 ns/iter (+/- 1,882) = 60 MB/s test sort_huge ... bench: 137,064,148 ns/iter (+/- 2,159,033) = 5 MB/s test sort_partially_sorted ... bench: 1,488,792 ns/iter (+/- 19,015) = 53 MB/s test sort_random_large ... bench: 2,010,436 ns/iter (+/- 92,632) = 39 MB/s test sort_random_medium ... bench: 4,134 ns/iter (+/- 39) = 193 MB/s test sort_random_small ... bench: 194 ns/iter (+/- 163) = 206 MB/s test sort_sorted ... bench: 13,043 ns/iter (+/- 540) = 6133 MB/s test sort_strings ... bench: 11,845,502 ns/iter (+/- 247,501) = 24 MB/s test sort_tiny_random_large ... bench: 2,049,110 ns/iter (+/- 12,357) = 4 MB/s test sort_tiny_random_medium ... bench: 4,227 ns/iter (+/- 98) = 23 MB/s test sort_tiny_random_small ... bench: 166 ns/iter (+/- 4) = 30 MB/s test result: ok. 0 passed; 0 failed; 0 ignored; 16 measured Running target/release/bench_default-a77273e7b72e7094 running 16 tests test sort_big_random_large ... bench: 1,383,147 ns/iter (+/- 31,362) = 231 MB/s test sort_big_random_medium ... bench: 7,107 ns/iter (+/- 162) = 450 MB/s test sort_big_random_small ... bench: 288 ns/iter (+/- 8) = 555 MB/s test sort_big_sorted ... bench: 464,047 ns/iter (+/- 7,236) = 689 MB/s test sort_equals ... bench: 15,959 ns/iter (+/- 949) = 501 MB/s test sort_few_unique ... bench: 66,069 ns/iter (+/- 2,187) = 60 MB/s test sort_huge ... bench: 9,503,439 ns/iter (+/- 377,908) = 84 MB/s test sort_partially_sorted ... bench: 501,055 ns/iter (+/- 7,756) = 159 MB/s test sort_random_large ... bench: 668,164 ns/iter (+/- 23,727) = 119 MB/s test sort_random_medium ... bench: 3,685 ns/iter (+/- 35) = 217 MB/s test sort_random_small ... bench: 187 ns/iter (+/- 15) = 213 MB/s test sort_sorted ... bench: 266,431 ns/iter (+/- 7,553) = 300 MB/s test sort_strings ... bench: 2,299,735 ns/iter (+/- 58,825) = 127 MB/s test sort_tiny_random_large ... bench: 737,314 ns/iter (+/- 18,718) = 13 MB/s test sort_tiny_random_medium ... bench: 4,141 ns/iter (+/- 45) = 24 MB/s test sort_tiny_random_small ... bench: 160 ns/iter (+/- 11) = 31 MB/s test result: ok. 0 passed; 0 failed; 0 ignored; 16 measured ``` License ------ Licensed under either of these: * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) timsort-0.1.2/benches/bench.rs010064400017500001750000000076011372155502700144430ustar 00000000000000//! This is the existing test case from //! https://raw.githubusercontent.com/veddan/rust-introsort/master/benches/bench.rs #![feature(test)] #![feature(unboxed_closures)] extern crate test; use rand::{distributions::Standard, prelude::SmallRng, seq::SliceRandom, Rng, SeedableRng}; use std::mem; use test::Bencher; use timsort::sort; type BigSortable = (u64, u64, u64, u64); fn rng() -> impl Rng { SmallRng::from_entropy() } macro_rules! bench_random( ($name: ident, $sortfun: ident, $typ: ty, $n: expr) => ( #[bench] fn $name(b: &mut Bencher) { let mut rng = rng(); b.iter(|| { let mut v = (&mut rng).sample_iter(Standard).take($n).collect::>(); $sortfun(&mut v[..]); }); b.bytes = $n * mem::size_of::<$typ>() as u64; } ) ); bench_random!(sort_tiny_random_small, sort, u8, 5); bench_random!(sort_tiny_random_medium, sort, u8, 100); bench_random!(sort_tiny_random_large, sort, u8, 10_000); bench_random!(sort_random_small, sort, u64, 5); bench_random!(sort_random_medium, sort, u64, 100); bench_random!(sort_random_large, sort, u64, 10_000); bench_random!(sort_big_random_small, sort, BigSortable, 5); bench_random!(sort_big_random_medium, sort, BigSortable, 100); bench_random!(sort_big_random_large, sort, BigSortable, 10_000); #[bench] fn sort_sorted(b: &mut Bencher) { let mut v: Vec<_> = (0..10000isize).collect(); b.iter(|| { sort(&mut v[..]); }); b.bytes = (v.len() * mem::size_of_val(&v[0])) as u64; } #[bench] fn sort_big_sorted(b: &mut Bencher) { let mut v: Vec<_> = (0..10000usize).map(|i| (i, i, i, i)).collect(); b.iter(|| { sort(&mut v[..]); }); b.bytes = (v.len() * mem::size_of_val(&v[0])) as u64; } #[bench] fn sort_few_unique(b: &mut Bencher) { let mut v = Vec::new(); for i in 0u32..10 { for _ in 0usize..100 { v.push(i); } } let mut rng = rng(); b.iter(|| { v.shuffle(&mut rng); sort(&mut v[..]); }); b.bytes = (v.len() * mem::size_of_val(&v[0])) as u64; } #[bench] fn sort_equals(b: &mut Bencher) { let mut v = vec![1u64; 1000]; b.iter(|| { sort(&mut v[..]); }); b.bytes = (v.len() * mem::size_of_val(&v[0])) as u64; } #[bench] fn sort_huge(b: &mut Bencher) { let mut rng = rng(); let n = 100_000; let mut v = (&mut rng) .sample_iter(Standard) .take(n) .collect::>(); b.iter(|| { v.shuffle(&mut rng); sort(&mut v[..]); }); b.bytes = (n * mem::size_of::()) as u64; } #[bench] fn sort_partially_sorted(b: &mut Bencher) { fn partially_sort(v: &mut [T]) { let s = v.len() / 100; if s == 0 { return; } let mut sorted = true; for c in v.chunks_mut(s) { if sorted { sort(&mut c[..]); } sorted = !sorted; } } let mut rng = rng(); let n = 10_000; let mut v = (&mut rng) .sample_iter(Standard) .take(n) .collect::>(); v.shuffle(&mut rng); partially_sort(&mut v[..]); b.iter(|| { let mut v2 = v.clone(); sort(&mut v2[..]); }); b.bytes = (n * mem::size_of::()) as u64; } #[bench] fn sort_strings(b: &mut Bencher) { let mut rng = rng(); let n = 10_000usize; let mut v = Vec::with_capacity(n); let mut bytes = 0; for _ in 0..n { let len = rng.gen_range(0, 60); bytes += len; let mut s = String::with_capacity(len); if len == 0 { v.push(s); continue; } for _ in 0..len { s.push(rng.gen_range(b'a', b'z') as char); } v.push(s); } b.iter(|| { v.shuffle(&mut rng); sort(&mut v[..]); }); b.bytes = bytes as u64; } timsort-0.1.2/benches/bench_default.rs010064400017500001750000000076451372155502700161570ustar 00000000000000//! This is the existing test case from //! https://raw.githubusercontent.com/veddan/rust-introsort/master/benches/bench.rs #![feature(test)] #![feature(unboxed_closures)] extern crate test; use rand::{distributions::Standard, rngs::SmallRng, seq::SliceRandom, Rng, SeedableRng}; use std::mem; use test::Bencher; fn rng() -> impl Rng { SmallRng::from_entropy() } #[inline] fn sort(l: &mut [T]) { l.sort(); } type BigSortable = (u64, u64, u64, u64); macro_rules! bench_random( ($name: ident, $sortfun: ident, $typ: ty, $n: expr) => ( #[bench] fn $name(b: &mut Bencher) { let mut rng = rng(); b.iter(|| { let mut v = (&mut rng).sample_iter(Standard).take($n).collect::>(); $sortfun(&mut v[..]); }); b.bytes = $n * mem::size_of::<$typ>() as u64; } ) ); bench_random!(sort_tiny_random_small, sort, u8, 5); bench_random!(sort_tiny_random_medium, sort, u8, 100); bench_random!(sort_tiny_random_large, sort, u8, 10_000); bench_random!(sort_random_small, sort, u64, 5); bench_random!(sort_random_medium, sort, u64, 100); bench_random!(sort_random_large, sort, u64, 10_000); bench_random!(sort_big_random_small, sort, BigSortable, 5); bench_random!(sort_big_random_medium, sort, BigSortable, 100); bench_random!(sort_big_random_large, sort, BigSortable, 10_000); #[bench] fn sort_sorted(b: &mut Bencher) { let mut v: Vec<_> = (0..10000isize).collect(); b.iter(|| { sort(&mut v[..]); }); b.bytes = (v.len() * mem::size_of_val(&v[0])) as u64; } #[bench] fn sort_big_sorted(b: &mut Bencher) { let mut v: Vec<_> = (0..10000usize).map(|i| (i, i, i, i)).collect(); b.iter(|| { sort(&mut v[..]); }); b.bytes = (v.len() * mem::size_of_val(&v[0])) as u64; } #[bench] fn sort_few_unique(b: &mut Bencher) { let mut v = Vec::new(); for i in 0u32..10 { for _ in 0usize..100 { v.push(i); } } let mut rng = rng(); b.iter(|| { v.shuffle(&mut rng); sort(&mut v[..]); }); b.bytes = (v.len() * mem::size_of_val(&v[0])) as u64; } #[bench] fn sort_equals(b: &mut Bencher) { let mut v = vec![1u64; 1000]; b.iter(|| { sort(&mut v[..]); }); b.bytes = (v.len() * mem::size_of_val(&v[0])) as u64; } #[bench] fn sort_huge(b: &mut Bencher) { let mut rng = rng(); let n = 100_000; let mut v = (&mut rng) .sample_iter(Standard) .take(n) .collect::>(); b.iter(|| { v.shuffle(&mut rng); sort(&mut v[..]); }); b.bytes = (n * mem::size_of::()) as u64; } #[bench] fn sort_partially_sorted(b: &mut Bencher) { fn partially_sort(v: &mut [T]) { let s = v.len() / 100; if s == 0 { return; } let mut sorted = true; for c in v.chunks_mut(s) { if sorted { sort(&mut c[..]); } sorted = !sorted; } } let mut rng = rng(); let n = 10_000; let mut v = (&mut rng) .sample_iter(Standard) .take(n) .collect::>(); v.shuffle(&mut rng); partially_sort(&mut v[..]); b.iter(|| { let mut v2 = v.clone(); sort(&mut v2[..]); }); b.bytes = (n * mem::size_of::()) as u64; } #[bench] fn sort_strings(b: &mut Bencher) { let mut rng = rng(); let n = 10_000usize; let mut v = Vec::with_capacity(n); let mut bytes = 0; for _ in 0..n { let len = rng.gen_range(0, 60); bytes += len; let mut s = String::with_capacity(len); if len == 0 { v.push(s); continue; } for _ in 0..len { s.push(rng.gen_range(b'a', b'z') as char); } v.push(s); } b.iter(|| { v.shuffle(&mut rng); sort(&mut v[..]); }); b.bytes = bytes as u64; } timsort-0.1.2/src/find_run/tests.rs010064400017500001750000000035041372155521700155110ustar 00000000000000use crate::{never, NeverResult}; #[test] fn empty() { let list: Vec = vec![]; let (ord, len) = find_run(&list); assert_eq!(ord, false); assert_eq!(len, 0); } #[test] fn single() { let (ord, len) = find_run(&[1]); assert_eq!(ord, false); assert_eq!(len, 1); } #[test] fn greater() { let (ord, len) = find_run(&[1, 2, 2, 3, 4, 5]); assert_eq!(ord, false); assert_eq!(len, 6); } // Note: I used to have a version that would allow sub-runs of equal elements in a // less ordering. Unfortunately, reversing those sub-runs creates an unstable sort. #[test] fn less_stable() { let (ord, len) = find_run(&[5, 4, 4, 3, 4, 5]); assert_eq!(ord, true); assert_eq!(len, 2); } #[test] fn less() { let (ord, len) = find_run(&[5, 4, 3, 2, 1, 0]); assert_eq!(ord, true); assert_eq!(len, 6); } #[test] fn equal() { let (ord, len) = find_run(&[2, 2, 2, 2, 2, 2]); assert_eq!(ord, false); assert_eq!(len, 6); } #[test] fn get_run_reverse() { let mut list = vec![7, 6, 5, 4, 3, 3]; let len = get_run(&mut list); assert_eq!(len, 5); assert_eq!(list[0], 3); assert_eq!(list[1], 4); assert_eq!(list[2], 5); assert_eq!(list[3], 6); assert_eq!(list[4], 7); } #[test] fn get_run_noreverse() { let mut list = vec![3, 4, 5, 6, 7, 3]; let len = get_run(&mut list); assert_eq!(len, 5); assert_eq!(list[0], 3); assert_eq!(list[1], 4); assert_eq!(list[2], 5); assert_eq!(list[3], 6); assert_eq!(list[4], 7); } /// With comparator. pub fn find_run(list: &[T]) -> (bool, usize) { super::find_run(list, |a, b| -> NeverResult<_> { Ok(a > b) }).unwrap_or_else(never) } /// With comparator. pub fn get_run(list: &mut [T]) -> usize { super::get_run(list, |a, b| -> NeverResult<_> { Ok(a > b) }).unwrap_or_else(never) } timsort-0.1.2/src/find_run.rs010064400017500001750000000022501373472672500143540ustar 00000000000000//! The run finder algorithm. Takes an unsorted slice, and returns the number //! of sequential elements in a row. #[cfg(test)] mod tests; /// Find a run, reversing if necessary. pub fn get_run Result>( list: &mut [T], is_greater: C, ) -> Result { let (ord, len) = find_run(list, is_greater)?; if ord { list[..len].reverse(); } Ok(len) } /// Find a run. Returns true if it needs reversed, and false otherwise. pub fn find_run Result>( list: &[T], is_greater: C, ) -> Result<(bool, usize), E> { let (first, second) = match list { [a, b, ..] => (a, b), _ => return Ok((false, list.len())), }; let mut pos = 1; let gt = if is_greater(first, second)? { for pair in list[1..].windows(2) { if !is_greater(&pair[0], &pair[1])? { break; } pos += 1; } true } else { for pair in list[1..].windows(2) { if is_greater(&pair[0], &pair[1])? { break; } pos += 1; } false }; Ok((gt, pos + 1)) } timsort-0.1.2/src/gallop/tests.rs010064400017500001750000000114471372155520300151630ustar 00000000000000use super::Mode; use crate::{never, NeverResult}; macro_rules! test_both { ($v:ident, $($x:expr);*) => {{ let $v = Mode::Forward; $($x;)* let $v = Mode::Reverse; $($x;)* }} } #[test] fn gallop_empty() { let list: &[usize] = &[]; test_both! {mode, assert_eq!(gallop_left(&0, list, mode), 0); assert_eq!(gallop_right(&0, list, mode), 0) } } #[test] fn gallop_single_greater() { let list: &[usize] = &[1]; test_both! {mode, assert_eq!(gallop_left(&0, list, mode), 0); assert_eq!(gallop_right(&0, list, mode), 0) } } #[test] fn gallop_single_equal() { let list: &[usize] = &[1]; test_both! {mode, assert_eq!(gallop_left(&1, list, mode), 0); assert_eq!(gallop_right(&1, list, mode), 1) } } #[test] fn gallop_single_less() { let list: &[usize] = &[1]; test_both! {mode, assert_eq!(gallop_left(&2, list, mode), 1); assert_eq!(gallop_right(&2, list, mode), 1) } } #[test] fn gallop_start_less() { let list: &[usize] = &[1, 2, 3]; test_both! {mode, assert_eq!(gallop_left(&0, list, mode), 0); assert_eq!(gallop_right(&0, list, mode), 0) } } #[test] fn gallop_start_equal() { let list: &[usize] = &[1, 2, 3]; test_both! {mode, assert_eq!(gallop_left(&1, list, mode), 0); assert_eq!(gallop_right(&1, list, mode), 1) } } #[test] fn gallop_middle_equal() { let list: &[usize] = &[1, 2, 3]; test_both! {mode, assert_eq!(gallop_left(&2, list, mode), 1); assert_eq!(gallop_right(&2, list, mode), 2) } } #[test] fn gallop_end_equal() { let list: &[usize] = &[1, 2, 3]; test_both! {mode, assert_eq!(gallop_left(&3, list, mode), 2); assert_eq!(gallop_right(&3, list, mode), 3) } } #[test] fn gallop_end_greater() { let list: &[usize] = &[1, 2, 3]; test_both! {mode, assert_eq!(gallop_left(&4, list, mode), 3); assert_eq!(gallop_right(&4, list, mode), 3) } } #[test] fn gallop_end_middle_before() { let list: &[usize] = &[1, 3, 5]; test_both! {mode, assert_eq!(gallop_left(&2, list, mode), 1); assert_eq!(gallop_right(&2, list, mode), 1) } } #[test] fn gallop_end_middle_after() { let list: &[usize] = &[1, 3, 5]; test_both! {mode, assert_eq!(gallop_left(&4, list, mode), 2); assert_eq!(gallop_right(&4, list, mode), 2) } } #[test] fn gallop_large_start_before() { let list: &[usize] = &[1, 3, 5, 7, 11, 21, 31, 41, 51, 61, 71, 81, 91, 101]; test_both! {mode, assert_eq!(gallop_left(&0, list, mode), 0); assert_eq!(gallop_right(&0, list, mode), 0) } } #[test] fn gallop_large_start_equal() { let list: &[usize] = &[1, 3, 5, 7, 11, 21, 31, 41, 51, 61, 71, 81, 91, 101]; test_both! {mode, assert_eq!(gallop_left(&1, list, mode), 0); assert_eq!(gallop_right(&1, list, mode), 1) } } #[test] fn gallop_large_start_after() { let list: &[usize] = &[1, 3, 5, 7, 11, 21, 31, 41, 51, 61, 71, 81, 91, 101]; test_both! {mode, assert_eq!(gallop_left(&2, list, mode), 1); assert_eq!(gallop_right(&2, list, mode), 1) } } #[test] fn gallop_large_center_equal() { let list: &[usize] = &[1, 3, 5, 7, 11, 21, 31, 41, 51, 61, 71, 81, 91, 101]; test_both! {mode, assert_eq!(gallop_left(&21, list, mode), 5); assert_eq!(gallop_right(&21, list, mode), 6) } } #[test] fn gallop_large_center_less() { let list: &[usize] = &[1, 3, 5, 7, 11, 21, 31, 41, 51, 61, 71, 81, 91, 101]; test_both! {mode, assert_eq!(gallop_left(&20, list, mode), 5); assert_eq!(gallop_right(&20, list, mode), 5) } } #[test] fn gallop_large_end_less() { let list: &[usize] = &[1, 3, 5, 7, 11, 21, 31, 41, 51, 61, 71, 81, 91, 101]; test_both! {mode, assert_eq!(gallop_left(&100, list, mode), 13); assert_eq!(gallop_right(&100, list, mode), 13) } } #[test] fn gallop_large_end_equal() { let list: &[usize] = &[1, 3, 5, 7, 11, 21, 31, 41, 51, 61, 71, 81, 91, 101]; test_both! {mode, assert_eq!(gallop_left(&101, list, mode), 13); assert_eq!(gallop_right(&101, list, mode), 14) } } #[test] fn gallop_large_end_greater() { let list: &[usize] = &[1, 3, 5, 7, 11, 21, 31, 41, 51, 61, 71, 81, 91, 101]; test_both! {mode, assert_eq!(gallop_left(&102, list, mode), 14); assert_eq!(gallop_right(&102, list, mode), 14) } } pub fn gallop_left(key: &T, list: &[T], mode: Mode) -> usize { super::gallop_left(key, list, mode, |a, b| -> NeverResult<_> { Ok(a > b) }) .unwrap_or_else(never) } pub fn gallop_right(key: &T, list: &[T], mode: Mode) -> usize { super::gallop_right(key, list, mode, |a, b| -> NeverResult<_> { Ok(a > b) }) .unwrap_or_else(never) } timsort-0.1.2/src/gallop.rs010064400017500001750000000072551372155511600140260ustar 00000000000000//! The galloping search algorithm. #[cfg(test)] mod tests; use std::cmp::Ordering; #[derive(Copy, Clone)] pub enum Mode { Forward, Reverse, } /// Returns the index where key should be inserted, assuming it shoul be placed /// at the beginning of any cluster of equal items. pub fn gallop_left Result>( key: &T, list: &[T], mode: Mode, is_greater: C, ) -> Result { let (mut base, mut lim) = gallop(key, list, mode, &is_greater)?; while lim != 0 { let ix = base + (lim / 2); match ordering(&is_greater, &list[ix], key)? { Ordering::Less => { base = ix + 1; lim -= 1; } Ordering::Greater => (), Ordering::Equal => { if ix == 0 || is_greater(key, &list[ix - 1])? { base = ix; break; } } }; lim /= 2; } Ok(base) } /// Returns the index where key should be inserted, assuming it shoul be placed /// at the end of any cluster of equal items. pub fn gallop_right Result>( key: &T, list: &[T], mode: Mode, is_greater: C, ) -> Result { let list_len = list.len(); let (mut base, mut lim) = gallop(key, list, mode, &is_greater)?; while lim != 0 { let ix = base + (lim / 2); match ordering(&is_greater, &list[ix], key)? { Ordering::Less => { base = ix + 1; lim -= 1; } Ordering::Greater => (), Ordering::Equal => { base = ix + 1; if ix == list_len - 1 || is_greater(&list[ix + 1], key)? { break; } else { lim -= 1; } } }; lim /= 2; } Ok(base) } fn gallop Result>( key: &T, list: &[T], mode: Mode, is_greater: C, ) -> Result<(usize, usize), E> { let list_len = list.len(); if list_len == 0 { return Ok((0, 0)); } let ret = match mode { Mode::Forward => { let mut prev_val = 0; let mut next_val = 1; while next_val < list_len { match ordering(&is_greater, &list[next_val], key)? { Ordering::Less => { prev_val = next_val; next_val = ((next_val + 1) * 2) - 1; } Ordering::Greater => { break; } Ordering::Equal => { next_val += 1; break; } } } if next_val > list_len { next_val = list_len; } (prev_val, next_val - prev_val) } Mode::Reverse => { let mut prev_val = list_len; let mut next_val = ((prev_val + 1) / 2) - 1; while is_greater(&list[next_val], key)? { prev_val = next_val + 1; next_val = (next_val + 1) / 2; if next_val != 0 { next_val -= 1; } else { break; } } (next_val, prev_val - next_val) } }; Ok(ret) } fn ordering Result>( is_greater: &C, a: &T, b: &T, ) -> Result { let ord = if is_greater(a, b)? { Ordering::Greater } else if is_greater(b, a)? { Ordering::Less } else { Ordering::Equal }; Ok(ord) } timsort-0.1.2/src/insort/tests.rs010064400017500001750000000040251372155514700152240ustar 00000000000000use crate::{never, NeverResult}; /// Test the insertion sort implementation with an empty list #[test] fn empty() { let mut list: Vec = vec![]; sort(&mut list); assert!(list.is_empty()); } /// Test the insertion sort implementation with a single-element list #[test] fn single() { let mut list = vec![42]; sort(&mut list); assert!(list[0] == 42); } /// Test the insertion sort implementation with a short unsorted list #[test] fn unsorted() { let mut list = vec![3, 1, 0, 4]; sort(&mut list); assert!(list[0] == 0); assert!(list[1] == 1); assert!(list[2] == 3); assert!(list[3] == 4); } /// Test the insertion sort implementation with a short backward list #[test] fn reverse() { let mut list = vec![21, 18, 7, 1]; sort(&mut list); assert!(list[0] == 1); assert!(list[1] == 7); assert!(list[2] == 18); assert!(list[3] == 21); } /// Test the insertion sort implementation with a short unsorted list #[test] fn sorted() { let mut list = vec![0, 1, 2, 3]; sort(&mut list); assert!(list[0] == 0); assert!(list[1] == 1); assert!(list[2] == 2); assert!(list[3] == 3); } /// Make sure the sort is stable. #[test] fn stable() { let len = 256; let mut key1: usize = 0; let mut key2: usize = 0; #[derive(Debug)] struct Item { key1: usize, key2: usize, }; let mut list: Vec = (0..len) .map(|_| { key1 += 1; key1 %= 5; key2 += 1; Item { key1, key2 } }) .collect(); super::sort(&mut list, |a, b| -> NeverResult<_> { Ok(a.key1 > b.key1) }).unwrap_or_else(never); for pair in list.windows(2) { let (a, b) = (&pair[0], &pair[1]); assert!(a.key1 <= b.key1); if a.key1 == b.key1 { assert!(a.key2 <= b.key2); } } } /// Insertion sort implementation convenience used for tests. pub fn sort(list: &mut [T]) { super::sort(list, |a, b| -> NeverResult<_> { Ok(a > b) }).unwrap_or_else(never); } timsort-0.1.2/src/insort.rs010064400017500001750000000016751372163044400140640ustar 00000000000000//! The bottom sorting algorithm (we could just have 1-element runs and do all //! the sorting with the merge algorithm, but that would be much slower). #[cfg(test)] mod tests; /// Sorts the list using insertion sort. // This version was almost completely copied from libcollections/slice.rs pub fn sort Result>( list: &mut [T], is_greater: C, ) -> Result<(), E> { if list.len() < 2 { return Ok(()); } for i in 0..list.len() { let i_el = &list[i]; // find the index just above the element that is in order wrt list[i] let mut j = 0; for (jj, j_el) in list[..i].iter().enumerate().rev() { if !is_greater(j_el, i_el)? { j = jj + 1; break; } } if i != j { // SAFETY: j = Result; fn never(x: Infallible) -> T { match x {} } pub fn try_sort_by Result>( list: &mut [T], c: C, ) -> Result<(), E> { try_sort_by_gt(list, move |a, b| { c(a, b).map(|ord| ord == Ordering::Greater) }) } pub fn sort_by_gt bool>(list: &mut [T], is_greater: C) { try_sort_by_gt(list, move |a, b| -> NeverResult<_> { Ok(is_greater(a, b)) }) .unwrap_or_else(never) } pub fn sort_by Ordering>(list: &mut [T], c: C) { try_sort_by_gt(list, move |a, b| -> NeverResult<_> { Ok(c(a, b) == Ordering::Greater) }) .unwrap_or_else(never) } pub fn sort(list: &mut [T]) { sort_by_gt(list, |a, b| a > b) } timsort-0.1.2/src/merge/tests.rs010064400017500001750000000151161372155523200150030ustar 00000000000000//! The merge algorithm. This one can merge unequal slices, allocating an n/2 //! sized temporary slice of the same type. Naturally, it can only merge slices //! that are themselves already sorted. use crate::{never, NeverResult}; /// Test mergeing two empty slices. #[test] fn empty() { let mut list: Vec = vec![]; merge(&mut list, 0); assert!(list.is_empty()); } /// Test merging two equal-sized single-element vectors that are already sorted. #[test] fn single_sorted() { let mut list = vec![42, 90]; merge(&mut list, 1); assert!(list[0] == 42); assert!(list[1] == 90); } /// Test merging two equal-sized single-element vectors that are already sorted. #[test] fn single_unsorted() { let mut list = vec![90, 42]; merge(&mut list, 1); assert!(list[0] == 42); assert!(list[1] == 90); } /// Test merging two unequal-sized vectors. #[test] fn hi_unsorted() { let mut list = vec![90, 17, 42]; merge(&mut list, 1); assert!(list[0] == 17); assert!(list[1] == 42); assert!(list[2] == 90); } /// Test merging two unequal-sized vectors. #[test] fn lo_unsorted() { let mut list = vec![17, 90, 42]; merge(&mut list, 2); assert!(list[0] == 17); assert!(list[1] == 42); assert!(list[2] == 90); } /// Test merging two unequal-sized vectors. #[test] fn hi_unsorted_multiple() { let mut list = vec![21, 32, 91, 17, 20, 40, 80]; merge(&mut list, 3); assert!(list[0] == 17); assert!(list[1] == 20); assert!(list[2] == 21); assert!(list[3] == 32); assert!(list[4] == 40); assert!(list[5] == 80); assert!(list[6] == 91); } /// Test merging two unequal-sized vectors. #[test] fn lo_unsorted_multiple() { let mut list = vec![17, 20, 40, 80, 21, 32, 91]; merge(&mut list, 4); assert!(list[0] == 17); assert!(list[1] == 20); assert!(list[2] == 21); assert!(list[3] == 32); assert!(list[4] == 40); assert!(list[5] == 80); assert!(list[6] == 91); } /// Test panic safety when the first run is longest #[test] fn lo_panic() { use std::panic::{catch_unwind, AssertUnwindSafe}; let mut list = vec![1usize, 2, 3, 4, 5]; catch_unwind(AssertUnwindSafe(|| { super::merge(&mut list, 3, |_, _| -> NeverResult<_> { panic!("Expected panic: this is normal") }) .unwrap_or_else(never) })) .err() .unwrap(); assert!(list[0] == 1); assert!(list[1] == 2); assert!(list[2] == 3); assert!(list[3] == 4); assert!(list[4] == 5); } /// Test panic safety when the second run is longest #[test] fn hi_panic() { use std::panic::{catch_unwind, AssertUnwindSafe}; let mut list = vec![1usize, 2, 3, 4, 5]; catch_unwind(AssertUnwindSafe(|| { super::merge(&mut list, 2, |_, _| -> NeverResult<_> { panic!("Expected panic: this is normal") }) .unwrap_or_else(never) })) .err() .unwrap(); assert!(list[0] == 1); assert!(list[1] == 2); assert!(list[2] == 3); assert!(list[3] == 4); assert!(list[4] == 5); } /// Test that the drop() is never run while sorting. #[test] fn lo_nodrop() { #[derive(Debug)] struct ExplodeOnDrop(usize); impl Drop for ExplodeOnDrop { fn drop(&mut self) { panic!("We're not supposed to panic."); } } let mut list = vec![ExplodeOnDrop(3), ExplodeOnDrop(7), ExplodeOnDrop(2)]; super::merge(&mut list, 2, |a, b| -> NeverResult<_> { Ok(a.0 > b.0) }).unwrap_or_else(never); assert!(list[0].0 == 2); assert!(list[1].0 == 3); assert!(list[2].0 == 7); list.into_iter().for_each(std::mem::forget); } #[test] fn hi_nodrop() { #[derive(Debug)] struct ExplodeOnDrop(usize); impl Drop for ExplodeOnDrop { fn drop(&mut self) { panic!("We're not supposed to panic."); } } let mut list = vec![ExplodeOnDrop(3), ExplodeOnDrop(2), ExplodeOnDrop(7)]; super::merge(&mut list, 1, |a, b| -> NeverResult<_> { Ok(a.0 > b.0) }).unwrap_or_else(never); assert!(list[0].0 == 2); assert!(list[1].0 == 3); assert!(list[2].0 == 7); list.into_iter().for_each(std::mem::forget); } /// Ensure that, when we enter galloping mode, we still work right. #[test] fn lo_gallop_stress() { let mut list = vec![ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ]; merge(&mut list, 21); assert!(list[0] == 1); assert!(list[1] == 2); assert!(list[2] == 3); assert!(list[3] == 4); assert!(list[4] == 5); assert!(list[5] == 6); assert!(list[6] == 7); assert!(list[7] == 8); assert!(list[8] == 9); assert!(list[9] == 10); assert!(list[10] == 11); assert!(list[11] == 12); assert!(list[12] == 13); assert!(list[13] == 14); assert!(list[14] == 15); assert!(list[15] == 16); assert!(list[16] == 17); assert!(list[17] == 18); assert!(list[18] == 19); assert!(list[19] == 20); assert!(list[20] == 20); assert!(list[21] == 21); assert!(list[22] == 22); assert!(list[23] == 23); assert!(list[24] == 24); assert!(list[25] == 25); assert!(list[26] == 26); assert!(list[27] == 27); assert!(list[28] == 28); assert!(list[29] == 29); assert!(list[30] == 30); } /// Ensure that, when we enter galloping mode, we still work right. #[test] fn hi_gallop_stress() { let mut list = vec![ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, ]; merge(&mut list, 10); assert!(list[0] == 1); assert!(list[1] == 2); assert!(list[2] == 3); assert!(list[3] == 4); assert!(list[4] == 5); assert!(list[5] == 6); assert!(list[6] == 7); assert!(list[7] == 8); assert!(list[8] == 9); assert!(list[9] == 10); assert!(list[10] == 11); assert!(list[11] == 12); assert!(list[12] == 13); assert!(list[13] == 14); assert!(list[14] == 15); assert!(list[15] == 16); assert!(list[16] == 17); assert!(list[17] == 18); assert!(list[18] == 19); assert!(list[19] == 20); assert!(list[20] == 20); assert!(list[21] == 21); assert!(list[22] == 22); assert!(list[23] == 23); assert!(list[24] == 24); assert!(list[25] == 25); assert!(list[26] == 26); assert!(list[27] == 27); assert!(list[28] == 28); assert!(list[29] == 29); assert!(list[30] == 30); } /// Merge convenience used for tests. pub fn merge(list: &mut [T], first_len: usize) { super::merge(list, first_len, |a, b| -> NeverResult<_> { Ok(a > b) }).unwrap_or_else(never); } timsort-0.1.2/src/merge.rs010064400017500001750000000326311373445416400136500ustar 00000000000000//! The merge algorithm. This one can merge unequal slices, allocating an n/2 //! sized temporary slice of the same type. Naturally, it can only merge slices //! that are themselves already sorted. #[cfg(test)] mod tests; use crate::gallop::{self, gallop_left, gallop_right}; use std::ptr; /// Merge implementation switch. pub fn merge Result>( list: &mut [T], mut first_len: usize, is_greater: C, ) -> Result<(), E> { if first_len == 0 { return Ok(()); } let (first, second) = list.split_at_mut(first_len); let second_len = gallop_left( &first[first_len - 1], second, gallop::Mode::Reverse, &is_greater, )?; if second_len == 0 { return Ok(()); } let first_off = gallop_right(&second[0], first, gallop::Mode::Forward, &is_greater)?; first_len -= first_off; if first_len == 0 { return Ok(()); } let nlist = &mut list[first_off..][..first_len + second_len]; if first_len > second_len { merge_hi(nlist, first_len, second_len, is_greater) } else { merge_lo(nlist, first_len, is_greater) } } /// The number of times any one run can win before we try galloping. /// Change this during testing. const MIN_GALLOP: usize = 7; /// Merge implementation used when the first run is smaller than the second. pub fn merge_lo Result>( list: &mut [T], first_len: usize, is_greater: C, ) -> Result<(), E> { MergeLo::new(list, first_len, is_greater).merge() } /// Implementation of `merge_lo`. We need to have an object in order to /// implement panic safety. struct MergeLo<'a, T: 'a, E, C: Fn(&T, &T) -> Result> { list_len: usize, first_pos: usize, first_len: usize, second_pos: usize, dest_pos: usize, list: &'a mut [T], tmp: Vec, is_greater: C, } impl<'a, T: 'a, E, C: Fn(&T, &T) -> Result> MergeLo<'a, T, E, C> { /// Constructor for a lower merge. fn new(list: &'a mut [T], first_len: usize, is_greater: C) -> Self { let mut ret_val = MergeLo { list_len: list.len(), first_pos: 0, first_len, second_pos: first_len, dest_pos: 0, list, tmp: Vec::with_capacity(first_len), is_greater, }; // First, move the smallest run into temporary storage, leaving the // original contents uninitialized. unsafe { ret_val.tmp.set_len(first_len); ptr::copy_nonoverlapping(ret_val.list.as_ptr(), ret_val.tmp.as_mut_ptr(), first_len); } ret_val } /// Perform the one-by-one comparison and insertion. fn merge(mut self) -> Result<(), E> { let is_greater = &self.is_greater; let mut first_count = 0; let mut second_count = 0; while self.second_pos > self.dest_pos && self.second_pos < self.list_len { debug_assert!(self.first_pos + (self.second_pos - self.first_len) == self.dest_pos); if (second_count | first_count) < MIN_GALLOP { // One-at-a-time mode. unsafe { if is_greater( self.tmp.get_unchecked(self.first_pos), self.list.get_unchecked(self.second_pos), )? { ptr::copy_nonoverlapping( self.list.get_unchecked(self.second_pos), self.list.get_unchecked_mut(self.dest_pos), 1, ); self.second_pos += 1; second_count += 1; first_count = 0; } else { ptr::copy_nonoverlapping( self.tmp.get_unchecked(self.first_pos), self.list.get_unchecked_mut(self.dest_pos), 1, ); self.first_pos += 1; first_count += 1; second_count = 0; } } self.dest_pos += 1; } else { // Galloping mode. second_count = gallop_left( unsafe { self.tmp.get_unchecked(self.first_pos) }, self.list.split_at(self.second_pos).1, gallop::Mode::Forward, is_greater, )?; unsafe { ptr::copy( self.list.get_unchecked(self.second_pos), self.list.get_unchecked_mut(self.dest_pos), second_count, ) } self.dest_pos += second_count; self.second_pos += second_count; debug_assert!(self.first_pos + (self.second_pos - self.first_len) == self.dest_pos); if self.second_pos > self.dest_pos && self.second_pos < self.list_len { first_count = gallop_right( unsafe { self.list.get_unchecked(self.second_pos) }, self.tmp.split_at(self.first_pos).1, gallop::Mode::Forward, is_greater, )?; unsafe { ptr::copy_nonoverlapping( self.tmp.get_unchecked(self.first_pos), self.list.get_unchecked_mut(self.dest_pos), first_count, ) }; self.dest_pos += first_count; self.first_pos += first_count; } } } Ok(()) } } impl<'a, T: 'a, E, C: Fn(&T, &T) -> Result> Drop for MergeLo<'a, T, E, C> { /// Copy all remaining items in the temporary storage into the list. /// If the comparator panics, the result will not be sorted, but will still /// contain no duplicates or uninitialized spots. fn drop(&mut self) { unsafe { // Make sure that the entire tmp storage is consumed. Since there are no uninitialized // spaces before dest_pos, and no uninitialized space after first_pos, this will ensure // that there are no uninitialized spaces inside the slice after we drop. Thus, the // function is safe. if self.first_pos < self.first_len { ptr::copy_nonoverlapping( self.tmp.get_unchecked(self.first_pos), self.list.get_unchecked_mut(self.dest_pos), self.first_len - self.first_pos, ); } // The temporary storage is now full of nothing but uninitialized. // We want to deallocate the space, but not call the destructors. self.tmp.set_len(0); } } } /// Merge implementation used when the first run is larger than the second. pub fn merge_hi Result>( list: &mut [T], first_len: usize, second_len: usize, is_greater: C, ) -> Result<(), E> { MergeHi::new(list, first_len, second_len, is_greater).merge() } /// Implementation of `merge_hi`. We need to have an object in order to /// implement panic safety. struct MergeHi<'a, T: 'a, E, C: Fn(&T, &T) -> Result> { first_pos: isize, second_pos: isize, dest_pos: isize, list: &'a mut [T], tmp: Vec, is_greater: C, } impl<'a, T: 'a, E, C: Fn(&T, &T) -> Result> MergeHi<'a, T, E, C> { /// Constructor for a higher merge. fn new(list: &'a mut [T], first_len: usize, second_len: usize, is_greater: C) -> Self { let mut ret_val = MergeHi { first_pos: first_len as isize - 1, second_pos: second_len as isize - 1, dest_pos: list.len() as isize - 1, list, tmp: Vec::with_capacity(second_len), is_greater, }; // First, move the smallest run into temporary storage, leaving the // original contents uninitialized. unsafe { ret_val.tmp.set_len(second_len); ptr::copy_nonoverlapping( ret_val.list.as_ptr().add(first_len), ret_val.tmp.as_mut_ptr(), second_len, ); } ret_val } /// Perform the one-by-one comparison and insertion. fn merge(mut self) -> Result<(), E> { let is_greater = &self.is_greater; let mut first_count: usize = 0; let mut second_count: usize = 0; while self.first_pos < self.dest_pos && self.first_pos >= 0 { debug_assert!(self.first_pos + self.second_pos + 1 == self.dest_pos); if (second_count | first_count) < MIN_GALLOP { // One-at-a-time mode. unsafe { if is_greater( self.list.get_unchecked(self.first_pos as usize), self.tmp.get_unchecked(self.second_pos as usize), )? { ptr::copy_nonoverlapping( self.list.get_unchecked(self.first_pos as usize), self.list.get_unchecked_mut(self.dest_pos as usize), 1, ); self.first_pos -= 1; } else { ptr::copy_nonoverlapping( self.tmp.get_unchecked(self.second_pos as usize), self.list.get_unchecked_mut(self.dest_pos as usize), 1, ); self.second_pos -= 1; } } self.dest_pos -= 1; } else { // Galloping mode. first_count = self.first_pos as usize + 1 - gallop_right( unsafe { self.tmp.get_unchecked(self.second_pos as usize) }, self.list.split_at(self.first_pos as usize + 1).0, gallop::Mode::Reverse, is_greater, )?; unsafe { copy_backwards( self.list.get_unchecked(self.first_pos as usize), self.list.get_unchecked_mut(self.dest_pos as usize), first_count, ) } self.dest_pos -= first_count as isize; self.first_pos -= first_count as isize; debug_assert!(self.first_pos + self.second_pos + 1 == self.dest_pos); if self.first_pos < self.dest_pos && self.first_pos >= 0 { second_count = self.second_pos as usize + 1 - gallop_left( unsafe { self.list.get_unchecked(self.first_pos as usize) }, self.tmp.split_at(self.second_pos as usize + 1).0, gallop::Mode::Reverse, is_greater, )?; unsafe { copy_nonoverlapping_backwards( self.tmp.get_unchecked(self.second_pos as usize), self.list.get_unchecked_mut(self.dest_pos as usize), second_count, ) } self.dest_pos -= second_count as isize; self.second_pos -= second_count as isize; } } } Ok(()) } } /// Perform a backwards `ptr::copy_nonoverlapping`. Behave identically when size = 1, but behave /// differently all other times unsafe fn copy_backwards(src: *const T, dest: *mut T, size: usize) { ptr::copy( src.sub(size.wrapping_sub(1)), dest.sub(size.wrapping_sub(1)), size, ) } /// Perform a backwards `ptr::copy_nonoverlapping`. Behave identically when size = 1, but behave /// differently all other times unsafe fn copy_nonoverlapping_backwards(src: *const T, dest: *mut T, size: usize) { ptr::copy_nonoverlapping( src.sub(size.wrapping_sub(1)), dest.sub(size.wrapping_sub(1)), size, ) } impl<'a, T: 'a, E, C: Fn(&T, &T) -> Result> Drop for MergeHi<'a, T, E, C> { /// Copy all remaining items in the temporary storage into the list. /// If the comparator panics, the result will not be sorted, but will still /// contain no duplicates or uninitialized spots. fn drop(&mut self) { unsafe { // Make sure that the entire tmp storage is consumed. Since there are no uninitialized // spaces before dest_pos, and no uninitialized space after first_pos, this will ensure // that there are no uninitialized spaces inside the slice after we drop. Thus, the // function is safe. if self.second_pos >= 0 { copy_nonoverlapping_backwards( self.tmp.get_unchecked(self.second_pos as usize), self.list.get_unchecked_mut(self.dest_pos as usize), self.second_pos as usize + 1, ); } // The temporary storage is now full of nothing but uninitialized. // We want to deallocate the space, but not call the destructors. self.tmp.set_len(0); } } } timsort-0.1.2/src/sort/tests.rs010064400017500001750000000053411372155524100146720ustar 00000000000000//! The top sorting algorithm; that is, the modified merge sort we keep //! talking about. use crate::{never, NeverResult}; /// Test the sort implementation with an empty list #[test] fn empty() { let mut list: Vec = vec![]; sort(&mut list); assert!(list.is_empty()); } /// Test the sort implementation with a single-element list #[test] fn single() { let mut list = vec![42]; sort(&mut list); assert!(list[0] == 42); } /// Test the sort implementation with a short unsorted list #[test] fn unsorted() { let mut list = vec![3, 1, 0, 4]; sort(&mut list); assert!(list[0] == 0); assert!(list[1] == 1); assert!(list[2] == 3); assert!(list[3] == 4); } /// Test the sort implementation with a short backward list #[test] fn reverse() { let mut list = vec![21, 18, 7, 1]; sort(&mut list); assert!(list[0] == 1); assert!(list[1] == 7); assert!(list[2] == 18); assert!(list[3] == 21); } /// Test the sort implementation with a short unsorted list #[test] fn sorted() { let mut list = vec![0, 1, 2, 3]; sort(&mut list); assert!(list[0] == 0); assert!(list[1] == 1); assert!(list[2] == 2); assert!(list[3] == 3); } /// Make sure the sort is stable. #[test] fn stable_npow2() { let len = 259; let mut key1: usize = 0; let mut key2: usize = 0; #[derive(Debug)] struct Item { key1: usize, key2: usize, }; let mut list: Vec = (0..len) .map(|_| { key1 += 1; key1 %= 5; key2 += 1; Item { key1, key2 } }) .collect(); crate::sort_by_gt(&mut list, |a, b| a.key1 > b.key1); for i in 0..(len - 1) { assert!(list[i].key1 <= list[i + 1].key1); if list[i].key1 == list[i + 1].key1 { assert!(list[i].key2 <= list[i + 1].key2); } } } /// Make sure the sort is stable. #[test] fn stable() { let len = 256; let mut key1: usize = 0; let mut key2: usize = 0; #[derive(Debug)] struct Item { key1: usize, key2: usize, }; let mut list: Vec = (0..len) .map(|_| { key1 += 1; key1 %= 5; key2 += 1; Item { key1, key2 } }) .collect(); crate::sort_by_gt(&mut list, |a, b| a.key1 > b.key1); for i in 0..(len - 1) { assert!(list[i].key1 <= list[i + 1].key1); if list[i].key1 == list[i + 1].key1 { assert!(list[i].key2 <= list[i + 1].key2); } } } /// Sort implementation convenience used for tests. pub fn sort(list: &mut [T]) { let mut sort_state = super::SortState::new(list, |a, b| -> NeverResult<_> { Ok(a > b) }); sort_state.sort().unwrap_or_else(never); } timsort-0.1.2/src/sort.rs010064400017500001750000000120341373472606600135360ustar 00000000000000//! The top sorting algorithm; that is, the modified merge sort we keep //! talking about. #[cfg(test)] mod tests; use crate::find_run::get_run; use crate::insort; use crate::merge::merge; use std::cmp::min; /// Minimum run length to merge; anything shorter will be lengthend and /// sorted using `insort::sort`. const MIN_MERGE: usize = 64; /// Compute the actual minimum merge size for a particular list. fn calc_min_merge(mut len: usize) -> usize { if len < MIN_MERGE { len } else { let mut r: usize = 0; while len >= MIN_MERGE { r |= len & 1; len >>= 1; } len + r } } /// Represents a known-sorted sublist. #[derive(Copy, Clone, Debug)] struct Run { pos: usize, len: usize, } /// All the ongoing state of the sort. struct SortState<'a, T: 'a, E, C: Fn(&T, &T) -> Result> { /// The list that is being sorted. list: &'a mut [T], /// The comparator function. Should return true if the first argument is /// greater than the second. is_greater: C, /// The list of known-sorted sections of the list that can be merged. /// To keep the size of this list down, this invariant is preserved: /// - `runs.len < 3 || runs[i-2].len > runs[i-1].len + runs[i].len` /// - `runs.len < 2 || runs[i-1].len > runs[i].len` runs: Vec, /// The current position in the list. When `pos == list.len()`, we can now /// merge the last of the runs, and we're done. pos: usize, } impl<'a, T: 'a, E, C: Fn(&T, &T) -> Result> SortState<'a, T, E, C> { fn new(list: &'a mut [T], is_greater: C) -> SortState<'a, T, E, C> { SortState { list, is_greater, runs: Vec::new(), pos: 0, } } /// The outer loop. Find runs, and move forward. fn sort(&mut self) -> Result<(), E> { let list_len = self.list.len(); // Minimum run size to use merge sort on. Any sorted sections of the // list that are shorter than this are lengthened using `insort::sort`. let min_run = calc_min_merge(list_len); while self.pos < list_len { let pos = self.pos; let mut run_len = get_run(&mut self.list[pos..], &self.is_greater)?; let run_min_len = min(min_run, list_len - pos); if run_len < run_min_len { run_len = run_min_len; let l = &mut self.list[pos..][..run_len]; insort::sort(l, &self.is_greater)?; } self.runs.push(Run { pos, len: run_len }); self.pos += run_len; self.merge_collapse()?; } self.merge_force_collapse()?; Ok(()) } /// Merge the runs if they're too big. /// Copied almost verbatim from /// http://envisage-project.eu/proving-android-java-and-python-sorting-algorithm-is-broken-and-how-to-fix-it/#sec3.2 fn merge_collapse(&mut self) -> Result<(), E> { let runs = &mut self.runs; while runs.len() > 1 { let l = runs.len(); if (l >= 3 && runs[l - 1].len <= runs[l - 2].len + runs[l - 1].len) || (l >= 4 && runs[l - 4].len <= runs[l - 2].len + runs[l - 3].len) { let (pos1, pos2) = if runs[l - 3].len < runs[l - 1].len { (l - 3, l - 2) } else { (l - 2, l - 1) }; let (run1, run2) = (runs[pos1], runs[pos2]); debug_assert_eq!(run1.pos + run1.len, run2.pos); runs.remove(pos2); runs[pos1] = Run { pos: run1.pos, len: run1.len + run2.len, }; let l = &mut self.list[run1.pos..][..run1.len + run2.len]; merge(l, run1.len, &self.is_greater)?; } else { break; // Invariant established. } } Ok(()) } /// Merge any outstanding runs, at the end. fn merge_force_collapse(&mut self) -> Result<(), E> { let runs = &mut self.runs; while runs.len() > 1 { let (mut pos1, mut pos2) = (runs.len() - 2, runs.len() - 1); if runs.len() > 2 && runs[runs.len() - 3].len < runs[runs.len() - 1].len { pos1 -= 1; pos2 -= 1; } let (run1, run2) = (runs[pos1], runs[pos2]); debug_assert_eq!(run1.len, run2.pos); runs.remove(pos2); runs[pos1] = Run { pos: run1.pos, len: run1.len + run2.len, }; let l = &mut self.list[run1.pos..][..run1.len + run2.len]; merge(l, run1.len, &self.is_greater)?; } Ok(()) } } /// Sorts the list using merge sort. pub fn try_sort_by Result>( list: &mut [T], is_greater: C, ) -> Result<(), E> { if list.len() < MIN_MERGE { insort::sort(list, is_greater) } else { let mut sort_state = SortState::new(list, is_greater); sort_state.sort() } }