diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 11:44:51 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 11:44:51 +0000 |
commit | 9e3c08db40b8916968b9f30096c7be3f00ce9647 (patch) | |
tree | a68f146d7fa01f0134297619fbe7e33db084e0aa /third_party/rust/range-map | |
parent | Initial commit. (diff) | |
download | thunderbird-9e3c08db40b8916968b9f30096c7be3f00ce9647.tar.xz thunderbird-9e3c08db40b8916968b9f30096c7be3f00ce9647.zip |
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/range-map')
-rw-r--r-- | third_party/rust/range-map/.cargo-checksum.json | 1 | ||||
-rw-r--r-- | third_party/rust/range-map/Cargo.toml | 29 | ||||
-rw-r--r-- | third_party/rust/range-map/LICENSE-APACHE | 201 | ||||
-rw-r--r-- | third_party/rust/range-map/LICENSE-MIT | 25 | ||||
-rw-r--r-- | third_party/rust/range-map/README.md | 12 | ||||
-rw-r--r-- | third_party/rust/range-map/src/lib.rs | 1146 |
6 files changed, 1414 insertions, 0 deletions
diff --git a/third_party/rust/range-map/.cargo-checksum.json b/third_party/rust/range-map/.cargo-checksum.json new file mode 100644 index 0000000000..20f82477b3 --- /dev/null +++ b/third_party/rust/range-map/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"24509e7128fc24c54de4a267d0dcba9a098e628f8966733db45c43bb76143153","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"9b0e1f1455802d86d04aa0e2108e768787465367e6af5384263b352fee01e051","src/lib.rs":"f5c106b6e557f0c45410b0445d84d494df3812cb59977c76b19060d24dd0d4a4"},"package":"12a5a2d6c7039059af621472a4389be1215a816df61aa4d531cfe85264aee95f"}
\ No newline at end of file diff --git a/third_party/rust/range-map/Cargo.toml b/third_party/rust/range-map/Cargo.toml new file mode 100644 index 0000000000..c41fc1cd3c --- /dev/null +++ b/third_party/rust/range-map/Cargo.toml @@ -0,0 +1,29 @@ +# 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 are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +name = "range-map" +version = "0.2.0" +authors = ["Joe Neeman <joeneeman@gmail.com>"] +description = "Maps and sets implemented using ranges." +documentation = "http://jneem.github.io/range-map" +readme = "README.md" +license = "MIT/Apache-2.0" +repository = "http://github.com/jneem/range-map" + +[dependencies.num-traits] +version = "0.2" + +[dev-dependencies.num-iter] +version = "0.1" + +[dev-dependencies.quickcheck] +version = "0.8" diff --git a/third_party/rust/range-map/LICENSE-APACHE b/third_party/rust/range-map/LICENSE-APACHE new file mode 100644 index 0000000000..16fe87b06e --- /dev/null +++ b/third_party/rust/range-map/LICENSE-APACHE @@ -0,0 +1,201 @@ + 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. diff --git a/third_party/rust/range-map/LICENSE-MIT b/third_party/rust/range-map/LICENSE-MIT new file mode 100644 index 0000000000..39d4bdb5ac --- /dev/null +++ b/third_party/rust/range-map/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 The Rust Project Developers + +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. diff --git a/third_party/rust/range-map/README.md b/third_party/rust/range-map/README.md new file mode 100644 index 0000000000..b3a23b1b1a --- /dev/null +++ b/third_party/rust/range-map/README.md @@ -0,0 +1,12 @@ +range-map +========= + +This crate provides maps and sets where the key is a primitive integer type. +Whereas in general-purpose maps and sets performance generally depends on the +number of keys, here it depends on the number of *ranges* of keys. For example, +in this crate it's very easy to represent the set of all `u32` values, but it +would be a bad idea to represent the same set using +`std::collections::HashSet<u32>`. + +[Documentation](http://jneem.github.io/range-map/range_map/index.html) + diff --git a/third_party/rust/range-map/src/lib.rs b/third_party/rust/range-map/src/lib.rs new file mode 100644 index 0000000000..365c0bd417 --- /dev/null +++ b/third_party/rust/range-map/src/lib.rs @@ -0,0 +1,1146 @@ +// Copyright 2015 Joe Neeman. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern crate num_traits; + +#[cfg(test)] +extern crate num_iter; +#[cfg(test)] +extern crate quickcheck; + +use num_traits::PrimInt; +use std::cmp::{max, min, Ordering}; +use std::fmt::{Debug, Formatter}; +use std::iter::FromIterator; +use std::{mem, usize}; + +const DISPLAY_LIMIT: usize = 10; + +/// A range of elements, including the endpoints. +#[derive(Copy, Clone, Hash, PartialEq, PartialOrd, Eq, Ord)] +pub struct Range<T> { + pub start: T, + pub end: T, +} + +impl<T: Debug> Debug for Range<T> { + fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> { + try!(self.start.fmt(f)); + try!(f.write_str(" -- ")); + try!(self.end.fmt(f)); + Ok(()) + } +} + +impl<T: PrimInt> Range<T> { + /// Creates a new range with the given start and endpoints (inclusive). + /// + /// # Panics + /// - if `start` is strictly larger than `end` + pub fn new(start: T, end: T) -> Range<T> { + if start > end { + panic!("Ranges must be ordered"); + } + Range { + start: start, + end: end, + } + } + + /// Creates a new range containing everything. + pub fn full() -> Range<T> { + Range { + start: T::min_value(), + end: T::max_value(), + } + } + + /// Creates a new range containing a single thing. + pub fn single(x: T) -> Range<T> { + Range::new(x, x) + } + + /// Tests whether a given element belongs to this range. + pub fn contains(&self, x: T) -> bool { + self.start <= x && x <= self.end + } + + /// Checks whether the intersections overlap. + pub fn intersects(&self, other: &Self) -> bool { + self.start <= other.end && self.end >= other.start + } + + /// Computes the intersection between two ranges. Returns none if the intersection is empty. + pub fn intersection(&self, other: &Self) -> Option<Self> { + if self.intersects(other) { + Some(Range::new( + max(self.start, other.start), + min(self.end, other.end), + )) + } else { + None + } + } + + /// Returns the smallest range that covers `self` and `other`. + pub fn cover(&self, other: &Self) -> Self { + Range::new(min(self.start, other.start), max(self.end, other.end)) + } +} + +impl<T: PrimInt> PartialEq<T> for Range<T> { + fn eq(&self, x: &T) -> bool { + self.contains(*x) + } +} + +impl<T: PrimInt> PartialOrd<T> for Range<T> { + fn partial_cmp(&self, x: &T) -> Option<Ordering> { + if self.end < *x { + Some(Ordering::Less) + } else if self.start > *x { + Some(Ordering::Greater) + } else { + Some(Ordering::Equal) + } + } +} + +/// When creating a [`RangeMap`] from a list of ranges and values, there's a possiblity that two +/// ranges will overlap. In this case, it's a problem if they want to be associated to different +/// values (because we don't know which value should be assigned to the intersection of the +/// ranges). An `OverlapError` is the result of such a situation. It contains two members. The +/// first is a [`RangeMap`] obtained by simply ignoring all the ranges that would cause a bad +/// overlap. The second is the collection of ranges that were ignored. +// TODO: an example +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub struct OverlapError<T, V> { + pub non_overlapping: RangeMap<T, V>, + pub discarded: Vec<(Range<T>, V)>, +} + +/// A set of characters. Optionally, each character in the set may be associated with some data. +#[derive(Clone, Eq, Hash, PartialEq)] +pub struct RangeMap<T, V> { + elts: Vec<(Range<T>, V)>, +} + +impl<T: Debug, V: Debug> Debug for RangeMap<T, V> { + // When alternate formatting is specified, only prints out the first bunch of mappings. + fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> { + try!(f.write_fmt(format_args!("RangeMap ("))); + + if f.alternate() { + try!(f + .debug_map() + .entries(self.elts.iter().map(|x| (&x.0, &x.1)).take(DISPLAY_LIMIT)) + .finish()); + if self.elts.len() > DISPLAY_LIMIT { + try!(f.write_str("...")); + } + } else { + try!(f + .debug_map() + .entries(self.elts.iter().map(|x| (&x.0, &x.1))) + .finish()); + } + try!(f.write_str(")")); + Ok(()) + } +} + +impl<T: Debug + PrimInt, V: Clone + Debug + Eq> FromIterator<(Range<T>, V)> for RangeMap<T, V> { + /// Builds a `RangeMap` from an iterator over pairs. If any ranges overlap, they must map to + /// the same value. + /// + /// # Panics + /// Panics if there are ranges that overlap and do not map to the same value. If you are not + /// sure whether this could happen, use [`RangeMap::try_from_iter`] instead. + fn from_iter<I: IntoIterator<Item = (Range<T>, V)>>(iter: I) -> Self { + RangeMap::try_from_iter(iter).ok().unwrap() + } +} + +impl<T: Debug + PrimInt, V: Clone + Debug + Eq> RangeMap<T, V> { + /// Creates a new empty `RangeMap`. + pub fn new() -> RangeMap<T, V> { + RangeMap { elts: Vec::new() } + } + + /// Builds a `RangeMap` from an iterator over pairs. If any ranges overlap, they should map to + /// the same value. If not, returns an [`OverlapError`]. + pub fn try_from_iter<I: IntoIterator<Item = (Range<T>, V)>>( + iter: I, + ) -> Result<RangeMap<T, V>, OverlapError<T, V>> { + let mut vec: Vec<_> = iter.into_iter().collect(); + vec.sort_by(|x, y| x.0.cmp(&y.0)); + let mut ret = RangeMap { elts: vec }; + let discarded = ret.normalize(); + + if discarded.is_empty() { + Ok(ret) + } else { + Err(OverlapError { + non_overlapping: ret, + discarded: discarded, + }) + } + } + + // Creates a `RangeMap` from a `Vec`, which must contain ranges in ascending order. If any + // ranges overlap, they must map to the same value. + // + // Panics if the ranges are not sorted, or if they overlap without mapping to the same value. + fn from_sorted_vec(vec: Vec<(Range<T>, V)>) -> RangeMap<T, V> { + let mut ret = RangeMap { elts: vec }; + ret.normalize(); + ret + } + + // Creates a RangeMap from a Vec, which must be sorted and normalized. + // + // Panics unless `vec` is sorted and normalized. + fn from_norm_vec(vec: Vec<(Range<T>, V)>) -> RangeMap<T, V> { + for i in 1..vec.len() { + if vec[i].0.start <= vec[i - 1].0.end { + panic!( + "vector {:?} has overlapping ranges {:?} and {:?}", + vec, + vec[i - 1], + vec[i] + ); + } + // If vec[i-1].0.end is T::max_value() then we've already panicked, so the unwrap is + // safe. + if vec[i].0.start == vec[i - 1].0.end.checked_add(&T::one()).unwrap() + && vec[i].1 == vec[i - 1].1 + { + panic!( + "vector {:?} has adjacent ranges with same value {:?} and {:?}", + vec, + vec[i - 1], + vec[i] + ); + } + } + + RangeMap { elts: vec } + } + + /// Returns the number of mapped ranges. + /// + /// Note that this is not usually the same as the number of mapped values. + pub fn num_ranges(&self) -> usize { + self.elts.len() + } + + /// Tests whether this map is empty. + pub fn is_empty(&self) -> bool { + self.elts.is_empty() + } + + /// Tests whether this `CharMap` maps every value. + pub fn is_full(&self) -> bool { + let mut last_end = T::min_value(); + for &(range, _) in &self.elts { + if range.start > last_end { + return false; + } + last_end = range.end; + } + last_end == T::max_value() + } + + /// Iterates over all the mapped ranges and values. + pub fn ranges_values<'a>(&'a self) -> std::slice::Iter<'a, (Range<T>, V)> { + self.elts.iter() + } + + /// Iterates over all mappings. + pub fn keys_values<'a>(&'a self) -> PairIter<'a, T, V> { + PairIter { + map: self, + next_range_idx: if self.is_empty() { None } else { Some(0) }, + next_key: if self.is_empty() { + T::min_value() + } else { + self.elts[0].0.start + }, + } + } + + /// Finds the value that `x` maps to, if it exists. + /// + /// Runs in `O(log n)` time, where `n` is the number of mapped ranges. + pub fn get(&self, x: T) -> Option<&V> { + self.elts + // The unwrap is ok because Range<T>::partial_cmp(&T) never returns None. + .binary_search_by(|r| r.0.partial_cmp(&x).unwrap()) + .ok() + .map(|idx| &self.elts[idx].1) + } + + // Minimizes the number of ranges in this map. + // + // If there are any overlapping ranges that map to the same data, merges them. Assumes that the + // ranges are sorted according to their start. + // + // If there are overlapping ranges that map to different values, we delete them. The return + // value is the collection of all ranges that were deleted. + // + // TODO: because the output is always smaller than the input, this could be done in-place. + fn normalize(&mut self) -> Vec<(Range<T>, V)> { + let mut vec = Vec::with_capacity(self.elts.len()); + let mut discarded = Vec::new(); + mem::swap(&mut vec, &mut self.elts); + + for (range, val) in vec.into_iter() { + if let Some(&mut (ref mut last_range, ref last_val)) = self.elts.last_mut() { + if range.start <= last_range.end && &val != last_val { + discarded.push((range, val)); + continue; + } + + if range.start <= last_range.end.saturating_add(T::one()) && &val == last_val { + last_range.end = max(range.end, last_range.end); + continue; + } + } + + self.elts.push((range, val)); + } + + discarded + } + + /// Returns those mappings whose keys belong to the given set. + pub fn intersection(&self, other: &RangeSet<T>) -> RangeMap<T, V> { + let mut ret = Vec::new(); + let mut other_iter = other.map.elts.iter().peekable(); + + for &(ref r, ref data) in &self.elts { + while let Some(&&(ref s, _)) = other_iter.peek() { + if let Some(int) = s.intersection(r) { + ret.push((int, data.clone())); + } + + if s.end >= r.end { + break; + } else { + other_iter.next(); + } + } + } + + RangeMap::from_sorted_vec(ret) + } + + /// Counts the number of mapped keys. + /// + /// This saturates at `usize::MAX`. + pub fn num_keys(&self) -> usize { + self.ranges_values().fold(0, |acc, range| { + acc.saturating_add( + (range.0.end - range.0.start) + .to_usize() + .unwrap_or(usize::MAX), + ) + .saturating_add(1) + }) + } + + /// Returns the set of mapped chars, forgetting what they are mapped to. + pub fn to_range_set(&self) -> RangeSet<T> { + RangeSet::from_sorted_vec(self.elts.iter().map(|x| (x.0, ())).collect()) + } + + /// Modifies the values in place. + pub fn map_values<F>(&mut self, mut f: F) + where + F: FnMut(&V) -> V, + { + for &mut (_, ref mut data) in &mut self.elts { + *data = f(data); + } + + // We need to re-normalize, because we might have mapped two adjacent ranges to the same + // value. + self.normalize(); + } + + /// Modifies this map to contain only those mappings with values `v` satisfying `f(v)`. + pub fn retain_values<F>(&mut self, mut f: F) + where + F: FnMut(&V) -> bool, + { + self.elts.retain(|x| f(&x.1)); + } + + /// Returns a mutable view into this map. + /// + /// The ranges should not be modified, since that might violate our invariants. + /// + /// This method will eventually be removed, probably once anonymous return values allow is to + /// write a values_mut() iterator more easily. + pub fn as_mut_slice(&mut self) -> &mut [(Range<T>, V)] { + &mut self.elts + } +} + +#[derive(Copy, Clone, Debug)] +pub struct PairIter<'a, T: 'a, V: 'a> { + map: &'a RangeMap<T, V>, + next_range_idx: Option<usize>, + next_key: T, +} + +impl<'a, T: PrimInt, V> Iterator for PairIter<'a, T, V> { + type Item = (T, &'a V); + fn next(&mut self) -> Option<Self::Item> { + if let Some(idx) = self.next_range_idx { + let ret = (self.next_key, &self.map.elts[idx].1); + + if self.next_key < self.map.elts[idx].0.end { + self.next_key = self.next_key + T::one(); + } else if idx < self.map.elts.len() - 1 { + self.next_range_idx = Some(idx + 1); + self.next_key = self.map.elts[idx + 1].0.start; + } else { + self.next_range_idx = None; + } + + Some(ret) + } else { + None + } + } +} + +/// A set of integers, implemented as a sorted list of (inclusive) ranges. +#[derive(Clone, Eq, Hash, PartialEq)] +pub struct RangeSet<T> { + map: RangeMap<T, ()>, +} + +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub struct RangeIter<'a, T: PrimInt + 'a> { + set: &'a RangeSet<T>, + next_idx: usize, +} + +impl<'a, T: Debug + PrimInt> Iterator for RangeIter<'a, T> { + type Item = Range<T>; + fn next(&mut self) -> Option<Range<T>> { + if self.next_idx < self.set.num_ranges() { + let ret = Some(self.set.map.elts[self.next_idx].0); + self.next_idx += 1; + ret + } else { + None + } + } +} + +#[derive(Copy, Clone, Debug)] +pub struct EltIter<'a, T: 'a + PrimInt> { + set: &'a RangeSet<T>, + next_range_idx: Option<usize>, + next_elt: T, +} + +impl<'a, T: Debug + PrimInt> Iterator for EltIter<'a, T> { + type Item = T; + fn next(&mut self) -> Option<T> { + if let Some(idx) = self.next_range_idx { + let ret = Some(self.next_elt); + if self.next_elt >= self.set.map.elts[idx].0.end { + if idx + 1 < self.set.num_ranges() { + self.next_range_idx = Some(idx + 1); + self.next_elt = self.set.map.elts[idx + 1].0.start; + } else { + self.next_range_idx = None; + } + } else { + self.next_elt = self.next_elt + T::one(); + } + ret + } else { + None + } + } +} + +impl<T: Debug + PrimInt> Debug for RangeSet<T> { + // When alternate formatting is specified, only prints out the first buch of mappings. + fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> { + try!(f.write_fmt(format_args!("RangeSet ("))); + + if f.alternate() { + try!(f + .debug_set() + .entries(self.ranges().take(DISPLAY_LIMIT)) + .finish()); + if self.num_ranges() > DISPLAY_LIMIT { + try!(f.write_str("...")); + } + } else { + try!(f.debug_set().entries(self.ranges()).finish()); + } + try!(f.write_str(")")); + Ok(()) + } +} + +impl<T: Debug + PrimInt> FromIterator<Range<T>> for RangeSet<T> { + /// Builds a `RangeSet` from an iterator over `Range`s. + fn from_iter<I: IntoIterator<Item = Range<T>>>(iter: I) -> Self { + RangeSet { + // The unwrap here is ok because RangeMap::try_from_iter only fails when two + // overlapping ranges map to different values. Since every range here maps to the same + // value, (i.e. ()), this will never happen. + map: RangeMap::try_from_iter(iter.into_iter().map(|x| (x, ()))) + .ok() + .unwrap(), + } + } +} + +impl<T: Debug + PrimInt> RangeSet<T> { + /// Creates a new empty `RangeSet`. + pub fn new() -> RangeSet<T> { + RangeSet { + map: RangeMap::new(), + } + } + + /// Tests if this set is empty. + pub fn is_empty(&self) -> bool { + self.map.is_empty() + } + + /// Tests whether this set contains every valid value of `T`. + pub fn is_full(&self) -> bool { + // We are assuming normalization here. + self.num_ranges() == 1 && self.map.elts[0].0 == Range::full() + } + + /// Returns the number of ranges used to represent this set. + pub fn num_ranges(&self) -> usize { + self.map.num_ranges() + } + + /// Returns the number of elements in the set. + /// + /// This saturates at `usize::MAX`. + pub fn num_elements(&self) -> usize { + self.map.num_keys() + } + + /// Returns an iterator over all ranges in this set. + pub fn ranges<'a>(&'a self) -> RangeIter<'a, T> { + RangeIter { + set: self, + next_idx: 0, + } + } + + /// Returns an iterator over all elements in this set. + pub fn elements<'a>(&'a self) -> EltIter<'a, T> { + if self.map.elts.is_empty() { + EltIter { + set: self, + next_range_idx: None, + next_elt: T::min_value(), + } + } else { + EltIter { + set: self, + next_range_idx: Some(0), + next_elt: self.map.elts[0].0.start, + } + } + } + + /// Checks if this set contains a value. + pub fn contains(&self, val: T) -> bool { + self.map.get(val).is_some() + } + + // Creates a RangeSet from a vector. The vector must be sorted, but it does not need to be + // normalized. + fn from_sorted_vec(vec: Vec<(Range<T>, ())>) -> RangeSet<T> { + RangeSet { + map: RangeMap::from_sorted_vec(vec), + } + } + + // Creates a RangeSet from a vector. The vector must be normalized, in the sense that it should + // contain no adjacent ranges. + fn from_norm_vec(vec: Vec<(Range<T>, ())>) -> RangeSet<T> { + RangeSet { + map: RangeMap::from_norm_vec(vec), + } + } + + /// Returns the union between `self` and `other`. + pub fn union(&self, other: &RangeSet<T>) -> RangeSet<T> { + if self.is_empty() { + return other.clone(); + } else if other.is_empty() { + return self.clone(); + } + + let mut ret = Vec::with_capacity(self.map.elts.len() + other.map.elts.len()); + let mut it1 = self.map.elts.iter(); + let mut it2 = other.map.elts.iter(); + let mut r1 = it1.next(); + let mut r2 = it2.next(); + let mut cur_range: Option<Range<T>> = None; + + while r1.is_some() || r2.is_some() { + let r1_start = if let Some(&(r, _)) = r1 { + r.start + } else { + T::max_value() + }; + let r2_start = if let Some(&(r, _)) = r2 { + r.start + } else { + T::max_value() + }; + if let Some(cur) = cur_range { + if min(r1_start, r2_start) > cur.end.saturating_add(T::one()) { + ret.push((cur_range.unwrap(), ())); + cur_range = None; + } + } + + let cover = |cur: &mut Option<Range<T>>, next: &Range<T>| { + if let &mut Some(ref mut r) = cur { + *r = r.cover(next); + } else { + *cur = Some(*next); + } + }; + + if r1_start < r2_start || r2.is_none() { + cover(&mut cur_range, &r1.unwrap().0); + r1 = it1.next(); + } else { + cover(&mut cur_range, &r2.unwrap().0); + r2 = it2.next(); + } + } + + if cur_range.is_some() { + ret.push((cur_range.unwrap(), ())); + } + + RangeSet::from_norm_vec(ret) + } + + /// Creates a set that contains every value of `T`. + pub fn full() -> RangeSet<T> { + RangeSet::from_norm_vec(vec![(Range::full(), ())]) + } + + /// Creates a set containing a single element. + pub fn single(x: T) -> RangeSet<T> { + RangeSet::from_norm_vec(vec![(Range::single(x), ())]) + } + + /// Creates a set containing all elements except the given ones. The input iterator must be + /// sorted. If it is not, this will return `None`. + pub fn except<I: Iterator<Item = T>>(it: I) -> Option<RangeSet<T>> { + let mut ret = Vec::new(); + let mut next_allowed = T::min_value(); + let mut last_forbidden = T::max_value(); + + for i in it { + if i > next_allowed { + ret.push((Range::new(next_allowed, i - T::one()), ())); + } else if i < next_allowed.saturating_sub(T::one()) { + return None; + } + + last_forbidden = i; + next_allowed = i.saturating_add(T::one()); + } + + if last_forbidden < T::max_value() { + ret.push((Range::new(last_forbidden + T::one(), T::max_value()), ())); + } + Some(RangeSet::from_norm_vec(ret)) + } + + /// Finds the intersection between this set and `other`. + pub fn intersection(&self, other: &RangeSet<T>) -> RangeSet<T> { + RangeSet { + map: self.map.intersection(other), + } + } + + /// Returns the set of all characters that are not in this set. + pub fn negated(&self) -> RangeSet<T> { + let mut ret = Vec::with_capacity(self.num_ranges() + 1); + let mut last_end = T::min_value(); + + for range in self.ranges() { + if range.start > last_end { + ret.push((Range::new(last_end, range.start - T::one()), ())); + } + last_end = range.end.saturating_add(T::one()); + } + if last_end < T::max_value() { + ret.push((Range::new(last_end, T::max_value()), ())); + } + + RangeSet::from_norm_vec(ret) + } +} + +/// A multi-valued mapping from primitive integers to other data. +#[derive(Clone, Eq, Hash, PartialEq)] +pub struct RangeMultiMap<T, V> { + elts: Vec<(Range<T>, V)>, +} + +impl<T: Debug + PrimInt, V: Clone + Debug + PartialEq> FromIterator<(Range<T>, V)> + for RangeMultiMap<T, V> +{ + /// Builds a `RangeMultiMap` from an iterator over `Range` and values.. + fn from_iter<I: IntoIterator<Item = (Range<T>, V)>>(iter: I) -> Self { + RangeMultiMap::from_vec(iter.into_iter().collect()) + } +} + +impl<T: Debug + PrimInt, V: Clone + Debug + PartialEq> Debug for RangeMultiMap<T, V> { + fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> { + try!(f.write_fmt(format_args!("RangeMultiMap ("))); + + if f.alternate() { + try!(f + .debug_map() + .entries( + self.ranges_values() + .map(|x| (&x.0, &x.1)) + .take(DISPLAY_LIMIT) + ) + .finish()); + if self.num_ranges() > DISPLAY_LIMIT { + try!(f.write_str("...")); + } + } else { + try!(f + .debug_set() + .entries(self.ranges_values().map(|x| (&x.0, &x.1))) + .finish()); + } + try!(f.write_str(")")); + Ok(()) + } +} + +impl<T: Debug + PrimInt, V: Clone + Debug + PartialEq> RangeMultiMap<T, V> { + /// Creates a new empty map. + pub fn new() -> RangeMultiMap<T, V> { + RangeMultiMap { elts: Vec::new() } + } + + /// Returns the number of mapped ranges. + pub fn num_ranges(&self) -> usize { + self.elts.len() + } + + /// Checks if the map is empty. + pub fn is_empty(&self) -> bool { + self.elts.is_empty() + } + + /// Adds a new mapping from a range of characters to `value`. + pub fn insert(&mut self, range: Range<T>, value: V) { + self.elts.push((range, value)); + } + + /// Creates a map from a vector of pairs. + pub fn from_vec(vec: Vec<(Range<T>, V)>) -> RangeMultiMap<T, V> { + RangeMultiMap { elts: vec } + } + + /// Returns a new `RangeMultiMap` containing only the mappings for keys that belong to the + /// given set. + pub fn intersection(&self, other: &RangeSet<T>) -> RangeMultiMap<T, V> { + let mut ret = Vec::new(); + for &(ref my_range, ref data) in &self.elts { + let start_idx = other + .map + .elts + .binary_search_by(|r| r.0.end.cmp(&my_range.start)) + .unwrap_or_else(|x| x); + for &(ref other_range, _) in &other.map.elts[start_idx..] { + if my_range.start > other_range.end { + break; + } else if let Some(r) = my_range.intersection(other_range) { + ret.push((r, data.clone())); + } + } + } + RangeMultiMap::from_vec(ret) + } + + pub fn map_values<F>(&mut self, mut f: F) + where + F: FnMut(&V) -> V, + { + for i in 0..self.elts.len() { + self.elts[i].1 = f(&self.elts[i].1); + } + } + + /// Modifies this map in place to only contain mappings whose values `v` satisfy `f(v)`. + pub fn retain_values<F>(&mut self, mut f: F) + where + F: FnMut(&V) -> bool, + { + self.elts.retain(|x| f(&x.1)); + } + + /// Returns the underlying `Vec`. + pub fn into_vec(self) -> Vec<(Range<T>, V)> { + self.elts + } + + /// Iterates over all the mapped ranges and values. + pub fn ranges_values<'a>(&'a self) -> std::slice::Iter<'a, (Range<T>, V)> { + self.elts.iter() + } +} + +impl<T: Debug + PrimInt, V: Clone + Debug + Ord> RangeMultiMap<T, V> { + /// Makes the ranges sorted and non-overlapping. The data associated with each range will + /// be a `Vec<T>` instead of a single `T`. + pub fn group(&self) -> RangeMap<T, Vec<V>> { + if self.elts.is_empty() { + return RangeMap::new(); + } + + let mut start_chars = Vec::with_capacity(self.elts.len() * 2); + + for &(ref range, _) in self.elts.iter() { + start_chars.push(range.start); + if range.end < T::max_value() { + start_chars.push(range.end + T::one()); + } + } + start_chars.sort(); + start_chars.dedup(); + + let mut ret: Vec<(Range<T>, Vec<V>)> = Vec::with_capacity(start_chars.len()); + for pair in start_chars.windows(2) { + ret.push((Range::new(pair[0], pair[1] - T::one()), Vec::new())); + } + ret.push(( + Range::new(*start_chars.last().unwrap(), T::max_value()), + Vec::new(), + )); + for &(range, ref val) in self.elts.iter() { + // The unwrap is OK because start_chars contains range.start for every range in elts. + let mut idx = start_chars.binary_search(&range.start).unwrap(); + while idx < start_chars.len() && start_chars[idx] <= range.end { + ret[idx].1.push(val.clone()); + idx += 1; + } + } + ret.retain(|x| !x.1.is_empty()); + RangeMap::from_sorted_vec(ret) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use num_iter::range_inclusive; + use num_traits::PrimInt; + use quickcheck::{quickcheck, Arbitrary, Gen, TestResult}; + use std::cmp::{max, min}; + use std::fmt::Debug; + use std::i32; + use std::ops::Add; + + impl<T: Arbitrary + Debug + PrimInt> Arbitrary for Range<T> { + fn arbitrary<G: Gen>(g: &mut G) -> Self { + let a = T::arbitrary(g); + let b = T::arbitrary(g); + Range::new(min(a, b), max(a, b)) + } + } + + impl<T> Arbitrary for RangeMultiMap<T, i32> + where + T: Arbitrary + Debug + PrimInt, + { + fn arbitrary<G: Gen>(g: &mut G) -> Self { + RangeMultiMap::from_vec(Vec::arbitrary(g)) + } + + fn shrink(&self) -> Box<Iterator<Item = Self>> { + Box::new(self.elts.shrink().map(|v| RangeMultiMap::from_vec(v))) + } + } + + impl<T> Arbitrary for RangeMap<T, i32> + where + T: Arbitrary + Debug + PrimInt, + { + fn arbitrary<G: Gen>(g: &mut G) -> Self { + let map: RangeMap<T, Vec<_>> = RangeMultiMap::arbitrary(g).group(); + // TODO: replace fold with sum once it's stable + map.ranges_values() + .map(|x| (x.0, x.1.iter().fold(0, Add::add))) + .collect() + } + + fn shrink(&self) -> Box<Iterator<Item = Self>> { + Box::new(self.elts.shrink().map(|v| RangeMap::from_norm_vec(v))) + } + } + + impl<T: Arbitrary + Debug + PrimInt> Arbitrary for RangeSet<T> { + fn arbitrary<G: Gen>(g: &mut G) -> Self { + RangeMap::arbitrary(g).to_range_set() + } + + fn shrink(&self) -> Box<Iterator<Item = Self>> { + Box::new(self.map.elts.shrink().map(|v| RangeSet::from_norm_vec(v))) + } + } + + #[test] + fn range_intersects_intersection() { + fn prop(r1: Range<i32>, r2: Range<i32>) -> bool { + r1.intersection(&r2).is_some() == r1.intersects(&r2) + } + quickcheck(prop as fn(_, _) -> _); + } + + #[test] + fn range_intersection_contains() { + fn prop(r1: Range<i32>, r2: Range<i32>, x: i32) -> TestResult { + if let Some(r) = r1.intersection(&r2) { + TestResult::from_bool(r.contains(x) == (r1.contains(x) && r2.contains(x))) + } else { + TestResult::discard() + } + } + quickcheck(prop as fn(_, _, _) -> _); + } + + #[test] + #[should_panic] + fn range_backwards() { + map(vec![(5, 1, 1), (6, 10, 2)]); + } + + #[test] + fn range_intersection_cover() { + fn prop(r1: Range<i32>, r2: Range<i32>) -> bool { + r1 == r1.cover(&r2).intersection(&r1).unwrap() + } + quickcheck(prop as fn(_, _) -> _); + } + + fn map(vec: Vec<(i32, i32, i32)>) -> RangeMap<i32, i32> { + vec.into_iter() + .map(|(a, b, c)| (Range::new(a, b), c)) + .collect() + } + + #[test] + fn rangemap_overlapping() { + assert_eq!(map(vec![(1, 5, 1), (2, 10, 1)]), map(vec![(1, 10, 1)])); + assert_eq!( + map(vec![(1, 5, 1), (2, 10, 1), (9, 11, 1)]), + map(vec![(1, 11, 1)]) + ); + map(vec![(1, 5, 1), (6, 10, 2)]); + } + + #[test] + #[should_panic] + fn rangemap_overlapping_nonequal() { + map(vec![(1, 5, 1), (5, 10, 2)]); + } + + #[test] + fn rangemap_intersection() { + fn prop(map: RangeMap<i32, i32>, set: RangeSet<i32>) -> bool { + let int = map.intersection(&set); + set.elements().all(|x| map.get(x) == int.get(x)) + && int.keys_values().all(|x| set.contains(x.0)) + } + quickcheck(prop as fn(_, _) -> _); + } + + #[test] + fn rangemap_num_ranges() { + fn prop(map: RangeMap<i32, i32>) -> bool { + map.num_ranges() == map.ranges_values().count() + } + quickcheck(prop as fn(_) -> _); + } + + #[test] + fn rangemap_num_keys() { + fn prop(map: RangeMap<i32, i32>) -> bool { + map.num_keys() == map.keys_values().count() + } + quickcheck(prop as fn(_) -> _); + } + + #[test] + fn rangemap_map_values() { + fn prop(map: RangeMap<i32, i32>, x: i32) -> bool { + let f = |y: &i32| (x + *y) % 10; + let new_map = { + let mut new_map = map.clone(); + new_map.map_values(&f); + new_map + }; + let new_map_norm = { + let mut new_map_norm = new_map.clone(); + new_map_norm.normalize(); + new_map_norm + }; + + new_map + .keys_values() + .all(|(k, v)| f(map.get(k).unwrap()) == *v) + && map + .keys_values() + .all(|(k, v)| *new_map.get(k).unwrap() == f(v)) + && new_map == new_map_norm + } + quickcheck(prop as fn(_, _) -> _); + } + + #[test] + fn rangemap_retain_values() { + fn prop(map: RangeMap<i32, i32>, r: Range<i32>) -> bool { + let mut new_map = map.clone(); + new_map.retain_values(|v| r.contains(*v)); + new_map.keys_values().all(|(_, v)| r.contains(*v)) + && map + .keys_values() + .all(|(k, v)| !r.contains(*v) || new_map.get(k).unwrap() == v) + } + quickcheck(prop as fn(_, _) -> _); + } + + #[test] + fn rangeset_contains() { + fn prop(set: RangeSet<i32>) -> bool { + set.elements().all(|e| set.contains(e)) + } + quickcheck(prop as fn(_) -> _); + } + + #[test] + fn rangeset_num_ranges() { + fn prop(set: RangeSet<i32>) -> bool { + set.num_ranges() == set.ranges().count() + } + quickcheck(prop as fn(_) -> _); + } + + #[test] + fn rangeset_num_elements() { + fn prop(set: RangeSet<i32>) -> bool { + set.num_elements() == set.elements().count() + } + quickcheck(prop as fn(_) -> _); + } + + #[test] + fn rangeset_union() { + fn prop(s1: RangeSet<i32>, s2: RangeSet<i32>) -> bool { + let un = s1.union(&s2); + un.elements().all(|e| s1.contains(e) || s2.contains(e)) + && s1.elements().all(|e| un.contains(e)) + && s2.elements().all(|e| un.contains(e)) + } + quickcheck(prop as fn(_, _) -> _); + } + + #[test] + fn rangeset_intersection() { + fn prop(s1: RangeSet<i32>, s2: RangeSet<i32>) -> bool { + let int = s1.intersection(&s2); + int.elements().all(|e| s1.contains(e) && s2.contains(e)) + && s1.elements().all(|e| int.contains(e) == s2.contains(e)) + } + quickcheck(prop as fn(_, _) -> _); + } + + #[test] + fn rangeset_negate() { + fn prop(set: RangeSet<i8>) -> bool { + let neg = set.negated(); + neg.elements().all(|e| !set.contains(e)) + && set.elements().all(|e| !neg.contains(e)) + && neg.negated() == set + } + quickcheck(prop as fn(_) -> _); + } + + #[test] + fn rangeset_except() { + fn prop(mut except: Vec<i8>) -> bool { + except.sort(); + let set = RangeSet::except(except.iter().cloned()).unwrap(); + set.elements().all(|e| except.binary_search(&e).is_err()) + && except.iter().all(|&e| !set.contains(e)) + } + quickcheck(prop as fn(_) -> _); + } + + #[test] + fn rangeset_except_unsorted() { + assert_eq!(None, RangeSet::except([1i32, 3, 2].iter().cloned())); + } + + // Check that things don't panic when we have MIN and MAX in the ranges (quickcheck doesn't + // check this properly). + #[test] + fn rangemultimap_boundaries() { + assert_eq!( + RangeMultiMap::from_vec(vec![ + (Range::new(i32::MIN, 200), 5), + (Range::new(100, i32::MAX), 10), + ]) + .group(), + RangeMap::from_sorted_vec(vec![ + (Range::new(i32::MIN, 99), vec![5]), + (Range::new(100, 200), vec![5, 10]), + (Range::new(201, i32::MAX), vec![10]), + ]) + ); + } + + #[test] + fn rangemultimap_group() { + fn prop(mm_vec: Vec<(Range<i32>, i32)>) -> bool { + let mm = RangeMultiMap::from_vec(mm_vec.clone()); + let grouped = mm.group(); + mm_vec.into_iter().all(|(range, val)| { + range_inclusive(range.start, range.end) + .all(|i| grouped.get(i).unwrap().contains(&val)) + }) + } + quickcheck(prop as fn(_) -> _); + } +} |