Skip to main content

csc_7b_fc/
bijectivemap.rs

1//! Skeleton module for the bijective hashmap assignment.
2//!
3//! Be sure to read the assignment description in the
4//! **[C++ version](https://github.com/chuckcscccl/csc_7b_fc/blob/main/src/bijectivemap.cpp)** of this
5//! program that you're supposed to emulate.
6//!
7//! This module currently compiles and provides you with some helpful code,
8//! but there are four methods that you must implement properly
9//! (see documentation for each [BijectiveMap] method).
10//!
11//! Go into the `csc_7b_fc` crate and `git pull` the latest updates.  Then
12//! `cargo new` a fresh crate for your assignment and optionally add the `path` to
13//! `csc_7b_fc` to Cargo.toml as you did for the first Rust assignment.
14//!
15//! Do not touch the `csc_7b_fc` crate.  Copy the `bijectivemap.rs` file
16//! to the src directory of your own crate, then
17//! place the following in the main.rs of your crate.
18//! ```
19//!    mod bijectivemap;
20//!    use bijectivemap::*;
21//! ```
22//!
23//! **NOTE: DO NOT EDIT THE csc_7b_fc CRATE. Copy the skeleton code to
24//!       your own crate!**
25//!
26//! When you have completed the implementation, emulate the main in the
27//! C++ program to test it.  It can begin with ...
28//!```
29//!    let mut daynum:BijectiveMap<&'static str,u8> = BijectiveMap::new();
30//!    let days = ["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"];
31//!    for i in 0..days.len() { daynum.set(days[i],(i+1) as u8); }
32//!    daynum.get_by_key(&"Wednesday").map(|d|{
33//!      println!("Wednesday is day {}",d);
34//!    });
35//!```
36//!The `studenthasher` component that tests hash collisions is optional.
37//!
38#![allow(unused_mut)]
39use std::collections::{hash_map::RandomState, HashMap};
40use std::hash::{BuildHasher, Hash, Hasher};
41
42///The `HashStealer` struct and methods allows you to "steal" the hash functions
43///from Rust, and base_hash can be called on any key that implements Hash+Eq.
44///Hashing requires equality and must be consistent with it: if x==y then
45///hash(x)==hash(y).
46
47pub struct HashStealer {
48    state: RandomState,
49}
50impl HashStealer {
51    /// creates a new hash stealer. Here, `Self` refers to the type being
52    /// "impl"ed while `self` refers to the current instance of `Self`.
53    pub fn new() -> Self {
54        HashStealer {
55            state: RandomState::new(),
56        }
57    } //new
58
59    /// do what's needed to return a hash value on any hashable key
60    pub fn base_hash<K: Hash + Eq>(&mut self, key: &K) -> usize {
61        let mut builder = self.state.build_hasher();
62        key.hash(&mut builder);
63        builder.finish() as usize
64    } //base_hash
65} //impl HashStealer
66
67/// This is your bijective map struct
68pub struct BijectiveMap<KT, VT, const CAP: usize = 16> {
69    keys: HashMap<usize, Vec<(KT, usize, usize)>>,
70    vals: HashMap<usize, Vec<(VT, usize, usize)>>,
71    size: usize,
72    hasher: HashStealer,
73} // struct BijectiveMap
74
75// some more code to get you started ...
76// Under no circumstances can KT, VT impl any trait other than Hash and Eq:
77impl<KT: Hash + Eq, VT: Hash + Eq, const CAP: usize> BijectiveMap<KT, VT, CAP> {
78    // non-public internal function to use HashStealer
79    fn hash<K: Hash + Eq>(&mut self, key: &K) -> usize {
80        self.hasher.base_hash(key)
81    } //hash
82
83    /// creates a new BijectiveMap with default initial capacity:
84    pub fn new() -> Self {
85        // Self refers to this TYPE, BijectiveMap
86        BijectiveMap {
87            keys: HashMap::with_capacity(CAP), // just initial capacity
88            vals: HashMap::with_capacity(CAP), // can expand if needed
89            size: 0,
90            hasher: HashStealer::new(),
91        }
92    } //new
93
94    /// Returns a immutable reference to the value corresponding to
95    /// the given key, if it exists.  Note that there can't be a
96    /// `Option<&mut T>` version of this method because changing the
97    /// value will require adjusting other associations in the map.
98    /// This function has been completed and you can consult its source
99    /// as hint.
100    pub fn get_by_key(&mut self, key: &KT) -> Option<&VT> {
101        let hk = self.hash(key);
102        if !self.keys.contains_key(&hk) {
103            return None;
104        }
105        for (k, vr, vc) in self.keys[&hk].iter() {
106            if k == key {
107                return Some(&self.vals[vr][*vc].0); //.0 is first in tuple
108            }
109        }
110        None
111    } //get
112} // impl
113
114/// **Place all your code in another impl block, and fully implement the
115/// methods** [BijectiveMap::get_by_val], [BijectiveMap::take_by_key],
116/// [BijectiveMap::take_by_val], and [BijectiveMap::set].
117impl<KT: Hash + Eq, VT: Hash + Eq, const CAP: usize> BijectiveMap<KT, VT, CAP> {
118    /// Returns number of key-value pairs in this map.
119    /// This one's too easy so I just did it for you again.  I will give
120    /// away more stuff if you come to me for help ...
121    pub fn len(&self) -> usize {
122        self.size
123    }
124
125    /// **This is the first method you need to implement.**
126    /// Returns an immutable reference to the key associated with the
127    /// given value, if it exists. The dummy provided here just returns
128    /// `None` and you need to rewrite it appropriately.
129    pub fn get_by_val(&mut self, val: &VT) -> Option<&KT> {
130        None
131    }
132
133    /// This is another method you need to implement.
134    /// Removes key-value pair from map by searching for it by key.
135    /// Returns the key and value if found.  Note that this function
136    /// is "take" and not "get" because it **moves** the actual key and value
137    /// out of the map.  It doesn't return references.  Sometimes you
138    /// may need to convert an `Option<T>` to an `Option<&T>`.  To do
139    /// that, given such an `Option<T>` `opt`, use the expression `opt.as_ref()`.
140    ///
141    /// The dummy implemenetation provided here just returns `None`
142    pub fn take_by_key(&mut self, key: &KT) -> Option<(KT, VT)> {
143        None
144    }
145
146    /// Dummies always return `None`.  Are you a dummy?
147    pub fn take_by_val(&mut self, val: &VT) -> Option<(KT, VT)> {
148        None
149    }
150
151    /// Change or add key-val pair, return a pair to represent information
152    /// that was deleted.  Note that the returned key,value, if they
153    /// exist, may indicate a different key or value that existed in the
154    /// map before the change (see "daynum" example that you should
155    /// replicate in main).  Replace the dummy implementation.
156    pub fn set(&mut self, mut key: KT, mut val: VT) -> Option<(KT, VT)> {
157        None
158    }
159} // can have multiple impl blocks