diff --git a/core/src/api.rs b/core/src/api.rs index 76cab3e..c8b1553 100644 --- a/core/src/api.rs +++ b/core/src/api.rs @@ -2,20 +2,31 @@ use std::collections::HashSet; use std::fmt::Debug; use crate::storage::{ - frozen_global_storage, Entry, GetOrElse, MultipleVersion, Tree, THREAD_STORAGE, + frozen_global_storage, Entry, GetOrElse, MultipleVersion, Params, THREAD_STORAGE, }; use crate::value::{Value, EMPTY}; use crate::xxh::XXHashable; +/// ParameterScope +/// +/// `ParameterScope` is a data structure that stores the current set of named parameters +/// and their values. `ParameterScope` is used to manage the scope of named parameters, +/// allowing parameters to be defined and used within a specific scope, +/// and then restored to the previous scope when the scope is exited. +/// +/// The parameter scope can be used to implement a variety of features, such +/// as named parameters, default parameter values, and parameter inheritance. #[derive(Debug, Clone)] pub enum ParamScope { + /// No parameters are defined in the current scope. Nothing, - Just(Tree), + /// The current scope contains a set of named parameters stored in `Params`. + Just(Params), } impl Default for ParamScope { fn default() -> Self { - ParamScope::Just(Tree::new()) + ParamScope::Just(Params::new()) } } @@ -505,3 +516,88 @@ mod tests { } } } + +// FILEPATH: /home/reiase/workspace/hyperparameter/core/src/api.rs +// BEGIN: test_code + +#[cfg(test)] +mod test_param_scope { + use super::*; + use std::convert::TryInto; + + #[test] + fn test_param_scope_default() { + let ps = ParamScope::default(); + match ps { + ParamScope::Just(_) => assert!(true), + _ => assert!(false, "Default ParamScope should be ParamScope::Just"), + } + } + + #[test] + fn test_param_scope_from_vec() { + let vec = vec!["param1=value1", "param2=value2"]; + let ps: ParamScope = (&vec).into(); + match ps { + ParamScope::Just(params) => { + assert_eq!(params.get(&"param1".xxh()).unwrap().value(), &Value::from("value1")); + assert_eq!(params.get(&"param2".xxh()).unwrap().value(), &Value::from("value2")); + } + _ => assert!(false, "ParamScope should be ParamScope::Just"), + } + } + + #[test] + fn test_param_scope_get_with_hash() { + let mut ps = ParamScope::default(); + ps.add("param=value"); + let value = ps.get_with_hash("param".xxh()); + assert_eq!(value, Value::from("value")); + } + + #[test] + fn test_param_scope_get() { + let mut ps = ParamScope::default(); + ps.add("param=value"); + let value: String = ps.get("param").try_into().unwrap(); + assert_eq!(value, "value"); + } + + #[test] + fn test_param_scope_add() { + let mut ps = ParamScope::default(); + ps.add("param=value"); + match ps { + ParamScope::Just(params) => { + assert_eq!(params.get(&"param".xxh()).unwrap().value(), &Value::from("value")); + } + _ => assert!(false, "ParamScope should be ParamScope::Just"), + } + } + + #[test] + fn test_param_scope_keys() { + let mut ps = ParamScope::default(); + ps.add("param=value"); + let keys = ps.keys(); + assert_eq!(keys, vec!["param"]); + } + + #[test] + fn test_param_scope_enter_exit() { + let mut ps = ParamScope::default(); + ps.add("param=value"); + ps.enter(); + match ps { + ParamScope::Nothing => assert!(true), + _ => assert!(false, "ParamScope should be ParamScope::Nothing after enter"), + } + ps.exit(); + match ps { + ParamScope::Just(_) => assert!(true), + _ => assert!(false, "ParamScope should be ParamScope::Just after exit"), + } + } +} + +// END: test_code \ No newline at end of file diff --git a/core/src/storage.rs b/core/src/storage.rs index 84de864..f84ae75 100644 --- a/core/src/storage.rs +++ b/core/src/storage.rs @@ -40,7 +40,7 @@ impl Entry { } } -pub type Tree = BTreeMap; +pub type Params = BTreeMap; pub trait MultipleVersion { fn update>(&mut self, key: K, val: V); @@ -48,15 +48,17 @@ pub trait MultipleVersion { fn rollback(&mut self, key: K); } -impl MultipleVersion for Tree { +impl MultipleVersion for Params { fn update>(&mut self, key: u64, val: V) { - self.entry(key).and_modify(|e| { + if let Some(e) = self.get_mut(&key) { e.val.update(val); - }); + } } fn revision>(&mut self, key: u64, val: V) { - self.entry(key).and_modify(|e| e.val.revision(val)); + if let Some(e) = self.get_mut(&key) { + e.val.revision(val); + } } fn rollback(&mut self, key: u64) { @@ -75,8 +77,8 @@ thread_local! { fn create_thread_storage() -> RefCell { let ts = RefCell::new(Storage::default()); ts.borrow_mut() - .tree - .clone_from(&GLOBAL_STORAGE.lock().unwrap().tree); + .params + .clone_from(&GLOBAL_STORAGE.lock().unwrap().params); ts } @@ -89,14 +91,14 @@ pub fn frozen_global_storage() { GLOBAL_STORAGE .lock() .unwrap() - .tree - .clone_from(&ts.borrow().tree); + .params + .clone_from(&ts.borrow().params); }); } #[derive(Debug)] pub struct Storage { - pub tree: Tree, + pub params: Params, pub history: Vec>, } @@ -105,7 +107,7 @@ unsafe impl Send for Storage {} impl Default for Storage { fn default() -> Self { Storage { - tree: Tree::new(), + params: Params::new(), history: vec![HashSet::new()], } } @@ -116,30 +118,30 @@ impl Storage { self.history.push(HashSet::new()); } - pub fn exit(&mut self) -> Tree { - let mut changes = Tree::new(); + pub fn exit(&mut self) -> Params { + let mut changes = Params::new(); for key in self.history.pop().unwrap() { - changes.insert(key, self.tree.get(&key).unwrap().shallow()); - self.tree.rollback(key); + changes.insert(key, self.params.get(&key).unwrap().shallow()); + self.params.rollback(key); } changes } pub fn get_entry(&self, key: u64) -> Option<&Entry> { - self.tree.get(&key) + self.params.get(&key) } pub fn put_entry(&mut self, key: u64, entry: Entry) -> Option { - self.tree.insert(key, entry) + self.params.insert(key, entry) } pub fn del_entry(&mut self, key: u64) { - self.tree.remove(&key); + self.params.remove(&key); } pub fn get(&self, key: T) -> &Value { let hkey = key.xxh(); - if let Some(e) = self.tree.get(&hkey) { + if let Some(e) = self.params.get(&hkey) { e.value() } else { &EMPTY @@ -150,15 +152,15 @@ impl Storage { let hkey = key.xxh(); let key: String = key.into(); if self.history.last().unwrap().contains(&hkey) { - self.tree.update(hkey, val); + self.params.update(hkey, val); } else { - if let std::collections::btree_map::Entry::Vacant(e) = self.tree.entry(hkey) { + if let std::collections::btree_map::Entry::Vacant(e) = self.params.entry(hkey) { e.insert(Entry { key, val: VersionedValue::from(val.into()), }); } else { - self.tree.revision(hkey, val); + self.params.revision(hkey, val); } self.history.last_mut().unwrap().insert(hkey); } @@ -167,15 +169,15 @@ impl Storage { pub fn del(&mut self, key: T) { let hkey = key.xxh(); if self.history.last().unwrap().contains(&hkey) { - self.tree.update(hkey, None::); + self.params.update(hkey, None::); } else { - self.tree.revision(hkey, None::); + self.params.revision(hkey, None::); self.history.last_mut().unwrap().insert(hkey); } } pub fn keys(&self) -> Vec { - self.tree + self.params .values() .filter(|x| !matches!(x.value(), Value::Empty)) .map(|x| x.key.clone()) @@ -202,7 +204,7 @@ where T: Into + TryFrom + for<'a> TryFrom<&'a Value>, { fn get_or_else(&self, key: u64, dval: T) -> T { - if let Some(val) = self.tree.get(&key) { + if let Some(val) = self.params.get(&key) { match val.value().try_into() { Ok(v) => v, Err(_) => dval, diff --git a/core/src/value.rs b/core/src/value.rs index 540a57c..46120c4 100644 --- a/core/src/value.rs +++ b/core/src/value.rs @@ -39,13 +39,7 @@ pub const EMPTY: Value = Value::Empty; impl> From> for Value { fn from(value: Option) -> Self { - match value { - Some(x) => { - let y: Value = x.into(); - y - } - None => Value::Empty, - } + value.map_or(Value::Empty, |x| x.into()) } } @@ -63,7 +57,7 @@ impl From for Value { impl From for Value { fn from(value: f32) -> Self { - Value::Float(value.into()) + Value::Float(value as f64) } } @@ -81,7 +75,7 @@ impl From for Value { impl From<&String> for Value { fn from(value: &String) -> Self { - Value::Text(value.clone()) + Value::Text(value.to_string()) } } diff --git a/core/src/xxh.rs b/core/src/xxh.rs index 69c4436..8ac78ca 100644 --- a/core/src/xxh.rs +++ b/core/src/xxh.rs @@ -29,15 +29,13 @@ impl XXHashable for &str { impl XXHashable for CStr { fn xxh(&self) -> u64 { - let bs = self.to_bytes(); - xxhash(bs) + xxhash(self.to_bytes()) } } impl XXHashable for CString { fn xxh(&self) -> u64 { - let bs = self.to_bytes(); - xxhash(bs) + xxhash(self.to_bytes()) } }