x_map/
maps.rs

1use std::alloc::Layout;
2use std::ptr;
3use crate::error::MapError;
4
5#[derive(Debug)]
6pub struct KeyValue<'a, K, V> {
7    key: &'a K,
8    value: &'a V,
9}
10
11impl<'a, K, V> KeyValue<'a, K, V> {
12    pub fn key(&self) -> &'a K {
13        &self.key
14    }
15
16    pub fn value(&self) -> &'a V {
17        &self.value
18    }
19}
20
21#[derive(Debug)]
22pub struct CIndexMap<K, V> {
23    key_layout: Layout,
24    val_layout: Layout,
25    keys: *mut K,
26    values: *mut V,
27
28    /// The total allocated memory for this map.
29    ///
30    /// Everything in the range `self.pos + 1..self.cap` is not uninitialized, but may be old
31    /// or unwanted.
32    cap: isize,
33
34    /// Position of the cursor where the **last valid value** was inserted. `keys[pos]` and
35    /// `values[pos]` will always be initialized with valid data.
36    ///
37    /// All elements 0 to `self.pos` are guaranteed to be initialized.
38    pos: isize,
39}
40
41impl<K, V> CIndexMap<K, V> {
42    /// Constructs a new `CIndexMap`.
43    ///
44    /// # Panics
45    /// When `size_of::<K>` or `size_of::<T>` is 0.
46    pub fn new() -> CIndexMap<K, V> {
47        if size_of::<K>() == 0 || size_of::<V>() == 0 {
48            panic!("Cannot initialize CIndexMap with ZSTs!");
49        }
50
51        let key_layout = unsafe {
52            Layout::from_size_align(size_of::<K>() * 1, align_of::<K>()).unwrap()
53        };
54        let val_layout = unsafe {
55            Layout::from_size_align(size_of::<V>() * 1, align_of::<V>()).unwrap()
56        };
57
58        // SAFETY:
59        // ZSTs are not supported, this point in the initializing cannot be reached
60        // if a ZST is provided.
61        let key_ptr = unsafe {
62            std::alloc::alloc(key_layout)
63        } as *mut K;
64
65        // SAFETY:
66        // ZSTs are not supported, this point in the initializing cannot be reached
67        // if a ZST is provided.
68        let val_ptr = unsafe {
69            std::alloc::alloc(val_layout)
70        } as *mut V;
71
72        CIndexMap {
73            key_layout,
74            val_layout,
75            keys: key_ptr,
76            values: val_ptr,
77            cap: 1,
78            pos: -1,
79        }
80    }
81
82    /// Inserts a new key/value pair into the map.
83    ///
84    /// This function returns `Ok(())` if the key/value pair was inserted successfully.
85    pub fn insert(&mut self, key: K, value: V) -> crate::result::Result<()> {
86        if (self.pos + 1) >= self.cap {
87            let new_cap = self.cap + 2;
88
89            let new_key_ptr = unsafe {
90                std::alloc::realloc(
91                    self.keys as *mut u8,
92                    self.key_layout,
93                    size_of::<K>() * (new_cap as usize)
94                ) as *mut K
95            };
96
97            let new_val_ptr = unsafe {
98                std::alloc::realloc(
99                    self.values as *mut u8,
100                    self.val_layout,
101                    size_of::<V>() * (new_cap as usize)
102                ) as *mut V
103            };
104
105            self.keys = new_key_ptr;
106            self.values = new_val_ptr;
107            self.cap = new_cap;
108        }
109
110        self.pos += 1;
111
112        // SAFETY:
113        // The data was properly aligned during initialization.
114        // The memory being pointed to was verified to be between 0 (the pointer starting position)
115        // and `self.cap`, which is the current amount of allocated space.
116        unsafe {
117            self.keys.offset(self.pos).write(key);
118            self.values.offset(self.pos).write(value);
119        }
120
121        Ok(())
122    }
123
124    /// Removes an element at the specified index.
125    pub fn remove(&mut self, index: usize) -> crate::result::Result<()> {
126        if index > (self.pos as usize) {
127            Err(MapError {})
128        } else {
129            // SAFETY:
130            // We've determined that the index requested fits within the range of valid data.
131            unsafe {
132                // Shift all elements between `index` and `self.pos` back by one by copying
133                // the pointer and overwriting it at the position specified by `index`.
134                ptr::copy(
135                    self.keys.offset((index as isize) + 1),
136                    self.keys.offset(index as isize),
137                    (self.pos as usize - index)
138                );
139
140                ptr::copy(
141                    self.values.offset((index as isize) + 1),
142                    self.values.offset(index as isize),
143                    self.pos as usize - index
144                );
145            }
146
147            // Decrement self.pos to ensure this is always set as the position of the
148            // last valid inserted value.
149            self.pos -= 1;
150            Ok(())
151        }
152    }
153
154    /// Returns the key/object pair based on insertion order.
155    pub fn index(&self, index: usize) -> Option<KeyValue<K, V>> {
156        if index > (self.pos as usize) {
157            None
158        } else {
159            // SAFETY:
160            // All elements `0..self.pos` should be already be initialized.
161            unsafe {
162                Some(
163                    KeyValue {
164                        key: &*self.keys.offset(index as isize),
165                        value: &*self.values.offset(index as isize)
166                    }
167                )
168            }
169        }
170    }
171}