Skip to content

Commit

Permalink
Add terrain crate
Browse files Browse the repository at this point in the history
  • Loading branch information
Manishearth committed Feb 17, 2021
1 parent 3be597c commit 8f2a5ac
Show file tree
Hide file tree
Showing 5 changed files with 179 additions and 0 deletions.
6 changes: 6 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ members = [
"tools/benchmark/macros",
"tools/benchmark/memory",
"utils/fixed_decimal",
"utils/terrain",
"utils/writeable",
]

Expand Down
9 changes: 9 additions & 0 deletions utils/terrain/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "terrain"
version = "0.1.0"
authors = ["Manish Goregaokar <[email protected]>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
18 changes: 18 additions & 0 deletions utils/terrain/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//! ## `terrain`
//!
//! `terrain` is a crate providing [`VecMap`], a highly simplistic "flat" key-value map
//! based off of a single sorted vector.
//!
//! The goal of this crate is to provide a map that is good enough for small
//! sizes, and does not carry the binary size impact of [`std::collections::HashMap`]
//! or [`std::collections::BTreeMap`].
//!
//! If binary size is not a concern, [`std::collections::BTreeMap`] may be a better choice
//! for your use case. It behaves very similarly to [`VecMap`] for less than 12 elements,
//! and upgrades itself gracefully for larger inputs.
//!

mod map;

pub use map::VecMap;
145 changes: 145 additions & 0 deletions utils/terrain/src/map.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
use std::mem;
use std::ops::{Index, IndexMut};

/// A simple "flat" map based on a sorted vector
///
/// See the [module level documentation][super] for why one should use this.
///
/// The API is roughly similar to that of [`std::collections::HashMap`], though it
/// requires `Ord` instead of `Hash`.
#[derive(Clone, Debug)]
pub struct VecMap<K, V> {
values: Vec<(K, V)>
}

impl<K, V> VecMap<K, V> {
/// Construct a new [`VecMap`]
pub fn new() -> Self {
Self::default()
}

/// The number of elements in the [`VecMap`]
pub fn len(&self) -> usize {
self.values.len()
}

/// Remove all elements from the [`VecMap`]
pub fn clear(&mut self) {
self.values.clear()
}

/// Reserve capacity for `additional` more elements to be inserted into
/// the [`VecMap`] to avoid frequent reallocations.
///
/// See [`Vec::reserve()`] for more information.
pub fn reserve(&mut self, additional: usize) {
self.values.reserve(additional)
}
}

impl<K: Ord, V> VecMap<K, V> {
/// Get the value associated with `key`, if it exists.
pub fn get(&self, key: &K) -> Option<&V> {
match self.values.binary_search_by(|k| k.0.cmp(&key)) {
Ok(found) => {
Some(&self.values[found].1)
}
Err(_) => {
None
}
}
}

/// Returns whether `key` is contained in this map
pub fn contains(&self, key: &K) -> bool {
self.values.binary_search_by(|k| k.0.cmp(&key)).is_ok()
}

/// Get the value associated with `key`, if it exists, as a mutable reference.
pub fn get_mut(&mut self, key: &K) -> Option<&mut V> {
match self.values.binary_search_by(|k| k.0.cmp(&key)) {
Ok(found) => {
Some(&mut self.values[found].1)
}
Err(_) => {
None
}
}
}

/// Appends `value` with `key` to the end of the underlying vector, returning
/// `value` _if it failed_. Useful for extending with an existing sorted list.
pub fn try_append(&mut self, key: K, value: V) -> Option<V> {
if let Some(ref last) = self.values.get(self.values.len() - 1) {
if last.0 > key {
return Some(value)
}
}

self.values.push((key, value));
None
}

/// Insert `value` with `key`, returning the existing value if it exists.
pub fn insert(&mut self, key: K, value: V) -> Option<V> {
match self.values.binary_search_by(|k| k.0.cmp(&key)) {
Ok(found) => {
Some(mem::replace(&mut self.values[found].1, value))
}
Err(ins) => {
self.values.insert(ins, (key, value));
None
}
}
}

/// Remove the value at `key`, returning it if it exists.
pub fn remove(&mut self, key: &K) -> Option<V> {
match self.values.binary_search_by(|k| k.0.cmp(key)) {
Ok(found) => {
Some(self.values.remove(found).1)
}
Err(_) => {
None
}
}
}
}

impl<K, V> Default for VecMap<K, V> {
fn default() -> Self {
VecMap {
values: vec![]
}
}
}
impl<K: Ord, V> Index<&'_ K> for VecMap<K, V> {
type Output = V;
fn index(&self, key: &K) -> &V {
self.get(key).expect("VecMap could not find key")
}
}
impl<K: Ord, V> IndexMut<&'_ K> for VecMap<K, V> {
fn index_mut(&mut self, key: &K) -> &mut V {
self.get_mut(key).expect("VecMap could not find key")
}
}


impl<K, V> VecMap<K, V> {
pub fn iter(&self) -> impl Iterator<Item=(&K, &V)> {
self.values.iter().map(|val| (&val.0, &val.1))
}

pub fn iter_keys(&self) -> impl Iterator<Item=&K> {
self.values.iter().map(|val| &val.0)
}

pub fn iter_values(&self) -> impl Iterator<Item=&V> {
self.values.iter().map(|val| &val.1)
}

pub fn iter_mut(&mut self) -> impl Iterator<Item=(&K, &mut V)> {
self.values.iter_mut().map(|val| (&val.0, &mut val.1))
}
}

0 comments on commit 8f2a5ac

Please sign in to comment.