Skip to content
Draft
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
27 changes: 27 additions & 0 deletions core/src/fixedvec.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use std::mem::MaybeUninit;

/// FixedVec is similar to `Vec`, but can't be resized beyond the compile-time spcecified size.
pub struct FixedVec<const N: usize, T> {
size: usize,
buf: [MaybeUninit<T>; N],
}

impl<const N: usize, T> Default for FixedVec<N, T> {
fn default() -> Self {
Self {
size: 0,
buf: [const { MaybeUninit::uninit() }; N],
}
}
}

impl<const N: usize, T> PartialEq for FixedVec<N, T>
where
T: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
todo!("missing")
}
}

impl<const N: usize, T> FixedVec<N, T> {}
73 changes: 73 additions & 0 deletions core/src/inlinemap.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
use std::{
collections::HashMap,
hash::{BuildHasher, Hash, RandomState},
};

use derive_where::derive_where;

use crate::fixedvec::FixedVec;

// TODO: Allow specifying N. for now let's say one, as it's cumbersome to support.
#[derive(Debug, Clone)]
#[derive_where(Default)]
#[derive_where(PartialEq; K: Eq + Hash, V: PartialEq, S: BuildHasher)]
#[derive_where(Eq; K: Eq + Hash, V: Eq, S: BuildHasher)]
pub struct InlineMap<K, V, S = RandomState> {
inner: InlineMapImpl<K, V, S>,
}

impl<K, V> InlineMap<K, V, RandomState> {
pub fn new() -> Self {
Self::with_capacity(0)
}

pub fn with_capacity(size: usize) -> Self {
Self {
inner: InlineMapImpl::with_capacity(size),
}
}
}

#[derive(Debug, Clone)]
#[derive_where(Default)]
#[derive_where(PartialEq; K: Eq + Hash, V: PartialEq, S: BuildHasher)]
#[derive_where(Eq; K: Eq + Hash, V: Eq, S: BuildHasher)]
enum InlineMapImpl<K, V, S = RandomState> {
#[derive_where(default)]
Small(Option<(K, V)>),
Large(HashMap<K, V, S>),
}

impl<K, V> InlineMapImpl<K, V, RandomState> {
fn with_capacity(size: usize) -> Self {
if size <= 1 {
Self::Small(None)
} else {
Self::Large(HashMap::with_capacity(size))
}
}
}
impl<K, V, S> InlineMapImpl<K, V, S>
where
K: Eq + Hash,
S: BuildHasher,
{
fn insert(&mut self, k: K, v: V) -> Option<V> {
let o = match self {
Self::Large(m) => return m.insert(k, v),
Self::Small(o) => o,
};
let (k1, _) = match o {
None => {
o.replace((k, v));
return None;
}
Some(x) => x,
};
if k == k1 {
o.replace((k, v)).map(|(_, val)| val)
} else {
*self = HashMap::from_iter([((k1,)), ()])
}
}
}
2 changes: 2 additions & 0 deletions core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
//! [okane](https://crates.io/crates/okane) CLI tool functionality,
//! withreusable components.

pub mod fixedvec;
pub mod format;
pub mod inlinemap;
pub mod load;
pub(crate) mod parse;
pub mod report;
Expand Down
16 changes: 11 additions & 5 deletions core/src/report/balance.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::collections::HashMap;
use crate::inlinemap::InlineMap;

use super::{
context::Account,
Expand All @@ -15,7 +15,7 @@ pub enum BalanceError {
/// Accumulated balance of accounts.
#[derive(Debug, Default, PartialEq, Eq, Clone)]
pub struct Balance<'ctx> {
accounts: HashMap<Account<'ctx>, Amount<'ctx>>,
accounts: InlineMap<Account<'ctx>, Amount<'ctx>>,
}

impl<'ctx> FromIterator<(Account<'ctx>, Amount<'ctx>)> for Balance<'ctx> {
Expand All @@ -24,9 +24,15 @@ impl<'ctx> FromIterator<(Account<'ctx>, Amount<'ctx>)> for Balance<'ctx> {
where
T: IntoIterator<Item = (Account<'ctx>, Amount<'ctx>)>,
{
Self {
accounts: iter.into_iter().collect(),
}
let iter = iter.into_iter();
let mut accounts = match iter.size_hint() {
(_, Some(size)) => InlineMap::with_capacity(size),
_ => InlineMap::new(),
};
iter.for_each(|(k, v)| {
accounts.insert(k, v);
});
Self { accounts }
}
}

Expand Down