From d4867978e4ab9ee1b8b410960f59e2c784612ec5 Mon Sep 17 00:00:00 2001 From: boocmp Date: Mon, 11 Aug 2025 12:03:02 +0700 Subject: [PATCH 01/13] Unsafe tools moved to flatbuffers. --- src/data_format/mod.rs | 2 +- src/data_format/storage.rs | 2 +- src/filters/fb_builder.rs | 2 +- src/filters/fb_network.rs | 2 +- src/{filters => flatbuffers}/unsafe_tools.rs | 0 src/lib.rs | 1 + 6 files changed, 5 insertions(+), 4 deletions(-) rename src/{filters => flatbuffers}/unsafe_tools.rs (100%) diff --git a/src/data_format/mod.rs b/src/data_format/mod.rs index b2e86263..0f8f5048 100644 --- a/src/data_format/mod.rs +++ b/src/data_format/mod.rs @@ -10,7 +10,7 @@ mod storage; pub(crate) mod utils; use crate::cosmetic_filter_cache::CosmeticFilterCache; -use crate::filters::unsafe_tools::VerifiedFlatbufferMemory; +use crate::flatbuffers::unsafe_tools::VerifiedFlatbufferMemory; use crate::network_filter_list::NetworkFilterListParsingError; /// Newer formats start with this magic byte sequence. diff --git a/src/data_format/storage.rs b/src/data_format/storage.rs index 3ffeab14..140d2bfc 100644 --- a/src/data_format/storage.rs +++ b/src/data_format/storage.rs @@ -10,7 +10,7 @@ use rmp_serde as rmps; use serde::{Deserialize, Serialize}; use crate::cosmetic_filter_cache::{CosmeticFilterCache, HostnameRuleDb, ProceduralOrActionFilter}; -use crate::filters::unsafe_tools::VerifiedFlatbufferMemory; +use crate::flatbuffers::unsafe_tools::VerifiedFlatbufferMemory; use crate::utils::Hash; use super::utils::{stabilize_hashmap_serialization, stabilize_hashset_serialization}; diff --git a/src/filters/fb_builder.rs b/src/filters/fb_builder.rs index 1a3134f2..d83833bc 100644 --- a/src/filters/fb_builder.rs +++ b/src/filters/fb_builder.rs @@ -9,7 +9,7 @@ use std::vec; use flatbuffers::WIPOffset; use crate::filters::network::{NetworkFilter, NetworkFilterMaskHelper}; -use crate::filters::unsafe_tools::VerifiedFlatbufferMemory; +use crate::flatbuffers::unsafe_tools::VerifiedFlatbufferMemory; use crate::network_filter_list::token_histogram; use crate::optimizer; use crate::utils::{to_short_hash, Hash, ShortHash}; diff --git a/src/filters/fb_network.rs b/src/filters/fb_network.rs index 54498b71..c6d7940c 100644 --- a/src/filters/fb_network.rs +++ b/src/filters/fb_network.rs @@ -4,7 +4,7 @@ use std::collections::HashMap; use crate::filters::fb_builder::FlatBufferBuilder; use crate::filters::network::{NetworkFilterMask, NetworkFilterMaskHelper, NetworkMatchable}; -use crate::filters::unsafe_tools::{fb_vector_to_slice, VerifiedFlatbufferMemory}; +use crate::flatbuffers::unsafe_tools::{fb_vector_to_slice, VerifiedFlatbufferMemory}; use crate::regex_manager::RegexManager; use crate::request::Request; diff --git a/src/filters/unsafe_tools.rs b/src/flatbuffers/unsafe_tools.rs similarity index 100% rename from src/filters/unsafe_tools.rs rename to src/flatbuffers/unsafe_tools.rs diff --git a/src/lib.rs b/src/lib.rs index a0bed513..d6327d2d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,6 +23,7 @@ pub mod cosmetic_filter_cache; mod data_format; mod engine; pub mod filters; +mod flatbuffers; pub mod lists; mod network_filter_list; mod optimizer; From 7a8ee9ef7a0783c5091cb907bd34993100e76857 Mon Sep 17 00:00:00 2001 From: boocmp Date: Mon, 11 Aug 2025 12:09:48 +0700 Subject: [PATCH 02/13] Added FlatMultiMapView, FlatFilterMap replaced. --- benches/bench_matching.rs | 6 +- src/filters/flat_filter_map.rs | 73 ------------------ src/filters/mod.rs | 2 - src/flatbuffers/containers/flat_multimap.rs | 84 +++++++++++++++++++++ src/flatbuffers/containers/indexable.rs | 61 +++++++++++++++ src/flatbuffers/containers/mod.rs | 2 + src/flatbuffers/containers/utils.rs | 49 ++++++++++++ src/flatbuffers/mod.rs | 2 + src/network_filter_list.rs | 13 +++- 9 files changed, 210 insertions(+), 82 deletions(-) delete mode 100644 src/filters/flat_filter_map.rs create mode 100644 src/flatbuffers/containers/flat_multimap.rs create mode 100644 src/flatbuffers/containers/indexable.rs create mode 100644 src/flatbuffers/containers/mod.rs create mode 100644 src/flatbuffers/containers/utils.rs create mode 100644 src/flatbuffers/mod.rs diff --git a/benches/bench_matching.rs b/benches/bench_matching.rs index 516374ac..7962469a 100644 --- a/benches/bench_matching.rs +++ b/benches/bench_matching.rs @@ -54,7 +54,7 @@ fn bench_rule_matching(engine: &Engine, requests: &[TestRequest]) -> (u32, u32) passes += 1; } }); - // println!("Got {} matches, {} passes, {} errors", matches, passes, errors); + println!("Got {} matches, {} passes", matches, passes); (matches, passes) } @@ -69,7 +69,7 @@ fn bench_matching_only(engine: &Engine, requests: &[Request]) -> (u32, u32) { passes += 1; } }); - // println!("Got {} matches, {} passes", matches, passes); + println!("Got {} matches, {} passes", matches, passes); (matches, passes) } @@ -94,7 +94,7 @@ fn bench_rule_matching_browserlike(blocker: &Engine, requests: &[ParsedRequest]) } }, ); - // println!("Got {} matches, {} passes", matches, passes); + println!("Got {} matches, {} passes", matches, passes); (matches, passes) } diff --git a/src/filters/flat_filter_map.rs b/src/filters/flat_filter_map.rs deleted file mode 100644 index 40df1958..00000000 --- a/src/filters/flat_filter_map.rs +++ /dev/null @@ -1,73 +0,0 @@ -//! Holds the implementation of [FlatFilterMap]. - -use flatbuffers::{Follow, ForwardsUOffset, Vector}; -use std::cmp::PartialOrd; - -/// A map-like container that uses flatbuffer references. -/// Provides O(log n) lookup time using binary search on the sorted index. -pub(crate) struct FlatFilterMap<'a, I: PartialOrd + Copy, V> { - index: &'a [I], - values: Vector<'a, ForwardsUOffset>, -} - -/// Iterator over NetworkFilter objects from [FlatFilterMap] -pub(crate) struct FlatFilterMapIterator<'a, I: PartialOrd + Copy, V> { - current_index: usize, - key: I, - indexes: &'a [I], - values: Vector<'a, ForwardsUOffset>, -} - -impl<'a, I, V> Iterator for FlatFilterMapIterator<'a, I, V> -where - I: PartialOrd + Copy, - V: Follow<'a>, -{ - type Item = (usize, >::Inner); - - fn next(&mut self) -> Option { - if self.current_index < self.indexes.len() { - if self.indexes[self.current_index] != self.key { - return None; - } - let index = self.current_index; - let filter = self.values.get(self.current_index); - self.current_index += 1; - Some((index, filter)) - } else { - None - } - } -} - -impl<'a, I: PartialOrd + Copy, V> FlatFilterMap<'a, I, V> { - /// Construct [FlatFilterMap] from two vectors: - /// - index: sorted array of keys - /// - values: array of values, same length as index - pub fn new(index: &'a [I], values: Vector<'a, ForwardsUOffset>) -> Self { - // Sanity check the size are equal. Note: next() will handle |values| correctly. - debug_assert!(index.len() == values.len()); - - debug_assert!(index.is_sorted()); - - Self { index, values } - } - - /// Get an iterator over NetworkFilter objects with the given hash key. - pub fn get(&self, key: I) -> FlatFilterMapIterator<'a, I, V> { - let start = self.index.partition_point(|x| *x < key); - FlatFilterMapIterator { - current_index: start, - key, - indexes: self.index, - values: self.values, - } - } -} - -impl FlatFilterMap<'_, I, V> { - #[cfg(test)] - pub fn total_size(&self) -> usize { - self.index.len() - } -} diff --git a/src/filters/mod.rs b/src/filters/mod.rs index d18e1f43..c1702a2d 100644 --- a/src/filters/mod.rs +++ b/src/filters/mod.rs @@ -6,6 +6,4 @@ mod network_matchers; pub mod cosmetic; pub(crate) mod fb_builder; pub(crate) mod fb_network; -pub(crate) mod flat_filter_map; pub mod network; -pub(crate) mod unsafe_tools; diff --git a/src/flatbuffers/containers/flat_multimap.rs b/src/flatbuffers/containers/flat_multimap.rs new file mode 100644 index 00000000..38f1bcd0 --- /dev/null +++ b/src/flatbuffers/containers/flat_multimap.rs @@ -0,0 +1,84 @@ +use std::marker::PhantomData; + +use crate::flatbuffers::containers::indexable::Indexable; +use flatbuffers::{Follow, Vector}; + +/// A map-like container that uses flatbuffer references. +/// Provides O(log n) lookup time using binary search on the sorted index. +pub(crate) struct FlatMultiMapView<'a, I: Ord + Copy, V, Idx> +where + Idx: Indexable, + V: Follow<'a>, +{ + index: Idx, + values: Vector<'a, V>, + _phantom: PhantomData, +} + +pub(crate) struct FlatMultiMapViewIterator<'a, I: Ord + Copy, V, Idx> +where + Idx: Indexable, + V: Follow<'a>, +{ + current_index: usize, + key: I, + indexes: Idx, + values: Vector<'a, V>, +} + +impl<'a, I, V, Idx> Iterator for FlatMultiMapViewIterator<'a, I, V, Idx> +where + I: Ord + Copy, + V: Follow<'a>, + Idx: Indexable, +{ + type Item = (usize, >::Inner); + + fn next(&mut self) -> Option { + if self.current_index < self.indexes.len() { + if self.indexes.get(self.current_index) != self.key { + return None; + } + let index = self.current_index; + let filter = self.values.get(self.current_index); + self.current_index += 1; + Some((index, filter)) + } else { + None + } + } +} + +impl<'a, I: Ord + Copy, V, Idx> FlatMultiMapView<'a, I, V, Idx> +where + Idx: Indexable, + V: Follow<'a>, +{ + pub fn new(index: Idx, values: Vector<'a, V>) -> Self { + debug_assert!(index.len() == values.len()); + + Self { + index, + values, + _phantom: PhantomData, + } + } + + pub fn get(&self, key: I) -> FlatMultiMapViewIterator<'a, I, V, Idx> + where + Idx: Clone, + { + let start = self.index.partition_point(|x| *x < key); + FlatMultiMapViewIterator { + current_index: start, + key, + indexes: self.index.clone(), + values: self.values, + } + } + + #[cfg(test)] + pub fn total_size(&self) -> usize { + self.index.len() + } +} diff --git a/src/flatbuffers/containers/indexable.rs b/src/flatbuffers/containers/indexable.rs new file mode 100644 index 00000000..499907eb --- /dev/null +++ b/src/flatbuffers/containers/indexable.rs @@ -0,0 +1,61 @@ +use flatbuffers::{Follow, Vector}; + +pub(crate) trait Indexable { + fn len(&self) -> usize; + fn get(&self, index: usize) -> I; + fn partition_point(&self, predicate: F) -> usize + where + F: FnMut(&I) -> bool; +} + +impl Indexable for &[I] { + #[inline(always)] + fn len(&self) -> usize { + <[I]>::len(self) + } + + #[inline(always)] + fn get(&self, index: usize) -> I { + self[index] + } + + #[inline(always)] + fn partition_point(&self, predicate: F) -> usize + where + F: FnMut(&I) -> bool, + { + <[I]>::partition_point(self, predicate) + } +} + +impl<'a, T: Follow<'a>> Indexable for Vector<'a, T> { + #[inline(always)] + fn len(&self) -> usize { + Vector::len(self) + } + + #[inline(always)] + fn get(&self, index: usize) -> T::Inner { + Vector::get(self, index) + } + + fn partition_point(&self, mut predicate: F) -> usize + where + F: FnMut(&T::Inner) -> bool, + { + let mut left = 0; + let mut right = self.len(); + + while left < right { + let mid = left + (right - left) / 2; + let value = self.get(mid); + if predicate(&value) { + left = mid + 1; + } else { + right = mid; + } + } + + left + } +} diff --git a/src/flatbuffers/containers/mod.rs b/src/flatbuffers/containers/mod.rs new file mode 100644 index 00000000..a6ebf6b0 --- /dev/null +++ b/src/flatbuffers/containers/mod.rs @@ -0,0 +1,2 @@ +pub(crate) mod flat_multimap; +pub(crate) mod utils; diff --git a/src/flatbuffers/containers/utils.rs b/src/flatbuffers/containers/utils.rs new file mode 100644 index 00000000..a6a80874 --- /dev/null +++ b/src/flatbuffers/containers/utils.rs @@ -0,0 +1,49 @@ +use crate::flatbuffers::unsafe_tools::fb_vector_to_slice; +use flatbuffers::{Follow, ForwardsUOffset, Vector}; + +pub(crate) trait PartitionPoint<'a, T: Ord> { + fn lower_bound(&'a self, key: &T) -> usize; +} + +fn partition_point_pod<'a, T: Ord + Follow<'a>>( + keys: &'a Vector<'a, T>, + pred: impl Fn(&T) -> bool, +) -> usize { + fb_vector_to_slice(*keys).partition_point(pred) +} + +fn partition_point_fbvector<'a, T: Follow<'a>>( + keys: &'a Vector<'a, T>, + pred: impl Fn(&T::Inner) -> bool, +) -> usize { + let mut start = 0; + let mut end: usize = keys.len(); + while start < end { + let mid = (start + end) / 2; + let mid_key = keys.get(mid); + if pred(&mid_key) { + start = mid + 1; + } else { + end = mid; + } + } + end +} + +impl<'a> PartitionPoint<'a, u32> for Vector<'a, u32> { + fn lower_bound(&'a self, key: &u32) -> usize { + partition_point_pod(self, |x| x < key) + } +} + +impl<'a> PartitionPoint<'a, u64> for Vector<'a, u64> { + fn lower_bound(&'a self, key: &u64) -> usize { + partition_point_pod(self, |x| x < key) + } +} + +impl<'a> PartitionPoint<'a, &str> for Vector<'a, ForwardsUOffset<&str>> { + fn lower_bound(&self, key: &&str) -> usize { + partition_point_fbvector(self, |x| *x < key) + } +} diff --git a/src/flatbuffers/mod.rs b/src/flatbuffers/mod.rs new file mode 100644 index 00000000..fd7ccc7d --- /dev/null +++ b/src/flatbuffers/mod.rs @@ -0,0 +1,2 @@ +pub(crate) mod unsafe_tools; +pub(crate) mod containers; \ No newline at end of file diff --git a/src/network_filter_list.rs b/src/network_filter_list.rs index ea27bb14..80e9a44d 100644 --- a/src/network_filter_list.rs +++ b/src/network_filter_list.rs @@ -2,13 +2,15 @@ use std::{collections::HashMap, collections::HashSet, fmt}; +use flatbuffers::ForwardsUOffset; + use crate::filters::fb_network::flat::fb; use crate::filters::fb_network::{FilterDataContext, FlatNetworkFilter}; -use crate::filters::flat_filter_map::FlatFilterMap; use crate::filters::network::{ NetworkFilter, NetworkFilterMask, NetworkFilterMaskHelper, NetworkMatchable, }; -use crate::filters::unsafe_tools::fb_vector_to_slice; +use crate::flatbuffers::containers::flat_multimap::FlatMultiMapView; +use crate::flatbuffers::unsafe_tools::fb_vector_to_slice; use crate::regex_manager::RegexManager; use crate::request::Request; use crate::utils::{fast_hash, to_short_hash, Hash, ShortHash}; @@ -60,10 +62,13 @@ pub(crate) struct NetworkFilterList<'a> { pub(crate) filter_data_context: &'a FilterDataContext, } +type FlatNetworkFilterMap<'a> = + FlatMultiMapView<'a, ShortHash, ForwardsUOffset>, &'a [ShortHash]>; + impl NetworkFilterList<'_> { - pub fn get_filter_map(&self) -> FlatFilterMap { + pub fn get_filter_map(&self) -> FlatNetworkFilterMap { let filters_list = &self.list; - FlatFilterMap::new( + FlatNetworkFilterMap::new( fb_vector_to_slice(filters_list.filter_map_index()), filters_list.filter_map_values(), ) From 54482dd918e808d0b7acc56fabf45aafd6cd74cc Mon Sep 17 00:00:00 2001 From: boocmp Date: Mon, 11 Aug 2025 17:53:00 +0700 Subject: [PATCH 03/13] Added FlatSetView. --- src/flatbuffers/containers/flat_set.rs | 41 ++++++++++++++++++++++++++ src/flatbuffers/containers/mod.rs | 2 ++ 2 files changed, 43 insertions(+) create mode 100644 src/flatbuffers/containers/flat_set.rs diff --git a/src/flatbuffers/containers/flat_set.rs b/src/flatbuffers/containers/flat_set.rs new file mode 100644 index 00000000..42ecc63d --- /dev/null +++ b/src/flatbuffers/containers/flat_set.rs @@ -0,0 +1,41 @@ +use std::marker::PhantomData; + +use crate::flatbuffers::containers::indexable::Indexable; + +/// A set-like container that uses flatbuffer references. +/// Provides O(log n) lookup time using binary search on the sorted data. +pub(crate) struct FlatSetView +where + Idx: Indexable, +{ + index: Idx, + _phantom: PhantomData, +} + +impl FlatSetView +where + I: Ord + Copy, + Idx: Indexable, +{ + pub fn new(index: Idx) -> Self { + Self { + index, + _phantom: PhantomData, + } + } + + pub fn contains(&self, value: I) -> bool { + let idx = self.index.partition_point(|x| *x < value); + idx < self.index.len() && self.index.get(idx) == value + } + + #[inline(always)] + pub fn len(&self) -> usize { + self.index.len() + } + + #[inline(always)] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } +} diff --git a/src/flatbuffers/containers/mod.rs b/src/flatbuffers/containers/mod.rs index a6ebf6b0..e333f2b6 100644 --- a/src/flatbuffers/containers/mod.rs +++ b/src/flatbuffers/containers/mod.rs @@ -1,2 +1,4 @@ pub(crate) mod flat_multimap; +pub(crate) mod flat_set; +pub(crate) mod indexable; pub(crate) mod utils; From c8975dc267fb9650ff95bd117d15995fe82b5a1f Mon Sep 17 00:00:00 2001 From: boocmp Date: Mon, 11 Aug 2025 18:09:09 +0700 Subject: [PATCH 04/13] Removed unused utils. --- src/flatbuffers/containers/mod.rs | 1 - src/flatbuffers/containers/utils.rs | 49 ----------------------------- 2 files changed, 50 deletions(-) delete mode 100644 src/flatbuffers/containers/utils.rs diff --git a/src/flatbuffers/containers/mod.rs b/src/flatbuffers/containers/mod.rs index e333f2b6..b76d7f9c 100644 --- a/src/flatbuffers/containers/mod.rs +++ b/src/flatbuffers/containers/mod.rs @@ -1,4 +1,3 @@ pub(crate) mod flat_multimap; pub(crate) mod flat_set; pub(crate) mod indexable; -pub(crate) mod utils; diff --git a/src/flatbuffers/containers/utils.rs b/src/flatbuffers/containers/utils.rs deleted file mode 100644 index a6a80874..00000000 --- a/src/flatbuffers/containers/utils.rs +++ /dev/null @@ -1,49 +0,0 @@ -use crate::flatbuffers::unsafe_tools::fb_vector_to_slice; -use flatbuffers::{Follow, ForwardsUOffset, Vector}; - -pub(crate) trait PartitionPoint<'a, T: Ord> { - fn lower_bound(&'a self, key: &T) -> usize; -} - -fn partition_point_pod<'a, T: Ord + Follow<'a>>( - keys: &'a Vector<'a, T>, - pred: impl Fn(&T) -> bool, -) -> usize { - fb_vector_to_slice(*keys).partition_point(pred) -} - -fn partition_point_fbvector<'a, T: Follow<'a>>( - keys: &'a Vector<'a, T>, - pred: impl Fn(&T::Inner) -> bool, -) -> usize { - let mut start = 0; - let mut end: usize = keys.len(); - while start < end { - let mid = (start + end) / 2; - let mid_key = keys.get(mid); - if pred(&mid_key) { - start = mid + 1; - } else { - end = mid; - } - } - end -} - -impl<'a> PartitionPoint<'a, u32> for Vector<'a, u32> { - fn lower_bound(&'a self, key: &u32) -> usize { - partition_point_pod(self, |x| x < key) - } -} - -impl<'a> PartitionPoint<'a, u64> for Vector<'a, u64> { - fn lower_bound(&'a self, key: &u64) -> usize { - partition_point_pod(self, |x| x < key) - } -} - -impl<'a> PartitionPoint<'a, &str> for Vector<'a, ForwardsUOffset<&str>> { - fn lower_bound(&self, key: &&str) -> usize { - partition_point_fbvector(self, |x| *x < key) - } -} From aab494040e7417859d2b04e7c378fbeec02c604f Mon Sep 17 00:00:00 2001 From: boocmp Date: Mon, 11 Aug 2025 18:10:00 +0700 Subject: [PATCH 05/13] Temporary marked FlatSet as dead_code. --- src/flatbuffers/containers/flat_set.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/flatbuffers/containers/flat_set.rs b/src/flatbuffers/containers/flat_set.rs index 42ecc63d..de82f21f 100644 --- a/src/flatbuffers/containers/flat_set.rs +++ b/src/flatbuffers/containers/flat_set.rs @@ -1,9 +1,12 @@ +#![warn(dead_code)] + use std::marker::PhantomData; use crate::flatbuffers::containers::indexable::Indexable; /// A set-like container that uses flatbuffer references. /// Provides O(log n) lookup time using binary search on the sorted data. + pub(crate) struct FlatSetView where Idx: Indexable, @@ -39,3 +42,7 @@ where self.len() == 0 } } + +#[cfg(test)] +#[path = "../../../tests/unit/flatbuffers/containers/flat_set.rs"] +mod unit_tests; From 06eda2358faa31ce655816859a817fa49228e5e9 Mon Sep 17 00:00:00 2001 From: boocmp Date: Mon, 11 Aug 2025 18:10:26 +0700 Subject: [PATCH 06/13] Added test for FlatSetView. --- tests/unit/flatbuffers/containers/flat_set.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 tests/unit/flatbuffers/containers/flat_set.rs diff --git a/tests/unit/flatbuffers/containers/flat_set.rs b/tests/unit/flatbuffers/containers/flat_set.rs new file mode 100644 index 00000000..6027d2d4 --- /dev/null +++ b/tests/unit/flatbuffers/containers/flat_set.rs @@ -0,0 +1,19 @@ +#[cfg(test)] +mod unit_tests { + use super::super::*; + + #[test] + fn test_flat_set_view() { + let data = vec![1, 2, 2, 3, 4, 4, 4, 5]; + let set = FlatSetView::::new(&data); + + // Test contains + assert!(set.contains(1)); + assert!(set.contains(2)); + assert!(set.contains(4)); + assert!(!set.contains(6)); + + // Test len + assert_eq!(set.len(), 8); + } +} From 5be314fa68683d64e03d49f26134b9eea9efd271 Mon Sep 17 00:00:00 2001 From: boocmp Date: Mon, 11 Aug 2025 19:17:24 +0700 Subject: [PATCH 07/13] Added FlatMultiMapView tests. --- src/flatbuffers/containers/flat_multimap.rs | 4 + .../flatbuffers/containers/flat_multimap.rs | 103 ++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 tests/unit/flatbuffers/containers/flat_multimap.rs diff --git a/src/flatbuffers/containers/flat_multimap.rs b/src/flatbuffers/containers/flat_multimap.rs index 38f1bcd0..a3483c00 100644 --- a/src/flatbuffers/containers/flat_multimap.rs +++ b/src/flatbuffers/containers/flat_multimap.rs @@ -82,3 +82,7 @@ where self.index.len() } } + +#[cfg(test)] +#[path = "../../../tests/unit/flatbuffers/containers/flat_multimap.rs"] +mod unit_tests; diff --git a/tests/unit/flatbuffers/containers/flat_multimap.rs b/tests/unit/flatbuffers/containers/flat_multimap.rs new file mode 100644 index 00000000..5e39c55c --- /dev/null +++ b/tests/unit/flatbuffers/containers/flat_multimap.rs @@ -0,0 +1,103 @@ +#[cfg(test)] +mod unit_tests { + use super::super::*; + use flatbuffers; + + // Helper function to create a Vector from a slice + fn create_vector_u32<'a>( + builder: &'a mut flatbuffers::FlatBufferBuilder, + data: &'a [u32], + ) -> flatbuffers::Vector<'a, u32> { + let vec_offset = builder.create_vector(&data); + builder.finish(vec_offset, None); + let buf = builder.finished_data(); + flatbuffers::root::>(buf).expect("OK") + } + + #[test] + fn test_empty_map() { + let index: &[u32] = &[]; + let mut builder = flatbuffers::FlatBufferBuilder::new(); + let values = create_vector_u32(&mut builder, &[]); + let map = FlatMultiMapView::new(index, values); + + assert_eq!(map.total_size(), 0); + assert_eq!(map.get(1).count(), 0); + } + + #[test] + fn test_single_element() { + let index: &[u32] = &[1]; + let mut builder = flatbuffers::FlatBufferBuilder::new(); + let values = create_vector_u32(&mut builder, &[100]); + let map = FlatMultiMapView::new(index, values); + + assert_eq!(map.total_size(), 1); + + // Test existing key + let mut iter = map.get(1); + assert_eq!(iter.next(), Some((0, 100))); + assert_eq!(iter.next(), None); + + // Test non-existing key + assert_eq!(map.get(2).count(), 0); + } + + #[test] + fn test_multiple_elements() { + let index: &[u32] = &[1, 1, 2, 2, 2, 3]; + let mut builder = flatbuffers::FlatBufferBuilder::new(); + let values = create_vector_u32(&mut builder, &[10, 20, 30, 40, 50, 60]); + + let map = FlatMultiMapView::new(index, values); + + assert_eq!(map.total_size(), 6); + + // Test key with single value + let mut iter = map.get(3); + assert_eq!(iter.next(), Some((5, 60))); + assert_eq!(iter.next(), None); + + // Test key with multiple values + let mut iter = map.get(2); + assert_eq!(iter.next(), Some((2, 30))); + assert_eq!(iter.next(), Some((3, 40))); + assert_eq!(iter.next(), Some((4, 50))); + assert_eq!(iter.next(), None); + + // Test non-existing key + assert_eq!(map.get(4).count(), 0); + } + + #[test] + fn test_all_same_keys() { + let index: &[u32] = &[5, 5, 5]; + let mut builder = flatbuffers::FlatBufferBuilder::new(); + let values = create_vector_u32(&mut builder, &[100, 200, 300]); + let map = FlatMultiMapView::new(index, values); + + assert_eq!(map.total_size(), 3); + + let mut iter = map.get(5); + assert_eq!(iter.next(), Some((0, 100))); + assert_eq!(iter.next(), Some((1, 200))); + assert_eq!(iter.next(), Some((2, 300))); + assert_eq!(iter.next(), None); + } + + #[test] + fn test_non_contiguous_keys() { + let index: &[u32] = &[1, 3, 5]; + let mut builder = flatbuffers::FlatBufferBuilder::new(); + let values = create_vector_u32(&mut builder, &[10, 30, 50]); + let map = FlatMultiMapView::new(index, values); + + assert_eq!(map.total_size(), 3); + + assert_eq!(map.get(1).next(), Some((0, 10))); + assert_eq!(map.get(3).next(), Some((1, 30))); + assert_eq!(map.get(5).next(), Some((2, 50))); + assert_eq!(map.get(2).count(), 0); + assert_eq!(map.get(4).count(), 0); + } +} From 4c0f0ed50bf11610b7bb8b0909f10ed8e4c3cb78 Mon Sep 17 00:00:00 2001 From: boocmp Date: Mon, 11 Aug 2025 19:18:43 +0700 Subject: [PATCH 08/13] Clean up. --- benches/bench_matching.rs | 6 +++--- src/flatbuffers/containers/flat_set.rs | 2 +- src/flatbuffers/mod.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/benches/bench_matching.rs b/benches/bench_matching.rs index 7962469a..516374ac 100644 --- a/benches/bench_matching.rs +++ b/benches/bench_matching.rs @@ -54,7 +54,7 @@ fn bench_rule_matching(engine: &Engine, requests: &[TestRequest]) -> (u32, u32) passes += 1; } }); - println!("Got {} matches, {} passes", matches, passes); + // println!("Got {} matches, {} passes, {} errors", matches, passes, errors); (matches, passes) } @@ -69,7 +69,7 @@ fn bench_matching_only(engine: &Engine, requests: &[Request]) -> (u32, u32) { passes += 1; } }); - println!("Got {} matches, {} passes", matches, passes); + // println!("Got {} matches, {} passes", matches, passes); (matches, passes) } @@ -94,7 +94,7 @@ fn bench_rule_matching_browserlike(blocker: &Engine, requests: &[ParsedRequest]) } }, ); - println!("Got {} matches, {} passes", matches, passes); + // println!("Got {} matches, {} passes", matches, passes); (matches, passes) } diff --git a/src/flatbuffers/containers/flat_set.rs b/src/flatbuffers/containers/flat_set.rs index de82f21f..3c9e97c0 100644 --- a/src/flatbuffers/containers/flat_set.rs +++ b/src/flatbuffers/containers/flat_set.rs @@ -1,4 +1,4 @@ -#![warn(dead_code)] +#![allow(dead_code)] use std::marker::PhantomData; diff --git a/src/flatbuffers/mod.rs b/src/flatbuffers/mod.rs index fd7ccc7d..61dc0bd6 100644 --- a/src/flatbuffers/mod.rs +++ b/src/flatbuffers/mod.rs @@ -1,2 +1,2 @@ +pub(crate) mod containers; pub(crate) mod unsafe_tools; -pub(crate) mod containers; \ No newline at end of file From 9be3ad457566dd0574cc488d37e65da81766b285 Mon Sep 17 00:00:00 2001 From: boocmp Date: Mon, 11 Aug 2025 20:06:09 +0700 Subject: [PATCH 09/13] Ignore live test. --- tests/live.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/live.rs b/tests/live.rs index cdb1999c..8cfa7a8c 100644 --- a/tests/live.rs +++ b/tests/live.rs @@ -230,6 +230,7 @@ fn check_live_from_filterlists() { #[cfg(feature = "resource-assembler")] #[test] +#[ignore = "issues/499"] fn check_live_redirects() { use adblock::resources::resource_assembler::assemble_web_accessible_resources; From b94b56c37fc56e1021438083863bfdc16fcd8ab2 Mon Sep 17 00:00:00 2001 From: boocmp Date: Mon, 11 Aug 2025 20:29:33 +0700 Subject: [PATCH 10/13] Clippy fixes. --- src/flatbuffers/containers/flat_set.rs | 1 - tests/unit/flatbuffers/containers/flat_multimap.rs | 5 ++--- tests/unit/flatbuffers/containers/flat_set.rs | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/flatbuffers/containers/flat_set.rs b/src/flatbuffers/containers/flat_set.rs index 3c9e97c0..277f313c 100644 --- a/src/flatbuffers/containers/flat_set.rs +++ b/src/flatbuffers/containers/flat_set.rs @@ -6,7 +6,6 @@ use crate::flatbuffers::containers::indexable::Indexable; /// A set-like container that uses flatbuffer references. /// Provides O(log n) lookup time using binary search on the sorted data. - pub(crate) struct FlatSetView where Idx: Indexable, diff --git a/tests/unit/flatbuffers/containers/flat_multimap.rs b/tests/unit/flatbuffers/containers/flat_multimap.rs index 5e39c55c..43ee0696 100644 --- a/tests/unit/flatbuffers/containers/flat_multimap.rs +++ b/tests/unit/flatbuffers/containers/flat_multimap.rs @@ -1,14 +1,13 @@ #[cfg(test)] -mod unit_tests { +mod tests { use super::super::*; - use flatbuffers; // Helper function to create a Vector from a slice fn create_vector_u32<'a>( builder: &'a mut flatbuffers::FlatBufferBuilder, data: &'a [u32], ) -> flatbuffers::Vector<'a, u32> { - let vec_offset = builder.create_vector(&data); + let vec_offset = builder.create_vector(data); builder.finish(vec_offset, None); let buf = builder.finished_data(); flatbuffers::root::>(buf).expect("OK") diff --git a/tests/unit/flatbuffers/containers/flat_set.rs b/tests/unit/flatbuffers/containers/flat_set.rs index 6027d2d4..2fb37813 100644 --- a/tests/unit/flatbuffers/containers/flat_set.rs +++ b/tests/unit/flatbuffers/containers/flat_set.rs @@ -1,5 +1,5 @@ #[cfg(test)] -mod unit_tests { +mod tests { use super::super::*; #[test] From c4bbdee6faecaf130f4a329ddbb1ee844549c915 Mon Sep 17 00:00:00 2001 From: boocmp Date: Tue, 12 Aug 2025 16:52:43 +0700 Subject: [PATCH 11/13] Review issues are addressed. --- src/flatbuffers/containers/flat_multimap.rs | 95 +++++++++---------- src/flatbuffers/containers/flat_set.rs | 28 +++--- src/flatbuffers/containers/mod.rs | 2 +- .../{indexable.rs => sorted_index.rs} | 18 +++- src/flatbuffers/containers/utils.rs | 49 ++++++++++ 5 files changed, 124 insertions(+), 68 deletions(-) rename src/flatbuffers/containers/{indexable.rs => sorted_index.rs} (67%) create mode 100644 src/flatbuffers/containers/utils.rs diff --git a/src/flatbuffers/containers/flat_multimap.rs b/src/flatbuffers/containers/flat_multimap.rs index a3483c00..8a579624 100644 --- a/src/flatbuffers/containers/flat_multimap.rs +++ b/src/flatbuffers/containers/flat_multimap.rs @@ -1,85 +1,78 @@ use std::marker::PhantomData; -use crate::flatbuffers::containers::indexable::Indexable; +use crate::flatbuffers::containers::sorted_index::SortedIndex; use flatbuffers::{Follow, Vector}; /// A map-like container that uses flatbuffer references. /// Provides O(log n) lookup time using binary search on the sorted index. -pub(crate) struct FlatMultiMapView<'a, I: Ord + Copy, V, Idx> +/// I is a key type, Keys is specific container of keys, &[I] for fast indexing (u32, u64) +/// and flatbuffers::Vector if there is no conversion from Vector (str) to slice. +pub(crate) struct FlatMultiMapView<'a, I: Ord, V, Keys> where - Idx: Indexable, + Keys: SortedIndex, V: Follow<'a>, { - index: Idx, + keys: Keys, values: Vector<'a, V>, _phantom: PhantomData, } -pub(crate) struct FlatMultiMapViewIterator<'a, I: Ord + Copy, V, Idx> +impl<'a, I: Ord + Copy, V, Keys> FlatMultiMapView<'a, I, V, Keys> where - Idx: Indexable, + Keys: SortedIndex + Clone, V: Follow<'a>, { - current_index: usize, - key: I, - indexes: Idx, - values: Vector<'a, V>, -} - -impl<'a, I, V, Idx> Iterator for FlatMultiMapViewIterator<'a, I, V, Idx> -where - I: Ord + Copy, - V: Follow<'a>, - Idx: Indexable, -{ - type Item = (usize, >::Inner); - - fn next(&mut self) -> Option { - if self.current_index < self.indexes.len() { - if self.indexes.get(self.current_index) != self.key { - return None; - } - let index = self.current_index; - let filter = self.values.get(self.current_index); - self.current_index += 1; - Some((index, filter)) - } else { - None - } - } -} - -impl<'a, I: Ord + Copy, V, Idx> FlatMultiMapView<'a, I, V, Idx> -where - Idx: Indexable, - V: Follow<'a>, -{ - pub fn new(index: Idx, values: Vector<'a, V>) -> Self { - debug_assert!(index.len() == values.len()); + pub fn new(keys: Keys, values: Vector<'a, V>) -> Self { + debug_assert!(keys.len() == values.len()); Self { - index, + keys, values, _phantom: PhantomData, } } - pub fn get(&self, key: I) -> FlatMultiMapViewIterator<'a, I, V, Idx> - where - Idx: Clone, - { - let start = self.index.partition_point(|x| *x < key); + pub fn get(&self, key: I) -> FlatMultiMapViewIterator<'a, I, V, Keys> { FlatMultiMapViewIterator { - current_index: start, + index: self.keys.partition_point(|x| *x < key), key, - indexes: self.index.clone(), + keys: self.keys.clone(), // Cloning is 3-4% faster than & in benchmarks values: self.values, } } #[cfg(test)] pub fn total_size(&self) -> usize { - self.index.len() + self.keys.len() + } +} + +pub(crate) struct FlatMultiMapViewIterator<'a, I: Ord + Copy, V, Keys> +where + Keys: SortedIndex, + V: Follow<'a>, +{ + index: usize, + key: I, + keys: Keys, + values: Vector<'a, V>, +} + +impl<'a, I, V, Keys> Iterator for FlatMultiMapViewIterator<'a, I, V, Keys> +where + I: Ord + Copy, + V: Follow<'a>, + Keys: SortedIndex, +{ + type Item = (usize, >::Inner); + + fn next(&mut self) -> Option { + if self.index < self.keys.len() && self.keys.get(self.index) == self.key { + self.index += 1; + Some((self.index - 1, self.values.get(self.index - 1))) + } else { + None + } } } diff --git a/src/flatbuffers/containers/flat_set.rs b/src/flatbuffers/containers/flat_set.rs index 277f313c..ed375db8 100644 --- a/src/flatbuffers/containers/flat_set.rs +++ b/src/flatbuffers/containers/flat_set.rs @@ -2,38 +2,40 @@ use std::marker::PhantomData; -use crate::flatbuffers::containers::indexable::Indexable; +use crate::flatbuffers::containers::sorted_index::SortedIndex; /// A set-like container that uses flatbuffer references. /// Provides O(log n) lookup time using binary search on the sorted data. -pub(crate) struct FlatSetView +/// I is a key type, Keys is specific container of keys, &[I] for fast indexing (u32, u64) +/// and flatbuffers::Vector if there is no conversion from Vector (str) to slice. +pub(crate) struct FlatSetView where - Idx: Indexable, + Keys: SortedIndex, { - index: Idx, + keys: Keys, _phantom: PhantomData, } -impl FlatSetView +impl<'a, I, Keys> FlatSetView where - I: Ord + Copy, - Idx: Indexable, + I: Ord, + Keys: SortedIndex, { - pub fn new(index: Idx) -> Self { + pub fn new(keys: Keys) -> Self { Self { - index, + keys, _phantom: PhantomData, } } - pub fn contains(&self, value: I) -> bool { - let idx = self.index.partition_point(|x| *x < value); - idx < self.index.len() && self.index.get(idx) == value + pub fn contains(&self, key: I) -> bool { + let index = self.keys.partition_point(|x| *x < key); + index < self.keys.len() && self.keys.get(index) == key } #[inline(always)] pub fn len(&self) -> usize { - self.index.len() + self.keys.len() } #[inline(always)] diff --git a/src/flatbuffers/containers/mod.rs b/src/flatbuffers/containers/mod.rs index b76d7f9c..507620de 100644 --- a/src/flatbuffers/containers/mod.rs +++ b/src/flatbuffers/containers/mod.rs @@ -1,3 +1,3 @@ pub(crate) mod flat_multimap; pub(crate) mod flat_set; -pub(crate) mod indexable; +pub(crate) mod sorted_index; diff --git a/src/flatbuffers/containers/indexable.rs b/src/flatbuffers/containers/sorted_index.rs similarity index 67% rename from src/flatbuffers/containers/indexable.rs rename to src/flatbuffers/containers/sorted_index.rs index 499907eb..a8446050 100644 --- a/src/flatbuffers/containers/indexable.rs +++ b/src/flatbuffers/containers/sorted_index.rs @@ -1,6 +1,7 @@ use flatbuffers::{Follow, Vector}; -pub(crate) trait Indexable { +// Represents sorted sequence to perform the binary search. +pub(crate) trait SortedIndex { fn len(&self) -> usize; fn get(&self, index: usize) -> I; fn partition_point(&self, predicate: F) -> usize @@ -8,7 +9,10 @@ pub(crate) trait Indexable { F: FnMut(&I) -> bool; } -impl Indexable for &[I] { +// Implementation for slices. Prefer using this with fb_vector_to_slice +// if possible, because it faster than getting values with flatbuffer's +// get method. +impl<'a, I: Ord + Copy> SortedIndex for &[I] { #[inline(always)] fn len(&self) -> usize { <[I]>::len(self) @@ -24,11 +28,17 @@ impl Indexable for &[I] { where F: FnMut(&I) -> bool, { + debug_assert!(self.is_sorted()); <[I]>::partition_point(self, predicate) } } -impl<'a, T: Follow<'a>> Indexable for Vector<'a, T> { +// General implementation for flatbuffers::Vector, it uses get to +// obtain values. +impl<'a, T: Follow<'a>> SortedIndex for Vector<'a, T> +where + T::Inner: Ord, +{ #[inline(always)] fn len(&self) -> usize { Vector::len(self) @@ -43,6 +53,8 @@ impl<'a, T: Follow<'a>> Indexable for Vector<'a, T> { where F: FnMut(&T::Inner) -> bool, { + debug_assert!(self.iter().is_sorted()); + let mut left = 0; let mut right = self.len(); diff --git a/src/flatbuffers/containers/utils.rs b/src/flatbuffers/containers/utils.rs new file mode 100644 index 00000000..a6a80874 --- /dev/null +++ b/src/flatbuffers/containers/utils.rs @@ -0,0 +1,49 @@ +use crate::flatbuffers::unsafe_tools::fb_vector_to_slice; +use flatbuffers::{Follow, ForwardsUOffset, Vector}; + +pub(crate) trait PartitionPoint<'a, T: Ord> { + fn lower_bound(&'a self, key: &T) -> usize; +} + +fn partition_point_pod<'a, T: Ord + Follow<'a>>( + keys: &'a Vector<'a, T>, + pred: impl Fn(&T) -> bool, +) -> usize { + fb_vector_to_slice(*keys).partition_point(pred) +} + +fn partition_point_fbvector<'a, T: Follow<'a>>( + keys: &'a Vector<'a, T>, + pred: impl Fn(&T::Inner) -> bool, +) -> usize { + let mut start = 0; + let mut end: usize = keys.len(); + while start < end { + let mid = (start + end) / 2; + let mid_key = keys.get(mid); + if pred(&mid_key) { + start = mid + 1; + } else { + end = mid; + } + } + end +} + +impl<'a> PartitionPoint<'a, u32> for Vector<'a, u32> { + fn lower_bound(&'a self, key: &u32) -> usize { + partition_point_pod(self, |x| x < key) + } +} + +impl<'a> PartitionPoint<'a, u64> for Vector<'a, u64> { + fn lower_bound(&'a self, key: &u64) -> usize { + partition_point_pod(self, |x| x < key) + } +} + +impl<'a> PartitionPoint<'a, &str> for Vector<'a, ForwardsUOffset<&str>> { + fn lower_bound(&self, key: &&str) -> usize { + partition_point_fbvector(self, |x| *x < key) + } +} From e1c705a5239b64d27a7cfe3582b5aa5e803c4196 Mon Sep 17 00:00:00 2001 From: boocmp Date: Tue, 12 Aug 2025 17:27:12 +0700 Subject: [PATCH 12/13] Optional iterator for multimap (improve perf). --- src/flatbuffers/containers/flat_multimap.rs | 17 +++--- src/flatbuffers/containers/flat_set.rs | 2 +- src/flatbuffers/containers/sorted_index.rs | 2 +- src/network_filter_list.rs | 54 ++++++++++--------- .../flatbuffers/containers/flat_multimap.rs | 24 ++++----- 5 files changed, 55 insertions(+), 44 deletions(-) diff --git a/src/flatbuffers/containers/flat_multimap.rs b/src/flatbuffers/containers/flat_multimap.rs index 8a579624..a90dcc59 100644 --- a/src/flatbuffers/containers/flat_multimap.rs +++ b/src/flatbuffers/containers/flat_multimap.rs @@ -32,12 +32,17 @@ where } } - pub fn get(&self, key: I) -> FlatMultiMapViewIterator<'a, I, V, Keys> { - FlatMultiMapViewIterator { - index: self.keys.partition_point(|x| *x < key), - key, - keys: self.keys.clone(), // Cloning is 3-4% faster than & in benchmarks - values: self.values, + pub fn get(&self, key: I) -> Option> { + let index = self.keys.partition_point(|x| *x < key); + if index < self.keys.len() && self.keys.get(index) == key { + Some(FlatMultiMapViewIterator { + index, + key, + keys: self.keys.clone(), // Cloning is 3-4% faster than & in benchmarks + values: self.values, + }) + } else { + None } } diff --git a/src/flatbuffers/containers/flat_set.rs b/src/flatbuffers/containers/flat_set.rs index ed375db8..48b1199c 100644 --- a/src/flatbuffers/containers/flat_set.rs +++ b/src/flatbuffers/containers/flat_set.rs @@ -16,7 +16,7 @@ where _phantom: PhantomData, } -impl<'a, I, Keys> FlatSetView +impl FlatSetView where I: Ord, Keys: SortedIndex, diff --git a/src/flatbuffers/containers/sorted_index.rs b/src/flatbuffers/containers/sorted_index.rs index a8446050..166f491f 100644 --- a/src/flatbuffers/containers/sorted_index.rs +++ b/src/flatbuffers/containers/sorted_index.rs @@ -12,7 +12,7 @@ pub(crate) trait SortedIndex { // Implementation for slices. Prefer using this with fb_vector_to_slice // if possible, because it faster than getting values with flatbuffer's // get method. -impl<'a, I: Ord + Copy> SortedIndex for &[I] { +impl SortedIndex for &[I] { #[inline(always)] fn len(&self) -> usize { <[I]>::len(self) diff --git a/src/network_filter_list.rs b/src/network_filter_list.rs index 80e9a44d..c0d2f6dc 100644 --- a/src/network_filter_list.rs +++ b/src/network_filter_list.rs @@ -94,18 +94,21 @@ impl NetworkFilterList<'_> { let filter_map = self.get_filter_map(); for token in request.get_tokens_for_match() { - for (index, fb_filter) in filter_map.get(to_short_hash(*token)) { - let filter = FlatNetworkFilter::new(&fb_filter, index, self.filter_data_context); - - // if matched, also needs to be tagged with an active tag (or not tagged at all) - if filter.matches(request, regex_manager) - && filter.tag().is_none_or(|t| active_tags.contains(t)) - { - return Some(CheckResult { - filter_mask: filter.mask, - modifier_option: filter.modifier_option(), - raw_line: filter.raw_line(), - }); + if let Some(iter) = filter_map.get(to_short_hash(*token)) { + for (index, fb_filter) in iter { + let filter = + FlatNetworkFilter::new(&fb_filter, index, self.filter_data_context); + + // if matched, also needs to be tagged with an active tag (or not tagged at all) + if filter.matches(request, regex_manager) + && filter.tag().is_none_or(|t| active_tags.contains(t)) + { + return Some(CheckResult { + filter_mask: filter.mask, + modifier_option: filter.modifier_option(), + raw_line: filter.raw_line(), + }); + } } } } @@ -134,18 +137,21 @@ impl NetworkFilterList<'_> { let filter_map = self.get_filter_map(); for token in request.get_tokens_for_match() { - for (index, fb_filter) in filter_map.get(to_short_hash(*token)) { - let filter = FlatNetworkFilter::new(&fb_filter, index, self.filter_data_context); - - // if matched, also needs to be tagged with an active tag (or not tagged at all) - if filter.matches(request, regex_manager) - && filter.tag().is_none_or(|t| active_tags.contains(t)) - { - filters.push(CheckResult { - filter_mask: filter.mask, - modifier_option: filter.modifier_option(), - raw_line: filter.raw_line(), - }); + if let Some(iter) = filter_map.get(to_short_hash(*token)) { + for (index, fb_filter) in iter { + let filter = + FlatNetworkFilter::new(&fb_filter, index, self.filter_data_context); + + // if matched, also needs to be tagged with an active tag (or not tagged at all) + if filter.matches(request, regex_manager) + && filter.tag().is_none_or(|t| active_tags.contains(t)) + { + filters.push(CheckResult { + filter_mask: filter.mask, + modifier_option: filter.modifier_option(), + raw_line: filter.raw_line(), + }); + } } } } diff --git a/tests/unit/flatbuffers/containers/flat_multimap.rs b/tests/unit/flatbuffers/containers/flat_multimap.rs index 43ee0696..74505bd6 100644 --- a/tests/unit/flatbuffers/containers/flat_multimap.rs +++ b/tests/unit/flatbuffers/containers/flat_multimap.rs @@ -21,7 +21,7 @@ mod tests { let map = FlatMultiMapView::new(index, values); assert_eq!(map.total_size(), 0); - assert_eq!(map.get(1).count(), 0); + assert!(map.get(1).is_none()); } #[test] @@ -34,12 +34,12 @@ mod tests { assert_eq!(map.total_size(), 1); // Test existing key - let mut iter = map.get(1); + let mut iter = map.get(1).unwrap(); assert_eq!(iter.next(), Some((0, 100))); assert_eq!(iter.next(), None); // Test non-existing key - assert_eq!(map.get(2).count(), 0); + assert!(map.get(2).is_none()); } #[test] @@ -53,19 +53,19 @@ mod tests { assert_eq!(map.total_size(), 6); // Test key with single value - let mut iter = map.get(3); + let mut iter = map.get(3).unwrap(); assert_eq!(iter.next(), Some((5, 60))); assert_eq!(iter.next(), None); // Test key with multiple values - let mut iter = map.get(2); + let mut iter = map.get(2).unwrap(); assert_eq!(iter.next(), Some((2, 30))); assert_eq!(iter.next(), Some((3, 40))); assert_eq!(iter.next(), Some((4, 50))); assert_eq!(iter.next(), None); // Test non-existing key - assert_eq!(map.get(4).count(), 0); + assert!(map.get(4).is_none()); } #[test] @@ -77,7 +77,7 @@ mod tests { assert_eq!(map.total_size(), 3); - let mut iter = map.get(5); + let mut iter = map.get(5).unwrap(); assert_eq!(iter.next(), Some((0, 100))); assert_eq!(iter.next(), Some((1, 200))); assert_eq!(iter.next(), Some((2, 300))); @@ -93,10 +93,10 @@ mod tests { assert_eq!(map.total_size(), 3); - assert_eq!(map.get(1).next(), Some((0, 10))); - assert_eq!(map.get(3).next(), Some((1, 30))); - assert_eq!(map.get(5).next(), Some((2, 50))); - assert_eq!(map.get(2).count(), 0); - assert_eq!(map.get(4).count(), 0); + assert_eq!(map.get(1).unwrap().next(), Some((0, 10))); + assert_eq!(map.get(3).unwrap().next(), Some((1, 30))); + assert_eq!(map.get(5).unwrap().next(), Some((2, 50))); + assert!(map.get(2).is_none()); + assert!(map.get(4).is_none()); } } From 82b6f4f623fb197790a42bac64d4312b5fb76ee2 Mon Sep 17 00:00:00 2001 From: boocmp Date: Wed, 13 Aug 2025 14:23:51 +0700 Subject: [PATCH 13/13] Removed unused file. --- src/flatbuffers/containers/utils.rs | 49 ----------------------------- 1 file changed, 49 deletions(-) delete mode 100644 src/flatbuffers/containers/utils.rs diff --git a/src/flatbuffers/containers/utils.rs b/src/flatbuffers/containers/utils.rs deleted file mode 100644 index a6a80874..00000000 --- a/src/flatbuffers/containers/utils.rs +++ /dev/null @@ -1,49 +0,0 @@ -use crate::flatbuffers::unsafe_tools::fb_vector_to_slice; -use flatbuffers::{Follow, ForwardsUOffset, Vector}; - -pub(crate) trait PartitionPoint<'a, T: Ord> { - fn lower_bound(&'a self, key: &T) -> usize; -} - -fn partition_point_pod<'a, T: Ord + Follow<'a>>( - keys: &'a Vector<'a, T>, - pred: impl Fn(&T) -> bool, -) -> usize { - fb_vector_to_slice(*keys).partition_point(pred) -} - -fn partition_point_fbvector<'a, T: Follow<'a>>( - keys: &'a Vector<'a, T>, - pred: impl Fn(&T::Inner) -> bool, -) -> usize { - let mut start = 0; - let mut end: usize = keys.len(); - while start < end { - let mid = (start + end) / 2; - let mid_key = keys.get(mid); - if pred(&mid_key) { - start = mid + 1; - } else { - end = mid; - } - } - end -} - -impl<'a> PartitionPoint<'a, u32> for Vector<'a, u32> { - fn lower_bound(&'a self, key: &u32) -> usize { - partition_point_pod(self, |x| x < key) - } -} - -impl<'a> PartitionPoint<'a, u64> for Vector<'a, u64> { - fn lower_bound(&'a self, key: &u64) -> usize { - partition_point_pod(self, |x| x < key) - } -} - -impl<'a> PartitionPoint<'a, &str> for Vector<'a, ForwardsUOffset<&str>> { - fn lower_bound(&self, key: &&str) -> usize { - partition_point_fbvector(self, |x| *x < key) - } -}