Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More buf builders #144

Merged
merged 5 commits into from
Sep 15, 2023
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/layer/internal/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@
pub fn add_node(&mut self, node: &str) -> u64 {
let id = self.builder.add_node(node);

id

Check warning on line 178 in src/layer/internal/base.rs

View workflow job for this annotation

GitHub Actions / clippy

returning the result of a `let` binding from a block

warning: returning the result of a `let` binding from a block --> src/layer/internal/base.rs:178:9 | 176 | let id = self.builder.add_node(node); | ------------------------------------- unnecessary `let` binding 177 | 178 | id | ^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return help: return the expression directly | 176 ~ 177 | 178 ~ self.builder.add_node(node) |
}

pub fn add_node_bytes(&mut self, node: Bytes) -> u64 {
Expand All @@ -188,7 +188,7 @@
pub fn add_predicate(&mut self, predicate: &str) -> u64 {
let id = self.builder.add_predicate(predicate);

id

Check warning on line 191 in src/layer/internal/base.rs

View workflow job for this annotation

GitHub Actions / clippy

returning the result of a `let` binding from a block

warning: returning the result of a `let` binding from a block --> src/layer/internal/base.rs:191:9 | 189 | let id = self.builder.add_predicate(predicate); | ----------------------------------------------- unnecessary `let` binding 190 | 191 | id | ^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return help: return the expression directly | 189 ~ 190 | 191 ~ self.builder.add_predicate(predicate) |
}

pub fn add_predicate_bytes(&mut self, predicate: Bytes) -> u64 {
Expand All @@ -201,7 +201,7 @@
pub fn add_value(&mut self, value: TypedDictEntry) -> u64 {
let id = self.builder.add_value(value);

id

Check warning on line 204 in src/layer/internal/base.rs

View workflow job for this annotation

GitHub Actions / clippy

returning the result of a `let` binding from a block

warning: returning the result of a `let` binding from a block --> src/layer/internal/base.rs:204:9 | 202 | let id = self.builder.add_value(value); | --------------------------------------- unnecessary `let` binding 203 | 204 | id | ^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return help: return the expression directly | 202 ~ 203 | 204 ~ self.builder.add_value(value) |
}

/// Add nodes from an iterable.
Expand All @@ -217,7 +217,7 @@
{
let ids = self.builder.add_nodes(nodes);

ids

Check warning on line 220 in src/layer/internal/base.rs

View workflow job for this annotation

GitHub Actions / clippy

returning the result of a `let` binding from a block

warning: returning the result of a `let` binding from a block --> src/layer/internal/base.rs:220:9 | 218 | let ids = self.builder.add_nodes(nodes); | ---------------------------------------- unnecessary `let` binding 219 | 220 | ids | ^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return help: return the expression directly | 218 ~ 219 | 220 ~ self.builder.add_nodes(nodes) |
}

pub fn add_nodes_bytes<I: 'static + IntoIterator<Item = Bytes> + Send>(
Expand All @@ -230,7 +230,7 @@
{
let ids = self.builder.add_nodes_bytes(nodes);

ids

Check warning on line 233 in src/layer/internal/base.rs

View workflow job for this annotation

GitHub Actions / clippy

returning the result of a `let` binding from a block

warning: returning the result of a `let` binding from a block --> src/layer/internal/base.rs:233:9 | 231 | let ids = self.builder.add_nodes_bytes(nodes); | ---------------------------------------------- unnecessary `let` binding 232 | 233 | ids | ^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return help: return the expression directly | 231 ~ 232 | 233 ~ self.builder.add_nodes_bytes(nodes) |
}

/// Add predicates from an iterable.
Expand All @@ -246,7 +246,7 @@
{
let ids = self.builder.add_predicates(predicates);

ids

Check warning on line 249 in src/layer/internal/base.rs

View workflow job for this annotation

GitHub Actions / clippy

returning the result of a `let` binding from a block

warning: returning the result of a `let` binding from a block --> src/layer/internal/base.rs:249:9 | 247 | let ids = self.builder.add_predicates(predicates); | -------------------------------------------------- unnecessary `let` binding 248 | 249 | ids | ^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return help: return the expression directly | 247 ~ 248 | 249 ~ self.builder.add_predicates(predicates) |
}

pub fn add_predicates_bytes<I: 'static + IntoIterator<Item = Bytes> + Send>(
Expand All @@ -259,7 +259,7 @@
{
let ids = self.builder.add_predicates_bytes(predicates);

ids

Check warning on line 262 in src/layer/internal/base.rs

View workflow job for this annotation

GitHub Actions / clippy

returning the result of a `let` binding from a block

warning: returning the result of a `let` binding from a block --> src/layer/internal/base.rs:262:9 | 260 | let ids = self.builder.add_predicates_bytes(predicates); | -------------------------------------------------------- unnecessary `let` binding 261 | 262 | ids | ^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return help: return the expression directly | 260 ~ 261 | 262 ~ self.builder.add_predicates_bytes(predicates) |
}

/// Add values from an iterable.
Expand All @@ -275,7 +275,7 @@
{
let ids = self.builder.add_values(values);

ids

Check warning on line 278 in src/layer/internal/base.rs

View workflow job for this annotation

GitHub Actions / clippy

returning the result of a `let` binding from a block

warning: returning the result of a `let` binding from a block --> src/layer/internal/base.rs:278:9 | 276 | let ids = self.builder.add_values(values); | ------------------------------------------ unnecessary `let` binding 277 | 278 | ids | ^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return help: return the expression directly | 276 ~ 277 | 278 ~ self.builder.add_values(values) |
}

/// Turn this builder into a phase 2 builder that will take triple data.
Expand Down Expand Up @@ -490,7 +490,7 @@
}

#[cfg(test)]
pub mod tests {
pub mod base_tests {
use super::*;
use crate::storage::memory::*;
use futures::stream::TryStreamExt;
Expand Down
4 changes: 2 additions & 2 deletions src/layer/internal/child.rs
Original file line number Diff line number Diff line change
Expand Up @@ -702,9 +702,9 @@ pub async fn open_child_triple_stream<F: 'static + FileLoad + FileStore>(
}

#[cfg(test)]
pub mod tests {
pub mod child_tests {
use super::*;
use crate::layer::base::tests::*;
use crate::layer::base::base_tests::*;
use crate::storage::memory::*;
use futures::stream::TryStreamExt;

Expand Down
2 changes: 1 addition & 1 deletion src/layer/internal/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -525,10 +525,10 @@
}

pub fn is_rollup(&self) -> bool {
match self {
Rollup(_) => true,
_ => false,
}

Check warning on line 531 in src/layer/internal/mod.rs

View workflow job for this annotation

GitHub Actions / clippy

match expression looks like `matches!` macro

warning: match expression looks like `matches!` macro --> src/layer/internal/mod.rs:528:9 | 528 | / match self { 529 | | Rollup(_) => true, 530 | | _ => false, 531 | | } | |_________^ help: try this: `matches!(self, Rollup(_))` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#match_like_matches_macro = note: `#[warn(clippy::match_like_matches_macro)]` on by default
}
}

Expand Down Expand Up @@ -636,7 +636,7 @@
parent_count = parent_count
- current_layer.node_dict_len() as u64
- current_layer.value_dict_len() as u64;
if corrected_id > parent_count as u64 {

Check warning on line 639 in src/layer/internal/mod.rs

View workflow job for this annotation

GitHub Actions / clippy

casting to the same type is unnecessary (`u64` -> `u64`)

warning: casting to the same type is unnecessary (`u64` -> `u64`) --> src/layer/internal/mod.rs:639:35 | 639 | if corrected_id > parent_count as u64 { | ^^^^^^^^^^^^^^^^^^^ help: try: `parent_count` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_cast = note: `#[warn(clippy::unnecessary_cast)]` on by default
// subject, if it exists, is in this layer
corrected_id -= parent_count;
} else {
Expand Down Expand Up @@ -667,7 +667,7 @@
let mut corrected_id = id;
if let Some(parent) = current_layer.immediate_parent() {
parent_count -= current_layer.predicate_dict_len() as u64;
if corrected_id > parent_count as u64 {

Check warning on line 670 in src/layer/internal/mod.rs

View workflow job for this annotation

GitHub Actions / clippy

casting to the same type is unnecessary (`u64` -> `u64`)

warning: casting to the same type is unnecessary (`u64` -> `u64`) --> src/layer/internal/mod.rs:670:35 | 670 | if corrected_id > parent_count as u64 { | ^^^^^^^^^^^^^^^^^^^ help: try: `parent_count` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_cast
// subject, if it exists, is in this layer
corrected_id -= parent_count;
} else {
Expand Down Expand Up @@ -1098,7 +1098,7 @@
assert_eq!(1, layer.triple_layer_removal_count().unwrap());
}

use crate::layer::base::tests::*;
use crate::layer::base::base_tests::*;
#[tokio::test]
async fn base_layer_with_gaps_addition_count() {
let files = base_layer_files();
Expand Down
2 changes: 1 addition & 1 deletion src/layer/internal/object_iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@
s_p_adjacency_list: AdjacencyList,
) -> Self {
Self {
subjects: subjects,

Check warning on line 25 in src/layer/internal/object_iterator.rs

View workflow job for this annotation

GitHub Actions / clippy

redundant field names in struct initialization

warning: redundant field names in struct initialization --> src/layer/internal/object_iterator.rs:25:13 | 25 | subjects: subjects, | ^^^^^^^^^^^^^^^^^^ help: replace it with: `subjects` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names = note: `#[warn(clippy::redundant_field_names)]` on by default
objects: objects,

Check warning on line 26 in src/layer/internal/object_iterator.rs

View workflow job for this annotation

GitHub Actions / clippy

redundant field names in struct initialization

warning: redundant field names in struct initialization --> src/layer/internal/object_iterator.rs:26:13 | 26 | objects: objects, | ^^^^^^^^^^^^^^^^ help: replace it with: `objects` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names
o_ps_adjacency_list: o_ps_adjacency_list,

Check warning on line 27 in src/layer/internal/object_iterator.rs

View workflow job for this annotation

GitHub Actions / clippy

redundant field names in struct initialization

warning: redundant field names in struct initialization --> src/layer/internal/object_iterator.rs:27:13 | 27 | o_ps_adjacency_list: o_ps_adjacency_list, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `o_ps_adjacency_list` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names
s_p_adjacency_list: s_p_adjacency_list,

Check warning on line 28 in src/layer/internal/object_iterator.rs

View workflow job for this annotation

GitHub Actions / clippy

redundant field names in struct initialization

warning: redundant field names in struct initialization --> src/layer/internal/object_iterator.rs:28:13 | 28 | s_p_adjacency_list: s_p_adjacency_list, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `s_p_adjacency_list` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names
o_position: 0,
o_ps_position: 0,
peeked: None,
Expand Down Expand Up @@ -227,7 +227,7 @@
#[cfg(test)]
mod tests {
use super::*;
use crate::layer::base::tests::*;
use crate::layer::base::base_tests::*;
use crate::storage::memory::*;
use crate::storage::*;

Expand Down
4 changes: 2 additions & 2 deletions src/layer/internal/predicate_iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,13 @@
// set the sp_boundary flag, ensuring that upon the subsequent
// next() call, we move on to the next predicate.
let next = self.subject_iterator.peek();
if next.is_none()
|| next.map(|t| (t.subject, t.predicate)) != result.map(|t| (t.subject, t.predicate))
{
self.sp_boundary = true;
} else {
self.sp_boundary = false;
}

Check warning on line 92 in src/layer/internal/predicate_iterator.rs

View workflow job for this annotation

GitHub Actions / clippy

this if-then-else expression assigns a bool literal

warning: this if-then-else expression assigns a bool literal --> src/layer/internal/predicate_iterator.rs:86:9 | 86 | / if next.is_none() 87 | | || next.map(|t| (t.subject, t.predicate)) != result.map(|t| (t.subject, t.predicate)) 88 | | { 89 | | self.sp_boundary = true; 90 | | } else { 91 | | self.sp_boundary = false; 92 | | } | |_________^ help: you can reduce it to: `self.sp_boundary = next.is_none() || next.map(|t| (t.subject, t.predicate)) != result.map(|t| (t.subject, t.predicate));` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_bool_assign = note: `#[warn(clippy::needless_bool_assign)]` on by default

result
}
Expand Down Expand Up @@ -182,8 +182,8 @@

#[cfg(test)]
mod tests {
use crate::layer::base::tests::*;
use crate::layer::child::tests::*;
use crate::layer::base::base_tests::*;
use crate::layer::child::child_tests::*;
use crate::layer::*;

use std::sync::Arc;
Expand Down
4 changes: 2 additions & 2 deletions src/layer/internal/subject_iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@
sp_o_adjacency_list: AdjacencyList,
) -> Self {
Self {
subjects: subjects,

Check warning on line 25 in src/layer/internal/subject_iterator.rs

View workflow job for this annotation

GitHub Actions / clippy

redundant field names in struct initialization

warning: redundant field names in struct initialization --> src/layer/internal/subject_iterator.rs:25:13 | 25 | subjects: subjects, | ^^^^^^^^^^^^^^^^^^ help: replace it with: `subjects` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names
s_p_adjacency_list: s_p_adjacency_list,

Check warning on line 26 in src/layer/internal/subject_iterator.rs

View workflow job for this annotation

GitHub Actions / clippy

redundant field names in struct initialization

warning: redundant field names in struct initialization --> src/layer/internal/subject_iterator.rs:26:13 | 26 | s_p_adjacency_list: s_p_adjacency_list, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `s_p_adjacency_list` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names
sp_o_adjacency_list: sp_o_adjacency_list,

Check warning on line 27 in src/layer/internal/subject_iterator.rs

View workflow job for this annotation

GitHub Actions / clippy

redundant field names in struct initialization

warning: redundant field names in struct initialization --> src/layer/internal/subject_iterator.rs:27:13 | 27 | sp_o_adjacency_list: sp_o_adjacency_list, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `sp_o_adjacency_list` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names
s_position: 0,
s_p_position: 0,
sp_o_position: 0,
Expand Down Expand Up @@ -422,7 +422,7 @@
(Some(lowest_pos_index), Some(lowest_neg_index)) => {
let lowest_pos = self.positives[lowest_pos_index].peek().unwrap();
let lowest_neg = self.negatives[lowest_neg_index].peek().unwrap();
match lowest_pos.cmp(&lowest_neg) {

Check warning on line 425 in src/layer/internal/subject_iterator.rs

View workflow job for this annotation

GitHub Actions / clippy

this expression creates a reference which is immediately dereferenced by the compiler

warning: this expression creates a reference which is immediately dereferenced by the compiler --> src/layer/internal/subject_iterator.rs:425:42 | 425 | match lowest_pos.cmp(&lowest_neg) { | ^^^^^^^^^^^ help: change this to: `lowest_neg` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow = note: `#[warn(clippy::needless_borrow)]` on by default
Ordering::Less => {
// next change is an addition, and there's no matching removal
return Some((
Expand Down Expand Up @@ -452,8 +452,8 @@

#[cfg(test)]
mod tests {
use crate::layer::base::tests::*;
use crate::layer::child::tests::*;
use crate::layer::base::base_tests::*;
use crate::layer::child::child_tests::*;
use crate::layer::*;
use crate::structure::TdbDataType;

Expand Down
4 changes: 2 additions & 2 deletions src/layer/layer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@
self.subject_id(&triple.subject).and_then(|subject| {
self.predicate_id(&triple.predicate).and_then(|predicate| {
match &triple.object {
ObjectType::Node(node) => self.object_node_id(&node),

Check warning on line 101 in src/layer/layer.rs

View workflow job for this annotation

GitHub Actions / clippy

this expression creates a reference which is immediately dereferenced by the compiler

warning: this expression creates a reference which is immediately dereferenced by the compiler --> src/layer/layer.rs:101:67 | 101 | ObjectType::Node(node) => self.object_node_id(&node), | ^^^^^ help: change this to: `node` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow
ObjectType::Value(value) => self.object_value_id(&value),

Check warning on line 102 in src/layer/layer.rs

View workflow job for this annotation

GitHub Actions / clippy

this expression creates a reference which is immediately dereferenced by the compiler

warning: this expression creates a reference which is immediately dereferenced by the compiler --> src/layer/layer.rs:102:70 | 102 | ObjectType::Value(value) => self.object_value_id(&value), | ^^^^^^ help: change this to: `value` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow
}
.map(|object| IdTriple {
subject,
Expand Down Expand Up @@ -127,11 +127,11 @@
.unwrap_or(PossiblyResolved::Unresolved(triple.predicate)),
object: match &triple.object {
ObjectType::Node(node) => self
.object_node_id(&node)

Check warning on line 130 in src/layer/layer.rs

View workflow job for this annotation

GitHub Actions / clippy

this expression creates a reference which is immediately dereferenced by the compiler

warning: this expression creates a reference which is immediately dereferenced by the compiler --> src/layer/layer.rs:130:37 | 130 | .object_node_id(&node) | ^^^^^ help: change this to: `node` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow
.map(PossiblyResolved::Resolved)
.unwrap_or(PossiblyResolved::Unresolved(triple.object)),
ObjectType::Value(value) => self
.object_value_id(&value)

Check warning on line 134 in src/layer/layer.rs

View workflow job for this annotation

GitHub Actions / clippy

this expression creates a reference which is immediately dereferenced by the compiler

warning: this expression creates a reference which is immediately dereferenced by the compiler --> src/layer/layer.rs:134:38 | 134 | .object_value_id(&value) | ^^^^^^ help: change this to: `value` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow
.map(PossiblyResolved::Resolved)
.unwrap_or(PossiblyResolved::Unresolved(triple.object)),
},
Expand Down Expand Up @@ -270,7 +270,7 @@
/// Return a PossiblyResolved with the inner value as a reference.
pub fn as_ref(&self) -> PossiblyResolved<&T> {
match self {
Self::Unresolved(u) => PossiblyResolved::Unresolved(&u),

Check warning on line 273 in src/layer/layer.rs

View workflow job for this annotation

GitHub Actions / clippy

this expression creates a reference which is immediately dereferenced by the compiler

warning: this expression creates a reference which is immediately dereferenced by the compiler --> src/layer/layer.rs:273:65 | 273 | Self::Unresolved(u) => PossiblyResolved::Unresolved(&u), | ^^ help: change this to: `u` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow
Self::Resolved(id) => PossiblyResolved::Resolved(*id),
}
}
Expand Down Expand Up @@ -306,7 +306,7 @@
&self,
node_map: &HashMap<String, u64>,
predicate_map: &HashMap<String, u64>,
value_map: &HashMap<TypedDictEntry, u64>,

Check warning on line 309 in src/layer/layer.rs

View workflow job for this annotation

GitHub Actions / clippy

mutable key type

warning: mutable key type --> src/layer/layer.rs:309:20 | 309 | value_map: &HashMap<TypedDictEntry, u64>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#mutable_key_type = note: `#[warn(clippy::mutable_key_type)]` on by default
) -> Option<IdTriple> {
let subject = match self.subject.as_ref() {
PossiblyResolved::Unresolved(s) => *node_map.get(s)?,
Expand Down Expand Up @@ -405,9 +405,9 @@
#[cfg(test)]
mod tests {
use super::*;
use crate::layer::internal::base::tests::base_layer_files;
use crate::layer::internal::base::base_tests::base_layer_files;
use crate::layer::internal::base::BaseLayer;
use crate::layer::internal::child::tests::child_layer_files;
use crate::layer::internal::child::child_tests::child_layer_files;
use crate::layer::internal::child::ChildLayer;
use crate::layer::internal::InternalLayer;
use crate::layer::simple_builder::{LayerBuilder, SimpleLayerBuilder};
Expand Down
151 changes: 151 additions & 0 deletions src/structure/adjacencylist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use std::io;
use std::pin::Pin;

use bytes::Bytes;
use bytes::BytesMut;

use super::bitarray::*;
use super::bitindex::*;
Expand All @@ -36,6 +37,15 @@ impl AdjacencyList {
AdjacencyList { nums, bits }
}

pub fn from_buffers(buffers: AdjacencyListBuffers) -> AdjacencyList {
Self::parse(
buffers.nums,
buffers.bits,
buffers.bitindex_blocks,
buffers.bitindex_sblocks,
)
}

pub fn parse(
nums_slice: Bytes,
bits_slice: Bytes,
Expand Down Expand Up @@ -224,6 +234,82 @@ pub async fn adjacency_list_stream_pairs<F: 'static + FileLoad>(
)
}

pub struct UnindexedAdjacencyListBufBuilder {
bitarray: BitArrayBufBuilder<BytesMut>,
nums: LogArrayBufBuilder<BytesMut>,
last_left: u64,
last_right: u64,
}

impl UnindexedAdjacencyListBufBuilder {
pub fn new(width: u8) -> Self {
Self {
bitarray: BitArrayBufBuilder::new(BytesMut::new()),
nums: LogArrayBufBuilder::new(BytesMut::new(), width),
last_left: 0,
last_right: 0,
}
}

pub fn push(&mut self, left: u64, right: u64) {
// the tricky thing with this code is that the bitarray lags one entry behind the logarray.
// The reason for this is that at push time, we do not yet know if this entry is going to be
// the last entry for `left`, we only know this when we push a greater `left` later on.
if left < self.last_left || (left == self.last_left && right <= self.last_right) {
panic!("tried to push an unordered adjacent pair");
}

// the left hand side of the adjacencylist is expected to be a continuous range from 1 up to the max
// but when adding entries, there may be holes. We handle holes by writing a '0' to the logarray
// (which is otherwise an invalid right-hand side) and pushing a 1 onto the bitarray to immediately close the segment.
let skip = left - self.last_left;

if self.last_left == 0 && skip == 1 {
// this is the first entry. we can't push a bit yet
} else if skip == 0 {
// same `left` as before. so the previous entry was not the last one, and the bitarray gets a 0 appended.
self.bitarray.push(false);
} else {
// if this is the first element, but we do need to skip, make sure we write one less bit than we'd usually do
let bitskip = if self.last_left == 0 { skip - 1 } else { skip };
// there's a different `left`. we push a bunch of 1s to the bitarray, and 0s to the num array.
for _ in 0..bitskip {
self.bitarray.push(true);
}
for _ in 0..(skip - 1) {
self.nums.push(0);
}
}

// finally push right to the logarray
self.nums.push(right);
self.last_left = left;
self.last_right = right;
}

pub fn push_all<I: Iterator<Item = (u64, u64)>>(&mut self, mut iter: I) {
while let Some((left, right)) = iter.next() {
self.push(left, right);
}
}

pub fn finalize(mut self) -> (Bytes, Bytes) {
if self.nums.count() != 0 {
// push last bit to bitarray
self.bitarray.push(true);
}

let ba = self.bitarray.finalize();
let nums = self.nums.finalize();

(ba.freeze(), nums.freeze())
}

pub fn count(&self) -> u64 {
self.bitarray.count()
}
}

pub struct UnindexedAdjacencyListBuilder<W1: SyncableFile, W2: SyncableFile> {
bitarray: BitArrayFileBuilder<W1>,
nums: LogArrayFileBuilder<W2>,
Expand Down Expand Up @@ -307,6 +393,59 @@ impl<W1: SyncableFile, W2: SyncableFile> UnindexedAdjacencyListBuilder<W1, W2> {
}
}

pub struct AdjacencyListBufBuilder {
builder: UnindexedAdjacencyListBufBuilder,
bitindex_blocks: BytesMut,
bitindex_sblocks: BytesMut,
}

impl AdjacencyListBufBuilder {
pub fn new(width: u8) -> AdjacencyListBufBuilder {
AdjacencyListBufBuilder {
builder: UnindexedAdjacencyListBufBuilder::new(width),
bitindex_blocks: BytesMut::new(),
bitindex_sblocks: BytesMut::new(),
}
}

pub fn push(&mut self, left: u64, right: u64) {
self.builder.push(left, right)
}

pub fn push_all<I: Iterator<Item = (u64, u64)>>(&mut self, iter: I) {
self.builder.push_all(iter)
}

pub fn finalize(self) -> AdjacencyListBuffers {
let AdjacencyListBufBuilder {
builder,
mut bitindex_blocks,
mut bitindex_sblocks,
} = self;
let (bitfile, nums) = builder.finalize();

build_bitindex_from_buf(&bitfile[..], &mut bitindex_blocks, &mut bitindex_sblocks);

AdjacencyListBuffers {
nums,
bits: bitfile,
bitindex_blocks: bitindex_blocks.freeze(),
bitindex_sblocks: bitindex_sblocks.freeze(),
}
}

pub fn count(&self) -> u64 {
self.builder.count()
}
}

pub struct AdjacencyListBuffers {
nums: Bytes,
bits: Bytes,
bitindex_blocks: Bytes,
bitindex_sblocks: Bytes,
}

pub struct AdjacencyListBuilder<F, W1, W2, W3>
where
F: 'static + FileLoad + FileStore,
Expand Down Expand Up @@ -778,4 +917,16 @@ mod tests {
result
);
}

#[test]
fn adjacencylist_buf_builder_works() {
let adjacencies = [(1, 1), (1, 5), (2, 3), (2, 7), (4, 8)];
let mut builder = AdjacencyListBufBuilder::new(8);
builder.push_all(adjacencies.iter().copied());
let buffers = builder.finalize();
let aj = AdjacencyList::from_buffers(buffers);

let result: Vec<_> = aj.iter().collect();
assert_eq!(&adjacencies[..], &result[..]);
}
}
76 changes: 70 additions & 6 deletions src/structure/bitarray.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ use super::util;
use crate::storage::*;
use crate::structure::bititer::BitIter;
use byteorder::{BigEndian, ByteOrder};
use bytes::{Buf, Bytes, BytesMut};
use bytes::{Buf, BufMut, Bytes, BytesMut};
use futures::io;
use futures::stream::{Stream, StreamExt, TryStreamExt};
use std::{convert::TryFrom, error, fmt};
Expand Down Expand Up @@ -200,6 +200,70 @@ impl BitArray {
}
}

pub struct BitArrayBufBuilder<B> {
/// Destination of the bit array data.
dest: B,
/// Storage for the next word to be written.
current: u64,
/// Number of bits written to the buffer
count: u64,
}

impl<B: BufMut> BitArrayBufBuilder<B> {
pub fn new(dest: B) -> BitArrayBufBuilder<B> {
BitArrayBufBuilder {
dest,
current: 0,
count: 0,
}
}

pub fn push(&mut self, bit: bool) {
// Set the bit in the current word.
if bit {
// Determine the position of the bit to be set from `count`.
let pos = self.count & 0b11_1111;
self.current |= 0x8000_0000_0000_0000 >> pos;
}

// Advance the bit count.
self.count += 1;

// Check if the new `count` has reached a word boundary.
if self.count & 0b11_1111 == 0 {
// We have filled `current`, so write it to the destination.
self.dest.put_u64(self.current);
self.current = 0;
}
}

pub fn push_all<I: Iterator<Item = bool>>(&mut self, mut iter: I) {
while let Some(bit) = iter.next() {
self.push(bit);
}
}

fn finalize_data(&mut self) {
if self.count & 0b11_1111 != 0 {
self.dest.put_u64(self.current);
}
}

pub fn finalize(mut self) -> B {
let count = self.count;
// Write the final data word.
self.finalize_data();
// Write the control word.
self.dest.put_u64(count);

self.dest
}

pub fn count(&self) -> u64 {
self.count
}
}

pub struct BitArrayFileBuilder<W> {
/// Destination of the bit array data.
dest: W,
Expand Down Expand Up @@ -317,22 +381,22 @@ pub fn bitarray_stream_blocks<R: AsyncRead + Unpin>(r: R) -> FramedRead<R, BitAr
FramedRead::new(r, BitArrayBlockDecoder { readahead: None })
}

pub fn bitarray_iter_blocks<B: Buf>(b: &mut B) -> BitArrayBlockIterator<B> {
pub fn bitarray_iter_blocks<B: Buf>(b: B) -> BitArrayBlockIterator<B> {
BitArrayBlockIterator {
buf: b,
readahead: None,
}
}

pub struct BitArrayBlockIterator<'a, B: Buf> {
buf: &'a mut B,
pub struct BitArrayBlockIterator<B: Buf> {
buf: B,
readahead: Option<u64>,
}

impl<'a, B: Buf> Iterator for BitArrayBlockIterator<'a, B> {
impl<B: Buf> Iterator for BitArrayBlockIterator<B> {
type Item = u64;
fn next(&mut self) -> Option<u64> {
decode_next_bitarray_block(self.buf, &mut self.readahead)
decode_next_bitarray_block(&mut self.buf, &mut self.readahead)
}
}

Expand Down
14 changes: 7 additions & 7 deletions src/structure/bitindex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -437,10 +437,10 @@ pub async fn build_bitindex<
Ok(())
}

pub fn build_bitindex_from_block_iter<'a, I: Iterator<Item = u64>, B1: BufMut, B2: BufMut>(
blocks_iter: &'a mut I,
blocks: &mut B1,
sblocks: &mut B2,
pub fn build_bitindex_from_block_iter<I: Iterator<Item = u64>, B1: BufMut, B2: BufMut>(
blocks_iter: I,
blocks: B1,
sblocks: B2,
) {
// the following widths are unoptimized, but should always be large enough
let mut blocks_builder =
Expand Down Expand Up @@ -474,9 +474,9 @@ pub fn build_bitindex_from_block_iter<'a, I: Iterator<Item = u64>, B1: BufMut, B
}

pub fn build_bitindex_from_buf<B1: Buf, B2: BufMut, B3: BufMut>(
bitarray: &mut B1,
blocks: &mut B2,
sblocks: &mut B3,
bitarray: B1,
blocks: B2,
sblocks: B3,
) {
let mut iter = bitarray_iter_blocks(bitarray);
build_bitindex_from_block_iter(&mut iter, blocks, sblocks)
Expand Down
Loading
Loading