Skip to content
This repository has been archived by the owner on Feb 18, 2024. It is now read-only.

Improved debug repr of buffers and bitmaps. #284

Merged
merged 1 commit into from Aug 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 16 additions & 2 deletions src/bitmap/immutable.rs
Expand Up @@ -4,7 +4,7 @@ use std::sync::Arc;
use crate::{buffer::bytes::Bytes, buffer::MutableBuffer, trusted_len::TrustedLen};

use super::{
utils::{get_bit, get_bit_unchecked, null_count, BitChunk, BitChunks, BitmapIter},
utils::{fmt, get_bit, get_bit_unchecked, null_count, BitChunk, BitChunks, BitmapIter},
MutableBitmap,
};

Expand All @@ -14,7 +14,7 @@ use super::{
/// * memory on this container is sharable across thread boundaries
/// * Cloning [`Bitmap`] is `O(1)`
/// * Slicing [`Bitmap`] is `O(1)`
#[derive(Debug, Clone)]
#[derive(Clone)]
pub struct Bitmap {
bytes: Arc<Bytes<u8>>,
// both are measured in bits. They are used to bound the bitmap to a region of Bytes.
Expand All @@ -24,6 +24,12 @@ pub struct Bitmap {
null_count: usize,
}

impl std::fmt::Debug for Bitmap {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fmt(&self.bytes, self.offset, self.length, f)
}
}

impl Default for Bitmap {
fn default() -> Self {
MutableBitmap::new().into()
Expand Down Expand Up @@ -272,4 +278,12 @@ mod tests {

assert_eq!(6, b.offset());
}

#[test]
fn test_debug() {
let b = Bitmap::from([true, true, false, true, true, true, true, true, true]);
let b = b.slice(2, 7);

assert_eq!(format!("{:?}", b), "[0b111110__, 0b_______1]");
}
}
27 changes: 25 additions & 2 deletions src/bitmap/mutable.rs
Expand Up @@ -2,7 +2,7 @@ use std::iter::FromIterator;

use crate::{buffer::MutableBuffer, trusted_len::TrustedLen};

use super::utils::{get_bit, null_count, set, set_bit, BitmapIter};
use super::utils::{fmt, get_bit, null_count, set, set_bit, BitmapIter};
use super::Bitmap;

/// A container to store booleans. [`MutableBitmap`] is semantically equivalent
Expand All @@ -12,12 +12,17 @@ use super::Bitmap;
/// The main difference against [`Vec<bool>`] is that a bitmap cannot be represented as `&[bool]`.
/// # Implementation
/// This container is backed by [`MutableBuffer<u8>`].
#[derive(Debug)]
pub struct MutableBitmap {
buffer: MutableBuffer<u8>,
length: usize,
}

impl std::fmt::Debug for MutableBitmap {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fmt(&self.buffer, 0, self.len(), f)
}
}

impl PartialEq for MutableBitmap {
fn eq(&self, other: &Self) -> bool {
self.iter().eq(other.iter())
Expand Down Expand Up @@ -603,4 +608,22 @@ mod tests {
assert_eq!(bitmap.len(), 6);
assert_eq!(bitmap.buffer[0], 0b00101101);
}

#[test]
fn test_debug() {
let mut b = MutableBitmap::new();
assert_eq!(format!("{:?}", b), "[]");
b.push(true);
b.push(false);
assert_eq!(format!("{:?}", b), "[0b______01]");
b.push(false);
b.push(false);
b.push(false);
b.push(false);
b.push(true);
b.push(true);
assert_eq!(format!("{:?}", b), "[0b11000001]");
b.push(true);
assert_eq!(format!("{:?}", b), "[0b11000001, 0b_______1]");
}
}
115 changes: 115 additions & 0 deletions src/bitmap/utils/fmt.rs
@@ -0,0 +1,115 @@
use std::fmt::Write;

use super::is_set;

/// Formats `bytes` taking into account an offset and length of the form
pub fn fmt(
bytes: &[u8],
offset: usize,
length: usize,
f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
assert!(offset < 8);

f.write_char('[')?;
let mut remaining = length;
if remaining == 0 {
f.write_char(']')?;
return Ok(());
}

let first = bytes[0];
let bytes = &bytes[1..];
let empty_before = 8usize.saturating_sub(remaining + offset);
f.write_str("0b")?;
for _ in 0..empty_before {
f.write_char('_')?;
}
let until = std::cmp::min(8, offset + remaining);
for i in offset..until {
if is_set(first, offset + until - 1 - i) {
f.write_char('1')?;
} else {
f.write_char('0')?;
}
}
for _ in 0..offset {
f.write_char('_')?;
}
remaining -= until - offset;

if remaining == 0 {
f.write_char(']')?;
return Ok(());
}

let number_of_bytes = remaining / 8;
for byte in &bytes[..number_of_bytes] {
f.write_str(", ")?;
f.write_fmt(format_args!("{:#010b}", byte))?;
}
remaining -= number_of_bytes * 8;
if remaining == 0 {
f.write_char(']')?;
return Ok(());
}

let last = bytes[std::cmp::min((length + offset + 7) / 8, bytes.len() - 1)];
let remaining = (length + offset) % 8;
f.write_str(", ")?;
f.write_str("0b")?;
for _ in 0..(8 - remaining) {
f.write_char('_')?;
}
for i in 0..remaining {
if is_set(last, remaining - 1 - i) {
f.write_char('1')?;
} else {
f.write_char('0')?;
}
}
f.write_char(']')
}

#[cfg(test)]
mod tests {
use super::*;

struct A<'a>(&'a [u8], usize, usize);
impl<'a> std::fmt::Debug for A<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fmt(self.0, self.1, self.2, f)
}
}

