build: conditionally use map_first_last feature if available

This commit is contained in:
Waleed Khan 2022-02-20 22:14:13 -08:00
parent dd3272fe90
commit 9202aae8b1
8 changed files with 75 additions and 34 deletions

1
Cargo.lock generated
View file

@ -618,6 +618,7 @@ dependencies = [
"test-case", "test-case",
"thiserror", "thiserror",
"uuid", "uuid",
"version_check",
"whoami", "whoami",
"zstd", "zstd",
] ]

View file

@ -14,6 +14,7 @@ readme = "../README.md"
[build-dependencies] [build-dependencies]
protobuf-codegen-pure = "2.27.1" protobuf-codegen-pure = "2.27.1"
version_check = "0.9.4"
[dependencies] [dependencies]
backoff = "0.4.0" backoff = "0.4.0"

View file

@ -13,6 +13,7 @@
// limitations under the License. // limitations under the License.
extern crate protobuf_codegen_pure; extern crate protobuf_codegen_pure;
extern crate version_check;
use std::path::Path; use std::path::Path;
@ -45,4 +46,8 @@ fn main() {
for file in input { for file in input {
println!("cargo:rerun-if-changed={}", file); println!("cargo:rerun-if-changed={}", file);
} }
if let Some(true) = version_check::supports_feature("map_first_last") {
println!("cargo:rustc-cfg=feature=\"map_first_last\"");
}
} }

View file

