1use crate::internal_types::FastHashMap;
37use malloc_size_of::MallocSizeOf;
38use std::fmt::Debug;
39use std::hash::Hash;
40use std::marker::PhantomData;
41use std::{ops, u64};
42use crate::util::VecHelper;
43use crate::profiler::TransactionProfile;
44
45#[cfg_attr(feature = "capture", derive(Serialize))]
46#[cfg_attr(feature = "replay", derive(Deserialize))]
47#[derive(Debug, Copy, Clone, Hash, MallocSizeOf, PartialEq, Eq)]
48struct Epoch(u32);
49
50#[cfg_attr(feature = "capture", derive(Serialize))]
53#[cfg_attr(feature = "replay", derive(Deserialize))]
54#[derive(MallocSizeOf)]
55pub struct UpdateList<S> {
56 pub insertions: Vec<Insertion<S>>,
58
59 pub removals: Vec<Removal>,
61}
62
63#[cfg_attr(feature = "capture", derive(Serialize))]
64#[cfg_attr(feature = "replay", derive(Deserialize))]
65#[derive(MallocSizeOf)]
66pub struct Insertion<S> {
67 pub index: usize,
68 pub uid: ItemUid,
69 pub value: S,
70}
71
72#[cfg_attr(feature = "capture", derive(Serialize))]
73#[cfg_attr(feature = "replay", derive(Deserialize))]
74#[derive(MallocSizeOf)]
75pub struct Removal {
76 pub index: usize,
77 pub uid: ItemUid,
78}
79
80impl<S> UpdateList<S> {
81 fn new() -> UpdateList<S> {
82 UpdateList {
83 insertions: Vec::new(),
84 removals: Vec::new(),
85 }
86 }
87
88 fn take_and_preallocate(&mut self) -> UpdateList<S> {
89 UpdateList {
90 insertions: self.insertions.take_and_preallocate(),
91 removals: self.removals.take_and_preallocate(),
92 }
93 }
94}
95
96#[cfg_attr(feature = "capture", derive(Serialize))]
98#[cfg_attr(feature = "replay", derive(Deserialize))]
99#[derive(Debug, Copy, Clone, Eq, Hash, MallocSizeOf, PartialEq)]
100pub struct ItemUid {
101 uid: u64,
102}
103
104impl ItemUid {
105 pub fn get_uid(&self) -> u64 {
107 self.uid
108 }
109}
110
111#[cfg_attr(feature = "capture", derive(Serialize))]
112#[cfg_attr(feature = "replay", derive(Deserialize))]
113#[derive(Debug, Hash, MallocSizeOf, PartialEq, Eq)]
114pub struct Handle<I> {
115 index: u32,
116 epoch: Epoch,
117 _marker: PhantomData<I>,
118}
119
120impl<I> Clone for Handle<I> {
121 fn clone(&self) -> Self {
122 Handle {
123 index: self.index,
124 epoch: self.epoch,
125 _marker: self._marker,
126 }
127 }
128}
129
130impl<I> Copy for Handle<I> {}
131
132impl<I> Handle<I> {
133 pub fn uid(&self) -> ItemUid {
134 ItemUid {
135 uid: ((self.index as u64) << 32) | self.epoch.0 as u64
138 }
139 }
140}
141
142pub trait InternDebug {
143 fn on_interned(&self, _uid: ItemUid) {}
144}
145
146#[cfg_attr(feature = "capture", derive(Serialize))]
149#[cfg_attr(feature = "replay", derive(Deserialize))]
150#[derive(MallocSizeOf)]
151pub struct DataStore<I: Internable> {
152 items: Vec<Option<I::StoreData>>,
153}
154
155impl<I: Internable> Default for DataStore<I> {
156 fn default() -> Self {
157 DataStore {
158 items: Vec::new(),
159 }
160 }
161}
162
163impl<I: Internable> DataStore<I> {
164 pub fn apply_updates(
167 &mut self,
168 update_list: UpdateList<I::Key>,
169 profile: &mut TransactionProfile,
170 ) {
171 for insertion in update_list.insertions {
172 self.items
173 .entry(insertion.index)
174 .set(Some(insertion.value.into()));
175 }
176
177 for removal in update_list.removals {
178 self.items[removal.index] = None;
179 }
180
181 profile.set(I::PROFILE_COUNTER, self.items.len());
182 }
183}
184
185impl<I: Internable> ops::Index<Handle<I>> for DataStore<I> {
187 type Output = I::StoreData;
188 fn index(&self, handle: Handle<I>) -> &I::StoreData {
189 self.items[handle.index as usize].as_ref().expect("Bad datastore lookup")
190 }
191}
192
193impl<I: Internable> ops::IndexMut<Handle<I>> for DataStore<I> {
196 fn index_mut(&mut self, handle: Handle<I>) -> &mut I::StoreData {
197 self.items[handle.index as usize].as_mut().expect("Bad datastore lookup")
198 }
199}
200
201#[cfg_attr(feature = "capture", derive(Serialize))]
202#[cfg_attr(feature = "replay", derive(Deserialize))]
203#[derive(MallocSizeOf)]
204struct ItemDetails<I> {
205 interned_epoch: Epoch,
207 last_used_epoch: Epoch,
209 index: usize,
211 _marker: PhantomData<I>,
213}
214
215impl<I> ItemDetails<I> {
216 fn create_handle(&self) -> Handle<I> {
218 Handle {
219 index: self.index as u32,
220 epoch: self.interned_epoch,
221 _marker: PhantomData,
222 }
223 }
224}
225
226#[cfg_attr(feature = "capture", derive(Serialize))]
232#[cfg_attr(feature = "replay", derive(Deserialize))]
233#[derive(MallocSizeOf)]
234pub struct Interner<I: Internable> {
235 map: FastHashMap<I::Key, ItemDetails<I>>,
237 free_list: Vec<usize>,
239 update_list: UpdateList<I::Key>,
241 current_epoch: Epoch,
243 local_data: Vec<I::InternData>,
246}
247
248impl<I: Internable> Default for Interner<I> {
249 fn default() -> Self {
250 Interner {
251 map: FastHashMap::default(),
252 free_list: Vec::new(),
253 update_list: UpdateList::new(),
254 current_epoch: Epoch(1),
255 local_data: Vec::new(),
256 }
257 }
258}
259
260impl<I: Internable> Interner<I> {
261 pub fn intern<F>(
269 &mut self,
270 data: &I::Key,
271 fun: F,
272 ) -> Handle<I> where F: FnOnce() -> I::InternData {
273 if let Some(details) = self.map.get_mut(data) {
277 details.last_used_epoch = self.current_epoch;
279 return details.create_handle();
281 }
282
283 let index = match self.free_list.pop() {
287 Some(index) => index,
288 None => self.local_data.len(),
289 };
290
291 let handle = Handle {
293 index: index as u32,
294 epoch: self.current_epoch,
295 _marker: PhantomData,
296 };
297
298 let uid = handle.uid();
299
300 self.update_list.insertions.push(Insertion {
302 index,
303 uid,
304 value: data.clone(),
305 });
306
307 #[cfg(debug_assertions)]
308 data.on_interned(uid);
309
310 self.map.insert(data.clone(), ItemDetails {
313 interned_epoch: self.current_epoch,
314 last_used_epoch: self.current_epoch,
315 index,
316 _marker: PhantomData,
317 });
318
319 self.local_data.entry(index).set(fun());
322
323 handle
324 }
325
326 pub fn end_frame_and_get_pending_updates(&mut self) -> UpdateList<I::Key> {
330 let mut update_list = self.update_list.take_and_preallocate();
331
332 let free_list = &mut self.free_list;
333 let current_epoch = self.current_epoch.0;
334
335 self.map.retain(|_, details| {
343 if details.last_used_epoch.0 + 10 < current_epoch {
344 free_list.push(details.index);
349 update_list.removals.push(Removal {
350 index: details.index,
351 uid: details.create_handle().uid(),
352 });
353 return false;
354 }
355
356 true
357 });
358
359 self.current_epoch = Epoch(self.current_epoch.0 + 1);
361
362 update_list
363 }
364}
365
366impl<I: Internable> ops::Index<Handle<I>> for Interner<I> {
368 type Output = I::InternData;
369 fn index(&self, handle: Handle<I>) -> &I::InternData {
370 &self.local_data[handle.index as usize]
371 }
372}
373
374#[macro_export]
381macro_rules! enumerate_interners {
382 ($macro_name: ident) => {
383 $macro_name! {
384 clip: ClipIntern,
385 prim: PrimitiveKeyKind,
386 normal_border: NormalBorderPrim,
387 image_border: ImageBorder,
388 image: Image,
389 yuv_image: YuvImage,
390 line_decoration: LineDecoration,
391 linear_grad: LinearGradient,
392 radial_grad: RadialGradient,
393 conic_grad: ConicGradient,
394 picture: Picture,
395 text_run: TextRun,
396 filter_data: FilterDataIntern,
397 backdrop: Backdrop,
398 polygon: PolygonIntern,
399 }
400 }
401}
402
403macro_rules! declare_interning_memory_report {
404 ( $( $name:ident: $ty:ident, )+ ) => {
405 #[repr(C)]
407 #[derive(AddAssign, Clone, Debug, Default)]
408 pub struct InternerSubReport {
409 $(
410 pub $name: usize,
412 )+
413 }
414 }
415}
416
417enumerate_interners!(declare_interning_memory_report);
418
419#[repr(C)]
423#[derive(Clone, Debug, Default)]
424pub struct InterningMemoryReport {
425 pub interners: InternerSubReport,
427 pub data_stores: InternerSubReport,
429}
430
431impl ::std::ops::AddAssign for InterningMemoryReport {
432 fn add_assign(&mut self, other: InterningMemoryReport) {
433 self.interners += other.interners;
434 self.data_stores += other.data_stores;
435 }
436}
437
438mod dummy {
440 #[cfg(not(feature = "capture"))]
441 pub trait Serialize {}
442 #[cfg(not(feature = "capture"))]
443 impl<T> Serialize for T {}
444 #[cfg(not(feature = "replay"))]
445 pub trait Deserialize<'a> {}
446 #[cfg(not(feature = "replay"))]
447 impl<'a, T> Deserialize<'a> for T {}
448}
449#[cfg(feature = "capture")]
450use serde::Serialize as InternSerialize;
451#[cfg(not(feature = "capture"))]
452use self::dummy::Serialize as InternSerialize;
453#[cfg(feature = "replay")]
454use serde::Deserialize as InternDeserialize;
455#[cfg(not(feature = "replay"))]
456use self::dummy::Deserialize as InternDeserialize;
457
458pub trait Internable: MallocSizeOf {
460 type Key: Eq + Hash + Clone + Debug + MallocSizeOf + InternDebug + InternSerialize + for<'a> InternDeserialize<'a>;
461 type StoreData: From<Self::Key> + MallocSizeOf + InternSerialize + for<'a> InternDeserialize<'a>;
462 type InternData: MallocSizeOf + InternSerialize + for<'a> InternDeserialize<'a>;
463
464 const PROFILE_COUNTER: usize;
466}