Snap for 7183507 from e9ea57ca26667663735443be8d1152d29a0eecb3 to sdk-release
Change-Id: I631dc94c6aaeb756515a19a74fa2c66e42531b0d
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 985f6e1..974ca7e 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,5 +1,5 @@
{
"git": {
- "sha1": "967ca418c00d0fab0be6baab55a639af69519697"
+ "sha1": "b2b3e0c7eb38ff288d32726594d32a90d0e684fc"
}
}
diff --git a/Android.bp b/Android.bp
index e2a16fd..ed6c334 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,5 +1,43 @@
// This file is generated by cargo2android.py --run --device --dependencies --features=alloc,default,tinyvec_macros.
+package {
+ default_applicable_licenses: ["external_rust_crates_tinyvec_license"],
+}
+
+// Added automatically by a large-scale-change that took the approach of
+// 'apply every license found to every target'. While this makes sure we respect
+// every license restriction, it may not be entirely correct.
+//
+// e.g. GPL in an MIT project might only apply to the contrib/ directory.
+//
+// Please consider splitting the single license below into multiple licenses,
+// taking care not to lose any license_kind information, and overriding the
+// default license using the 'licenses: [...]' property on targets as needed.
+//
+// For unused files, consider creating a 'fileGroup' with "//visibility:private"
+// to attach the license to, and including a comment whether the files may be
+// used in the current project.
+//
+// large-scale-change included anything that looked like it might be a license
+// text as a license_text. e.g. LICENSE, NOTICE, COPYING etc.
+//
+// Please consider removing redundant or irrelevant files from 'license_text:'.
+// See: http://go/android-license-faq
+license {
+ name: "external_rust_crates_tinyvec_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ "SPDX-license-identifier-MIT",
+ "SPDX-license-identifier-Zlib",
+ ],
+ license_text: [
+ "LICENSE-APACHE.md",
+ "LICENSE-MIT.md",
+ "LICENSE-ZLIB.md",
+ ],
+}
+
rust_library {
name: "libtinyvec",
host_supported: true,
@@ -14,11 +52,6 @@
rustlibs: [
"libtinyvec_macros",
],
- apex_available: [
- "//apex_available:platform",
- "com.android.resolv",
- ],
- min_sdk_version: "29",
}
// dependent_library ["feature_list"]
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 54dd314..6baa057 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,15 @@
# Changelog
+## 1.1.1
+
+* [saethlin](https://github.com/saethlin) contributed many PRs (
+ [127](https://github.com/Lokathor/tinyvec/pull/127),
+ [128](https://github.com/Lokathor/tinyvec/pull/128),
+ [129](https://github.com/Lokathor/tinyvec/pull/129),
+ [131](https://github.com/Lokathor/tinyvec/pull/131),
+ [132](https://github.com/Lokathor/tinyvec/pull/132)
+ ) to help in several benchmarks.
+
## 1.1.0
* [slightlyoutofphase](https://github.com/slightlyoutofphase)
diff --git a/Cargo.toml b/Cargo.toml
index e3fd556..c7d90dd 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,7 +13,7 @@
[package]
edition = "2018"
name = "tinyvec"
-version = "1.1.0"
+version = "1.1.1"
authors = ["Lokathor <zefria@gmail.com>"]
description = "`tinyvec` provides 100% safe vec-like data structures."
keywords = ["vec", "no_std", "no-std"]
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index 1a27866..ea42ed8 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,7 +1,7 @@
[package]
name = "tinyvec"
description = "`tinyvec` provides 100% safe vec-like data structures."
-version = "1.1.0"
+version = "1.1.1"
authors = ["Lokathor <zefria@gmail.com>"]
edition = "2018"
license = "Zlib OR Apache-2.0 OR MIT"
diff --git a/METADATA b/METADATA
index 73e220a..32fb288 100644
--- a/METADATA
+++ b/METADATA
@@ -7,13 +7,13 @@
}
url {
type: ARCHIVE
- value: "https://static.crates.io/crates/tinyvec/tinyvec-1.1.0.crate"
+ value: "https://static.crates.io/crates/tinyvec/tinyvec-1.1.1.crate"
}
- version: "1.1.0"
+ version: "1.1.1"
license_type: NOTICE
last_upgrade_date {
- year: 2020
- month: 12
- day: 15
+ year: 2021
+ month: 2
+ day: 9
}
}
diff --git a/TEST_MAPPING b/TEST_MAPPING
new file mode 100644
index 0000000..ef16d49
--- /dev/null
+++ b/TEST_MAPPING
@@ -0,0 +1,14 @@
+// Generated by update_crate_tests.py for tests that depend on this crate.
+{
+ "presubmit": [
+ {
+ "name": "quiche_device_test_src_lib"
+ },
+ {
+ "name": "url_device_test_src_lib"
+ },
+ {
+ "name": "unicode-normalization_device_test_src_lib"
+ }
+ ]
+}
diff --git a/src/arrayvec.rs b/src/arrayvec.rs
index c744050..55e67db 100644
--- a/src/arrayvec.rs
+++ b/src/arrayvec.rs
@@ -403,10 +403,19 @@
pub fn fill<I: IntoIterator<Item = A::Item>>(
&mut self, iter: I,
) -> I::IntoIter {
+ // If this is written as a call to push for each element in iter, the
+ // compiler emits code that updates the length for every element. The
+ // additional complexity from that length update is worth nearly 2x in
+ // the runtime of this function.
let mut iter = iter.into_iter();
- for element in iter.by_ref().take(self.capacity() - self.len()) {
- self.push(element);
+ let mut pushed = 0;
+ let to_take = self.capacity() - self.len();
+ let target = &mut self.data.as_slice_mut()[self.len as usize..];
+ for element in iter.by_ref().take(to_take) {
+ target[pushed] = element;
+ pushed += 1;
}
+ self.len += pushed as u16;
iter
}
@@ -471,7 +480,9 @@
/// assert_eq!(av.try_insert(4, "five"), Some("five"));
/// ```
#[inline]
- pub fn try_insert(&mut self, index: usize, item: A::Item) -> Option<A::Item> {
+ pub fn try_insert(
+ &mut self, index: usize, mut item: A::Item,
+ ) -> Option<A::Item> {
assert!(
index <= self.len as usize,
"ArrayVec::try_insert> index {} is out of bounds {}",
@@ -479,11 +490,23 @@
self.len
);
- if let Some(x) = self.try_push(item) {
- return Some(x);
+ // A previous implementation used self.try_push and slice::rotate_right
+ // rotate_right and rotate_left generate a huge amount of code and fail to
+ // inline; calling them here incurs the cost of all the cases they
+ // handle even though we're rotating a usually-small array by a constant
+ // 1 offset. This swap-based implementation benchmarks much better for
+ // small array lengths in particular.
+
+ if (self.len as usize) < A::CAPACITY {
+ self.len += 1;
+ } else {
+ return Some(item);
}
- self.as_mut_slice()[index..].rotate_right(1);
+ let target = &mut self.as_mut_slice()[index..];
+ for i in 0..target.len() {
+ core::mem::swap(&mut item, &mut target[i]);
+ }
return None;
}
@@ -601,7 +624,17 @@
pub fn remove(&mut self, index: usize) -> A::Item {
let targets: &mut [A::Item] = &mut self.deref_mut()[index..];
let item = take(&mut targets[0]);
- targets.rotate_left(1);
+
+ // A previous implementation used rotate_left
+ // rotate_right and rotate_left generate a huge amount of code and fail to
+ // inline; calling them here incurs the cost of all the cases they
+ // handle even though we're rotating a usually-small array by a constant
+ // 1 offset. This swap-based implementation benchmarks much better for
+ // small array lengths in particular.
+
+ for i in 0..targets.len() - 1 {
+ targets.swap(i, i + 1);
+ }
self.len -= 1;
item
}
diff --git a/src/tinyvec.rs b/src/tinyvec.rs
index ed13433..c578ccb 100644
--- a/src/tinyvec.rs
+++ b/src/tinyvec.rs
@@ -676,18 +676,34 @@
/// tv.push(4);
/// assert_eq!(tv.as_slice(), &[1, 2, 3, 4]);
/// ```
- #[inline(always)]
+ #[inline]
pub fn push(&mut self, val: A::Item) {
- let arr = match self {
- TinyVec::Heap(v) => return v.push(val),
- TinyVec::Inline(a) => a,
- };
-
- if let Some(x) = arr.try_push(val) {
+ // The code path for moving the inline contents to the heap produces a lot
+ // of instructions, but we have a strong guarantee that this is a cold
+ // path. LLVM doesn't know this, inlines it, and this tends to cause a
+ // cascade of other bad inlining decisions because the body of push looks
+ // huge even though nearly every call executes the same few instructions.
+ //
+ // Moving the logic out of line with #[cold] causes the hot code to be
+ // inlined together, and we take the extra cost of a function call only
+ // in rare cases.
+ #[cold]
+ fn drain_to_heap_and_push<A: Array>(
+ arr: &mut ArrayVec<A>, val: A::Item,
+ ) -> TinyVec<A> {
/* Make the Vec twice the size to amortize the cost of draining */
let mut v = arr.drain_to_vec_and_reserve(arr.len());
- v.push(x);
- *self = TinyVec::Heap(v);
+ v.push(val);
+ TinyVec::Heap(v)
+ }
+
+ match self {
+ TinyVec::Heap(v) => v.push(val),
+ TinyVec::Inline(arr) => {
+ if let Some(x) = arr.try_push(val) {
+ *self = drain_to_heap_and_push(arr, x);
+ }
+ }
}
}
@@ -1102,8 +1118,15 @@
TinyVec::Heap(slice.into())
} else {
let mut arr = ArrayVec::new();
- arr.extend_from_slice(slice);
-
+ // We do not use ArrayVec::extend_from_slice, because it looks like LLVM
+ // fails to deduplicate all the length-checking logic between the
+ // above if and the contents of that method, thus producing much
+ // slower code. Unlike many of the other optimizations in this
+ // crate, this one is worth keeping an eye on. I see no reason, for
+ // any element type, that these should produce different code. But
+ // they do. (rustc 1.51.0)
+ arr.set_len(slice.len());
+ arr.as_mut_slice().clone_from_slice(slice);
TinyVec::Inline(arr)
}
}