move HybridSet to own file
Signed-off-by: kernelkind <kernelkind@gmail.com>
This commit is contained in:
@@ -3,10 +3,8 @@ use crate::{
|
|||||||
nav::{RouterAction, RouterType},
|
nav::{RouterAction, RouterType},
|
||||||
route::Route,
|
route::Route,
|
||||||
timeline::{
|
timeline::{
|
||||||
thread::{
|
thread::{selected_has_at_least_n_replies, NoteSeenFlags, ThreadNode, Threads},
|
||||||
selected_has_at_least_n_replies, InsertionResponse, NoteSeenFlags, ThreadNode, Threads,
|
InsertionResponse, ThreadSelection, TimelineCache, TimelineKind,
|
||||||
},
|
|
||||||
ThreadSelection, TimelineCache, TimelineKind,
|
|
||||||
},
|
},
|
||||||
view_state::ViewState,
|
view_state::ViewState,
|
||||||
};
|
};
|
||||||
|
|||||||
99
crates/notedeck_columns/src/timeline/hybrid_set.rs
Normal file
99
crates/notedeck_columns/src/timeline/hybrid_set.rs
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
use std::{
|
||||||
|
collections::{BTreeSet, HashSet},
|
||||||
|
hash::Hash,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::timeline::MergeKind;
|
||||||
|
|
||||||
|
/// Affords:
|
||||||
|
/// - O(1) contains
|
||||||
|
/// - O(log n) sorted insertion
|
||||||
|
pub struct HybridSet<T> {
|
||||||
|
reversed: bool,
|
||||||
|
lookup: HashSet<T>, // fast deduplication
|
||||||
|
ordered: BTreeSet<T>, // sorted iteration
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Default for HybridSet<T> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
reversed: Default::default(),
|
||||||
|
lookup: Default::default(),
|
||||||
|
ordered: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum InsertionResponse {
|
||||||
|
AlreadyExists,
|
||||||
|
Merged(MergeKind),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Copy + Ord + Eq + Hash> HybridSet<T> {
|
||||||
|
pub fn insert(&mut self, val: T) -> InsertionResponse {
|
||||||
|
if !self.lookup.insert(val) {
|
||||||
|
return InsertionResponse::AlreadyExists;
|
||||||
|
}
|
||||||
|
|
||||||
|
let front_insertion = match self.ordered.iter().next() {
|
||||||
|
Some(first) => (val >= *first) == self.reversed,
|
||||||
|
None => true,
|
||||||
|
};
|
||||||
|
|
||||||
|
self.ordered.insert(val); // O(log n)
|
||||||
|
|
||||||
|
InsertionResponse::Merged(if front_insertion {
|
||||||
|
MergeKind::FrontInsert
|
||||||
|
} else {
|
||||||
|
MergeKind::Spliced
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Eq + Hash> HybridSet<T> {
|
||||||
|
pub fn contains(&self, val: &T) -> bool {
|
||||||
|
self.lookup.contains(val) // O(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> HybridSet<T> {
|
||||||
|
pub fn iter(&self) -> HybridIter<'_, T> {
|
||||||
|
HybridIter {
|
||||||
|
inner: self.ordered.iter(),
|
||||||
|
reversed: self.reversed,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(reversed: bool) -> Self {
|
||||||
|
Self {
|
||||||
|
reversed,
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> IntoIterator for &'a HybridSet<T> {
|
||||||
|
type Item = &'a T;
|
||||||
|
type IntoIter = HybridIter<'a, T>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
self.iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct HybridIter<'a, T> {
|
||||||
|
inner: std::collections::btree_set::Iter<'a, T>,
|
||||||
|
reversed: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> Iterator for HybridIter<'a, T> {
|
||||||
|
type Item = &'a T;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
if self.reversed {
|
||||||
|
self.inner.next_back()
|
||||||
|
} else {
|
||||||
|
self.inner.next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,11 +26,13 @@ use std::{rc::Rc, time::SystemTime};
|
|||||||
use tracing::{debug, error, info, warn};
|
use tracing::{debug, error, info, warn};
|
||||||
|
|
||||||
pub mod cache;
|
pub mod cache;
|
||||||
|
mod hybrid_set;
|
||||||
pub mod kind;
|
pub mod kind;
|
||||||
pub mod route;
|
pub mod route;
|
||||||
pub mod thread;
|
pub mod thread;
|
||||||
|
|
||||||
pub use cache::TimelineCache;
|
pub use cache::TimelineCache;
|
||||||
|
pub use hybrid_set::{HybridSet, InsertionResponse};
|
||||||
pub use kind::{ColumnTitle, PubkeySource, ThreadSelection, TimelineKind};
|
pub use kind::{ColumnTitle, PubkeySource, ThreadSelection, TimelineKind};
|
||||||
|
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Debug, Default)]
|
#[derive(Copy, Clone, Eq, PartialEq, Debug, Default)]
|
||||||
|
|||||||
@@ -1,8 +1,3 @@
|
|||||||
use std::{
|
|
||||||
collections::{BTreeSet, HashSet},
|
|
||||||
hash::Hash,
|
|
||||||
};
|
|
||||||
|
|
||||||
use egui_nav::ReturnType;
|
use egui_nav::ReturnType;
|
||||||
use egui_virtual_list::VirtualList;
|
use egui_virtual_list::VirtualList;
|
||||||
use enostr::{NoteId, RelayPool};
|
use enostr::{NoteId, RelayPool};
|
||||||
@@ -13,7 +8,7 @@ use notedeck::{NoteCache, NoteRef, UnknownIds};
|
|||||||
use crate::{
|
use crate::{
|
||||||
actionbar::{process_thread_notes, NewThreadNotes},
|
actionbar::{process_thread_notes, NewThreadNotes},
|
||||||
multi_subscriber::ThreadSubs,
|
multi_subscriber::ThreadSubs,
|
||||||
timeline::MergeKind,
|
timeline::hybrid_set::HybridSet,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::ThreadSelection;
|
use super::ThreadSelection;
|
||||||
@@ -33,99 +28,6 @@ pub enum ParentState {
|
|||||||
Parent(NoteId),
|
Parent(NoteId),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Affords:
|
|
||||||
/// - O(1) contains
|
|
||||||
/// - O(log n) sorted insertion
|
|
||||||
pub struct HybridSet<T> {
|
|
||||||
reversed: bool,
|
|
||||||
lookup: HashSet<T>, // fast deduplication
|
|
||||||
ordered: BTreeSet<T>, // sorted iteration
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Default for HybridSet<T> {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
reversed: Default::default(),
|
|
||||||
lookup: Default::default(),
|
|
||||||
ordered: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum InsertionResponse {
|
|
||||||
AlreadyExists,
|
|
||||||
Merged(MergeKind),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Copy + Ord + Eq + Hash> HybridSet<T> {
|
|
||||||
pub fn insert(&mut self, val: T) -> InsertionResponse {
|
|
||||||
if !self.lookup.insert(val) {
|
|
||||||
return InsertionResponse::AlreadyExists;
|
|
||||||
}
|
|
||||||
|
|
||||||
let front_insertion = match self.ordered.iter().next() {
|
|
||||||
Some(first) => (val >= *first) == self.reversed,
|
|
||||||
None => true,
|
|
||||||
};
|
|
||||||
|
|
||||||
self.ordered.insert(val); // O(log n)
|
|
||||||
|
|
||||||
InsertionResponse::Merged(if front_insertion {
|
|
||||||
MergeKind::FrontInsert
|
|
||||||
} else {
|
|
||||||
MergeKind::Spliced
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Eq + Hash> HybridSet<T> {
|
|
||||||
pub fn contains(&self, val: &T) -> bool {
|
|
||||||
self.lookup.contains(val) // O(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> HybridSet<T> {
|
|
||||||
pub fn iter(&self) -> HybridIter<'_, T> {
|
|
||||||
HybridIter {
|
|
||||||
inner: self.ordered.iter(),
|
|
||||||
reversed: self.reversed,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new(reversed: bool) -> Self {
|
|
||||||
Self {
|
|
||||||
reversed,
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T> IntoIterator for &'a HybridSet<T> {
|
|
||||||
type Item = &'a T;
|
|
||||||
type IntoIter = HybridIter<'a, T>;
|
|
||||||
|
|
||||||
fn into_iter(self) -> Self::IntoIter {
|
|
||||||
self.iter()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct HybridIter<'a, T> {
|
|
||||||
inner: std::collections::btree_set::Iter<'a, T>,
|
|
||||||
reversed: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T> Iterator for HybridIter<'a, T> {
|
|
||||||
type Item = &'a T;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
if self.reversed {
|
|
||||||
self.inner.next_back()
|
|
||||||
} else {
|
|
||||||
self.inner.next()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ThreadNode {
|
impl ThreadNode {
|
||||||
pub fn new(parent: ParentState) -> Self {
|
pub fn new(parent: ParentState) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|||||||
Reference in New Issue
Block a user