Copilot commented on code in PR #191:
URL: https://github.com/apache/datasketches-rust/pull/191#discussion_r3744460187


##########
datasketches/src/frequencies/sketch.rs:
##########
@@ -131,11 +131,18 @@ impl<T: Eq + Hash> FrequentItemsSketch<T> {
         Self::with_lg_map_sizes(lg_max_map_size, LG_MIN_MAP_SIZE)
     }
 
-    /// Returns true if the sketch is empty.
+    /// Returns true if the sketch has no active items.
+    ///
+    /// A purge can remove all active items while retaining a non-zero total 
weight and
+    /// maximum error. Use [`Self::total_weight`] to distinguish that state 
from a virgin sketch.
     pub fn is_empty(&self) -> bool {
         self.hash_map.num_active() == 0
     }
 
+    fn is_virgin(&self) -> bool {
+        self.stream_weight == 0
+    }

Review Comment:
   `is_virgin()` is currently defined as `stream_weight == 0`. Because 
`stream_weight` is a `u64` updated via `+=`, it can wrap to 0 on overflow in 
release builds; that would incorrectly treat a non-virgin sketch (possibly with 
active items) as virgin, collapsing serialization to the 8-byte empty image and 
causing `merge()` to skip state. Consider including `offset` and `num_active` 
in the virgin predicate so it reflects the actual "never updated" state and is 
robust against `stream_weight` wraparound/corrupt inputs.



##########
datasketches/tests/serde_tests/frequencies.rs:
##########
@@ -104,14 +104,26 @@ fn test_empty_round_trip() {
 #[test]
 fn test_purged_to_empty_round_trip() {
     // Saturating the map with count-1 items makes the purge median 1, which
-    // removes every counter and leaves a non-trivial sketch empty.
+    // removes every counter while retaining stream and error state.
     let mut sketch = FrequentItemsSketch::<i64>::new(32);
     for i in 0..=(32 * 3 / 4) {
         sketch.update(i);
     }
     assert!(sketch.is_empty());
-    let restored = 
FrequentItemsSketch::<i64>::deserialize(&sketch.serialize()).unwrap();
+    assert_eq!(sketch.num_active_items(), 0);
+    assert_eq!(sketch.total_weight(), 25);
+    assert_eq!(sketch.maximum_error(), 1);
+    assert_eq!(sketch.upper_bound(&1000), 1);
+
+    let bytes = sketch.serialize();
+    assert_eq!(bytes.len(), 4 * size_of::<u64>());
+    let restored = FrequentItemsSketch::<i64>::deserialize(&bytes).unwrap();

Review Comment:
   This test file calls `size_of::<...>()` but does not import 
`std::mem::size_of` (and it is also used earlier in the file). As written, this 
won’t compile on stable Rust unless `size_of` happens to be in scope via some 
nonstandard prelude; please either add a module-level `use std::mem::size_of;` 
or fully-qualify the calls as `std::mem::size_of::<...>()` throughout the file.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to