diff --git a/roaring/Cargo.toml b/roaring/Cargo.toml index 17f74493..a9dd5663 100644 --- a/roaring/Cargo.toml +++ b/roaring/Cargo.toml @@ -22,9 +22,12 @@ byteorder = { workspace = true, optional = true } serde = { workspace = true, optional = true } [features] -default = ["std"] +default = ["std", "run-length-serialization"] serde = ["dep:serde", "std"] simd = [] +# When enabled, run-length encoding is used for serialization. +# Note that run-length decoding is always supported. +run-length-serialization = [] std = ["dep:bytemuck", "dep:byteorder"] [dev-dependencies] diff --git a/roaring/src/bitmap/serialization.rs b/roaring/src/bitmap/serialization.rs index cce50270..19474366 100644 --- a/roaring/src/bitmap/serialization.rs +++ b/roaring/src/bitmap/serialization.rs @@ -76,7 +76,8 @@ impl RoaringBitmap { /// assert_eq!(rb1, rb2); /// ``` pub fn serialize_into(&self, mut writer: W) -> io::Result<()> { - let has_run_containers = self.containers.iter().any(|c| matches!(c.store, Store::Run(_))); + let has_run_containers = cfg!(feature = "run-length-serialization") + && self.containers.iter().any(|c| matches!(c.store, Store::Run(_))); let size = self.containers.len(); // Depending on if run containers are present or not write the appropriate header @@ -118,9 +119,17 @@ impl RoaringBitmap { offset += 8 * 1024; } Store::Run(ref intervals) => { - offset += (RUN_NUM_BYTES - + (intervals.run_amount() as usize * RUN_ELEMENT_BYTES)) - as u32; + offset += if cfg!(feature = "run-length-serialization") { + (RUN_NUM_BYTES + (intervals.run_amount() as usize * RUN_ELEMENT_BYTES)) + as u32 + } else { + let count = intervals.len(); + if count <= ARRAY_LIMIT { + count as u32 * 2 + } else { + 8 * 1024 + } + }; } } } @@ -139,10 +148,23 @@ impl RoaringBitmap { } } Store::Run(ref intervals) => { - writer.write_u16::(intervals.run_amount() as u16)?; - for iv in intervals.iter_intervals() { - writer.write_u16::(iv.start())?; - writer.write_u16::(iv.end() - iv.start())?; + if cfg!(feature = "run-length-serialization") { + writer.write_u16::(intervals.run_amount() as u16)?; + for iv in intervals.iter_intervals() { + writer.write_u16::(iv.start())?; + writer.write_u16::(iv.end() - iv.start())?; + } + } else { + let count = intervals.len(); + if count <= ARRAY_LIMIT { + for &value in intervals.to_array().iter() { + writer.write_u16::(value)?; + } + } else { + for &value in intervals.to_bitmap().as_array() { + writer.write_u64::(value)?; + } + } } } }