1 // Copyright (c) 2016 The vulkano developers
2 // Licensed under the Apache License, Version 2.0
3 // <LICENSE-APACHE or
4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT
5 // license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
6 // at your option. All files in the project carrying such
7 // notice may not be copied, modified, or distributed except
8 // according to those terms.
9 
10 use ahash::HashMap;
11 use parking_lot::RwLock;
12 use std::{collections::hash_map::Entry, hash::Hash};
13 
14 /// A map specialized to caching properties that are specific to a Vulkan implementation.
15 ///
16 /// Readers never block each other, except when an entry is vacant. In that case it gets written to
17 /// once and then never again, entries are immutable after insertion.
18 #[derive(Debug)]
19 pub(crate) struct OnceCache<K, V> {
20     inner: RwLock<HashMap<K, V>>,
21 }
22 
23 impl<K, V> Default for OnceCache<K, V> {
default() -> Self24     fn default() -> Self {
25         OnceCache {
26             inner: RwLock::new(HashMap::default()),
27         }
28     }
29 }
30 
31 impl<K, V> OnceCache<K, V> {
32     /// Creates a new `OnceCache`.
new() -> Self33     pub fn new() -> Self {
34         Self::default()
35     }
36 }
37 
38 impl<K, V> OnceCache<K, V>
39 where
40     K: Eq + Hash,
41     V: Clone,
42 {
43     /// Returns the value for the specified `key`. The entry gets written to with the value
44     /// returned by `f` if it doesn't exist.
get_or_insert(&self, key: K, f: impl FnOnce(&K) -> V) -> V45     pub fn get_or_insert(&self, key: K, f: impl FnOnce(&K) -> V) -> V {
46         if let Some(value) = self.inner.read().get(&key) {
47             return value.clone();
48         }
49 
50         match self.inner.write().entry(key) {
51             Entry::Occupied(entry) => {
52                 // This can happen if someone else inserted an entry between when we released
53                 // the read lock and acquired the write lock.
54                 entry.get().clone()
55             }
56             Entry::Vacant(entry) => {
57                 let value = f(entry.key());
58                 entry.insert(value.clone());
59 
60                 value
61             }
62         }
63     }
64 
65     /// Returns the value for the specified `key`. The entry gets written to with the value
66     /// returned by `f` if it doesn't exist. If `f` returns [`Err`], the error is propagated and
67     /// the entry isn't written to.
get_or_try_insert<E>(&self, key: K, f: impl FnOnce(&K) -> Result<V, E>) -> Result<V, E>68     pub fn get_or_try_insert<E>(&self, key: K, f: impl FnOnce(&K) -> Result<V, E>) -> Result<V, E> {
69         if let Some(value) = self.inner.read().get(&key) {
70             return Ok(value.clone());
71         }
72 
73         match self.inner.write().entry(key) {
74             Entry::Occupied(entry) => {
75                 // This can happen if someone else inserted an entry between when we released
76                 // the read lock and acquired the write lock.
77                 Ok(entry.get().clone())
78             }
79             Entry::Vacant(entry) => {
80                 let value = f(entry.key())?;
81                 entry.insert(value.clone());
82 
83                 Ok(value)
84             }
85         }
86     }
87 }
88