Function hyperscan::alloc::set_db_allocator
source · pub fn set_db_allocator(
tracker: LayoutTracker
) -> Result<Option<LayoutTracker>, HyperscanRuntimeError>Available on crate feature
alloc only.Expand description
#[cfg(feature = "compiler")]
fn main() -> Result<(), hyperscan::error::HyperscanError> {
use hyperscan::{expression::*, flags::*, database::*, matchers::*, alloc::*};
use std::{alloc::System, mem::ManuallyDrop};
// Set the process-global allocator to use for Database instances:
let tracker = LayoutTracker::new(System.into());
// There was no custom allocator registered yet.
assert!(set_db_allocator(tracker).unwrap().is_none());
let expr: Expression = "asdf".parse()?;
// Use ManuallyDrop to avoid calling the hyperscan db free method,
// since we will be invalidating the pointer by changing the allocator,
// and the .try_drop() method and Drop impl both call into
// whatever allocator is currently active to free the pointer, which will error.
let mut db = ManuallyDrop::new(expr.compile(Flags::SOM_LEFTMOST, Mode::BLOCK)?);
// Change the allocator to a fresh LayoutTracker:
let mut tracker = set_db_allocator(LayoutTracker::new(System.into())).unwrap().unwrap();
// Get the extant allocations from the old LayoutTracker:
let allocs = tracker.current_allocations();
// Verify that only the single known db was allocated:
assert_eq!(1, allocs.len());
let (p, layout) = allocs[0];
let db_ptr: *mut NativeDb = db.as_mut_native();
assert_eq!(p.as_ptr() as *mut NativeDb, db_ptr);
// Despite having reset the allocator, our previous db is still valid
// and can be used for matching:
let mut scratch = db.allocate_scratch()?;
let mut matches: Vec<&str> = Vec::new();
scratch.scan_sync(&db, "asdf asdf".into(), |m| {
matches.push(unsafe { m.source.as_str() });
MatchResult::Continue
})?;
assert_eq!(&matches, &["asdf", "asdf"]);
// We can deserialize something from somewhere else into the db handle:
let expr: Literal = "hello".parse()?;
let serialized_db = expr.compile(Flags::SOM_LEFTMOST, Mode::BLOCK)?.serialize()?;
// Ensure the allocated database is large enough to contain the deserialized one:
assert!(layout.size() >= serialized_db.deserialized_size()?);
// NB: overwrite the old database!
unsafe { serialized_db.deserialize_db_at(db.as_mut_native())?; }
// Reuse the same database object now:
scratch.setup_for_db(&db)?;
matches.clear();
scratch.scan_sync(&db, "hello hello".into(), |m| {
matches.push(unsafe { m.source.as_str() });
MatchResult::Continue
})?;
assert_eq!(&matches, &["hello", "hello"]);
// Need to deallocate the db by hand in order to drop the original LayoutTracker
// without panicking:
tracker.deallocate(p);
// NB: `db` is now INVALID and points to FREED MEMORY!!!
Ok(())
}