use crate::{
OwnedEntry,
database::{Entry, iterator::DatabaseIterator},
};
use std::collections::BinaryHeap;
pub struct MergedIterator {
iterators: BinaryHeap<Box<dyn DatabaseIterator>>,
first_entry: Option<OwnedEntry>,
last_entry: Option<OwnedEntry>,
}
impl MergedIterator {
pub fn new() -> Self {
Self {
iterators: BinaryHeap::new(),
first_entry: None,
last_entry: None,
}
}
pub fn add_iterator(&mut self, iterator: Box<dyn DatabaseIterator>) {
if iterator.peek().is_some() {
match (self.first_entry.take(), iterator.first_entry()) {
(Some(existing), Some(new)) => {
if (existing.get_key() > new.get_key())
|| (existing.get_key() == new.get_key()
&& existing.get_seq_no() < new.get_seq_no())
{
self.first_entry = Some(new.into())
} else {
self.first_entry = Some(existing)
}
}
(None, Some(new)) => self.first_entry = Some(new.into()),
_ => {
}
}
match (self.last_entry.take(), iterator.last_entry()) {
(Some(existing), Some(new)) => {
if (existing.get_key() < new.get_key())
|| (existing.get_key() == new.get_key()
&& existing.get_seq_no() < new.get_seq_no())
{
self.last_entry = Some(new.into())
} else {
self.last_entry = Some(existing)
}
}
(None, Some(new)) => self.last_entry = Some(new.into()),
_ => {
}
}
self.iterators.push(iterator);
}
}
}
impl DatabaseIterator for MergedIterator {
fn peek(&self) -> Option<Entry<'_>> {
self.iterators.peek()?.peek()
}
fn next_owned(&mut self) -> Option<OwnedEntry> {
let mut top = self.iterators.pop()?;
let result = top.next_owned();
if top.peek().is_some() {
self.iterators.push(top);
}
while result.is_some()
&& let Some(x) = self.iterators.peek()
{
if let Some(x) = x.peek() {
if x.get_key() == result.as_ref()?.get_key() {
let mut top = self.iterators.pop()?;
top.next_owned();
if top.peek().is_some() {
self.iterators.push(top);
}
} else {
break;
}
}
}
result
}
fn first_entry(&self) -> Option<Entry<'_>> {
self.first_entry.as_ref().map(|e| e.into())
}
fn last_entry(&self) -> Option<Entry<'_>> {
self.last_entry.as_ref().map(|e| e.into())
}
}