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