#[test]
fn test_debug() -> std::fmt::Result {
assert_eq!(format!("{:?}", A(&[1], 0, 0)), "[]");
assert_eq!(format!("{:?}", A(&[0b11000001], 0, 8)), "[0b11000001]");
assert_eq!(
format!("{:?}", A(&[0b11000001, 1], 0, 9)),
"[0b11000001, 0b_______1]"
);
assert_eq!(format!("{:?}", A(&[1], 0, 2)), "[0b______01]");
assert_eq!(format!("{:?}", A(&[1], 1, 2)), "[0b_____00_]");
assert_eq!(format!("{:?}", A(&[1], 2, 2)), "[0b____00__]");
assert_eq!(format!("{:?}", A(&[1], 3, 2)), "[0b___00___]");
assert_eq!(format!("{:?}", A(&[1], 4, 2)), "[0b__00____]");
assert_eq!(format!("{:?}", A(&[1], 5, 2)), "[0b_00_____]");
assert_eq!(format!("{:?}", A(&[1], 6, 2)), "[0b00______]");
assert_eq!(
format!("{:?}", A(&[0b11000001, 1], 1, 9)),
"[0b1100000_, 0b______01]"
);
// extra bytes are ignored
assert_eq!(
format!("{:?}", A(&[0b11000001, 1, 1, 1], 1, 9)),
"[0b1100000_, 0b______01]"
);
assert_eq!(
format!("{:?}", A(&[0b11000001, 1, 1], 2, 16)),
"[0b110000__, 0b00000001, 0b______01]"
);
Ok(())
}
}
2 changes: 2 additions & 0 deletions src/bitmap/utils/mod.rs
@@ -1,9 +1,11 @@
mod chunk_iterator;
mod fmt;
mod iterator;
mod slice_iterator;
mod zip_validity;

pub use chunk_iterator::{BitChunk, BitChunkIterExact, BitChunks, BitChunksExact};
pub use fmt::fmt;
pub use iterator::BitmapIter;
pub use slice_iterator::SlicesIterator;
pub use zip_validity::{zip_validity, ZipValidity};
Expand Down
20 changes: 16 additions & 4 deletions src/buffer/immutable.rs
@@ -1,6 +1,4 @@
use std::sync::Arc;
use std::{convert::AsRef, usize};
use std::{fmt::Debug, iter::FromIterator};
use std::{convert::AsRef, iter::FromIterator, sync::Arc, usize};

use crate::{trusted_len::TrustedLen, types::NativeType};

Expand All @@ -9,7 +7,7 @@ use super::mutable::MutableBuffer;

/// Buffer represents a contiguous memory region that can be shared with other buffers and across
/// thread boundaries.
#[derive(Clone, PartialEq, Debug)]
#[derive(Clone, PartialEq)]
pub struct Buffer<T: NativeType> {
/// the internal byte buffer.
data: Arc<Bytes<T>>,
Expand All @@ -22,6 +20,12 @@ pub struct Buffer<T: NativeType> {
length: usize,
}

impl<T: NativeType> std::fmt::Debug for Buffer<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Debug::fmt(&**self, f)
}
}

impl<T: NativeType> Default for Buffer<T> {
#[inline]
fn default() -> Self {
Expand Down Expand Up @@ -226,4 +230,12 @@ mod tests {
let ptr = buffer.as_ptr();
assert_eq!(unsafe { *ptr }, 1);
}

#[test]
fn test_debug() {
let buffer = Buffer::<i32>::from(&[0, 1, 2, 3]);
let buffer = buffer.slice(1, 2);
let a = format!("{:?}", buffer);
assert_eq!(a, "[1, 2]")
}
}
16 changes: 14 additions & 2 deletions src/buffer/mutable.rs
@@ -1,7 +1,7 @@
use std::iter::FromIterator;
use std::mem::size_of;
use std::ptr::NonNull;
use std::usize;
use std::{fmt::Debug, mem::size_of};

use crate::types::NativeType;
use crate::{alloc, trusted_len::TrustedLen};
Expand Down Expand Up @@ -32,7 +32,6 @@ fn capacity_multiple_of_64<T: NativeType>(capacity: usize) -> usize {
/// let buffer: Buffer<u32> = buffer.into();
/// assert_eq!(buffer.as_slice(), &[256, 1])
/// ```
#[derive(Debug)]
pub struct MutableBuffer<T: NativeType> {
// dangling iff capacity = 0
ptr: NonNull<T>,
Expand All @@ -41,6 +40,12 @@ pub struct MutableBuffer<T: NativeType> {
capacity: usize,
}

impl<T: NativeType> std::fmt::Debug for MutableBuffer<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Debug::fmt(&**self, f)
}
}

impl<T: NativeType> PartialEq for MutableBuffer<T> {
fn eq(&self, other: &Self) -> bool {
self.as_slice() == other.as_slice()
Expand Down Expand Up @@ -770,4 +775,11 @@ mod tests {
let b: Bytes<i32> = b.into();
assert_eq!(b.as_ref(), &[0, 1, 2]);
}

#[test]
fn test_debug() {
let buffer = MutableBuffer::<i32>::from(&[0, 1, 2, 3]);
let a = format!("{:?}", buffer);
assert_eq!(a, "[0, 1, 2, 3]")
}
}