author | alfadur |
Thu, 29 Aug 2019 00:06:31 +0300 | |
changeset 15402 | 52844baced17 |
parent 15401 | 6e3e5be8b2e2 |
child 15408 | 90a79670de52 |
permissions | -rw-r--r-- |
15375 | 1 |
use super::common::GearId; |
2 |
use std::{ |
|
3 |
any::TypeId, |
|
15396
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
4 |
fmt::{Debug, Error, Formatter}, |
15375 | 5 |
mem::{size_of, MaybeUninit}, |
6 |
num::NonZeroU16, |
|
15389 | 7 |
ptr::{copy_nonoverlapping, null_mut, NonNull}, |
15375 | 8 |
slice, |
9 |
}; |
|
15326 | 10 |
|
15389 | 11 |
pub trait TypeTuple: Sized { |
15394 | 12 |
fn get_types(types: &mut Vec<TypeId>); |
15400 | 13 |
unsafe fn iter<F: FnMut(GearId, Self)>(slices: &[*mut u8], count: usize, mut f: F); |
15326 | 14 |
} |
15 |
||
15390 | 16 |
macro_rules! type_tuple_impl { |
17 |
($($n: literal: $t: ident),+) => { |
|
18 |
impl<$($t: 'static),+> TypeTuple for ($(&$t),+,) { |
|
15389 | 19 |
fn get_types(types: &mut Vec<TypeId>) { |
15390 | 20 |
$(types.push(TypeId::of::<$t>()));+ |
15389 | 21 |
} |
15326 | 22 |
|
15400 | 23 |
unsafe fn iter<F: FnMut(GearId, Self)>(slices: &[*mut u8], count: usize, mut f: F) { |
15389 | 24 |
for i in 0..count { |
15401 | 25 |
f(*(*slices.get_unchecked(0) as *const GearId).add(i), |
26 |
($(&*(*slices.get_unchecked($n + 1) as *mut $t).add(i)),+,)); |
|
15389 | 27 |
} |
28 |
} |
|
29 |
} |
|
15375 | 30 |
|
15390 | 31 |
impl<$($t: 'static),+> TypeTuple for ($(&mut $t),+,) { |
15389 | 32 |
fn get_types(types: &mut Vec<TypeId>) { |
15390 | 33 |
$(types.push(TypeId::of::<$t>()));+ |
15389 | 34 |
} |
35 |
||
15400 | 36 |
unsafe fn iter<F: FnMut(GearId, Self)>(slices: &[*mut u8], count: usize, mut f: F) { |
15389 | 37 |
for i in 0..count { |
15401 | 38 |
f(*(*slices.get_unchecked(0) as *const GearId).add(i), |
39 |
($(&mut *(*slices.get_unchecked($n + 1) as *mut $t).add(i)),+,)); |
|
15389 | 40 |
} |
41 |
} |
|
15375 | 42 |
} |
43 |
} |
|
15326 | 44 |
} |
45 |
||
15390 | 46 |
type_tuple_impl!(0: A); |
47 |
type_tuple_impl!(0: A, 1: B); |
|
48 |
type_tuple_impl!(0: A, 1: B, 2: C); |
|
49 |
type_tuple_impl!(0: A, 1: B, 2: C, 3: D); |
|
50 |
type_tuple_impl!(0: A, 1: B, 2: C, 3: D, 4: E); |
|
15389 | 51 |
|
15375 | 52 |
const BLOCK_SIZE: usize = 32768; |
53 |
||
54 |
struct DataBlock { |
|
55 |
max_elements: u16, |
|
56 |
elements_count: u16, |
|
57 |
data: Box<[u8; BLOCK_SIZE]>, |
|
15380 | 58 |
component_blocks: [Option<NonNull<u8>>; 64], |
15396
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
59 |
element_sizes: Box<[u16]>, |
15326 | 60 |
} |
61 |
||
15375 | 62 |
impl Unpin for DataBlock {} |
63 |
||
15396
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
64 |
impl Debug for DataBlock { |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
65 |
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
66 |
write!( |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
67 |
f, |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
68 |
"Block ({}/{}) {{\n", |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
69 |
self.elements_count, self.max_elements |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
70 |
)?; |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
71 |
write!(f, "\tIDs: [")?; |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
72 |
let id_slice = unsafe { |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
73 |
slice::from_raw_parts( |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
74 |
self.data.as_ptr() as *const GearId, |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
75 |
self.elements_count as usize, |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
76 |
) |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
77 |
}; |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
78 |
for gear_id in id_slice { |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
79 |
write!(f, "{}, ", gear_id)?; |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
80 |
} |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
81 |
write!(f, "]\n")?; |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
82 |
for type_index in 0..self.element_sizes.len() { |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
83 |
if let Some(ptr) = self.component_blocks[type_index] { |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
84 |
write!(f, "\tC{}: [", type_index)?; |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
85 |
let slice = unsafe { |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
86 |
slice::from_raw_parts( |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
87 |
ptr.as_ptr(), |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
88 |
(self.elements_count * self.element_sizes[type_index]) as usize, |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
89 |
) |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
90 |
}; |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
91 |
for byte in slice { |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
92 |
write!(f, "{}, ", byte)?; |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
93 |
} |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
94 |
write!(f, "]\n")?; |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
95 |
} |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
96 |
} |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
97 |
write!(f, "}}\n") |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
98 |
} |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
99 |
} |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
100 |
|
15375 | 101 |
impl DataBlock { |
15396
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
102 |
fn new(mask: u64, element_sizes: &[u16]) -> Self { |
15375 | 103 |
let total_size: u16 = element_sizes |
104 |
.iter() |
|
105 |
.enumerate() |
|
15380 | 106 |
.filter(|(i, _)| mask & (1 << *i as u64) != 0) |
15375 | 107 |
.map(|(_, size)| *size) |
108 |
.sum(); |
|
15396
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
109 |
let max_elements = (BLOCK_SIZE / (total_size as usize + size_of::<GearId>())) as u16; |
15375 | 110 |
|
111 |
let mut data: Box<[u8; BLOCK_SIZE]> = |
|
15379 | 112 |
Box::new(unsafe { MaybeUninit::uninit().assume_init() }); |
15375 | 113 |
let mut blocks = [None; 64]; |
15396
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
114 |
let mut offset = size_of::<GearId>() * max_elements as usize; |
15375 | 115 |
|
15393 | 116 |
for i in 0..element_sizes.len() { |
117 |
if mask & (1 << i as u64) != 0 { |
|
15375 | 118 |
blocks[i] = Some(NonNull::new(data[offset..].as_mut_ptr()).unwrap()); |
119 |
offset += element_sizes[i] as usize * max_elements as usize; |
|
120 |
} |
|
121 |
} |
|
15326 | 122 |
Self { |
15375 | 123 |
elements_count: 0, |
124 |
max_elements, |
|
125 |
data, |
|
15380 | 126 |
component_blocks: blocks, |
15396
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
127 |
element_sizes: Box::from(element_sizes), |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
128 |
} |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
129 |
} |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
130 |
|
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
131 |
fn gear_ids(&self) -> &[GearId] { |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
132 |
unsafe { |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
133 |
slice::from_raw_parts( |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
134 |
self.data.as_ptr() as *const GearId, |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
135 |
self.max_elements as usize, |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
136 |
) |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
137 |
} |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
138 |
} |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
139 |
|
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
140 |
fn gear_ids_mut(&mut self) -> &mut [GearId] { |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
141 |
unsafe { |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
142 |
slice::from_raw_parts_mut( |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
143 |
self.data.as_mut_ptr() as *mut GearId, |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
144 |
self.max_elements as usize, |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
145 |
) |
15326 | 146 |
} |
147 |
} |
|
148 |
||
15375 | 149 |
fn is_full(&self) -> bool { |
150 |
self.elements_count == self.max_elements |
|
151 |
} |
|
15326 | 152 |
} |
153 |
||
15375 | 154 |
#[derive(Clone, Copy, Debug, Default)] |
15400 | 155 |
struct LookupEntry { |
15375 | 156 |
index: Option<NonZeroU16>, |
157 |
block_index: u16, |
|
15326 | 158 |
} |
159 |
||
15396
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
160 |
impl LookupEntry { |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
161 |
fn new(block_index: u16, index: u16) -> Self { |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
162 |
Self { |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
163 |
index: unsafe { Some(NonZeroU16::new_unchecked(index + 1)) }, |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
164 |
block_index, |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
165 |
} |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
166 |
} |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
167 |
} |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
168 |
|
15326 | 169 |
pub struct GearDataManager { |
170 |
types: Vec<TypeId>, |
|
15375 | 171 |
blocks: Vec<DataBlock>, |
172 |
block_masks: Vec<u64>, |
|
173 |
element_sizes: Box<[u16; 64]>, |
|
174 |
lookup: Box<[LookupEntry]>, |
|
15326 | 175 |
} |
176 |
||
177 |
impl GearDataManager { |
|
178 |
pub fn new() -> Self { |
|
179 |
Self { |
|
180 |
types: vec![], |
|
15375 | 181 |
blocks: vec![], |
182 |
block_masks: vec![], |
|
183 |
element_sizes: Box::new([0; 64]), |
|
184 |
lookup: vec![LookupEntry::default(); u16::max_value() as usize].into_boxed_slice(), |
|
185 |
} |
|
186 |
} |
|
187 |
||
188 |
#[inline] |
|
189 |
fn get_type_index<T: 'static>(&self) -> Option<usize> { |
|
190 |
let type_id = TypeId::of::<T>(); |
|
191 |
self.types.iter().position(|id| *id == type_id) |
|
192 |
} |
|
193 |
||
15396
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
194 |
fn move_between_blocks(&mut self, src_block_index: u16, src_index: u16, dest_block_index: u16) { |
15394 | 195 |
debug_assert!(src_block_index != dest_block_index); |
196 |
let src_mask = self.block_masks[src_block_index as usize]; |
|
197 |
let dest_mask = self.block_masks[dest_block_index as usize]; |
|
198 |
debug_assert!(src_mask & dest_mask == src_mask); |
|
15375 | 199 |
|
15394 | 200 |
let src_block = &self.blocks[src_block_index as usize]; |
201 |
let dest_block = &self.blocks[dest_block_index as usize]; |
|
202 |
debug_assert!(src_index < src_block.elements_count); |
|
203 |
debug_assert!(!dest_block.is_full()); |
|
15379 | 204 |
|
15394 | 205 |
let dest_index = dest_block.elements_count; |
15393 | 206 |
for i in 0..self.types.len() { |
15394 | 207 |
if src_mask & (1 << i as u64) != 0 { |
208 |
let size = self.element_sizes[i]; |
|
209 |
let src_ptr = src_block.component_blocks[i].unwrap().as_ptr(); |
|
210 |
let dest_ptr = dest_block.component_blocks[i].unwrap().as_ptr(); |
|
15379 | 211 |
unsafe { |
212 |
copy_nonoverlapping( |
|
15394 | 213 |
src_ptr.add((src_index * size) as usize), |
214 |
dest_ptr.add((dest_index * size) as usize), |
|
215 |
size as usize, |
|
15379 | 216 |
); |
15394 | 217 |
if src_index < src_block.elements_count - 1 { |
218 |
copy_nonoverlapping( |
|
219 |
src_ptr.add((size * (src_block.elements_count - 1)) as usize), |
|
220 |
src_ptr.add((size * src_index) as usize), |
|
221 |
size as usize, |
|
222 |
); |
|
223 |
} |
|
15379 | 224 |
} |
225 |
} |
|
15375 | 226 |
} |
15396
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
227 |
|
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
228 |
let src_block = &mut self.blocks[src_block_index as usize]; |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
229 |
let gear_id = src_block.gear_ids()[src_index as usize]; |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
230 |
|
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
231 |
if src_index < src_block.elements_count - 1 { |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
232 |
let relocated_index = src_block.elements_count as usize - 1; |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
233 |
let gear_ids = src_block.gear_ids_mut(); |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
234 |
let relocated_id = gear_ids[relocated_index]; |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
235 |
|
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
236 |
gear_ids[src_index as usize] = relocated_id; |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
237 |
self.lookup[relocated_id.get() as usize - 1] = |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
238 |
LookupEntry::new(src_block_index, src_index); |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
239 |
} |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
240 |
src_block.elements_count -= 1; |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
241 |
|
15394 | 242 |
let dest_block = &mut self.blocks[dest_block_index as usize]; |
15396
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
243 |
let dest_index = dest_block.elements_count; |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
244 |
|
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
245 |
dest_block.gear_ids_mut()[dest_index as usize] = gear_id; |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
246 |
self.lookup[gear_id.get() as usize - 1] = LookupEntry::new(dest_block_index, dest_index); |
15394 | 247 |
dest_block.elements_count += 1; |
15375 | 248 |
} |
249 |
||
15396
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
250 |
fn add_to_block<T: Clone>(&mut self, gear_id: GearId, block_index: u16, value: &T) { |
15378 | 251 |
debug_assert!(self.block_masks[block_index as usize].count_ones() == 1); |
252 |
||
253 |
let block = &mut self.blocks[block_index as usize]; |
|
254 |
debug_assert!(block.elements_count < block.max_elements); |
|
255 |
||
256 |
unsafe { |
|
257 |
let slice = slice::from_raw_parts_mut( |
|
15396
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
258 |
block.component_blocks[0].unwrap().as_ptr() as *mut T, |
15378 | 259 |
block.max_elements as usize, |
260 |
); |
|
261 |
*slice.get_unchecked_mut(block.elements_count as usize) = value.clone(); |
|
262 |
}; |
|
15396
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
263 |
|
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
264 |
let index = block.elements_count; |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
265 |
self.lookup[gear_id.get() as usize - 1] = LookupEntry::new(block_index, index); |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
266 |
block.gear_ids_mut()[index as usize] = gear_id; |
15378 | 267 |
block.elements_count += 1; |
15375 | 268 |
} |
269 |
||
270 |
fn remove_from_block(&mut self, block_index: u16, index: u16) { |
|
15378 | 271 |
let block = &mut self.blocks[block_index as usize]; |
272 |
debug_assert!(index < block.elements_count); |
|
273 |
||
274 |
for (i, size) in self.element_sizes.iter().cloned().enumerate() { |
|
275 |
if index < block.elements_count - 1 { |
|
15380 | 276 |
if let Some(ptr) = block.component_blocks[i] { |
15378 | 277 |
unsafe { |
15379 | 278 |
copy_nonoverlapping( |
15378 | 279 |
ptr.as_ptr() |
280 |
.add((size * (block.elements_count - 1)) as usize), |
|
281 |
ptr.as_ptr().add((size * index) as usize), |
|
282 |
size as usize, |
|
283 |
); |
|
284 |
} |
|
285 |
} |
|
286 |
} |
|
287 |
} |
|
15396
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
288 |
|
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
289 |
self.lookup[block.gear_ids()[index as usize].get() as usize - 1] = LookupEntry::default(); |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
290 |
if index < block.elements_count - 1 { |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
291 |
let relocated_index = block.elements_count as usize - 1; |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
292 |
let gear_ids = block.gear_ids_mut(); |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
293 |
|
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
294 |
gear_ids[index as usize] = gear_ids[relocated_index]; |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
295 |
self.lookup[gear_ids[relocated_index].get() as usize - 1] = |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
296 |
LookupEntry::new(block_index, index); |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
297 |
} |
15378 | 298 |
block.elements_count -= 1; |
15375 | 299 |
} |
300 |
||
301 |
#[inline] |
|
15380 | 302 |
fn ensure_block(&mut self, mask: u64) -> u16 { |
15375 | 303 |
if let Some(index) = self |
304 |
.block_masks |
|
305 |
.iter() |
|
306 |
.enumerate() |
|
307 |
.position(|(i, m)| *m == mask && !self.blocks[i].is_full()) |
|
308 |
{ |
|
309 |
index as u16 |
|
310 |
} else { |
|
15396
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
311 |
self.blocks.push(DataBlock::new( |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
312 |
mask, |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
313 |
&self.element_sizes[0..self.types.len()], |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
314 |
)); |
15380 | 315 |
self.block_masks.push(mask); |
15375 | 316 |
(self.blocks.len() - 1) as u16 |
317 |
} |
|
318 |
} |
|
319 |
||
320 |
pub fn add<T: Clone + 'static>(&mut self, gear_id: GearId, value: &T) { |
|
321 |
if let Some(type_index) = self.get_type_index::<T>() { |
|
15380 | 322 |
let type_bit = 1 << type_index as u64; |
15375 | 323 |
let entry = self.lookup[gear_id.get() as usize - 1]; |
324 |
||
325 |
if let Some(index) = entry.index { |
|
326 |
let mask = self.block_masks[entry.block_index as usize]; |
|
327 |
let new_mask = mask | type_bit; |
|
328 |
||
329 |
if new_mask != mask { |
|
15380 | 330 |
let dest_block_index = self.ensure_block(new_mask); |
15396
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
331 |
self.move_between_blocks(entry.block_index, index.get() - 1, dest_block_index); |
15375 | 332 |
} |
333 |
} else { |
|
15380 | 334 |
let dest_block_index = self.ensure_block(type_bit); |
15396
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
335 |
self.add_to_block(gear_id, dest_block_index, value); |
15375 | 336 |
} |
337 |
} else { |
|
338 |
panic!("Unregistered type") |
|
339 |
} |
|
340 |
} |
|
341 |
||
342 |
pub fn remove<T: 'static>(&mut self, gear_id: GearId) { |
|
343 |
if let Some(type_index) = self.get_type_index::<T>() { |
|
344 |
let entry = self.lookup[gear_id.get() as usize - 1]; |
|
345 |
if let Some(index) = entry.index { |
|
15394 | 346 |
let dest_mask = |
15380 | 347 |
self.block_masks[entry.block_index as usize] & !(1 << type_index as u64); |
15379 | 348 |
|
15394 | 349 |
if dest_mask == 0 { |
15379 | 350 |
self.remove_all(gear_id) |
351 |
} else { |
|
15394 | 352 |
let dest_block_index = self.ensure_block(dest_mask); |
353 |
self.move_between_blocks(entry.block_index, index.get() - 1, dest_block_index); |
|
15379 | 354 |
} |
15375 | 355 |
} |
15379 | 356 |
} else { |
357 |
panic!("Unregistered type") |
|
358 |
} |
|
359 |
} |
|
360 |
||
361 |
pub fn remove_all(&mut self, gear_id: GearId) { |
|
362 |
let entry = self.lookup[gear_id.get() as usize - 1]; |
|
363 |
if let Some(index) = entry.index { |
|
364 |
self.remove_from_block(entry.block_index, index.get() - 1); |
|
15326 | 365 |
} |
366 |
} |
|
367 |
||
368 |
pub fn register<T: 'static>(&mut self) { |
|
15378 | 369 |
debug_assert!(!std::mem::needs_drop::<T>()); |
370 |
debug_assert!(self.types.len() <= 64); |
|
371 |
debug_assert!(size_of::<T>() <= u16::max_value() as usize); |
|
15375 | 372 |
|
15326 | 373 |
let id = TypeId::of::<T>(); |
374 |
if !self.types.contains(&id) { |
|
15375 | 375 |
self.element_sizes[self.types.len()] = size_of::<T>() as u16; |
15326 | 376 |
self.types.push(id); |
377 |
} |
|
378 |
} |
|
379 |
||
15400 | 380 |
pub fn iter<T: TypeTuple + 'static, F: FnMut(T)>(&mut self, mut f: F) { |
381 |
self.iter_id(|_, x| f(x)); |
|
382 |
} |
|
383 |
||
384 |
pub fn iter_id<T: TypeTuple + 'static, F: FnMut(GearId, T)>(&mut self, mut f: F) { |
|
15388
d6b4586b271f
make sure component slice order corresponds to the type args
alfadur
parents:
15380
diff
changeset
|
385 |
let mut arg_types = Vec::with_capacity(64); |
d6b4586b271f
make sure component slice order corresponds to the type args
alfadur
parents:
15380
diff
changeset
|
386 |
T::get_types(&mut arg_types); |
d6b4586b271f
make sure component slice order corresponds to the type args
alfadur
parents:
15380
diff
changeset
|
387 |
|
d6b4586b271f
make sure component slice order corresponds to the type args
alfadur
parents:
15380
diff
changeset
|
388 |
let mut type_indices = vec![-1i8; arg_types.len()]; |
d6b4586b271f
make sure component slice order corresponds to the type args
alfadur
parents:
15380
diff
changeset
|
389 |
let mut selector = 0u64; |
d6b4586b271f
make sure component slice order corresponds to the type args
alfadur
parents:
15380
diff
changeset
|
390 |
|
d6b4586b271f
make sure component slice order corresponds to the type args
alfadur
parents:
15380
diff
changeset
|
391 |
for (arg_index, type_id) in arg_types.iter().enumerate() { |
d6b4586b271f
make sure component slice order corresponds to the type args
alfadur
parents:
15380
diff
changeset
|
392 |
match self.types.iter().position(|t| t == type_id) { |
15394 | 393 |
Some(i) if selector & (1 << i as u64) != 0 => panic!("Duplicate type"), |
15388
d6b4586b271f
make sure component slice order corresponds to the type args
alfadur
parents:
15380
diff
changeset
|
394 |
Some(i) => { |
d6b4586b271f
make sure component slice order corresponds to the type args
alfadur
parents:
15380
diff
changeset
|
395 |
type_indices[arg_index] = i as i8; |
15393 | 396 |
selector |= 1 << i as u64; |
15389 | 397 |
} |
398 |
None => panic!("Unregistered type"), |
|
15326 | 399 |
} |
400 |
} |
|
15400 | 401 |
let mut slices = vec![null_mut(); arg_types.len() + 1]; |
15380 | 402 |
|
15375 | 403 |
for (block_index, mask) in self.block_masks.iter().enumerate() { |
404 |
if mask & selector == selector { |
|
15400 | 405 |
let block = &mut self.blocks[block_index]; |
406 |
slices[0] = block.data.as_mut_ptr(); |
|
407 |
||
15388
d6b4586b271f
make sure component slice order corresponds to the type args
alfadur
parents:
15380
diff
changeset
|
408 |
for (arg_index, type_index) in type_indices.iter().cloned().enumerate() { |
15400 | 409 |
slices[arg_index as usize + 1] = block.component_blocks[type_index as usize] |
15389 | 410 |
.unwrap() |
411 |
.as_ptr() |
|
15375 | 412 |
} |
15380 | 413 |
|
414 |
unsafe { |
|
15400 | 415 |
T::iter(&slices[..], block.elements_count as usize, |id, x| f(id, x)); |
15380 | 416 |
} |
15326 | 417 |
} |
418 |
} |
|
419 |
} |
|
420 |
} |
|
15375 | 421 |
|
422 |
#[cfg(test)] |
|
423 |
mod test { |
|
15380 | 424 |
use super::{super::common::GearId, GearDataManager}; |
15375 | 425 |
|
15380 | 426 |
#[derive(Clone)] |
15375 | 427 |
struct Datum { |
428 |
value: u32, |
|
429 |
} |
|
430 |
||
15392 | 431 |
#[derive(Clone)] |
432 |
struct Tag { |
|
433 |
nothing: u8, |
|
434 |
} |
|
435 |
||
15375 | 436 |
#[test] |
15380 | 437 |
fn single_component_iteration() { |
15375 | 438 |
let mut manager = GearDataManager::new(); |
439 |
manager.register::<Datum>(); |
|
15380 | 440 |
for i in 1..=5 { |
441 |
manager.add(GearId::new(i as u16).unwrap(), &Datum { value: i }); |
|
442 |
} |
|
443 |
||
444 |
let mut sum = 0; |
|
445 |
manager.iter(|(d,): (&Datum,)| sum += d.value); |
|
15389 | 446 |
assert_eq!(sum, 15); |
15380 | 447 |
|
15389 | 448 |
manager.iter(|(d,): (&mut Datum,)| d.value += 1); |
449 |
manager.iter(|(d,): (&Datum,)| sum += d.value); |
|
450 |
assert_eq!(sum, 35); |
|
15375 | 451 |
} |
15392 | 452 |
|
453 |
#[test] |
|
454 |
fn multiple_component_iteration() { |
|
455 |
let mut manager = GearDataManager::new(); |
|
456 |
manager.register::<Datum>(); |
|
457 |
manager.register::<Tag>(); |
|
458 |
for i in 1..=10 { |
|
459 |
let gear_id = GearId::new(i as u16).unwrap(); |
|
460 |
manager.add(gear_id, &Datum { value: i }); |
|
15396
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
461 |
} |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
462 |
|
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
463 |
for i in 1..=10 { |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
464 |
let gear_id = GearId::new(i as u16).unwrap(); |
15392 | 465 |
if i & 1 == 0 { |
15396
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
466 |
manager.add(GearId::new(i as u16).unwrap(), &Tag { nothing: 0 }); |
15392 | 467 |
} |
468 |
} |
|
469 |
||
15396
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
470 |
let mut sum = 0; |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
471 |
manager.iter(|(d,): (&Datum,)| sum += d.value); |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
472 |
assert_eq!(sum, 55); |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
473 |
|
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
474 |
let mut tag_sum1 = 0; |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
475 |
let mut tag_sum2 = 0; |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
476 |
manager.iter(|(d, _): (&Datum, &Tag)| tag_sum1 += d.value); |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
477 |
manager.iter(|(_, d): (&Tag, &Datum)| tag_sum2 += d.value); |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
478 |
assert_eq!(tag_sum1, 30); |
37b632d38f14
properly update gear id lookup on block modifications
alfadur
parents:
15394
diff
changeset
|
479 |
assert_eq!(tag_sum2, tag_sum1); |
15392 | 480 |
} |
15375 | 481 |
} |