diff --git a/crates/brk_vecs/src/variants/computed/computation.rs b/crates/brk_vecs/src/variants/computed/computation.rs new file mode 100644 index 000000000..cb9c491d1 --- /dev/null +++ b/crates/brk_vecs/src/variants/computed/computation.rs @@ -0,0 +1,21 @@ +use clap_derive::ValueEnum; +use serde::{Deserialize, Serialize}; + +#[derive( + Default, Debug, PartialEq, PartialOrd, Ord, Eq, Clone, Copy, Serialize, Deserialize, ValueEnum, +)] +pub enum Computation { + Eager, + #[default] + Lazy, +} + +impl Computation { + pub fn eager(&self) -> bool { + *self == Self::Eager + } + + pub fn lazy(&self) -> bool { + *self == Self::Lazy + } +} diff --git a/crates/brk_vecs/src/variants/computed/mod.rs b/crates/brk_vecs/src/variants/computed/mod.rs new file mode 100644 index 000000000..792fda5f0 --- /dev/null +++ b/crates/brk_vecs/src/variants/computed/mod.rs @@ -0,0 +1,382 @@ +use std::{borrow::Cow, sync::Arc}; + +use brk_core::{Result, StoredPhantom, Version}; +use brk_exit::Exit; + +use crate::{ + AnyCollectableVec, AnyIterableVec, AnyVec, BaseVecIterator, BoxedAnyIterableVec, + BoxedVecIterator, CollectableVec, File, Format, StoredIndex, StoredType, +}; + +use super::{ + ComputeFrom1, ComputeFrom2, ComputeFrom3, EagerVec, LazyVecFrom1, LazyVecFrom1Iterator, + LazyVecFrom2, LazyVecFrom2Iterator, LazyVecFrom3, LazyVecFrom3Iterator, StoredVecIterator, +}; + +mod computation; + +pub use computation::*; + +#[derive(Clone)] +pub enum Dependencies +where + S1T: Clone, + S2T: Clone, + S3T: Clone, +{ + From1(BoxedAnyIterableVec, ComputeFrom1), + From2( + (BoxedAnyIterableVec, BoxedAnyIterableVec), + ComputeFrom2, + ), + From3( + ( + BoxedAnyIterableVec, + BoxedAnyIterableVec, + BoxedAnyIterableVec, + ), + ComputeFrom3, + ), +} + +pub type ComputedVecFrom1 = + ComputedVec; +pub type ComputedVecFrom2 = + ComputedVec; +pub type ComputedVecFrom3 = + ComputedVec; + +#[derive(Clone)] +pub enum ComputedVec +where + S1T: Clone, + S2T: Clone, + S3T: Clone, +{ + Eager { + vec: EagerVec, + deps: Dependencies, + }, + LazyFrom1(LazyVecFrom1), + LazyFrom2(LazyVecFrom2), + LazyFrom3(LazyVecFrom3), +} + +impl ComputedVec +where + I: StoredIndex, + T: StoredType, + S1I: StoredIndex, + S1T: StoredType, + S2I: StoredIndex, + S2T: StoredType, + S3I: StoredIndex, + S3T: StoredType, +{ + pub fn forced_import_or_init_from_1( + computation: Computation, + file: &Arc, + name: &str, + version: Version, + format: Format, + source: BoxedAnyIterableVec, + compute: ComputeFrom1, + ) -> Result { + Ok(match computation { + Computation::Eager => Self::Eager { + vec: EagerVec::forced_import(file, name, version, format)?, + deps: Dependencies::From1(source, compute), + }, + Computation::Lazy => { + Self::LazyFrom1(LazyVecFrom1::init(name, version, source, compute)) + } + }) + } + + #[allow(clippy::too_many_arguments)] + pub fn forced_import_or_init_from_2( + computation: Computation, + file: &Arc, + name: &str, + version: Version, + format: Format, + source1: BoxedAnyIterableVec, + source2: BoxedAnyIterableVec, + compute: ComputeFrom2, + ) -> Result { + Ok(match computation { + Computation::Eager => Self::Eager { + vec: EagerVec::forced_import(file, name, version, format)?, + deps: Dependencies::From2((source1, source2), compute), + }, + Computation::Lazy => { + Self::LazyFrom2(LazyVecFrom2::init(name, version, source1, source2, compute)) + } + }) + } + + #[allow(clippy::too_many_arguments)] + pub fn forced_import_or_init_from_3( + computation: Computation, + file: &Arc, + name: &str, + version: Version, + format: Format, + source1: BoxedAnyIterableVec, + source2: BoxedAnyIterableVec, + source3: BoxedAnyIterableVec, + compute: ComputeFrom3, + ) -> Result { + Ok(match computation { + Computation::Eager => Self::Eager { + vec: EagerVec::forced_import(file, name, version, format)?, + deps: Dependencies::From3((source1, source2, source3), compute), + }, + Computation::Lazy => Self::LazyFrom3(LazyVecFrom3::init( + name, version, source1, source2, source3, compute, + )), + }) + } + + pub fn compute_if_necessary( + &mut self, + max_from: I, + len_source: &impl AnyIterableVec, + exit: &Exit, + ) -> Result<()> { + let (vec, dependencies) = if let ComputedVec::Eager { + vec, + deps: dependencies, + } = self + { + (vec, dependencies) + } else { + return Ok(()); + }; + + let len = len_source.len(); + + match dependencies { + Dependencies::From1(source, compute) => { + let version = source.version(); + let mut iter = source.iter(); + let t = |i: I| compute(i, &mut *iter).map(|v| (i, v)).unwrap(); + vec.compute_to(max_from, len, version, t, exit) + } + Dependencies::From2((source1, source2), compute) => { + let version = source1.version() + source2.version(); + let mut iter1 = source1.iter(); + let mut iter2 = source2.iter(); + let t = |i: I| { + compute(i, &mut *iter1, &mut *iter2) + .map(|v| (i, v)) + .unwrap() + }; + vec.compute_to(max_from, len, version, t, exit) + } + Dependencies::From3((source1, source2, source3), compute) => { + let version = source1.version() + source2.version() + source3.version(); + let mut iter1 = source1.iter(); + let mut iter2 = source2.iter(); + let mut iter3 = source3.iter(); + let t = |i: I| { + compute(i, &mut *iter1, &mut *iter2, &mut *iter3) + .map(|v| (i, v)) + .unwrap() + }; + vec.compute_to(max_from, len, version, t, exit) + } + } + } +} + +impl AnyVec for ComputedVec +where + I: StoredIndex, + T: StoredType, + S1I: StoredIndex, + S1T: StoredType, + S2I: StoredIndex, + S2T: StoredType, + S3I: StoredIndex, + S3T: StoredType, +{ + fn version(&self) -> Version { + match self { + ComputedVec::Eager { vec, .. } => vec.version(), + ComputedVec::LazyFrom1(v) => v.version(), + ComputedVec::LazyFrom2(v) => v.version(), + ComputedVec::LazyFrom3(v) => v.version(), + } + } + + fn name(&self) -> &str { + match self { + ComputedVec::Eager { vec, .. } => vec.name(), + ComputedVec::LazyFrom1(v) => v.name(), + ComputedVec::LazyFrom2(v) => v.name(), + ComputedVec::LazyFrom3(v) => v.name(), + } + } + + fn index_type_to_string(&self) -> &'static str { + I::to_string() + } + + fn len(&self) -> usize { + match self { + ComputedVec::Eager { vec, .. } => vec.len(), + ComputedVec::LazyFrom1(v) => v.len(), + ComputedVec::LazyFrom2(v) => v.len(), + ComputedVec::LazyFrom3(v) => v.len(), + } + } + + #[inline] + fn value_type_to_size_of(&self) -> usize { + size_of::() + } +} + +pub enum ComputedVecIterator<'a, I, T, S1I, S1T, S2I, S2T, S3I, S3T> +where + S1T: Clone, + S2T: Clone, + S3T: Clone, +{ + Eager(StoredVecIterator<'a, I, T>), + LazyFrom1(LazyVecFrom1Iterator<'a, I, T, S1I, S1T>), + LazyFrom2(LazyVecFrom2Iterator<'a, I, T, S1I, S1T, S2I, S2T>), + LazyFrom3(LazyVecFrom3Iterator<'a, I, T, S1I, S1T, S2I, S2T, S3I, S3T>), +} + +impl<'a, I, T, S1I, S1T, S2I, S2T, S3I, S3T> Iterator + for ComputedVecIterator<'a, I, T, S1I, S1T, S2I, S2T, S3I, S3T> +where + I: StoredIndex, + T: StoredType, + S1I: StoredIndex, + S1T: StoredType, + S2I: StoredIndex, + S2T: StoredType, + S3I: StoredIndex, + S3T: StoredType, +{ + type Item = (I, Cow<'a, T>); + fn next(&mut self) -> Option { + match self { + Self::Eager(i) => i.next(), + Self::LazyFrom1(i) => i.next(), + Self::LazyFrom2(i) => i.next(), + Self::LazyFrom3(i) => i.next(), + } + } +} + +impl BaseVecIterator + for ComputedVecIterator<'_, I, T, S1I, S1T, S2I, S2T, S3I, S3T> +where + I: StoredIndex, + T: StoredType, + S1I: StoredIndex, + S1T: StoredType, + S2I: StoredIndex, + S2T: StoredType, + S3I: StoredIndex, + S3T: StoredType, +{ + #[inline] + fn mut_index(&mut self) -> &mut usize { + match self { + Self::Eager(i) => i.mut_index(), + Self::LazyFrom1(i) => i.mut_index(), + Self::LazyFrom2(i) => i.mut_index(), + Self::LazyFrom3(i) => i.mut_index(), + } + } + + fn len(&self) -> usize { + match self { + Self::Eager(i) => i.len(), + Self::LazyFrom1(i) => i.len(), + Self::LazyFrom2(i) => i.len(), + Self::LazyFrom3(i) => i.len(), + } + } + + #[inline] + fn name(&self) -> &str { + match self { + Self::Eager(i) => i.name(), + Self::LazyFrom1(i) => i.name(), + Self::LazyFrom2(i) => i.name(), + Self::LazyFrom3(i) => i.name(), + } + } +} + +impl<'a, I, T, S1I, S1T, S2I, S2T, S3I, S3T> IntoIterator + for &'a ComputedVec +where + I: StoredIndex, + T: StoredType, + S1I: StoredIndex, + S1T: StoredType, + S2I: StoredIndex, + S2T: StoredType, + S3I: StoredIndex, + S3T: StoredType, +{ + type Item = (I, Cow<'a, T>); + type IntoIter = ComputedVecIterator<'a, I, T, S1I, S1T, S2I, S2T, S3I, S3T>; + + fn into_iter(self) -> Self::IntoIter { + match self { + ComputedVec::Eager { vec, .. } => ComputedVecIterator::Eager(vec.into_iter()), + ComputedVec::LazyFrom1(v) => ComputedVecIterator::LazyFrom1(v.into_iter()), + ComputedVec::LazyFrom2(v) => ComputedVecIterator::LazyFrom2(v.into_iter()), + ComputedVec::LazyFrom3(v) => ComputedVecIterator::LazyFrom3(v.into_iter()), + } + } +} + +impl AnyIterableVec + for ComputedVec +where + I: StoredIndex, + T: StoredType, + S1I: StoredIndex, + S1T: StoredType, + S2I: StoredIndex, + S2T: StoredType, + S3I: StoredIndex, + S3T: StoredType, +{ + fn boxed_iter<'a>(&'a self) -> BoxedVecIterator<'a, I, T> + where + T: 'a, + { + Box::new(self.into_iter()) + } +} + +impl AnyCollectableVec + for ComputedVec +where + I: StoredIndex, + T: StoredType, + S1I: StoredIndex, + S1T: StoredType, + S2I: StoredIndex, + S2T: StoredType, + S3I: StoredIndex, + S3T: StoredType, +{ + fn collect_range_serde_json( + &self, + from: Option, + to: Option, + ) -> Result> { + CollectableVec::collect_range_serde_json(self, from, to) + } +} diff --git a/crates/brk_vecs/src/variants/eager.rs b/crates/brk_vecs/src/variants/eager.rs new file mode 100644 index 000000000..560d9a717 --- /dev/null +++ b/crates/brk_vecs/src/variants/eager.rs @@ -0,0 +1,1316 @@ +use core::error; +use std::{ + borrow::Cow, + cmp::Ordering, + f32, + fmt::Debug, + ops::{Add, Div, Mul}, + sync::Arc, +}; + +use brk_core::{ + Bitcoin, CheckedSub, Close, Date, DateIndex, Dollars, Error, Result, Sats, StoredF32, + StoredUsize, Version, +}; +use brk_exit::Exit; +use log::info; + +use crate::{ + AnyCollectableVec, AnyIterableVec, AnyVec, BoxedVecIterator, CollectableVec, File, Format, + GenericStoredVec, Reader, StoredIndex, StoredType, StoredVec, StoredVecIterator, VecIterator, +}; + +const ONE_KIB: usize = 1024; +const ONE_MIB: usize = ONE_KIB * ONE_KIB; +const MAX_CACHE_SIZE: usize = 256 * ONE_MIB; +const DCA_AMOUNT: Dollars = Dollars::mint(100.0); + +#[derive(Debug, Clone)] +pub struct EagerVec(StoredVec); +// computed_version: Arc>>, + +impl EagerVec +where + I: StoredIndex, + T: StoredType, +{ + const SIZE_OF: usize = size_of::(); + + pub fn forced_import( + file: &Arc, + value_name: &str, + version: Version, + format: Format, + ) -> Result { + Ok(Self(StoredVec::forced_import( + file, value_name, version, format, + )?)) + } + + fn safe_truncate_if_needed(&mut self, index: I, exit: &Exit) -> Result<()> { + let _lock = exit.lock(); + self.0.truncate_if_needed(index)?; + Ok(()) + } + + #[inline] + pub fn forced_push_at(&mut self, index: I, value: T, exit: &Exit) -> Result<()> { + match self.len().cmp(&index.to_usize()?) { + Ordering::Less => { + return Err(Error::IndexTooHigh); + } + ord => { + if ord == Ordering::Greater { + self.safe_truncate_if_needed(index, exit)?; + } + self.0.push(value); + } + } + + if self.0.pushed_len() * Self::SIZE_OF >= MAX_CACHE_SIZE { + self.safe_flush(exit) + } else { + Ok(()) + } + } + + pub fn safe_flush(&mut self, exit: &Exit) -> Result<()> { + let _lock = exit.lock(); + self.0.flush()?; + Ok(()) + } + + pub fn get_or_read(&self, index: I, reader: &Reader) -> Result>> { + self.0.get_or_read(index, reader) + } + + pub fn inner_version(&self) -> Version { + self.0.version() + } + + fn update_computed_version(&mut self, computed_version: Version) { + self.0 + .mut_header() + .update_computed_version(computed_version); + } + + pub fn validate_computed_version_or_reset_file(&mut self, version: Version) -> Result<()> { + if version != self.0.header().computed_version() { + self.update_computed_version(version); + if !self.is_empty() { + self.0.reset()?; + } + } + + if self.is_empty() { + info!( + "Computing {}_to_{}...", + self.index_type_to_string(), + self.name() + ) + } + + Ok(()) + } + + pub fn compute_to( + &mut self, + max_from: I, + to: usize, + version: Version, + mut t: F, + exit: &Exit, + ) -> Result<()> + where + F: FnMut(I) -> (I, T), + { + self.validate_computed_version_or_reset_file(Version::ZERO + self.0.version() + version)?; + + let index = max_from.min(I::from(self.len())); + (index.to_usize()?..to).try_for_each(|i| { + let (i, v) = t(I::from(i)); + self.forced_push_at(i, v, exit) + })?; + + self.safe_flush(exit) + } + + pub fn compute_range( + &mut self, + max_from: I, + other: &impl AnyIterableVec, + t: F, + exit: &Exit, + ) -> Result<()> + where + A: StoredType, + F: FnMut(I) -> (I, T), + { + self.compute_to(max_from, other.len(), other.version(), t, exit) + } + + pub fn compute_from_index( + &mut self, + max_from: I, + other: &impl AnyIterableVec, + exit: &Exit, + ) -> Result<()> + where + T: From, + T2: StoredType, + { + self.compute_to( + max_from, + other.len(), + other.version(), + |i| (i, T::from(i)), + exit, + ) + } + + pub fn compute_transform( + &mut self, + max_from: A, + other: &impl AnyIterableVec, + mut t: F, + exit: &Exit, + ) -> Result<()> + where + A: StoredIndex, + B: StoredType, + F: FnMut((A, B, &Self)) -> (I, T), + { + self.validate_computed_version_or_reset_file( + Version::ZERO + self.0.version() + other.version(), + )?; + + let index = max_from.min(A::from(self.len())); + other.iter_at(index).try_for_each(|(a, b)| { + let (i, v) = t((a, b.into_owned(), self)); + self.forced_push_at(i, v, exit) + })?; + + self.safe_flush(exit) + } + + pub fn compute_add( + &mut self, + max_from: I, + added: &impl AnyIterableVec, + adder: &impl AnyIterableVec, + exit: &Exit, + ) -> Result<()> + where + T: Add, + { + self.validate_computed_version_or_reset_file( + Version::ZERO + self.0.version() + added.version() + adder.version(), + )?; + + let index = max_from.min(I::from(self.len())); + let mut adder_iter = adder.iter(); + + added.iter_at(index).try_for_each(|(i, v)| { + let v = v.into_owned() + adder_iter.unwrap_get_inner(i); + + self.forced_push_at(i, v, exit) + })?; + + self.safe_flush(exit) + } + + pub fn compute_subtract( + &mut self, + max_from: I, + subtracted: &impl AnyIterableVec, + subtracter: &impl AnyIterableVec, + exit: &Exit, + ) -> Result<()> + where + T: CheckedSub, + { + self.validate_computed_version_or_reset_file( + Version::ZERO + self.0.version() + subtracted.version() + subtracter.version(), + )?; + + let index = max_from.min(I::from(self.len())); + let mut subtracter_iter = subtracter.iter(); + + subtracted.iter_at(index).try_for_each(|(i, v)| { + let v = v + .into_owned() + .checked_sub(subtracter_iter.unwrap_get_inner(i)) + .unwrap(); + + self.forced_push_at(i, v, exit) + })?; + + self.safe_flush(exit) + } + + pub fn compute_max( + &mut self, + max_from: I, + source: &impl AnyIterableVec, + exit: &Exit, + ) -> Result<()> + where + T: From + Ord, + T2: StoredType, + { + self.validate_computed_version_or_reset_file( + Version::ZERO + self.0.version() + source.version(), + )?; + + let index = max_from.min(I::from(self.len())); + + let mut prev = None; + + source.iter_at(index).try_for_each(|(i, v)| { + if prev.is_none() { + let i = i.unwrap_to_usize(); + prev.replace(if i > 0 { + self.into_iter().unwrap_get_inner_(i - 1) + } else { + T::from(source.iter().unwrap_get_inner_(0)) + }); + } + let max = prev.clone().unwrap().max(T::from(v.into_owned())); + prev.replace(max.clone()); + + self.forced_push_at(i, max, exit) + })?; + + self.safe_flush(exit) + } + + pub fn compute_multiply( + &mut self, + max_from: I, + multiplied: &impl AnyIterableVec, + multiplier: &impl AnyIterableVec, + exit: &Exit, + ) -> Result<()> + where + T2: StoredType + Mul, + T3: StoredType, + T4: StoredType, + T: From, + { + self.validate_computed_version_or_reset_file( + Version::ZERO + self.0.version() + multiplied.version() + multiplier.version(), + )?; + + let index = max_from.min(I::from(self.len())); + let mut multiplier_iter = multiplier.iter(); + + multiplied.iter_at(index).try_for_each(|(i, v)| { + let v = v.into_owned() * multiplier_iter.unwrap_get_inner(i); + + self.forced_push_at(i, v.into(), exit) + })?; + + self.safe_flush(exit) + } + + pub fn compute_divide( + &mut self, + max_from: I, + divided: &impl AnyIterableVec, + divider: &impl AnyIterableVec, + exit: &Exit, + ) -> Result<()> + where + T2: StoredType + Mul, + T3: StoredType, + T4: Div + From, + T5: CheckedSub, + T: From, + { + self.compute_divide_(max_from, divided, divider, exit, false, false) + } + + pub fn compute_percentage( + &mut self, + max_from: I, + divided: &impl AnyIterableVec, + divider: &impl AnyIterableVec, + exit: &Exit, + ) -> Result<()> + where + T2: StoredType + Mul, + T3: StoredType, + T4: Div + From, + T5: CheckedSub, + T: From, + { + self.compute_divide_(max_from, divided, divider, exit, true, false) + } + + pub fn compute_percentage_difference( + &mut self, + max_from: I, + divided: &impl AnyIterableVec, + divider: &impl AnyIterableVec, + exit: &Exit, + ) -> Result<()> + where + T2: StoredType + Mul, + T3: StoredType, + T4: Div + From, + T5: CheckedSub, + T: From, + { + self.compute_divide_(max_from, divided, divider, exit, true, true) + } + + pub fn compute_divide_( + &mut self, + max_from: I, + divided: &impl AnyIterableVec, + divider: &impl AnyIterableVec, + exit: &Exit, + as_percentage: bool, + as_difference: bool, + ) -> Result<()> + where + T2: StoredType + Mul, + T3: StoredType, + T4: Div + From, + T5: CheckedSub, + T: From, + { + self.validate_computed_version_or_reset_file( + Version::ONE + self.0.version() + divided.version() + divider.version(), + )?; + + let index = max_from.min(I::from(self.len())); + let multiplier = if as_percentage { 100 } else { 1 }; + + let mut divider_iter = divider.iter(); + divided.iter_at(index).try_for_each(|(i, divided)| { + let divided = divided.into_owned(); + let divider = divider_iter.unwrap_get_inner(i); + + let v = if as_percentage { + divided * multiplier + } else { + T4::from(divided) + }; + let mut v = v / divider; + if as_difference { + v = v.checked_sub(multiplier).unwrap(); + } + self.forced_push_at(i, T::from(v), exit) + })?; + + self.safe_flush(exit) + } + + pub fn compute_drawdown( + &mut self, + max_from: I, + close: &impl AnyIterableVec>, + ath: &impl AnyIterableVec, + exit: &Exit, + ) -> Result<()> + where + T: From, + { + self.validate_computed_version_or_reset_file( + Version::ZERO + self.0.version() + ath.version() + close.version(), + )?; + + let index = max_from.min(I::from(self.len())); + let mut close_iter = close.iter(); + ath.iter_at(index).try_for_each(|(i, ath)| { + let ath = ath.into_owned(); + if ath == Dollars::ZERO { + self.forced_push_at(i, T::from(StoredF32::default()), exit) + } else { + let close = *close_iter.unwrap_get_inner(i); + let drawdown = StoredF32::from((*ath - *close) / *ath * -100.0); + self.forced_push_at(i, T::from(drawdown), exit) + } + })?; + + self.safe_flush(exit) + } + + pub fn compute_inverse_more_to_less( + &mut self, + max_from: T, + other: &impl AnyIterableVec, + exit: &Exit, + ) -> Result<()> + where + I: StoredType + StoredIndex, + T: StoredIndex, + { + self.validate_computed_version_or_reset_file( + Version::ZERO + self.0.version() + other.version(), + )?; + + let index = max_from.min( + VecIterator::last(self.0.into_iter()).map_or_else(T::default, |(_, v)| v.into_owned()), + ); + let mut prev_i = None; + other.iter_at(index).try_for_each(|(v, i)| -> Result<()> { + let i = i.into_owned(); + if prev_i.is_some_and(|prev_i| prev_i == i) { + return Ok(()); + } + if self.iter().get_inner(i).is_none_or(|old_v| old_v > v) { + self.forced_push_at(i, v, exit)?; + } + prev_i.replace(i); + Ok(()) + })?; + + self.safe_flush(exit) + } + + pub fn compute_inverse_less_to_more( + &mut self, + max_from: T, + first_indexes: &impl AnyIterableVec, + indexes_count: &impl AnyIterableVec, + exit: &Exit, + ) -> Result<()> + where + I: StoredType, + T: StoredIndex, + { + self.validate_computed_version_or_reset_file( + Version::ZERO + self.0.version() + first_indexes.version() + indexes_count.version(), + )?; + + let mut indexes_count_iter = indexes_count.iter(); + + let index = max_from.min(T::from(self.len())); + first_indexes + .iter_at(index) + .try_for_each(|(value, first_index)| { + let first_index = (first_index).to_usize()?; + let count = *indexes_count_iter.unwrap_get_inner(value); + (first_index..first_index + count) + .try_for_each(|index| self.forced_push_at(I::from(index), value, exit)) + })?; + + self.safe_flush(exit) + } + + pub fn compute_count_from_indexes( + &mut self, + max_from: I, + first_indexes: &impl AnyIterableVec, + other_to_else: &impl AnyIterableVec, + exit: &Exit, + ) -> Result<()> + where + T: From, + T2: StoredType + + StoredIndex + + Copy + + Add + + CheckedSub + + TryInto + + Default, + >::Error: error::Error + 'static, + T3: StoredType, + { + let opt: Option bool>> = None; + self.compute_filtered_count_from_indexes_(max_from, first_indexes, other_to_else, opt, exit) + } + + pub fn compute_filtered_count_from_indexes( + &mut self, + max_from: I, + first_indexes: &impl AnyIterableVec, + other_to_else: &impl AnyIterableVec, + filter: F, + exit: &Exit, + ) -> Result<()> + where + T: From, + T2: StoredType + + StoredIndex + + Copy + + Add + + CheckedSub + + TryInto + + Default, + >::Error: error::Error + 'static, + T3: StoredType, + F: FnMut(T2) -> bool, + { + self.compute_filtered_count_from_indexes_( + max_from, + first_indexes, + other_to_else, + Some(Box::new(filter)), + exit, + ) + } + + fn compute_filtered_count_from_indexes_( + &mut self, + max_from: I, + first_indexes: &impl AnyIterableVec, + other_to_else: &impl AnyIterableVec, + mut filter: Option bool + '_>>, + exit: &Exit, + ) -> Result<()> + where + T: From, + T2: StoredType + + StoredIndex + + Copy + + Add + + CheckedSub + + TryInto + + Default, + T3: StoredType, + >::Error: error::Error + 'static, + { + self.validate_computed_version_or_reset_file( + Version::ZERO + self.0.version() + first_indexes.version() + other_to_else.version(), + )?; + + let mut other_iter = first_indexes.iter(); + let index = max_from.min(I::from(self.len())); + first_indexes + .iter_at(index) + .try_for_each(|(i, first_index)| { + let end = other_iter + .get_inner(i + 1) + .map(|v| v.unwrap_to_usize()) + .unwrap_or_else(|| other_to_else.len()); + + let range = first_index.unwrap_to_usize()..end; + let count = if let Some(filter) = filter.as_mut() { + range.into_iter().filter(|i| filter(T2::from(*i))).count() + } else { + range.count() + }; + self.forced_push_at(i, T::from(T2::from(count)), exit) + })?; + + self.safe_flush(exit) + } + + pub fn compute_is_first_ordered( + &mut self, + max_from: I, + self_to_other: &impl AnyIterableVec, + other_to_self: &impl AnyIterableVec, + exit: &Exit, + ) -> Result<()> + where + I: StoredType, + T: From, + A: StoredIndex + StoredType, + { + self.validate_computed_version_or_reset_file( + Version::ZERO + self.0.version() + self_to_other.version() + other_to_self.version(), + )?; + + let mut other_to_self_iter = other_to_self.iter(); + let index = max_from.min(I::from(self.len())); + self_to_other.iter_at(index).try_for_each(|(i, other)| { + self.forced_push_at( + i, + T::from(other_to_self_iter.unwrap_get_inner(other.into_owned()) == i), + exit, + ) + })?; + + self.safe_flush(exit) + } + + pub fn compute_sum_from_indexes( + &mut self, + max_from: I, + first_indexes: &impl AnyIterableVec, + indexes_count: &impl AnyIterableVec, + source: &impl AnyIterableVec, + exit: &Exit, + ) -> Result<()> + where + T: From + Add, + T2: StoredIndex + StoredType, + { + self.validate_computed_version_or_reset_file( + Version::ZERO + self.0.version() + first_indexes.version() + indexes_count.version(), + )?; + + let mut indexes_count_iter = indexes_count.iter(); + let mut source_iter = source.iter(); + let index = max_from.min(I::from(self.len())); + first_indexes + .iter_at(index) + .try_for_each(|(i, first_index)| { + let count = *indexes_count_iter.unwrap_get_inner(i); + let first_index = first_index.unwrap_to_usize(); + let range = first_index..first_index + count; + let mut sum = T::from(0_usize); + range.into_iter().for_each(|i| { + sum = sum.clone() + source_iter.unwrap_get_inner(T2::from(i)); + }); + self.forced_push_at(i, sum, exit) + })?; + + self.safe_flush(exit) + } + + pub fn compute_sum_of_others( + &mut self, + max_from: I, + others: &[&impl AnyIterableVec], + exit: &Exit, + ) -> Result<()> + where + T: From + Add, + { + self.validate_computed_version_or_reset_file( + Version::ZERO + self.0.version() + others.iter().map(|v| v.version()).sum(), + )?; + + if others.is_empty() { + unreachable!("others should've length of 1 at least"); + } + + let mut others_iter = others[1..].iter().map(|v| v.iter()).collect::>(); + + let index = max_from.min(I::from(self.len())); + others + .first() + .unwrap() + .iter_at(index) + .try_for_each(|(i, v)| { + let mut sum = v.into_owned(); + others_iter.iter_mut().for_each(|iter| { + sum = sum.clone() + iter.unwrap_get_inner(i); + }); + self.forced_push_at(i, sum, exit) + })?; + + self.safe_flush(exit) + } + + pub fn compute_min_of_others( + &mut self, + max_from: I, + others: &[&impl AnyIterableVec], + exit: &Exit, + ) -> Result<()> + where + T: From + Add + Ord, + { + self.validate_computed_version_or_reset_file( + Version::ZERO + self.0.version() + others.iter().map(|v| v.version()).sum(), + )?; + + if others.is_empty() { + unreachable!("others should've length of 1 at least"); + } + + let mut others_iter = others[1..].iter().map(|v| v.iter()).collect::>(); + + let index = max_from.min(I::from(self.len())); + others + .first() + .unwrap() + .iter_at(index) + .try_for_each(|(i, v)| { + let min = v.into_owned(); + let min = others_iter + .iter_mut() + .map(|iter| iter.unwrap_get_inner(i)) + .min() + .map_or(min.clone(), |min2| min.min(min2)); + self.forced_push_at(i, min, exit) + })?; + + self.safe_flush(exit) + } + + pub fn compute_max_of_others( + &mut self, + max_from: I, + others: &[&impl AnyIterableVec], + exit: &Exit, + ) -> Result<()> + where + T: From + Add + Ord, + { + self.validate_computed_version_or_reset_file( + Version::ZERO + self.0.version() + others.iter().map(|v| v.version()).sum(), + )?; + + if others.is_empty() { + unreachable!("others should've length of 1 at least"); + } + + let mut others_iter = others[1..].iter().map(|v| v.iter()).collect::>(); + + let index = max_from.min(I::from(self.len())); + others + .first() + .unwrap() + .iter_at(index) + .try_for_each(|(i, v)| { + let max = v.into_owned(); + let max = others_iter + .iter_mut() + .map(|iter| iter.unwrap_get_inner(i)) + .max() + .map_or(max.clone(), |max2| max.max(max2)); + self.forced_push_at(i, max, exit) + })?; + + self.safe_flush(exit) + } + + pub fn compute_sma( + &mut self, + max_from: I, + source: &impl AnyIterableVec, + sma: usize, + exit: &Exit, + ) -> Result<()> + where + T: Add + From + Div + From, + T2: StoredType, + f32: From + From, + { + self.compute_sma_(max_from, source, sma, exit, None) + } + + pub fn compute_sma_( + &mut self, + max_from: I, + source: &impl AnyIterableVec, + sma: usize, + exit: &Exit, + min_i: Option, + ) -> Result<()> + where + T: Add + From + Div + From, + T2: StoredType, + f32: From + From, + { + self.validate_computed_version_or_reset_file( + Version::ONE + self.0.version() + source.version(), + )?; + + let index = max_from.min(I::from(self.len())); + let mut prev = None; + let min_prev_i = min_i.unwrap_or_default().unwrap_to_usize(); + let mut other_iter = source.iter(); + source.iter_at(index).try_for_each(|(i, value)| { + let value = value.into_owned(); + + if min_i.is_none() || min_i.is_some_and(|min_i| min_i <= i) { + if prev.is_none() { + let i = i.unwrap_to_usize(); + prev.replace(if i > min_prev_i { + self.into_iter().unwrap_get_inner_(i - 1) + } else { + T::from(0.0) + }); + } + + let processed_values_count = i.unwrap_to_usize() - min_prev_i + 1; + let len = (processed_values_count).min(sma); + + let value = f32::from(value); + + let sma = T::from(if processed_values_count > sma { + let prev_sum = f32::from(prev.clone().unwrap()) * len as f32; + let value_to_subtract = f32::from( + other_iter.unwrap_get_inner_(i.unwrap_to_usize().checked_sub(sma).unwrap()), + ); + (prev_sum - value_to_subtract + value) / len as f32 + } else { + (f32::from(prev.clone().unwrap()) * (len - 1) as f32 + value) / len as f32 + }); + + prev.replace(sma.clone()); + self.forced_push_at(i, sma, exit) + } else { + self.forced_push_at(i, T::from(f32::NAN), exit) + } + })?; + + self.safe_flush(exit) + } + + pub fn compute_previous_value( + &mut self, + max_from: I, + source: &impl AnyIterableVec, + len: usize, + exit: &Exit, + ) -> Result<()> + where + I: CheckedSub, + T2: StoredType + Default, + f32: From, + T: From, + { + self.validate_computed_version_or_reset_file( + Version::ZERO + self.0.version() + source.version(), + )?; + + let index = max_from.min(I::from(self.len())); + let mut source_iter = source.iter(); + (index.to_usize()?..source.len()).try_for_each(|i| { + let i = I::from(i); + + let previous_value = i + .checked_sub(I::from(len)) + .map(|prev_i| f32::from(source_iter.unwrap_get_inner(prev_i))) + .unwrap_or(f32::NAN); + + self.forced_push_at(i, T::from(previous_value), exit) + })?; + + self.safe_flush(exit) + } + + pub fn compute_change( + &mut self, + max_from: I, + source: &impl AnyIterableVec, + len: usize, + exit: &Exit, + ) -> Result<()> + where + I: CheckedSub, + T: CheckedSub + Default, + { + self.validate_computed_version_or_reset_file( + Version::ZERO + self.0.version() + source.version(), + )?; + + let index = max_from.min(I::from(self.len())); + let mut source_iter = source.iter(); + source.iter_at(index).try_for_each(|(i, current)| { + let current = current.into_owned(); + + let prev = i + .checked_sub(I::from(len)) + .map(|prev_i| source_iter.unwrap_get_inner(prev_i)) + .unwrap_or_default(); + + self.forced_push_at(i, current.checked_sub(prev).unwrap(), exit) + })?; + + self.safe_flush(exit) + } + + pub fn compute_percentage_change( + &mut self, + max_from: I, + source: &impl AnyIterableVec, + len: usize, + exit: &Exit, + ) -> Result<()> + where + I: CheckedSub, + T2: StoredType + Default, + f32: From, + T: From, + { + self.validate_computed_version_or_reset_file( + Version::ZERO + self.0.version() + source.version(), + )?; + + let index = max_from.min(I::from(self.len())); + let mut source_iter = source.iter(); + source.iter_at(index).try_for_each(|(i, b)| { + let previous_value = f32::from( + i.checked_sub(I::from(len)) + .map(|prev_i| source_iter.unwrap_get_inner(prev_i)) + .unwrap_or_default(), + ); + + let last_value = f32::from(b.into_owned()); + + let percentage_change = ((last_value / previous_value) - 1.0) * 100.0; + + self.forced_push_at(i, T::from(percentage_change), exit) + })?; + + self.safe_flush(exit) + } + + pub fn compute_cagr( + &mut self, + max_from: I, + percentage_returns: &impl AnyIterableVec, + days: usize, + exit: &Exit, + ) -> Result<()> + where + I: CheckedSub, + T2: StoredType + Default, + f32: From, + T: From, + { + self.validate_computed_version_or_reset_file( + Version::ZERO + self.0.version() + percentage_returns.version(), + )?; + + if days % 365 != 0 { + panic!("bad days"); + } + + let years = days / 365; + let index = max_from.min(I::from(self.len())); + percentage_returns + .iter_at(index) + .try_for_each(|(i, percentage)| { + let percentage = percentage.into_owned(); + + let cagr = (((f32::from(percentage) / 100.0 + 1.0).powf(1.0 / years as f32)) - 1.0) + * 100.0; + + self.forced_push_at(i, T::from(cagr), exit) + })?; + + self.safe_flush(exit) + } + + pub fn compute_zscore( + &mut self, + max_from: I, + ratio: &impl AnyIterableVec, + sma: &impl AnyIterableVec, + sd: &impl AnyIterableVec, + exit: &Exit, + ) -> Result<()> + where + T: From, + { + let mut sma_iter = sma.iter(); + let mut sd_iter = sd.iter(); + + self.compute_transform( + max_from, + ratio, + |(i, ratio, ..)| { + let sma = sma_iter.unwrap_get_inner(i); + let sd = sd_iter.unwrap_get_inner(i); + (i, T::from((ratio - sma) / sd)) + }, + exit, + ) + } +} + +impl EagerVec { + pub fn compute_dca_stack_via_len( + &mut self, + max_from: DateIndex, + closes: &impl AnyIterableVec>, + len: usize, + exit: &Exit, + ) -> Result<()> { + self.validate_computed_version_or_reset_file( + Version::ZERO + self.0.version() + closes.version(), + )?; + + let mut other_iter = closes.iter(); + let mut prev = None; + + let index = max_from.min(DateIndex::from(self.len())); + closes.iter_at(index).try_for_each(|(i, closes)| { + let price = *closes.into_owned(); + let i_usize = i.unwrap_to_usize(); + if prev.is_none() { + if i_usize == 0 { + prev.replace(Sats::ZERO); + } else { + prev.replace(self.into_iter().unwrap_get_inner_(i_usize - 1)); + } + } + + let mut stack = Sats::ZERO; + + if price != Dollars::ZERO { + stack = prev.unwrap() + Sats::from(Bitcoin::from(DCA_AMOUNT / price)); + + if i_usize >= len { + let prev_price = *other_iter.unwrap_get_inner_(i_usize - len); + if prev_price != Dollars::ZERO { + stack = stack + .checked_sub(Sats::from(Bitcoin::from(DCA_AMOUNT / prev_price))) + .unwrap(); + } + } + } + + prev.replace(stack); + + self.forced_push_at(i, stack, exit) + })?; + + self.safe_flush(exit) + } + + pub fn compute_dca_stack_via_from( + &mut self, + max_from: DateIndex, + closes: &impl AnyIterableVec>, + from: DateIndex, + exit: &Exit, + ) -> Result<()> { + self.validate_computed_version_or_reset_file( + Version::ZERO + self.0.version() + closes.version(), + )?; + + let mut prev = None; + + let index = max_from.min(DateIndex::from(self.len())); + closes.iter_at(index).try_for_each(|(i, closes)| { + let price = *closes.into_owned(); + let i_usize = i.unwrap_to_usize(); + if prev.is_none() { + if i_usize == 0 { + prev.replace(Sats::ZERO); + } else { + prev.replace(self.into_iter().unwrap_get_inner_(i_usize - 1)); + } + } + + let mut stack = Sats::ZERO; + + if price != Dollars::ZERO && i >= from { + stack = prev.unwrap() + Sats::from(Bitcoin::from(DCA_AMOUNT / price)); + } + + prev.replace(stack); + + self.forced_push_at(i, stack, exit) + })?; + + self.safe_flush(exit) + } +} + +impl EagerVec { + pub fn compute_dca_avg_price_via_len( + &mut self, + max_from: DateIndex, + stacks: &impl AnyIterableVec, + len: usize, + exit: &Exit, + ) -> Result<()> { + self.validate_computed_version_or_reset_file( + Version::ONE + self.0.version() + stacks.version(), + )?; + + let index = max_from.min(DateIndex::from(self.len())); + + let first_price_date = DateIndex::try_from(Date::new(2010, 7, 12)).unwrap(); + + stacks.iter_at(index).try_for_each(|(i, stack)| { + let stack = stack.into_owned(); + let mut avg_price = Dollars::from(f64::NAN); + if i > first_price_date { + avg_price = DCA_AMOUNT + * len + .min(i.unwrap_to_usize() + 1) + .min(i.checked_sub(first_price_date).unwrap().unwrap_to_usize() + 1) + / Bitcoin::from(stack); + } + self.forced_push_at(i, avg_price, exit) + })?; + + self.safe_flush(exit) + } + + pub fn compute_dca_avg_price_via_from( + &mut self, + max_from: DateIndex, + stacks: &impl AnyIterableVec, + from: DateIndex, + exit: &Exit, + ) -> Result<()> { + self.validate_computed_version_or_reset_file( + Version::ZERO + self.0.version() + stacks.version(), + )?; + + let index = max_from.min(DateIndex::from(self.len())); + + let from_usize = from.unwrap_to_usize(); + + stacks.iter_at(index).try_for_each(|(i, stack)| { + let stack = stack.into_owned(); + let mut avg_price = Dollars::from(f64::NAN); + if i >= from { + avg_price = + DCA_AMOUNT * (i.unwrap_to_usize() + 1 - from_usize) / Bitcoin::from(stack); + } + self.forced_push_at(i, avg_price, exit) + })?; + + self.safe_flush(exit) + } +} + +impl EagerVec +where + I: StoredIndex, +{ + pub fn compute_from_sats( + &mut self, + max_from: I, + sats: &impl AnyIterableVec, + exit: &Exit, + ) -> Result<()> { + self.validate_computed_version_or_reset_file( + Version::ZERO + self.0.version() + sats.version(), + )?; + + let index = max_from.min(I::from(self.len())); + sats.iter_at(index).try_for_each(|(i, sats)| { + let (i, v) = (i, Bitcoin::from(sats.into_owned())); + self.forced_push_at(i, v, exit) + })?; + + self.safe_flush(exit) + } +} + +impl EagerVec +where + I: StoredIndex, +{ + pub fn compute_from_bitcoin( + &mut self, + max_from: I, + bitcoin: &impl AnyIterableVec, + price: &impl AnyIterableVec>, + exit: &Exit, + ) -> Result<()> { + self.validate_computed_version_or_reset_file( + Version::ZERO + self.0.version() + bitcoin.version(), + )?; + + let mut price_iter = price.iter(); + let index = max_from.min(I::from(self.len())); + bitcoin.iter_at(index).try_for_each(|(i, bitcoin)| { + let dollars = price_iter.unwrap_get_inner(i); + let (i, v) = (i, *dollars * bitcoin.into_owned()); + self.forced_push_at(i, v, exit) + })?; + + self.safe_flush(exit) + } +} + +// impl EagerVec { +// pub fn compute_txindex_from_bitcoin( +// &mut self, +// max_from: TxIndex, +// bitcoin: &impl AnyIterableVec, +// i_to_height: &impl AnyIterableVec, +// price: &impl AnyIterableVec>, +// exit: &Exit, +// ) -> Result<()> { +// self.validate_computed_version_or_reset_file( +// Version::ZERO +// + self.0.version() +// + bitcoin.version() +// + i_to_height.version() +// + price.version(), +// )?; + +// let mut i_to_height_iter = i_to_height.iter(); +// let mut price_iter = price.iter(); +// let index = max_from.min(TxIndex::from(self.len())); +// bitcoin.iter_at(index).try_for_each(|(i, bitcoin, ..)| { +// let height = i_to_height_iter.unwrap_get_inner(i); +// let dollars = price_iter.unwrap_get_inner(height); +// let (i, v) = (i, *dollars * bitcoin.into_owned()); +// self.forced_push_at(i, v, exit) +// })?; + +// self.safe_flush(exit) +// } +// } + +impl<'a, I, T> IntoIterator for &'a EagerVec +where + I: StoredIndex, + T: StoredType, +{ + type Item = (I, Cow<'a, T>); + type IntoIter = StoredVecIterator<'a, I, T>; + + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() + } +} + +impl AnyVec for EagerVec +where + I: StoredIndex, + T: StoredType, +{ + #[inline] + fn version(&self) -> Version { + self.0.header().computed_version() + } + + #[inline] + fn name(&self) -> &str { + self.0.name() + } + + #[inline] + fn len(&self) -> usize { + self.0.len() + } + + #[inline] + fn index_type_to_string(&self) -> &'static str { + I::to_string() + } + + #[inline] + fn value_type_to_size_of(&self) -> usize { + size_of::() + } +} + +impl AnyIterableVec for EagerVec +where + I: StoredIndex, + T: StoredType, +{ + fn boxed_iter<'a>(&'a self) -> BoxedVecIterator<'a, I, T> + where + I: StoredIndex, + T: StoredType + 'a, + { + Box::new(self.0.into_iter()) + } +} + +impl AnyCollectableVec for EagerVec +where + I: StoredIndex, + T: StoredType, +{ + fn collect_range_serde_json( + &self, + from: Option, + to: Option, + ) -> Result> { + CollectableVec::collect_range_serde_json(self, from, to) + } +} diff --git a/crates/brk_vecs/src/variants/lazy/lazy1.rs b/crates/brk_vecs/src/variants/lazy/lazy1.rs new file mode 100644 index 000000000..568192ca5 --- /dev/null +++ b/crates/brk_vecs/src/variants/lazy/lazy1.rs @@ -0,0 +1,185 @@ +use std::borrow::Cow; + +use brk_core::{Result, Version}; + +use crate::{ + AnyCollectableVec, AnyIterableVec, AnyVec, BaseVecIterator, BoxedAnyIterableVec, + BoxedVecIterator, CollectableVec, StoredIndex, StoredType, +}; + +pub type ComputeFrom1 = + for<'a> fn(I, &mut dyn BaseVecIterator)>) -> Option; + +#[derive(Clone)] +pub struct LazyVecFrom1 +where + S1T: Clone, +{ + name: String, + version: Version, + source: BoxedAnyIterableVec, + compute: ComputeFrom1, +} + +impl LazyVecFrom1 +where + I: StoredIndex, + T: StoredType, + S1I: StoredIndex, + S1T: StoredType, +{ + pub fn init( + name: &str, + version: Version, + source: BoxedAnyIterableVec, + compute: ComputeFrom1, + ) -> Self { + if I::to_string() != S1I::to_string() { + unreachable!() + } + + Self { + name: name.to_string(), + version, + source, + compute, + } + } + + fn version(&self) -> Version { + self.version + } +} + +pub struct LazyVecFrom1Iterator<'a, I, T, S1I, S1T> +where + S1T: Clone, +{ + lazy: &'a LazyVecFrom1, + source: BoxedVecIterator<'a, S1I, S1T>, + index: usize, +} + +impl<'a, I, T, S1I, S1T> Iterator for LazyVecFrom1Iterator<'a, I, T, S1I, S1T> +where + I: StoredIndex, + T: StoredType + 'a, + S1I: StoredIndex, + S1T: StoredType, +{ + type Item = (I, Cow<'a, T>); + + fn next(&mut self) -> Option { + if self.index >= self.len() { + return None; + } + let index = I::from(self.index); + let opt = (self.lazy.compute)(index, &mut *self.source).map(|v| (index, Cow::Owned(v))); + if opt.is_some() { + self.index += 1; + } + opt + } +} + +impl BaseVecIterator for LazyVecFrom1Iterator<'_, I, T, S1I, S1T> +where + I: StoredIndex, + T: StoredType, + S1I: StoredIndex, + S1T: StoredType, +{ + #[inline] + fn mut_index(&mut self) -> &mut usize { + &mut self.index + } + + #[inline] + fn len(&self) -> usize { + self.source.len() + } + + #[inline] + fn name(&self) -> &str { + self.source.name() + } +} + +impl<'a, I, T, S1I, S1T> IntoIterator for &'a LazyVecFrom1 +where + I: StoredIndex, + T: StoredType + 'a, + S1I: StoredIndex, + S1T: StoredType, +{ + type Item = (I, Cow<'a, T>); + type IntoIter = LazyVecFrom1Iterator<'a, I, T, S1I, S1T>; + + fn into_iter(self) -> Self::IntoIter { + LazyVecFrom1Iterator { + lazy: self, + source: self.source.iter(), + index: 0, + } + } +} + +impl AnyVec for LazyVecFrom1 +where + I: StoredIndex, + T: StoredType, + S1I: StoredIndex, + S1T: StoredType, +{ + fn version(&self) -> Version { + self.version() + } + + fn name(&self) -> &str { + self.name.as_str() + } + + fn index_type_to_string(&self) -> &'static str { + I::to_string() + } + + fn len(&self) -> usize { + self.source.len() + } + + #[inline] + fn value_type_to_size_of(&self) -> usize { + size_of::() + } +} + +impl AnyIterableVec for LazyVecFrom1 +where + I: StoredIndex, + T: StoredType, + S1I: StoredIndex, + S1T: StoredType, +{ + fn boxed_iter<'a>(&'a self) -> BoxedVecIterator<'a, I, T> + where + T: 'a, + { + Box::new(self.into_iter()) + } +} + +impl AnyCollectableVec for LazyVecFrom1 +where + I: StoredIndex, + T: StoredType, + S1I: StoredIndex, + S1T: StoredType, +{ + fn collect_range_serde_json( + &self, + from: Option, + to: Option, + ) -> Result> { + CollectableVec::collect_range_serde_json(self, from, to) + } +} diff --git a/crates/brk_vecs/src/variants/lazy/lazy2.rs b/crates/brk_vecs/src/variants/lazy/lazy2.rs new file mode 100644 index 000000000..0093f6454 --- /dev/null +++ b/crates/brk_vecs/src/variants/lazy/lazy2.rs @@ -0,0 +1,236 @@ +use std::borrow::Cow; + +use brk_core::{Result, Version}; + +use crate::{ + AnyCollectableVec, AnyIterableVec, AnyVec, BaseVecIterator, BoxedAnyIterableVec, + BoxedVecIterator, CollectableVec, StoredIndex, StoredType, +}; + +pub type ComputeFrom2 = for<'a> fn( + I, + &mut dyn BaseVecIterator)>, + &mut dyn BaseVecIterator)>, +) -> Option; + +#[derive(Clone)] +pub struct LazyVecFrom2 +where + S1T: Clone, + S2T: Clone, +{ + name: String, + version: Version, + source1: BoxedAnyIterableVec, + source2: BoxedAnyIterableVec, + compute: ComputeFrom2, +} + +impl LazyVecFrom2 +where + I: StoredIndex, + T: StoredType, + S1I: StoredIndex, + S1T: StoredType, + S2I: StoredIndex, + S2T: StoredType, +{ + pub fn init( + name: &str, + version: Version, + source1: BoxedAnyIterableVec, + source2: BoxedAnyIterableVec, + compute: ComputeFrom2, + ) -> Self { + if ([ + source1.index_type_to_string(), + source2.index_type_to_string(), + ]) + .into_iter() + .filter(|t| *t == I::to_string()) + .count() + == 0 + { + panic!("At least one should have same index"); + } + + Self { + name: name.to_string(), + version, + source1, + source2, + compute, + } + } + + fn version(&self) -> Version { + self.version + } +} + +pub struct LazyVecFrom2Iterator<'a, I, T, S1I, S1T, S2I, S2T> +where + S1T: Clone, + S2T: Clone, +{ + lazy: &'a LazyVecFrom2, + source1: BoxedVecIterator<'a, S1I, S1T>, + source2: BoxedVecIterator<'a, S2I, S2T>, + index: usize, +} + +impl<'a, I, T, S1I, S1T, S2I, S2T> Iterator for LazyVecFrom2Iterator<'a, I, T, S1I, S1T, S2I, S2T> +where + I: StoredIndex, + T: StoredType + 'a, + S1I: StoredIndex, + S1T: StoredType, + S2I: StoredIndex, + S2T: StoredType, +{ + type Item = (I, Cow<'a, T>); + + fn next(&mut self) -> Option { + let index = I::from(self.index); + let opt = (self.lazy.compute)(index, &mut *self.source1, &mut *self.source2) + .map(|v| (index, Cow::Owned(v))); + if opt.is_some() { + self.index += 1; + } + opt + } +} + +impl BaseVecIterator + for LazyVecFrom2Iterator<'_, I, T, S1I, S1T, S2I, S2T> +where + I: StoredIndex, + T: StoredType, + S1I: StoredIndex, + S1T: StoredType, + S2I: StoredIndex, + S2T: StoredType, +{ + #[inline] + fn mut_index(&mut self) -> &mut usize { + &mut self.index + } + + #[inline] + fn len(&self) -> usize { + let len1 = if self.source1.index_type_to_string() == I::to_string() { + self.source1.len() + } else { + usize::MAX + }; + let len2 = if self.source2.index_type_to_string() == I::to_string() { + self.source2.len() + } else { + usize::MAX + }; + len1.min(len2) + } + + #[inline] + fn name(&self) -> &str { + self.source1.name() + } +} + +impl<'a, I, T, S1I, S1T, S2I, S2T> IntoIterator for &'a LazyVecFrom2 +where + I: StoredIndex, + T: StoredType + 'a, + S1I: StoredIndex, + S1T: StoredType, + S2I: StoredIndex, + S2T: StoredType, +{ + type Item = (I, Cow<'a, T>); + type IntoIter = LazyVecFrom2Iterator<'a, I, T, S1I, S1T, S2I, S2T>; + + fn into_iter(self) -> Self::IntoIter { + LazyVecFrom2Iterator { + lazy: self, + source1: self.source1.iter(), + source2: self.source2.iter(), + index: 0, + } + } +} + +impl AnyVec for LazyVecFrom2 +where + I: StoredIndex, + T: StoredType, + S1I: StoredIndex, + S1T: StoredType, + S2I: StoredIndex, + S2T: StoredType, +{ + fn version(&self) -> Version { + self.version() + } + + fn name(&self) -> &str { + self.name.as_str() + } + + fn index_type_to_string(&self) -> &'static str { + I::to_string() + } + + fn len(&self) -> usize { + let len1 = if self.source1.index_type_to_string() == I::to_string() { + self.source1.len() + } else { + usize::MAX + }; + let len2 = if self.source2.index_type_to_string() == I::to_string() { + self.source2.len() + } else { + usize::MAX + }; + len1.min(len2) + } + + #[inline] + fn value_type_to_size_of(&self) -> usize { + size_of::() + } +} + +impl AnyIterableVec for LazyVecFrom2 +where + I: StoredIndex, + T: StoredType, + S1I: StoredIndex, + S1T: StoredType, + S2I: StoredIndex, + S2T: StoredType, +{ + fn boxed_iter<'a>(&'a self) -> BoxedVecIterator<'a, I, T> + where + T: 'a, + { + Box::new(self.into_iter()) + } +} + +impl AnyCollectableVec for LazyVecFrom2 +where + I: StoredIndex, + T: StoredType, + S1I: StoredIndex, + S1T: StoredType, + S2I: StoredIndex, + S2T: StoredType, +{ + fn collect_range_serde_json( + &self, + from: Option, + to: Option, + ) -> Result> { + CollectableVec::collect_range_serde_json(self, from, to) + } +} diff --git a/crates/brk_vecs/src/variants/lazy/lazy3.rs b/crates/brk_vecs/src/variants/lazy/lazy3.rs new file mode 100644 index 000000000..b94ad165b --- /dev/null +++ b/crates/brk_vecs/src/variants/lazy/lazy3.rs @@ -0,0 +1,278 @@ +use std::borrow::Cow; + +use brk_core::{Result, Version}; + +use crate::{ + AnyCollectableVec, AnyIterableVec, AnyVec, BaseVecIterator, BoxedAnyIterableVec, + BoxedVecIterator, CollectableVec, StoredIndex, StoredType, +}; + +pub type ComputeFrom3 = for<'a> fn( + I, + &mut dyn BaseVecIterator)>, + &mut dyn BaseVecIterator)>, + &mut dyn BaseVecIterator)>, +) -> Option; + +#[derive(Clone)] +pub struct LazyVecFrom3 +where + S1T: Clone, + S2T: Clone, + S3T: Clone, +{ + name: String, + version: Version, + source1: BoxedAnyIterableVec, + source2: BoxedAnyIterableVec, + source3: BoxedAnyIterableVec, + compute: ComputeFrom3, +} + +impl LazyVecFrom3 +where + I: StoredIndex, + T: StoredType, + S1I: StoredIndex, + S1T: StoredType, + S2I: StoredIndex, + S2T: StoredType, + S3I: StoredIndex, + S3T: StoredType, +{ + pub fn init( + name: &str, + version: Version, + source1: BoxedAnyIterableVec, + source2: BoxedAnyIterableVec, + source3: BoxedAnyIterableVec, + compute: ComputeFrom3, + ) -> Self { + if ([ + source1.index_type_to_string(), + source2.index_type_to_string(), + source3.index_type_to_string(), + ]) + .into_iter() + .filter(|t| *t == I::to_string()) + .count() + == 0 + { + panic!("At least one should have same index"); + } + + Self { + name: name.to_string(), + version, + source1, + source2, + source3, + compute, + } + } + + fn version(&self) -> Version { + self.version + } +} + +pub struct LazyVecFrom3Iterator<'a, I, T, S1I, S1T, S2I, S2T, S3I, S3T> +where + S1T: Clone, + S2T: Clone, + S3T: Clone, +{ + lazy: &'a LazyVecFrom3, + source1: BoxedVecIterator<'a, S1I, S1T>, + source2: BoxedVecIterator<'a, S2I, S2T>, + source3: BoxedVecIterator<'a, S3I, S3T>, + index: usize, +} + +impl<'a, I, T, S1I, S1T, S2I, S2T, S3I, S3T> Iterator + for LazyVecFrom3Iterator<'a, I, T, S1I, S1T, S2I, S2T, S3I, S3T> +where + I: StoredIndex, + T: StoredType + 'a, + S1I: StoredIndex, + S1T: StoredType, + S2I: StoredIndex, + S2T: StoredType, + S3I: StoredIndex, + S3T: StoredType, +{ + type Item = (I, Cow<'a, T>); + + fn next(&mut self) -> Option { + let index = I::from(self.index); + let opt = (self.lazy.compute)( + index, + &mut *self.source1, + &mut *self.source2, + &mut *self.source3, + ) + .map(|v| (index, Cow::Owned(v))); + if opt.is_some() { + self.index += 1; + } + opt + } +} + +impl BaseVecIterator + for LazyVecFrom3Iterator<'_, I, T, S1I, S1T, S2I, S2T, S3I, S3T> +where + I: StoredIndex, + T: StoredType, + S1I: StoredIndex, + S1T: StoredType, + S2I: StoredIndex, + S2T: StoredType, + S3I: StoredIndex, + S3T: StoredType, +{ + #[inline] + fn mut_index(&mut self) -> &mut usize { + &mut self.index + } + + #[inline] + fn len(&self) -> usize { + let len1 = if self.source1.index_type_to_string() == I::to_string() { + self.source1.len() + } else { + usize::MAX + }; + let len2 = if self.source2.index_type_to_string() == I::to_string() { + self.source2.len() + } else { + usize::MAX + }; + let len3 = if self.source3.index_type_to_string() == I::to_string() { + self.source3.len() + } else { + usize::MAX + }; + len1.min(len2).min(len3) + } + + #[inline] + fn name(&self) -> &str { + self.source1.name() + } +} + +impl<'a, I, T, S1I, S1T, S2I, S2T, S3I, S3T> IntoIterator + for &'a LazyVecFrom3 +where + I: StoredIndex, + T: StoredType + 'a, + S1I: StoredIndex, + S1T: StoredType, + S2I: StoredIndex, + S2T: StoredType, + S3I: StoredIndex, + S3T: StoredType, +{ + type Item = (I, Cow<'a, T>); + type IntoIter = LazyVecFrom3Iterator<'a, I, T, S1I, S1T, S2I, S2T, S3I, S3T>; + + fn into_iter(self) -> Self::IntoIter { + LazyVecFrom3Iterator { + lazy: self, + source1: self.source1.iter(), + source2: self.source2.iter(), + source3: self.source3.iter(), + index: 0, + } + } +} + +impl AnyVec for LazyVecFrom3 +where + I: StoredIndex, + T: StoredType, + S1I: StoredIndex, + S1T: StoredType, + S2I: StoredIndex, + S2T: StoredType, + S3I: StoredIndex, + S3T: StoredType, +{ + fn version(&self) -> Version { + self.version() + } + + fn name(&self) -> &str { + self.name.as_str() + } + + fn index_type_to_string(&self) -> &'static str { + I::to_string() + } + + fn len(&self) -> usize { + let len1 = if self.source1.index_type_to_string() == I::to_string() { + self.source1.len() + } else { + usize::MAX + }; + let len2 = if self.source2.index_type_to_string() == I::to_string() { + self.source2.len() + } else { + usize::MAX + }; + let len3 = if self.source3.index_type_to_string() == I::to_string() { + self.source3.len() + } else { + usize::MAX + }; + len1.min(len2).min(len3) + } + + #[inline] + fn value_type_to_size_of(&self) -> usize { + size_of::() + } +} + +impl AnyIterableVec + for LazyVecFrom3 +where + I: StoredIndex, + T: StoredType, + S1I: StoredIndex, + S1T: StoredType, + S2I: StoredIndex, + S2T: StoredType, + S3I: StoredIndex, + S3T: StoredType, +{ + fn boxed_iter<'a>(&'a self) -> BoxedVecIterator<'a, I, T> + where + T: 'a, + { + Box::new(self.into_iter()) + } +} + +impl AnyCollectableVec + for LazyVecFrom3 +where + I: StoredIndex, + T: StoredType, + S1I: StoredIndex, + S1T: StoredType, + S2I: StoredIndex, + S2T: StoredType, + S3I: StoredIndex, + S3T: StoredType, +{ + fn collect_range_serde_json( + &self, + from: Option, + to: Option, + ) -> Result> { + CollectableVec::collect_range_serde_json(self, from, to) + } +} diff --git a/crates/brk_vecs/src/variants/lazy/mod.rs b/crates/brk_vecs/src/variants/lazy/mod.rs new file mode 100644 index 000000000..490b7f251 --- /dev/null +++ b/crates/brk_vecs/src/variants/lazy/mod.rs @@ -0,0 +1,7 @@ +mod lazy1; +mod lazy2; +mod lazy3; + +pub use lazy1::*; +pub use lazy2::*; +pub use lazy3::*;