From 11cf89ca37cfd9e8bfb213b262be4b166ea85a1f Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Mon, 28 Aug 2023 16:52:32 +0200 Subject: [PATCH 1/2] Impl nth for External(Partial)Iterator --- packages/std/src/imports.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/packages/std/src/imports.rs b/packages/std/src/imports.rs index 8f99e6941e..7df3f22c95 100644 --- a/packages/std/src/imports.rs +++ b/packages/std/src/imports.rs @@ -200,6 +200,15 @@ struct ExternalPartialIterator { impl Iterator for ExternalPartialIterator { type Item = Vec; + /// The default implementation calls `next` repeatedly, + /// which we can do a little more efficiently by using `db_next_key` instead. + /// It is used by `skip`, so it allows cheaper skipping. + #[cfg(feature = "cosmwasm_1_4")] + fn nth(&mut self, n: usize) -> Option { + skip_iter(self.iterator_id, n); + self.next() + } + fn next(&mut self) -> Option { // here we differentiate between the two types let next_result = match self.partial_type { @@ -229,6 +238,15 @@ struct ExternalIterator { impl Iterator for ExternalIterator { type Item = Record; + /// The default implementation calls `next` repeatedly, + /// which we can do a little more efficiently by using `db_next_key` instead. + /// It is used by `skip`, so it allows cheaper skipping. + #[cfg(feature = "cosmwasm_1_4")] + fn nth(&mut self, n: usize) -> Option { + skip_iter(self.iterator_id, n); + self.next() + } + fn next(&mut self) -> Option { let next_result = unsafe { db_next(self.iterator_id) }; let kv_region_ptr = next_result as *mut Region; @@ -242,6 +260,20 @@ impl Iterator for ExternalIterator { } } +/// Helper function to skip `count` elements of an iterator. +#[cfg(all(feature = "iterator", feature = "cosmwasm_1_4"))] +fn skip_iter(iter_id: u32, count: usize) { + for _ in 0..count { + let region = unsafe { db_next_key(iter_id) }; + if region == 0 { + // early return + return; + } + // just deallocate the region + unsafe { consume_region(region as *mut Region) }; + } +} + /// A stateless convenience wrapper around imports provided by the VM #[derive(Copy, Clone)] pub struct ExternalApi {} From 8e4907ae2d5cb16ff228220df48907f9172819d3 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Mon, 28 Aug 2023 17:03:08 +0200 Subject: [PATCH 2/2] Add changelog entry --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a859fa4c0..8724ef54eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,9 @@ and this project adheres to - cosmwasm-vm: Use `wasmparser` for initial validation instead of `parity-wasm` ([#1786]) - cosmwasm-std: Make constructors `Decimal{,256}::{percent,permille,bps}` const +- cosmwasm-std: Use new `db_next_key` import to make `skip` and `nth` + implementation of `range` iterators more efficient. This requires the + `cosmwasm_1_4` feature to be enabled. ([#1838]) [#1667]: https://github.com/CosmWasm/cosmwasm/pull/1667 [#1674]: https://github.com/CosmWasm/cosmwasm/pull/1674 @@ -46,6 +49,7 @@ and this project adheres to [#1701]: https://github.com/CosmWasm/cosmwasm/pull/1701 [#1786]: https://github.com/CosmWasm/cosmwasm/pull/1786 [#1793]: https://github.com/CosmWasm/cosmwasm/pull/1793 +[#1838]: https://github.com/CosmWasm/cosmwasm/pull/1838 ## [1.3.3] - 2023-08-22