// 960: Key-Value Store
// OCaml: Hashtbl (mutable) or association list (functional)
// Rust: HashMap<String, String> (mutable) or BTreeMap for sorted iteration
use std::collections::HashMap;
// Approach 1: HashMap-based mutable store
pub struct KvStore {
data: HashMap<String, String>,
}
impl KvStore {
pub fn new() -> Self {
KvStore { data: HashMap::new() }
}
pub fn set(&mut self, key: impl Into<String>, value: impl Into<String>) {
self.data.insert(key.into(), value.into());
}
pub fn get(&self, key: &str) -> Option<&str> {
self.data.get(key).map(|s| s.as_str())
}
pub fn delete(&mut self, key: &str) -> bool {
self.data.remove(key).is_some()
}
pub fn contains(&self, key: &str) -> bool {
self.data.contains_key(key)
}
pub fn keys(&self) -> Vec<&str> {
let mut keys: Vec<&str> = self.data.keys().map(|s| s.as_str()).collect();
keys.sort();
keys
}
pub fn values(&self) -> Vec<&str> {
self.data.values().map(|s| s.as_str()).collect()
}
pub fn size(&self) -> usize {
self.data.len()
}
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
}
impl Default for KvStore {
fn default() -> Self {
Self::new()
}
}
// Approach 2: Functional (immutable) KV using Vec of pairs
#[derive(Clone, Debug)]
pub struct FunctionalStore<V: Clone> {
data: Vec<(String, V)>,
}
impl<V: Clone> FunctionalStore<V> {
pub fn new() -> Self {
FunctionalStore { data: vec![] }
}
pub fn set(&self, key: impl Into<String>, value: V) -> Self {
let key = key.into();
let mut data: Vec<(String, V)> = self.data.iter()
.filter(|(k, _)| k != &key)
.cloned()
.collect();
data.insert(0, (key, value));
FunctionalStore { data }
}
pub fn get(&self, key: &str) -> Option<&V> {
self.data.iter().find(|(k, _)| k == key).map(|(_, v)| v)
}
pub fn delete(&self, key: &str) -> Self {
let data = self.data.iter().filter(|(k, _)| k != key).cloned().collect();
FunctionalStore { data }
}
pub fn keys(&self) -> Vec<&str> {
self.data.iter().map(|(k, _)| k.as_str()).collect()
}
}
impl<V: Clone> Default for FunctionalStore<V> {
fn default() -> Self {
Self::new()
}
}
fn main() {
let mut store = KvStore::new();
store.set("name", "Alice");
store.set("age", "30");
store.set("city", "Amsterdam");
println!("name: {:?}", store.get("name"));
println!("missing: {:?}", store.get("missing"));
println!("size: {}", store.size());
println!("keys: {:?}", store.keys());
store.delete("age");
println!("after delete, size: {}", store.size());
let fs: FunctionalStore<i32> = FunctionalStore::new();
let fs = fs.set("x", 1).set("y", 2).set("x", 10);
println!("\nfunctional x: {:?}", fs.get("x"));
println!("functional y: {:?}", fs.get("y"));
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_mutable_store() {
let mut s = KvStore::new();
assert_eq!(s.size(), 0);
assert!(s.is_empty());
s.set("name", "Alice");
s.set("age", "30");
s.set("city", "Amsterdam");
assert_eq!(s.get("name"), Some("Alice"));
assert_eq!(s.get("age"), Some("30"));
assert_eq!(s.get("missing"), None);
assert!(s.contains("city"));
assert!(!s.contains("missing"));
assert_eq!(s.size(), 3);
}
#[test]
fn test_update() {
let mut s = KvStore::new();
s.set("name", "Alice");
s.set("name", "Bob");
assert_eq!(s.get("name"), Some("Bob"));
assert_eq!(s.size(), 1);
}
#[test]
fn test_delete() {
let mut s = KvStore::new();
s.set("name", "Alice");
s.set("age", "30");
let removed = s.delete("age");
assert!(removed);
assert_eq!(s.get("age"), None);
assert_eq!(s.size(), 1);
assert!(!s.delete("missing"));
}
#[test]
fn test_keys_sorted() {
let mut s = KvStore::new();
s.set("city", "Amsterdam");
s.set("name", "Alice");
assert_eq!(s.keys(), vec!["city", "name"]);
}
#[test]
fn test_functional_store() {
let fs: FunctionalStore<i32> = FunctionalStore::new();
let fs = fs.set("x", 1);
let fs = fs.set("y", 2);
let fs = fs.set("x", 10); // update
assert_eq!(fs.get("x"), Some(&10));
assert_eq!(fs.get("y"), Some(&2));
assert_eq!(fs.get("z"), None);
let fs2 = fs.delete("y");
assert_eq!(fs2.get("y"), None);
assert_eq!(fs.get("y"), Some(&2)); // original unchanged
}
}
(* 960: Key-Value Store *)
(* Simple in-memory KV store using Hashtbl *)
(* Approach 1: Hashtbl-based store with functional interface *)
type 'a store = (string, 'a) Hashtbl.t
let create () : 'a store = Hashtbl.create 16
let set store key value =
Hashtbl.replace store key value
let get store key =
Hashtbl.find_opt store key
let delete store key =
Hashtbl.remove store key
let keys store =
Hashtbl.fold (fun k _ acc -> k :: acc) store []
let values store =
Hashtbl.fold (fun _ v acc -> v :: acc) store []
let size store = Hashtbl.length store
let contains store key = Hashtbl.mem store key
(* Approach 2: Functional (immutable) KV using association list *)
type 'a fstore = (string * 'a) list
let fset (store : 'a fstore) key value : 'a fstore =
(key, value) :: List.filter (fun (k, _) -> k <> key) store
let fget (store : 'a fstore) key =
List.assoc_opt key store
let fdelete (store : 'a fstore) key : 'a fstore =
List.filter (fun (k, _) -> k <> key) store
let fkeys (store : 'a fstore) =
List.map fst store
let () =
(* Mutable store *)
let s = create () in
assert (size s = 0);
set s "name" "Alice";
set s "age" "30";
set s "city" "Amsterdam";
assert (get s "name" = Some "Alice");
assert (get s "age" = Some "30");
assert (get s "missing" = None);
assert (contains s "city");
assert (not (contains s "missing"));
assert (size s = 3);
(* Update existing key *)
set s "name" "Bob";
assert (get s "name" = Some "Bob");
assert (size s = 3);
(* Delete *)
delete s "age";
assert (get s "age" = None);
assert (size s = 2);
let ks = List.sort compare (keys s) in
assert (ks = ["city"; "name"]);
(* Functional store *)
let fs = [] in
let fs = fset fs "x" 1 in
let fs = fset fs "y" 2 in
let fs = fset fs "x" 10 in (* update *)
assert (fget fs "x" = Some 10);
assert (fget fs "y" = Some 2);
assert (fget fs "z" = None);
let fs = fdelete fs "y" in
assert (fget fs "y" = None);
assert (fkeys fs = ["x"]);
Printf.printf "โ All tests passed\n"