chj_rustbin/
region.rs

1//! A region with lifetime tracking for ids and sync support.
2
3use std::convert::TryInto;
4use std::marker::PhantomData;
5use std::ops::{Deref, DerefMut};
6
7#[cfg(debug_assertions)]
8use crate::checked_mutex::{
9    CheckedMutex as Mutex, CheckedMutexGuard as MutexGuard,
10};
11#[cfg(not(debug_assertions))]
12use std::sync::{Mutex, MutexGuard};
13
14#[derive(Debug)]
15pub struct Region<'region, T> {
16    region_phantom: PhantomData<&'region T>,
17    region: Mutex<Vec<T>>,
18}
19
20// Do not implement Hash or Ordering, it would be confusing (this is
21// *not* interning, hence there is no way to get to the same id from
22// the same source object, and "pointer" comparisons normally do not
23// make sense)!
24#[derive(Debug, PartialEq)]
25pub struct RegionId<'region, T> {
26    region_phantom: PhantomData<&'region T>,
27    id: u32,
28}
29
30impl<'region, T> RegionId<'region, T> {
31    /// Use carefully.
32    pub fn as_index(self) -> usize {
33        self.id as usize
34    }
35}
36
37impl<'region, T> Clone for RegionId<'region, T> {
38    fn clone(&self) -> Self {
39        *self
40    }
41}
42
43impl<'region, T> Copy for RegionId<'region, T> {}
44
45// Have to do my own MappedMutexGuard since that is nightly only.
46pub struct MutexRef<'m, T: 'm, R, M: for<'g> Fn(&'g T) -> &'g R> {
47    guard: MutexGuard<'m, T>,
48    mapper: M,
49}
50
51impl<'m, T: 'm, R, M: for<'g> Fn(&'g T) -> &'g R> MutexRef<'m, T, R, M> {
52    pub fn map(guard: MutexGuard<'m, T>, mapper: M) -> Self {
53        MutexRef { guard, mapper }
54    }
55}
56
57impl<'m, T: 'm, R, M: for<'g> Fn(&'g T) -> &'g R> Deref
58    for MutexRef<'m, T, R, M>
59{
60    type Target = R;
61
62    fn deref(&self) -> &Self::Target {
63        (self.mapper)(&self.guard)
64    }
65}
66
67pub struct MutexRefMut<'m, T: 'm, R, M: for<'g> Fn(&'g mut T) -> &'g mut R> {
68    guard: MutexGuard<'m, T>,
69    mapper: M,
70}
71
72impl<'m, T: 'm, R, M: for<'g> Fn(&'g mut T) -> &'g mut R>
73    MutexRefMut<'m, T, R, M>
74{
75    pub fn map(guard: MutexGuard<'m, T>, mapper: M) -> Self {
76        MutexRefMut { guard, mapper }
77    }
78}
79
80// XX ah ok,  is &mut variant enough?  returning as &  anyway. 'weakening' the closure but fine?
81// -> no.  worse, deref not implementable huh
82
83impl<'m, T: 'm, R, M: for<'g> Fn(&'g mut T) -> &'g mut R> Deref
84    for MutexRefMut<'m, T, R, M>
85{
86    type Target = R;
87
88    fn deref(&self) -> &Self::Target {
89        // (self.mapper_mut)(&self.guard)
90        panic!("can't actually make deref workable for MutexRefMut?")
91    }
92}
93
94impl<'m, T: 'm, R, M: for<'g> Fn(&'g mut T) -> &'g mut R> DerefMut
95    for MutexRefMut<'m, T, R, M>
96{
97    fn deref_mut(&mut self) -> &mut Self::Target {
98        (self.mapper)(&mut self.guard)
99    }
100}
101
102impl<'region, T> Region<'region, T> {
103    pub fn new() -> Self {
104        Self {
105            region_phantom: Default::default(),
106            region: Mutex::new(Vec::new()),
107        }
108    }
109
110    /// Panics when allocating more than 2^32 items
111    pub fn store(&self, value: T) -> RegionId<'region, T> {
112        let mut region = self.region.lock().unwrap();
113        let id = RegionId {
114            region_phantom: Default::default(),
115            id: region.len().try_into().expect("fewer than 2^32 items"),
116        };
117        region.push(value);
118        id
119    }
120
121    /// Takes a mutex lock for the life time of MutexRef. To avoid
122    /// this cost for every access, use `lock` instead.  May panic on
123    /// invalid ids.
124    pub fn get<'m>(
125        &'m self,
126        id: RegionId<'m, T>,
127    ) -> MutexRef<'m, Vec<T>, T, impl for<'g> Fn(&'g Vec<T>) -> &'g T + 'm>
128    {
129        MutexRef::map(self.region.lock().unwrap(), move |r| &r[id.as_index()])
130    }
131
132    /// Takes a mutex lock for the life time of MutexRefMut. To avoid
133    /// this cost for every access, use `lock` instead.  May panic on
134    /// invalid ids.
135    pub fn get_mut<'m>(
136        &'m self,
137        id: RegionId<'m, T>,
138    ) -> MutexRefMut<
139        'm,
140        Vec<T>,
141        T,
142        impl for<'g> Fn(&'g mut Vec<T>) -> &'g mut T + 'm,
143    > {
144        MutexRefMut::map(self.region.lock().unwrap(), move |r| {
145            &mut r[id.as_index()]
146        })
147    }
148
149    /// Lock access to the region for the life time of the
150    /// `RegionGuard`. This makes multiple accesses of existing
151    /// entries more efficient.
152    pub fn lock<'m>(&'m self) -> RegionGuard<'m, T> {
153        RegionGuard {
154            region_guard: self.region.lock().unwrap(),
155        }
156    }
157}
158
159#[cfg(test)]
160mod tests {
161    use super::*;
162
163    // #[test]
164    // fn t_wrong_association() {
165    //     let region1 = Region::new();
166    //     let _p = {
167    //         let region2 = Region::new();
168    //         let p1 = region1.store(PathBuf::from("hi"));
169    //         let p2 = region2.store(PathBuf::from("hi2"));
170    //         println!("p1 from region1 = {:?}", &*region1.get(p1));
171    //         println!("p1 from region2 = {:?}", &*region2.get(p1));
172    //         println!("p2 from region1 = {:?}", &*region1.get(p2));
173    //         p1
174    //     };
175    //     panic!()
176    // }
177
178    struct Pair<'region, T> {
179        value: T,
180        prev: Option<RegionId<'region, Pair<'region, T>>>,
181        next: Option<RegionId<'region, Pair<'region, T>>>,
182    }
183
184    // impl<'region, T> Pair<'region, T> {
185    //     fn cons_left(
186    // }
187    // no, don't have a Pair just an id
188
189    // trait RegionTrait<'region, T> {
190    //     fn new() -> Self;
191    //     fn store(&self, value: T) -> RegionId<'region, T>;
192    //     fn get<'m>(
193    //         &'m self, id: RegionId<'m, T>
194    //     ) -> MutexRef<'m, Vec<T>, T,
195    //                   impl for<'g> Fn(&'g MutexGuard<Vec<T>>) -> &'g T + 'm>;
196    // }
197    //  ^ can't use impl in traits
198    //
199    // trait LinkedList<'region, T>: RegionTrait<'region, T> {
200    //     fn cons_left(
201    //         &self, val: T, right: Option<RegionId<'region, Pair<'region, T>>>
202    //     ) -> RegionId<'region, Pair<'region, T>> {
203    //         ...
204    //     }
205    // }
206
207    fn cons_left<'region, T>(
208        region: &Region<'region, Pair<'region, T>>,
209        value: T,
210        next: Option<RegionId<'region, Pair<'region, T>>>,
211    ) -> RegionId<'region, Pair<'region, T>> {
212        let id = region.store(Pair {
213            value,
214            next,
215            prev: None,
216        });
217        if let Some(next) = next {
218            let mut n = region.get_mut(next);
219            n.prev = Some(id);
220        }
221        id
222    }
223
224    #[test]
225    fn t_() {
226        let region = Region::new();
227        let c5 = cons_left(&region, 5, None);
228        let c4 = cons_left(&region, 4, Some(c5));
229        let c3 = cons_left(&region, 3, Some(c4));
230        assert_eq!(region.get(c3).value, 3);
231        // These deadlock!
232        // assert_eq!(region.get(region.get(c3).next.unwrap()).value, 4);
233        // assert_eq!(region.get(region.get(c5).prev.unwrap()).value, 4);
234
235        let c3_next = region.get(c3).next.unwrap();
236        assert_eq!(region.get(c3_next).value, 4);
237
238        let c5_prev = region.get(c5).prev.unwrap();
239        assert_eq!(region.get(c5_prev).value, 4);
240
241        assert_eq!(
242            region
243                .get({
244                    let x = region.get(c3).next.unwrap();
245                    x
246                })
247                .value,
248            4
249        );
250    }
251}
252
253// -----------------------------------------------------------------------------
254// Course-grained locking for better performance for batch accesses
255
256pub struct RegionGuard<'m, T> {
257    region_guard: MutexGuard<'m, Vec<T>>,
258}
259
260impl<'m, T> RegionGuard<'m, T> {
261    /// May panic on invalid ids.
262    pub fn get(&'m self, id: RegionId<'m, T>) -> &'m T {
263        &(*self.region_guard)[id.as_index()]
264    }
265
266    /// May panic on invalid ids.
267    pub fn get_mut(&'m mut self, id: RegionId<'m, T>) -> &'m mut T {
268        &mut (*self.region_guard)[id.as_index()]
269    }
270}