@ -177,7 +177,7 @@ pub(crate) fn unchanged_ranges(
let max_occurrences = 100; let max_occurrences = 100;
let mut left_histogram = Histogram::calculate(left, left_ranges, max_occurrences); let mut left_histogram = Histogram::calculate(left, left_ranges, max_occurrences);
if *left_histogram.count_to_words.ext_first_key().unwrap() > max_occurrences { if *left_histogram.count_to_words.first_key().unwrap() > max_occurrences {
// If there are very many occurrences of all words, then we just give up. // If there are very many occurrences of all words, then we just give up.
return vec![]; return vec![];
} }
@ -187,7 +187,7 @@ pub(crate) fn unchanged_ranges(
// the LCS. // the LCS.
let mut uncommon_shared_words = vec![]; let mut uncommon_shared_words = vec![];
while !left_histogram.count_to_words.is_empty() && uncommon_shared_words.is_empty() { while !left_histogram.count_to_words.is_empty() && uncommon_shared_words.is_empty() {
let left_words = left_histogram.count_to_words.ext_pop_first_value().unwrap(); let left_words = left_histogram.count_to_words.pop_first_value().unwrap();
for left_word in left_words { for left_word in left_words {
if right_histogram.word_to_positions.contains_key(left_word) { if right_histogram.word_to_positions.contains_key(left_word) {
uncommon_shared_words.push(left_word); uncommon_shared_words.push(left_word);

View file

@ -34,6 +34,8 @@ use thiserror::Error;
use crate::backend::{ChangeId, CommitId}; use crate::backend::{ChangeId, CommitId};
use crate::commit::Commit; use crate::commit::Commit;
use crate::file_util::persist_content_addressed_temp_file; use crate::file_util::persist_content_addressed_temp_file;
#[cfg(not(feature = "map_first_last"))]
use crate::nightly_shims::BTreeSetExt; use crate::nightly_shims::BTreeSetExt;
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)] #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
@ -813,25 +815,25 @@ impl<'a> CompositeIndex<'a> {
let mut result = BTreeSet::new(); let mut result = BTreeSet::new();
while !(items1.is_empty() || items2.is_empty()) { while !(items1.is_empty() || items2.is_empty()) {
let entry1 = items1.ext_last().unwrap(); let entry1 = items1.last().unwrap();
let entry2 = items2.ext_last().unwrap(); let entry2 = items2.last().unwrap();
match entry1.cmp(entry2) { match entry1.cmp(entry2) {
Ordering::Greater => { Ordering::Greater => {
let entry1 = items1.ext_pop_last().unwrap(); let entry1 = items1.pop_last().unwrap();
for parent_entry in entry1.0.parents() { for parent_entry in entry1.0.parents() {
items1.insert(IndexEntryByGeneration(parent_entry)); items1.insert(IndexEntryByGeneration(parent_entry));
} }
} }
Ordering::Less => { Ordering::Less => {
let entry2 = items2.ext_pop_last().unwrap(); let entry2 = items2.pop_last().unwrap();
for parent_entry in entry2.0.parents() { for parent_entry in entry2.0.parents() {
items2.insert(IndexEntryByGeneration(parent_entry)); items2.insert(IndexEntryByGeneration(parent_entry));
} }
} }
Ordering::Equal => { Ordering::Equal => {
result.insert(entry1.0.pos); result.insert(entry1.0.pos);
items1.ext_pop_last(); items1.pop_last();
items2.ext_pop_last(); items2.pop_last();
} }
} }
} }

View file

@ -13,6 +13,7 @@
// limitations under the License. // limitations under the License.
#![deny(unused_must_use)] #![deny(unused_must_use)]
#![cfg_attr(feature = "map_first_last", feature(map_first_last))]
#[macro_use] #[macro_use]
extern crate pest_derive; extern crate pest_derive;

View file

@ -1,60 +1,91 @@
use std::collections::{BTreeMap, BTreeSet}; #[cfg(feature = "map_first_last")]
pub trait BTreeMapExt<K, V> { pub trait BTreeMapExt<K, V> {
fn ext_first_key(&self) -> Option<&K>; fn first_key(&self) -> Option<&K>;
fn ext_last_key(&self) -> Option<&K>; fn last_key(&self) -> Option<&K>;
fn ext_pop_first_key(&mut self) -> Option<K>; fn pop_first_value(&mut self) -> Option<V>;
fn ext_pop_last_key(&mut self) -> Option<K>; fn pop_last_value(&mut self) -> Option<V>;
fn ext_pop_first_value(&mut self) -> Option<V>;
fn ext_pop_last_value(&mut self) -> Option<V>;
} }
impl<K: Ord + Clone, V> BTreeMapExt<K, V> for BTreeMap<K, V> { #[cfg(feature = "map_first_last")]
fn ext_first_key(&self) -> Option<&K> { impl<K: Ord + Clone, V> BTreeMapExt<K, V> for std::collections::BTreeMap<K, V> {
fn first_key(&self) -> Option<&K> {
self.keys().next() self.keys().next()
} }
fn ext_last_key(&self) -> Option<&K> { fn last_key(&self) -> Option<&K> {
self.keys().next_back()
}
fn pop_first_value(&mut self) -> Option<V> {
self.first_entry().map(|x| x.remove())
}
fn pop_last_value(&mut self) -> Option<V> {
self.last_entry().map(|x| x.remove())
}
}
#[cfg(not(feature = "map_first_last"))]
pub trait BTreeMapExt<K, V> {
fn first_key(&self) -> Option<&K>;
fn last_key(&self) -> Option<&K>;
fn pop_first_key(&mut self) -> Option<K>;
fn pop_last_key(&mut self) -> Option<K>;
fn pop_first_value(&mut self) -> Option<V>;
fn pop_last_value(&mut self) -> Option<V>;
}
#[cfg(not(feature = "map_first_last"))]
impl<K: Ord + Clone, V> BTreeMapExt<K, V> for std::collections::BTreeMap<K, V> {
fn first_key(&self) -> Option<&K> {
self.keys().next()
}
fn last_key(&self) -> Option<&K> {
self.keys().next_back() self.keys().next_back()
} }
fn ext_pop_first_key(&mut self) -> Option<K> { fn pop_first_key(&mut self) -> Option<K> {
let key = self.ext_first_key()?; let key = self.first_key()?;
let key = key.clone(); // ownership hack let key = key.clone(); // ownership hack
Some(self.remove_entry(&key).unwrap().0) Some(self.remove_entry(&key).unwrap().0)
} }
fn ext_pop_last_key(&mut self) -> Option<K> { fn pop_last_key(&mut self) -> Option<K> {
let key = self.ext_last_key()?; let key = self.last_key()?;
let key = key.clone(); // ownership hack let key = key.clone(); // ownership hack
Some(self.remove_entry(&key).unwrap().0) Some(self.remove_entry(&key).unwrap().0)
} }
fn ext_pop_first_value(&mut self) -> Option<V> { fn pop_first_value(&mut self) -> Option<V> {
let key = self.ext_first_key()?; let key = self.first_key()?;
let key = key.clone(); // ownership hack let key = key.clone(); // ownership hack
Some(self.remove_entry(&key).unwrap().1) Some(self.remove_entry(&key).unwrap().1)
} }
fn ext_pop_last_value(&mut self) -> Option<V> { fn pop_last_value(&mut self) -> Option<V> {
let key = self.ext_last_key()?; let key = self.last_key()?;
let key = key.clone(); // ownership hack let key = key.clone(); // ownership hack
Some(self.remove_entry(&key).unwrap().1) Some(self.remove_entry(&key).unwrap().1)
} }
} }
#[cfg(feature = "map_first_last")]
pub trait BTreeSetExt<K> {}
#[cfg(not(feature = "map_first_last"))]
pub trait BTreeSetExt<K> { pub trait BTreeSetExt<K> {
fn ext_last(&self) -> Option<&K>; fn last(&self) -> Option<&K>;
fn ext_pop_last(&mut self) -> Option<K>; fn pop_last(&mut self) -> Option<K>;
} }
impl<K: Ord + Clone> BTreeSetExt<K> for BTreeSet<K> { #[cfg(not(feature = "map_first_last"))]
fn ext_last(&self) -> Option<&K> { impl<K: Ord + Clone> BTreeSetExt<K> for std::collections::BTreeSet<K> {
fn last(&self) -> Option<&K> {
self.iter().next_back() self.iter().next_back()
} }
fn ext_pop_last(&mut self) -> Option<K> { fn pop_last(&mut self) -> Option<K> {
let key = self.ext_last()?; let key = self.last()?;
let key = key.clone(); // ownership hack let key = key.clone(); // ownership hack
self.take(&key) self.take(&key)
} }

View file

@ -150,7 +150,7 @@ impl<'revset, 'repo> RevsetGraphIterator<'revset, 'repo> {
} }
fn next_index_entry(&mut self) -> Option<IndexEntry<'repo>> { fn next_index_entry(&mut self) -> Option<IndexEntry<'repo>> {
if let Some(index_entry) = self.look_ahead.ext_pop_last_value() { if let Some(index_entry) = self.look_ahead.pop_last_value() {
return Some(index_entry); return Some(index_entry);
} }
self.input_set_iter.next() self.input_set_iter.next()