aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid LeGare <legare@google.com>2022-03-03 13:57:29 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2022-03-03 13:57:29 +0000
commit1fb6683fdb400578ebccc1d1c576310452a66106 (patch)
treedf29fa23f8ecd8a1b65de854c4e2907ee3fb5fc7
parentea08e0e871a76c38dd763eb77bb35256c918d942 (diff)
parent38f28c3b882cf5d08d93f59e7feb6d087a13d88f (diff)
downloadtinyvec-1fb6683fdb400578ebccc1d1c576310452a66106.tar.gz
Update tinyvec to 1.5.1 am: 38f28c3b88
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/tinyvec/+/2005056 Change-Id: I13c6e70d0e15f49112e3a06dca3eef3ab0c8dba2
-rw-r--r--.cargo_vcs_info.json7
-rw-r--r--.github/workflows/rust.yml10
-rw-r--r--Android.bp40
-rw-r--r--CHANGELOG.md11
-rw-r--r--Cargo.toml21
-rw-r--r--Cargo.toml.orig55
-rw-r--r--METADATA10
-rw-r--r--benches/smallvec.rs500
-rw-r--r--compare_benchmarks.py30
-rw-r--r--src/lib.rs2
-rw-r--r--src/tinyvec.rs19
-rw-r--r--tests/tinyvec.rs15
12 files changed, 656 insertions, 64 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 3d0fa1e..6772581 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,5 +1,6 @@
{
"git": {
- "sha1": "7518868e4b9c802b214ce393f79f82fa13bef251"
- }
-}
+ "sha1": "1ef53f632b9cb6f2e7ff603586f4472317b9a25c"
+ },
+ "path_in_vcs": ""
+} \ No newline at end of file
diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml
index 16bf072..050e70d 100644
--- a/.github/workflows/rust.yml
+++ b/.github/workflows/rust.yml
@@ -11,6 +11,7 @@ jobs:
matrix:
rust:
- 1.34.0
+ - 1.36.0
- stable
- beta
- nightly
@@ -25,10 +26,17 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: build
- - name: Test on Stable/Beta
+ - name: Build the crate on 1.36 with features.
if: matrix.rust != '1.34.0'
uses: actions-rs/cargo@v1
with:
+ command: build
+ # Using `extern crate alloc` is only possible after 1.36
+ args: --features=alloc,std,grab_spare_slice
+ - name: Test on Stable/Beta
+ if: matrix.rust != '1.34.0' && matrix.rust != '1.36.0'
+ uses: actions-rs/cargo@v1
+ with:
command: test
args: --features=alloc --features=grab_spare_slice --features=rustc_1_40
- name: Test on Nightly with All Features
diff --git a/Android.bp b/Android.bp
index 15a216e..3888f8c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -44,7 +44,7 @@ rust_library {
host_supported: true,
crate_name: "tinyvec",
cargo_env_compat: true,
- cargo_pkg_version: "1.4.0",
+ cargo_pkg_version: "1.5.1",
srcs: ["src/lib.rs"],
edition: "2018",
features: [
@@ -62,47 +62,29 @@ rust_library {
min_sdk_version: "29",
}
-rust_defaults {
- name: "tinyvec_test_defaults",
- crate_name: "tinyvec",
+rust_test {
+ name: "tinyvec_test_tests_arrayvec",
+ host_supported: true,
+ crate_name: "arrayvec",
cargo_env_compat: true,
- cargo_pkg_version: "1.4.0",
+ cargo_pkg_version: "1.5.1",
+ srcs: ["tests/arrayvec.rs"],
test_suites: ["general-tests"],
auto_gen_config: true,
+ test_options: {
+ unit_test: true,
+ },
edition: "2018",
features: [
"alloc",
"default",
"tinyvec_macros",
],
- flags: [
- "-C debug-assertions=on",
- "-C opt-level=3",
- ],
rustlibs: [
"libcriterion",
"libserde_test",
+ "libsmallvec",
"libtinyvec",
"libtinyvec_macros",
],
}
-
-rust_test {
- name: "tinyvec_test_tests_arrayvec",
- defaults: ["tinyvec_test_defaults"],
- host_supported: true,
- srcs: ["tests/arrayvec.rs"],
- test_options: {
- unit_test: true,
- },
-}
-
-rust_test {
- name: "tinyvec_test_tests_tinyvec",
- defaults: ["tinyvec_test_defaults"],
- host_supported: true,
- srcs: ["tests/tinyvec.rs"],
- test_options: {
- unit_test: true,
- },
-}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1bcc2a1..93ef808 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,16 @@
# Changelog
+## 1.5.1
+
+* [madsmtm](https://github.com/madsmtm) fixed an error with the `alloc` feature on very old rustc versions.
+ [pr 154](https://github.com/Lokathor/tinyvec/pull/154)
+
+## 1.5.0
+
+* [eeeebbbbrrrr](https://github.com/eeeebbbbrrrr) added an impl for [std::io::Write](https://doc.rust-lang.org/std/io/trait.Write.html) to `TinyVec` when the element type is `u8`.
+ This is gated behind the new `std` feature.
+ [pr 152](https://github.com/Lokathor/tinyvec/pull/152)
+
## 1.4.0
* [saethlin](https://github.com/saethlin) stabilized the usage of const generics and array map with the `rustc_1_55` feature.
diff --git a/Cargo.toml b/Cargo.toml
index 3ab13bd..24dfa0d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -12,7 +12,7 @@
[package]
edition = "2018"
name = "tinyvec"
-version = "1.4.0"
+version = "1.5.1"
authors = ["Lokathor <zefria@gmail.com>"]
description = "`tinyvec` provides 100% safe vec-like data structures."
keywords = ["vec", "no_std", "no-std"]
@@ -20,22 +20,30 @@ categories = ["data-structures", "no-std"]
license = "Zlib OR Apache-2.0 OR MIT"
repository = "https://github.com/Lokathor/tinyvec"
[package.metadata.docs.rs]
-features = ["alloc", "grab_spare_slice", "rustc_1_40", "rustc_1_55", "serde"]
+features = ["alloc", "std", "grab_spare_slice", "rustc_1_40", "rustc_1_55", "serde"]
rustdoc-args = ["--cfg", "docs_rs"]
[package.metadata.playground]
-features = ["alloc", "grab_spare_slice", "rustc_1_40", "rustc_1_55", "serde"]
+features = ["alloc", "std", "grab_spare_slice", "rustc_1_40", "rustc_1_55", "serde"]
+[profile.bench]
+debug = 2
+
[profile.test]
opt-level = 3
[[test]]
name = "tinyvec"
-required-features = ["alloc"]
+required-features = ["alloc", "std"]
[[bench]]
name = "macros"
harness = false
required-features = ["alloc"]
+
+[[bench]]
+name = "smallvec"
+harness = false
+required-features = ["alloc", "real_blackbox"]
[dependencies.arbitrary]
version = "1"
optional = true
@@ -54,11 +62,16 @@ version = "0.3.0"
[dev-dependencies.serde_test]
version = "1.0"
+[dev-dependencies.smallvec]
+version = "1"
+
[features]
alloc = ["tinyvec_macros"]
default = []
experimental_write_impl = []
grab_spare_slice = []
nightly_slice_partition_dedup = []
+real_blackbox = ["criterion/real_blackbox"]
rustc_1_40 = []
rustc_1_55 = ["rustc_1_40"]
+std = []
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index a262ed1..28a5874 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,73 +1,90 @@
[package]
name = "tinyvec"
description = "`tinyvec` provides 100% safe vec-like data structures."
-version = "1.4.0"
+version = "1.5.1"
authors = ["Lokathor <zefria@gmail.com>"]
edition = "2018"
license = "Zlib OR Apache-2.0 OR MIT"
keywords = ["vec", "no_std", "no-std"]
categories = ["data-structures", "no-std"]
repository = "https://github.com/Lokathor/tinyvec"
-
+
[dependencies]
tinyvec_macros = { version = "0.1", optional = true }
# Provides `Serialize` and `Deserialize` implementations
serde = { version = "1.0", optional = true, default-features = false }
# Provides derived `Arbitrary` implementations
arbitrary = { version = "1", optional = true }
-
+
[features]
default = []
-
+
# Provide things that utilize the `alloc` crate, namely `TinyVec`.
alloc = ["tinyvec_macros"]
-
+
+# Provide things that require Rust's `std` module
+std = []
+
# (not part of Vec!) Extra methods to let you grab the slice of memory after the
# "active" portion of an `ArrayVec` or `SliceVec`.
grab_spare_slice = []
-
+
# features that require rustc 1.40
# use Vec::append if possible in TinyVec::append - 1.37
# DoubleEndedIterator::nth_back - 1.40
rustc_1_40 = []
-
+
# features that require rustc 1.55
# use const generics to implement Array for all array lengths
rustc_1_55 = ["rustc_1_40"]
-
+
# allow use of nightly feature `slice_partition_dedup`,
# will become useless once that is stabilized:
# https://github.com/rust-lang/rust/issues/54279
nightly_slice_partition_dedup = []
-
+
# EXPERIMENTAL: Not part of SemVer. It adds `core::fmt::Write` to `ArrayVec`
# and `SliceVec`. It works on Stable Rust, but Vec normally supports the
# `std::io::Write` trait instead of `core::fmt::Write`, so we're keeping it as
# an experimental impl only for now.
experimental_write_impl = []
-
+
+# Some benchmarks are optimized away with the stable black_box function
+# which is based on read_volatile. This feature requires inline assembly
+# and thus a nightly compiler, but is only used in benchmarks.
+real_blackbox = ["criterion/real_blackbox"]
+
[package.metadata.docs.rs]
-features = ["alloc", "grab_spare_slice", "rustc_1_40", "rustc_1_55", "serde"]
+features = ["alloc", "std", "grab_spare_slice", "rustc_1_40", "rustc_1_55", "serde"]
rustdoc-args = ["--cfg","docs_rs"]
-
+
[package.metadata.playground]
-features = ["alloc", "grab_spare_slice", "rustc_1_40", "rustc_1_55", "serde"]
-
+features = ["alloc", "std", "grab_spare_slice", "rustc_1_40", "rustc_1_55", "serde"]
+
[profile.test]
opt-level = 3
-
+
+[profile.bench]
+debug = 2
+
[workspace]
members = ["fuzz"]
-
+
[dev-dependencies]
criterion = "0.3.0"
serde_test = "1.0"
-
+smallvec = "1"
+
[[test]]
name = "tinyvec"
-required-features = ["alloc"]
-
+required-features = ["alloc", "std"]
+
[[bench]]
name = "macros"
harness = false
required-features = ["alloc"]
+
+[[bench]]
+name = "smallvec"
+harness = false
+required-features = ["alloc", "real_blackbox"]
diff --git a/METADATA b/METADATA
index 8445b96..a632067 100644
--- a/METADATA
+++ b/METADATA
@@ -7,13 +7,13 @@ third_party {
}
url {
type: ARCHIVE
- value: "https://static.crates.io/crates/tinyvec/tinyvec-1.4.0.crate"
+ value: "https://static.crates.io/crates/tinyvec/tinyvec-1.5.1.crate"
}
- version: "1.4.0"
+ version: "1.5.1"
license_type: NOTICE
last_upgrade_date {
- year: 2021
- month: 9
- day: 22
+ year: 2022
+ month: 3
+ day: 1
}
}
diff --git a/benches/smallvec.rs b/benches/smallvec.rs
new file mode 100644
index 0000000..8cd16d3
--- /dev/null
+++ b/benches/smallvec.rs
@@ -0,0 +1,500 @@
+//! Benchmarks that compare TinyVec to SmallVec
+//!
+//! All the following commentary is based on the latest nightly at the time:
+//! rustc 1.55.0 (c8dfcfe04 2021-09-06).
+//!
+//! Some of these benchmarks are just a few instructions, so we put our own for loop inside
+//! the criterion::Bencher::iter call. This seems to improve the stability of measurements, and it
+//! has the wonderful side effect of making the emitted assembly easier to follow. Some of these
+//! benchmarks are totally inlined so that there are no calls at all in the hot path, so finding
+//! this for loop is an easy way to find your way around the emitted assembly.
+//!
+//! The clear method is cheaper to call for arrays of elements without a Drop impl, so wherever
+//! possible we reuse a single object in the benchmark loop, with a clear + black_box on each
+//! iteration in an attempt to not make that visible to the optimizer.
+//!
+//! We always call black_box(&v), instead of v = black_box(v) because the latter does a move of the
+//! inline array, which is linear in the size of the array and thus varies based on the array type
+//! being benchmarked, and this move can be more expensive than the function we're trying to
+//! benchmark.
+//!
+//! We also black_box the input to each method call. This has a significant effect on the assembly
+//! emitted, for example if we do not black_box the range we iterate over in the ::push benchmarks,
+//! the loop is unrolled. It's not entirely clear if it's better to black_box the iterator that
+//! yields the items being pushed, or to black_box at a deeper level: v.push(black_box(i)) for
+//! example. Anecdotally, it seems like the latter approach produces unreasonably bad assembly.
+//!
+
+use criterion::{black_box, criterion_group, criterion_main, Criterion};
+use smallvec::SmallVec;
+use std::iter::FromIterator;
+use tinyvec::TinyVec;
+
+const ITERS: usize = 10_000;
+
+macro_rules! tinyvec_benches {
+ ($c:expr, $type:ty ; $len:expr) => {{
+ let mut g = $c.benchmark_group(concat!(
+ "TinyVec_",
+ stringify!($type),
+ "_",
+ stringify!($len)
+ ));
+
+ g.bench_function(
+ concat!(
+ "TinyVec<[",
+ stringify!($type),
+ "; ",
+ stringify!($len),
+ "]>::default"
+ ),
+ |b| {
+ b.iter(|| {
+ for _ in 0..ITERS {
+ let v: TinyVec<[$type; $len]> = TinyVec::default();
+ black_box(&v);
+ }
+ });
+ },
+ );
+
+ g.bench_function(
+ concat!(
+ "TinyVec<[",
+ stringify!($type),
+ "; ",
+ stringify!($len),
+ "]>::clone"
+ ),
+ |b| {
+ b.iter(|| {
+ let outer: TinyVec<[$type; $len]> =
+ black_box(TinyVec::from_iter(0..=($len as usize - 1) as _));
+ for _ in 0..ITERS {
+ let v = outer.clone();
+ black_box(&v);
+ }
+ });
+ },
+ );
+
+ g.bench_function(
+ concat!(
+ "TinyVec<[",
+ stringify!($type),
+ "; ",
+ stringify!($len),
+ "]>::clear"
+ ),
+ |b| {
+ b.iter(|| {
+ let mut v: TinyVec<[$type; $len]> = TinyVec::default();
+ for _ in 0..ITERS {
+ v.clear();
+ black_box(&v);
+ }
+ });
+ },
+ );
+
+ g.bench_function(
+ concat!(
+ "TinyVec<[",
+ stringify!($type),
+ "; ",
+ stringify!($len),
+ "]>::push"
+ ),
+ |b| {
+ b.iter(|| {
+ let mut v: TinyVec<[$type; $len]> = TinyVec::default();
+ for _ in 0..ITERS {
+ v.clear();
+ black_box(&v);
+ for i in black_box(0..=($len as usize - 1) as _) {
+ v.push(i);
+ }
+ black_box(&v);
+ }
+ });
+ },
+ );
+
+ g.bench_function(
+ concat!(
+ "TinyVec<[",
+ stringify!($type),
+ "; ",
+ stringify!($len),
+ "]>::from_iter"
+ ),
+ |b| {
+ b.iter(|| {
+ for _ in 0..ITERS {
+ let v: TinyVec<[$type; $len]> =
+ TinyVec::from_iter(black_box(0..=($len as usize - 1) as _));
+ black_box(&v);
+ }
+ });
+ },
+ );
+
+ g.bench_function(
+ concat!(
+ "TinyVec<[",
+ stringify!($type),
+ "; ",
+ stringify!($len),
+ "]>::from_slice"
+ ),
+ |b| {
+ b.iter(|| {
+ let data: &[$type] = &[0, 1, 2, 3, 4, 5, 6, 7];
+ for _ in 0..ITERS {
+ let v: TinyVec<[$type; $len]> = TinyVec::from(black_box(data));
+ black_box(&v);
+ }
+ });
+ },
+ );
+
+ g.bench_function(
+ concat!(
+ "TinyVec<[",
+ stringify!($type),
+ "; ",
+ stringify!($len),
+ "]>::extend"
+ ),
+ |b| {
+ b.iter(|| {
+ let mut v: TinyVec<[$type; $len]> = black_box(TinyVec::default());
+ for _ in 0..ITERS {
+ v.clear();
+ black_box(&v);
+ v.extend(black_box(0..=($len as usize - 1) as _));
+ black_box(&v);
+ }
+ });
+ },
+ );
+
+ g.bench_function(
+ concat!(
+ "TinyVec<[",
+ stringify!($type),
+ "; ",
+ stringify!($len),
+ "]>::extend_from_slice"
+ ),
+ |b| {
+ b.iter(|| {
+ let data: &[$type] = black_box(&[0, 1, 2, 3, 4, 5, 6, 7]);
+ let mut v: TinyVec<[$type; $len]> = black_box(TinyVec::default());
+ for _ in 0..ITERS {
+ v.clear();
+ black_box(&v);
+ v.extend_from_slice(data);
+ black_box(&v);
+ }
+ });
+ },
+ );
+
+ g.bench_function(
+ concat!(
+ "TinyVec<[",
+ stringify!($type),
+ "; ",
+ stringify!($len),
+ "]>::insert"
+ ),
+ |b| {
+ b.iter(|| {
+ let mut v: TinyVec<[$type; $len]> = TinyVec::default();
+ for _ in 0..ITERS {
+ v.clear();
+ black_box(&v);
+ for i in black_box(0..=($len as usize - 1) as _) {
+ v.insert(i as usize, i);
+ }
+ black_box(&v);
+ }
+ });
+ },
+ );
+
+ g.bench_function(
+ concat!(
+ "TinyVec<[",
+ stringify!($type),
+ "; ",
+ stringify!($len),
+ "]>::remove"
+ ),
+ |b| {
+ b.iter(|| {
+ let outer: TinyVec<[$type; $len]> =
+ black_box(TinyVec::from_iter(0..=($len as usize - 1) as _));
+ for _ in 0..ITERS {
+ let mut v = outer.clone();
+ for i in black_box((0..=($len as usize - 1) as _).rev()) {
+ v.remove(i);
+ }
+ black_box(&v);
+ }
+ });
+ },
+ );
+ }};
+}
+
+fn tinyvec_benches(c: &mut Criterion) {
+ tinyvec_benches!(c, u8; 8);
+ tinyvec_benches!(c, u8; 16);
+ tinyvec_benches!(c, u8; 32);
+ tinyvec_benches!(c, u8; 64);
+ tinyvec_benches!(c, u8; 128);
+ tinyvec_benches!(c, u8; 256);
+ tinyvec_benches!(c, u64; 2);
+ tinyvec_benches!(c, u64; 4);
+ tinyvec_benches!(c, u64; 8);
+ tinyvec_benches!(c, u64; 16);
+ tinyvec_benches!(c, u64; 32);
+}
+
+macro_rules! smallvec_benches {
+ ($c:expr, $type:ty ; $len:expr) => {{
+ let mut g = $c.benchmark_group(concat!(
+ "SmallVec_",
+ stringify!($type),
+ "_",
+ stringify!($len)
+ ));
+
+ g.bench_function(
+ concat!(
+ "SmallVec<[",
+ stringify!($type),
+ "; ",
+ stringify!($len),
+ "]>::default"
+ ),
+ |b| {
+ b.iter(|| {
+ for _ in 0..ITERS {
+ let v: SmallVec<[$type; $len]> = SmallVec::default();
+ black_box(&v);
+ }
+ });
+ },
+ );
+
+ g.bench_function(
+ concat!(
+ "SmallVec<[",
+ stringify!($type),
+ "; ",
+ stringify!($len),
+ "]>::clone"
+ ),
+ |b| {
+ b.iter(|| {
+ let outer: SmallVec<[$type; $len]> =
+ black_box(SmallVec::from_iter(0..=($len as usize - 1) as _));
+ for _ in 0..ITERS {
+ let v = outer.clone();
+ black_box(&v);
+ }
+ });
+ },
+ );
+
+ g.bench_function(
+ concat!(
+ "SmallVec<[",
+ stringify!($type),
+ "; ",
+ stringify!($len),
+ "]>::clear"
+ ),
+ |b| {
+ b.iter(|| {
+ let mut v: SmallVec<[$type; $len]> = SmallVec::default();
+ for _ in 0..ITERS {
+ v.clear();
+ black_box(&v);
+ }
+ });
+ },
+ );
+
+ g.bench_function(
+ concat!(
+ "SmallVec<[",
+ stringify!($type),
+ "; ",
+ stringify!($len),
+ "]>::push"
+ ),
+ |b| {
+ b.iter(|| {
+ let mut v: SmallVec<[$type; $len]> = SmallVec::default();
+ for _ in 0..ITERS {
+ v.clear();
+ black_box(&v);
+ for i in black_box(0..=($len as usize - 1) as _) {
+ v.push(i);
+ }
+ black_box(&v);
+ }
+ });
+ },
+ );
+
+ g.bench_function(
+ concat!(
+ "SmallVec<[",
+ stringify!($type),
+ "; ",
+ stringify!($len),
+ "]>::from_iter"
+ ),
+ |b| {
+ b.iter(|| {
+ for _ in 0..ITERS {
+ let v: SmallVec<[$type; $len]> =
+ SmallVec::from_iter(black_box(0..=($len as usize - 1) as _));
+ black_box(&v);
+ }
+ });
+ },
+ );
+
+ g.bench_function(
+ concat!(
+ "SmallVec<[",
+ stringify!($type),
+ "; ",
+ stringify!($len),
+ "]>::from_slice"
+ ),
+ |b| {
+ b.iter(|| {
+ let data: &[$type] = &[0, 1, 2, 3, 4, 5, 6, 7];
+ for _ in 0..ITERS {
+ let v: SmallVec<[$type; $len]> = SmallVec::from(black_box(data));
+ black_box(&v);
+ }
+ });
+ },
+ );
+
+ g.bench_function(
+ concat!(
+ "SmallVec<[",
+ stringify!($type),
+ "; ",
+ stringify!($len),
+ "]>::extend"
+ ),
+ |b| {
+ b.iter(|| {
+ let mut v: SmallVec<[$type; $len]> = black_box(SmallVec::default());
+ for _ in 0..ITERS {
+ v.clear();
+ black_box(&v);
+ v.extend(black_box(0..=($len as usize - 1) as _));
+ black_box(&v);
+ }
+ });
+ },
+ );
+
+ g.bench_function(
+ concat!(
+ "SmallVec<[",
+ stringify!($type),
+ "; ",
+ stringify!($len),
+ "]>::extend_from_slice"
+ ),
+ |b| {
+ b.iter(|| {
+ let data: &[$type] = black_box(&[0, 1, 2, 3, 4, 5, 6, 7]);
+ let mut v: SmallVec<[$type; $len]> = black_box(SmallVec::default());
+ for _ in 0..ITERS {
+ v.clear();
+ black_box(&v);
+ v.extend_from_slice(data);
+ black_box(&v);
+ }
+ });
+ },
+ );
+
+ g.bench_function(
+ concat!(
+ "SmallVec<[",
+ stringify!($type),
+ "; ",
+ stringify!($len),
+ "]>::insert"
+ ),
+ |b| {
+ b.iter(|| {
+ let mut v: SmallVec<[$type; $len]> = SmallVec::default();
+ for _ in 0..ITERS {
+ v.clear();
+ black_box(&v);
+ for i in black_box(0..=($len as usize - 1) as _) {
+ v.insert(i as usize, i);
+ }
+ black_box(&v);
+ }
+ });
+ },
+ );
+
+ g.bench_function(
+ concat!(
+ "SmallVec<[",
+ stringify!($type),
+ "; ",
+ stringify!($len),
+ "]>::remove"
+ ),
+ |b| {
+ b.iter(|| {
+ let outer: SmallVec<[$type; $len]> =
+ black_box(SmallVec::from_iter(0..=($len as usize - 1) as _));
+ for _ in 0..ITERS {
+ let mut v = outer.clone();
+ for i in black_box((0..=($len as usize - 1) as _).rev()) {
+ v.remove(i);
+ }
+ black_box(&v);
+ }
+ });
+ },
+ );
+ }};
+}
+
+fn smallvec_benches(c: &mut Criterion) {
+ smallvec_benches!(c, u8; 8);
+ smallvec_benches!(c, u8; 16);
+ smallvec_benches!(c, u8; 32);
+ smallvec_benches!(c, u8; 64);
+ smallvec_benches!(c, u8; 128);
+ smallvec_benches!(c, u8; 256);
+ smallvec_benches!(c, u64; 2);
+ smallvec_benches!(c, u64; 4);
+ smallvec_benches!(c, u64; 8);
+ smallvec_benches!(c, u64; 16);
+ smallvec_benches!(c, u64; 32);
+}
+
+criterion_group!(benches, tinyvec_benches, smallvec_benches);
+criterion_main!(benches);
diff --git a/compare_benchmarks.py b/compare_benchmarks.py
new file mode 100644
index 0000000..86eb7e8
--- /dev/null
+++ b/compare_benchmarks.py
@@ -0,0 +1,30 @@
+import os
+import os.path
+import json
+
+comparisons = []
+
+for (root, _dirs, files) in os.walk('target/criterion'):
+ for file in files:
+ if file == 'estimates.json' and root.endswith(
+ 'new') and 'TinyVec' in root:
+ path = os.path.join(root, file)
+
+ bench_name = path.split('/')[3]
+ tinyvec_time = json.load(open(path))['mean']['point_estimate']
+
+ path = path.replace('TinyVec', 'SmallVec')
+
+ smallvec_time = json.load(open(path))['mean']['point_estimate']
+
+ comparisons.append((bench_name, tinyvec_time / smallvec_time))
+
+comparisons.sort(key=lambda x: x[1])
+longest_name = max(len(c[0]) for c in comparisons)
+for (name, ratio) in comparisons:
+ # Undo the criterion name mangling
+ name = name.replace('_[', '<[')
+ name = name.replace(']___', ']>::')
+
+ name = name.ljust(longest_name)
+ print(f"{name} {ratio:.2f}")
diff --git a/src/lib.rs b/src/lib.rs
index b3ee259..c66705d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,4 +1,4 @@
-#![no_std]
+#![cfg_attr(not(feature = "std"), no_std)]
#![forbid(unsafe_code)]
#![cfg_attr(
feature = "nightly_slice_partition_dedup",
diff --git a/src/tinyvec.rs b/src/tinyvec.rs
index 3e884fc..1e11a47 100644
--- a/src/tinyvec.rs
+++ b/src/tinyvec.rs
@@ -107,8 +107,8 @@ where
#[inline]
fn clone(&self) -> Self {
match self {
- Self::Heap(v) => Self::Heap(v.clone()),
- Self::Inline(v) => Self::Inline(v.clone()),
+ TinyVec::Heap(v) => TinyVec::Heap(v.clone()),
+ TinyVec::Inline(v) => TinyVec::Inline(v.clone()),
}
}
@@ -172,6 +172,21 @@ impl<A: Array, I: SliceIndex<[A::Item]>> IndexMut<I> for TinyVec<A> {
}
}
+#[cfg(feature = "std")]
+#[cfg_attr(docs_rs, doc(cfg(feature = "std")))]
+impl<A: Array<Item = u8>> std::io::Write for TinyVec<A> {
+ #[inline(always)]
+ fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
+ self.extend_from_slice(buf);
+ Ok(buf.len())
+ }
+
+ #[inline(always)]
+ fn flush(&mut self) -> std::io::Result<()> {
+ Ok(())
+ }
+}
+
#[cfg(feature = "serde")]
#[cfg_attr(docs_rs, doc(cfg(feature = "serde")))]
impl<A: Array> Serialize for TinyVec<A>
diff --git a/tests/tinyvec.rs b/tests/tinyvec.rs
index e59a83b..ab4d9bd 100644
--- a/tests/tinyvec.rs
+++ b/tests/tinyvec.rs
@@ -394,3 +394,18 @@ fn TinyVec_pretty_debug() {
assert_eq!(s, expected);
}
+
+#[cfg(feature = "std")]
+#[test]
+fn TinyVec_std_io_write() {
+ use std::io::Write;
+ let mut tv: TinyVec<[u8; 3]> = TinyVec::new();
+
+ tv.write_all(b"foo").ok();
+ assert!(tv.is_inline());
+ assert_eq!(tv, tiny_vec![b'f', b'o', b'o']);
+
+ tv.write_all(b"bar").ok();
+ assert!(tv.is_heap());
+ assert_eq!(tv, tiny_vec![b'f', b'o', b'o', b'b', b'a', b'r']);
+}