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;
44use peek_poke::PeekPoke;
45
46#[cfg_attr(feature = "capture", derive(Serialize))]
47#[cfg_attr(feature = "replay", derive(Deserialize))]
48#[derive(Debug, Copy, Clone, Hash, MallocSizeOf, PartialEq, Eq)]
49struct Epoch(u32);
50
51#[cfg_attr(feature = "capture", derive(Serialize))]
54#[cfg_attr(feature = "replay", derive(Deserialize))]
55#[derive(MallocSizeOf)]
56pub struct UpdateList<S> {
57 pub insertions: Vec<Insertion<S>>,
59
60 pub removals: Vec<Removal>,
62}
63
64#[cfg_attr(feature = "capture", derive(Serialize))]
65#[cfg_attr(feature = "replay", derive(Deserialize))]
66#[derive(MallocSizeOf)]
67pub struct Insertion<S> {
68 pub index: usize,
69 pub uid: ItemUid,
70 pub value: S,
71}
72
73#[cfg_attr(feature = "capture", derive(Serialize))]
74#[cfg_attr(feature = "replay", derive(Deserialize))]
75#[derive(MallocSizeOf)]
76pub struct Removal {
77 pub index: usize,
78 pub uid: ItemUid,
79}
80
81impl<S> UpdateList<S> {
82 fn new() -> UpdateList<S> {
83 UpdateList {
84 insertions: Vec::new(),
85 removals: Vec::new(),
86 }
87 }
88
89 fn take_and_preallocate(&mut self) -> UpdateList<S> {
90 UpdateList {
91 insertions: self.insertions.take_and_preallocate(),
92 removals: self.removals.take_and_preallocate(),
93 }
94 }
95}
96
97#[cfg_attr(feature = "capture", derive(Serialize))]
99#[cfg_attr(feature = "replay", derive(Deserialize))]
100#[derive(Debug, Copy, Clone, Eq, Hash, MallocSizeOf, PartialEq, PeekPoke, Default)]
101pub struct ItemUid {
102 uid: u64,
103}
104
105impl ItemUid {
106 pub fn get_uid(&self) -> u64 {
108 self.uid
109 }
110}
111
112#[cfg_attr(feature = "capture", derive(Serialize))]
113#[cfg_attr(feature = "replay", derive(Deserialize))]
114#[derive(Debug, Hash, MallocSizeOf, PartialEq, Eq)]
115pub struct Handle<I> {
116 index: u32,
117 epoch: Epoch,
118 _marker: PhantomData<I>,
119}
120
121impl<I> Clone for Handle<I> {
122 fn clone(&self) -> Self {
123 Handle {
124 index: self.index,
125 epoch: self.epoch,
126 _marker: self._marker,
127 }
128 }
129}
130
131impl<I> Copy for Handle<I> {}
132
133impl<I> Handle<I> {
134 pub fn uid(&self) -> ItemUid {
135 ItemUid {
136 uid: ((self.index as u64) << 32) | self.epoch.0 as u64
139 }
140 }
141
142 pub const INVALID: Self = Handle { index: !0, epoch: Epoch(!0), _marker: PhantomData };
143}
144
145pub trait InternDebug {
146 fn on_interned(&self, _uid: ItemUid) {}
147}
148
149#[cfg_attr(feature = "capture", derive(Serialize))]
152#[cfg_attr(feature = "replay", derive(Deserialize))]
153#[derive(MallocSizeOf)]
154pub struct DataStore<I: Internable> {
155 items: Vec<Option<I::StoreData>>,
156}
157
158impl<I: Internable> Default for DataStore<I> {
159 fn default() -> Self {
160 DataStore {
161 items: Vec::new(),
162 }
163 }
164}
165
166impl<I: Internable> DataStore<I> {
167 pub fn apply_updates(
170 &mut self,
171 update_list: UpdateList<I::Key>,
172 profile: &mut TransactionProfile,
173 ) {
174 for insertion in update_list.insertions {
175 self.items
176 .entry(insertion.index)
177 .set(Some(insertion.value.into()));
178 }
179
180 for removal in update_list.removals {
181 self.items[removal.index] = None;
182 }
183
184 profile.set(I::PROFILE_COUNTER, self.items.len());
185 }
186}
187
188impl<I: Internable> ops::Index<Handle<I>> for DataStore<I> {
190 type Output = I::StoreData;
191 fn index(&self, handle: Handle<I>) -> &I::StoreData {
192 self.items[handle.index as usize].as_ref().expect("Bad datastore lookup")
193 }
194}
195
196impl<I: Internable> ops::IndexMut<Handle<I>> for DataStore<I> {
199 fn index_mut(&mut self, handle: Handle<I>) -> &mut I::StoreData {
200 self.items[handle.index as usize].as_mut().expect("Bad datastore lookup")
201 }
202}
203
204#[cfg_attr(feature = "capture", derive(Serialize))]
205#[cfg_attr(feature = "replay", derive(Deserialize))]
206#[derive(MallocSizeOf)]
207struct ItemDetails<I> {
208 interned_epoch: Epoch,
210 last_used_epoch: Epoch,
212 index: usize,
214 _marker: PhantomData<I>,
216}
217
218impl<I> ItemDetails<I> {
219 fn create_handle(&self) -> Handle<I> {
221 Handle {
222 index: self.index as u32,
223 epoch: self.interned_epoch,
224 _marker: PhantomData,
225 }
226 }
227}
228
229#[cfg_attr(feature = "capture", derive(Serialize))]
235#[cfg_attr(feature = "replay", derive(Deserialize))]
236#[derive(MallocSizeOf)]
237pub struct Interner<I: Internable> {
238 map: FastHashMap<I::Key, ItemDetails<I>>,
240 free_list: Vec<usize>,
242 update_list: UpdateList<I::Key>,
244 current_epoch: Epoch,
246 local_data: Vec<I::InternData>,
249}
250
251impl<I: Internable> Default for Interner<I> {
252 fn default() -> Self {
253 Interner {
254 map: FastHashMap::default(),
255 free_list: Vec::new(),
256 update_list: UpdateList::new(),
257 current_epoch: Epoch(1),
258 local_data: Vec::new(),
259 }
260 }
261}
262
263impl<I: Internable> Interner<I> {
264 pub fn intern<F>(
272 &mut self,
273 data: &I::Key,
274 fun: F,
275 ) -> Handle<I> where F: FnOnce() -> I::InternData {
276 if let Some(details) = self.map.get_mut(data) {
280 details.last_used_epoch = self.current_epoch;
282 return details.create_handle();
284 }
285
286 let index = match self.free_list.pop() {
290 Some(index) => index,
291 None => self.local_data.len(),
292 };
293
294 let handle = Handle {
296 index: index as u32,
297 epoch: self.current_epoch,
298 _marker: PhantomData,
299 };
300
301 let uid = handle.uid();
302
303 self.update_list.insertions.push(Insertion {
305 index,
306 uid,
307 value: data.clone(),
308 });
309
310 #[cfg(debug_assertions)]
311 data.on_interned(uid);
312
313 self.map.insert(data.clone(), ItemDetails {
316 interned_epoch: self.current_epoch,
317 last_used_epoch: self.current_epoch,
318 index,
319 _marker: PhantomData,
320 });
321
322 self.local_data.entry(index).set(fun());
325
326 handle
327 }
328
329 pub fn end_frame_and_get_pending_updates(&mut self) -> UpdateList<I::Key> {
333 let mut update_list = self.update_list.take_and_preallocate();
334
335 let free_list = &mut self.free_list;
336 let current_epoch = self.current_epoch.0;
337
338 self.map.retain(|_, details| {
346 if details.last_used_epoch.0 + 10 < current_epoch {
347 free_list.push(details.index);
352 update_list.removals.push(Removal {
353 index: details.index,
354 uid: details.create_handle().uid(),
355 });
356 return false;
357 }
358
359 true
360 });
361
362 self.current_epoch = Epoch(self.current_epoch.0 + 1);
364
365 update_list
366 }
367}
368
369impl<I: Internable> ops::Index<Handle<I>> for Interner<I> {
371 type Output = I::InternData;
372 fn index(&self, handle: Handle<I>) -> &I::InternData {
373 &self.local_data[handle.index as usize]
374 }
375}
376
377#[macro_export]
384macro_rules! enumerate_interners {
385 ($macro_name: ident) => {
386 $macro_name! {
387 clip: ClipIntern,
388 prim: PrimitiveKeyKind,
389 normal_border: NormalBorderPrim,
390 image_border: ImageBorder,
391 image: Image,
392 yuv_image: YuvImage,
393 line_decoration: LineDecoration,
394 linear_grad: LinearGradient,
395 radial_grad: RadialGradient,
396 conic_grad: ConicGradient,
397 picture: Picture,
398 text_run: TextRun,
399 filter_data: FilterDataIntern,
400 backdrop_capture: BackdropCapture,
401 backdrop_render: BackdropRender,
402 polygon: PolygonIntern,
403 box_shadow: BoxShadow,
404 }
405 }
406}
407
408macro_rules! declare_interning_memory_report {
409 ( $( $name:ident: $ty:ident, )+ ) => {
410 #[repr(C)]
412 #[derive(AddAssign, Clone, Debug, Default)]
413 pub struct InternerSubReport {
414 $(
415 pub $name: usize,
417 )+
418 }
419 }
420}
421
422enumerate_interners!(declare_interning_memory_report);
423
424#[repr(C)]
428#[derive(Clone, Debug, Default)]
429pub struct InterningMemoryReport {
430 pub interners: InternerSubReport,
432 pub data_stores: InternerSubReport,
434}
435
436impl ::std::ops::AddAssign for InterningMemoryReport {
437 fn add_assign(&mut self, other: InterningMemoryReport) {
438 self.interners += other.interners;
439 self.data_stores += other.data_stores;
440 }
441}
442
443mod dummy {
445 #[cfg(not(feature = "capture"))]
446 pub trait Serialize {}
447 #[cfg(not(feature = "capture"))]
448 impl<T> Serialize for T {}
449 #[cfg(not(feature = "replay"))]
450 pub trait Deserialize<'a> {}
451 #[cfg(not(feature = "replay"))]
452 impl<'a, T> Deserialize<'a> for T {}
453}
454#[cfg(feature = "capture")]
455use serde::Serialize as InternSerialize;
456#[cfg(not(feature = "capture"))]
457use self::dummy::Serialize as InternSerialize;
458#[cfg(feature = "replay")]
459use serde::Deserialize as InternDeserialize;
460#[cfg(not(feature = "replay"))]
461use self::dummy::Deserialize as InternDeserialize;
462
463pub trait Internable: MallocSizeOf {
465 type Key: Eq + Hash + Clone + Debug + MallocSizeOf + InternDebug + InternSerialize + for<'a> InternDeserialize<'a>;
466 type StoreData: From<Self::Key> + MallocSizeOf + InternSerialize + for<'a> InternDeserialize<'a>;
467 type InternData: MallocSizeOf + InternSerialize + for<'a> InternDeserialize<'a>;
468
469 const PROFILE_COUNTER: usize;
471}