New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
IRI resolution using user-provided buffers #6
Comments
I want more tests before releasing it. |
#[bench]
fn bench_new_resolve(b: &mut test::Bencher) {
let base = IriStr::new("https://sub.example.com/foo1/foo2/foo3/foo4/foo5")
.expect("should be valid IRI");
let rel = IriReferenceStr::new("bar1/bar2/bar3/../bar4/../../bar5/../../../../../bar6/../../../bar7/././././././bar8/bar9")
.expect("should be valid IRI");
b.iter(|| {
let resolved = crate::resolve::resolve(rel, base);
resolved
});
}
#[bench]
fn bench_old_resolve(b: &mut test::Bencher) {
use crate::types::IriAbsoluteStr;
let base = IriAbsoluteStr::new("https://sub.example.com/foo1/foo2/foo3/foo4/foo5")
.expect("should be valid IRI");
let rel = IriReferenceStr::new("bar1/bar2/bar3/../bar4/../../bar5/../../../../../bar6/../../../bar7/././././././bar8/bar9")
.expect("should be valid IRI");
b.iter(|| {
let resolved = crate::resolve_old::resolve(rel, base, true);
resolved
});
}
😩 |
Inspecting flamegraphs, I realized that the parsings are quite heavy. New // Previous impl:
/// Resolves the IRI, and writes it to the buffer.
fn write_to_buf<'b, B: Buffer<'b>>(&self, buf: B) -> Result<&'b RiStr<S>, B::ExtendError> {
let s = self.common.write_to_buf(buf)?;
// Convert the type.
// This should never fail (unless the crate has bugs), but do the
// validation here for extra safety.
let s = <&RiStr<S>>::try_from(s).expect("[consistency] the resolved IRI must be valid");
Ok(s)
} // Improved impl:
/// Resolves the IRI, and writes it to the buffer.
fn write_to_buf<'b, B: Buffer<'b>>(&self, buf: B) -> Result<&'b RiStr<S>, B::ExtendError> {
let s = self.common.write_to_buf(buf)?;
// Convert the type.
// This should never fail (unless the crate has bugs), but do the
// validation here for extra safety.
debug_assert!(<&RiStr<S>>::try_from(s).is_ok(), "[consistency] the resolved IRI must be valid");
let s = core::str::from_utf8(s).expect("[consistency] the resolved IRI must be valid");
let s = unsafe { RiStr::<S>::new_maybe_unchecked(s) };
Ok(s)
}
This means that the resolution logic itself has not become slow, but extra parsing has simply slowed the function. |
Anyway, I'll make the parser faster. |
Currently IRI resolution implementation is provided only when
alloc
feature is enabled.This is because the algorithm uses a (variable-size) stack to manipulate the IRI.
However, the maximum size of the necessary stack is easy to estimate, since the length of the resulting IRI won't exceed the sum of the lengths of the two inputs.
So, providing IRI resolution that utilize user-provided
&[u8]
buffer would be useful.Additionally, a variation that utilize user-provided
&mut String
would also be useful, since it can reduce memory allocations when users attempts to resolve multiple IRIs at once.The text was updated successfully, but these errors were encountered: