rust/hwphysics/src/data.rs
author alfadur
Wed, 28 Aug 2019 00:34:26 +0300
changeset 15376 24a9afbf33c6
parent 15374 0f2fd8d12734
child 15377 7a3ed957cee9
permissions -rw-r--r--
add multicomponent iteration test
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
15359
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
     1
use super::common::GearId;
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
     2
use std::{
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
     3
    any::TypeId,
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
     4
    mem::{size_of, MaybeUninit},
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
     5
    num::NonZeroU16,
15373
445138f388d4 expand iteration implementation to larger tuples
alfadur
parents: 15372
diff changeset
     6
    ptr::{copy_nonoverlapping, null_mut, NonNull},
15359
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
     7
    slice,
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
     8
};
15310
0076bf602969 start gear data group implementation
alfadur
parents:
diff changeset
     9
15373
445138f388d4 expand iteration implementation to larger tuples
alfadur
parents: 15372
diff changeset
    10
pub trait TypeTuple: Sized {
15310
0076bf602969 start gear data group implementation
alfadur
parents:
diff changeset
    11
    fn len() -> usize;
0076bf602969 start gear data group implementation
alfadur
parents:
diff changeset
    12
    fn get_types(dest: &mut Vec<TypeId>);
15373
445138f388d4 expand iteration implementation to larger tuples
alfadur
parents: 15372
diff changeset
    13
    unsafe fn iter<F: FnMut(Self)>(slices: &[*mut u8], count: usize, mut f: F);
15310
0076bf602969 start gear data group implementation
alfadur
parents:
diff changeset
    14
}
0076bf602969 start gear data group implementation
alfadur
parents:
diff changeset
    15
15374
0f2fd8d12734 fix tupo
alfadur
parents: 15373
diff changeset
    16
macro_rules! type_tuple_impl {
0f2fd8d12734 fix tupo
alfadur
parents: 15373
diff changeset
    17
    ($($n: literal: $t: ident),+) => {
0f2fd8d12734 fix tupo
alfadur
parents: 15373
diff changeset
    18
        impl<$($t: 'static),+> TypeTuple for ($(&$t),+,) {
15373
445138f388d4 expand iteration implementation to larger tuples
alfadur
parents: 15372
diff changeset
    19
            fn len() -> usize {
15374
0f2fd8d12734 fix tupo
alfadur
parents: 15373
diff changeset
    20
                [$({TypeId::of::<$t>(); 1}),+].iter().sum()
15373
445138f388d4 expand iteration implementation to larger tuples
alfadur
parents: 15372
diff changeset
    21
            }
445138f388d4 expand iteration implementation to larger tuples
alfadur
parents: 15372
diff changeset
    22
445138f388d4 expand iteration implementation to larger tuples
alfadur
parents: 15372
diff changeset
    23
            fn get_types(types: &mut Vec<TypeId>) {
15374
0f2fd8d12734 fix tupo
alfadur
parents: 15373
diff changeset
    24
                $(types.push(TypeId::of::<$t>()));+
15373
445138f388d4 expand iteration implementation to larger tuples
alfadur
parents: 15372
diff changeset
    25
            }
15310
0076bf602969 start gear data group implementation
alfadur
parents:
diff changeset
    26
15376
24a9afbf33c6 add multicomponent iteration test
alfadur
parents: 15374
diff changeset
    27
            unsafe fn iter<F: FnMut(Self)>(slices: &[*mut u8], count: usize, mut f: F) {
15373
445138f388d4 expand iteration implementation to larger tuples
alfadur
parents: 15372
diff changeset
    28
                for i in 0..count {
445138f388d4 expand iteration implementation to larger tuples
alfadur
parents: 15372
diff changeset
    29
                    unsafe {
15374
0f2fd8d12734 fix tupo
alfadur
parents: 15373
diff changeset
    30
                        f(($(&*(*slices.get_unchecked($n) as *mut $t).add(i)),+,));
15373
445138f388d4 expand iteration implementation to larger tuples
alfadur
parents: 15372
diff changeset
    31
                    }
445138f388d4 expand iteration implementation to larger tuples
alfadur
parents: 15372
diff changeset
    32
                }
445138f388d4 expand iteration implementation to larger tuples
alfadur
parents: 15372
diff changeset
    33
            }
445138f388d4 expand iteration implementation to larger tuples
alfadur
parents: 15372
diff changeset
    34
        }
15359
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
    35
15374
0f2fd8d12734 fix tupo
alfadur
parents: 15373
diff changeset
    36
        impl<$($t: 'static),+> TypeTuple for ($(&mut $t),+,) {
15373
445138f388d4 expand iteration implementation to larger tuples
alfadur
parents: 15372
diff changeset
    37
            fn len() -> usize {
15374
0f2fd8d12734 fix tupo
alfadur
parents: 15373
diff changeset
    38
                [$({TypeId::of::<$t>(); 1}),+].iter().sum()
15373
445138f388d4 expand iteration implementation to larger tuples
alfadur
parents: 15372
diff changeset
    39
            }
445138f388d4 expand iteration implementation to larger tuples
alfadur
parents: 15372
diff changeset
    40
445138f388d4 expand iteration implementation to larger tuples
alfadur
parents: 15372
diff changeset
    41
            fn get_types(types: &mut Vec<TypeId>) {
15374
0f2fd8d12734 fix tupo
alfadur
parents: 15373
diff changeset
    42
                $(types.push(TypeId::of::<$t>()));+
15373
445138f388d4 expand iteration implementation to larger tuples
alfadur
parents: 15372
diff changeset
    43
            }
445138f388d4 expand iteration implementation to larger tuples
alfadur
parents: 15372
diff changeset
    44
15376
24a9afbf33c6 add multicomponent iteration test
alfadur
parents: 15374
diff changeset
    45
            unsafe fn iter<F: FnMut(Self)>(slices: &[*mut u8], count: usize, mut f: F) {
15373
445138f388d4 expand iteration implementation to larger tuples
alfadur
parents: 15372
diff changeset
    46
                for i in 0..count {
445138f388d4 expand iteration implementation to larger tuples
alfadur
parents: 15372
diff changeset
    47
                    unsafe {
15374
0f2fd8d12734 fix tupo
alfadur
parents: 15373
diff changeset
    48
                        f(($(&mut *(*slices.get_unchecked($n) as *mut $t).add(i)),+,));
15373
445138f388d4 expand iteration implementation to larger tuples
alfadur
parents: 15372
diff changeset
    49
                    }
445138f388d4 expand iteration implementation to larger tuples
alfadur
parents: 15372
diff changeset
    50
                }
445138f388d4 expand iteration implementation to larger tuples
alfadur
parents: 15372
diff changeset
    51
            }
15359
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
    52
        }
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
    53
    }
15310
0076bf602969 start gear data group implementation
alfadur
parents:
diff changeset
    54
}
0076bf602969 start gear data group implementation
alfadur
parents:
diff changeset
    55
15374
0f2fd8d12734 fix tupo
alfadur
parents: 15373
diff changeset
    56
type_tuple_impl!(0: A);
0f2fd8d12734 fix tupo
alfadur
parents: 15373
diff changeset
    57
type_tuple_impl!(0: A, 1: B);
0f2fd8d12734 fix tupo
alfadur
parents: 15373
diff changeset
    58
type_tuple_impl!(0: A, 1: B, 2: C);
0f2fd8d12734 fix tupo
alfadur
parents: 15373
diff changeset
    59
type_tuple_impl!(0: A, 1: B, 2: C, 3: D);
0f2fd8d12734 fix tupo
alfadur
parents: 15373
diff changeset
    60
type_tuple_impl!(0: A, 1: B, 2: C, 3: D, 4: E);
15373
445138f388d4 expand iteration implementation to larger tuples
alfadur
parents: 15372
diff changeset
    61
15359
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
    62
const BLOCK_SIZE: usize = 32768;
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
    63
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
    64
struct DataBlock {
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
    65
    max_elements: u16,
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
    66
    elements_count: u16,
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
    67
    data: Box<[u8; BLOCK_SIZE]>,
15363
b5e0a39856fd complete basic ecs
alfadur
parents: 15362
diff changeset
    68
    component_blocks: [Option<NonNull<u8>>; 64],
15310
0076bf602969 start gear data group implementation
alfadur
parents:
diff changeset
    69
}
0076bf602969 start gear data group implementation
alfadur
parents:
diff changeset
    70
15359
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
    71
impl Unpin for DataBlock {}
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
    72
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
    73
impl DataBlock {
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
    74
    fn new(mask: u64, element_sizes: &[u16; 64]) -> Self {
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
    75
        let total_size: u16 = element_sizes
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
    76
            .iter()
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
    77
            .enumerate()
15363
b5e0a39856fd complete basic ecs
alfadur
parents: 15362
diff changeset
    78
            .filter(|(i, _)| mask & (1 << *i as u64) != 0)
15359
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
    79
            .map(|(_, size)| *size)
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
    80
            .sum();
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
    81
        let max_elements = (BLOCK_SIZE / total_size as usize) as u16;
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
    82
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
    83
        let mut data: Box<[u8; BLOCK_SIZE]> =
15362
135c29237a56 implement moving between blocks
alfadur
parents: 15361
diff changeset
    84
            Box::new(unsafe { MaybeUninit::uninit().assume_init() });
15359
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
    85
        let mut blocks = [None; 64];
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
    86
        let mut offset = 0;
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
    87
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
    88
        for i in 0..64 {
15363
b5e0a39856fd complete basic ecs
alfadur
parents: 15362
diff changeset
    89
            if mask & (1 << i) != 0 {
15359
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
    90
                blocks[i] = Some(NonNull::new(data[offset..].as_mut_ptr()).unwrap());
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
    91
                offset += element_sizes[i] as usize * max_elements as usize;
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
    92
            }
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
    93
        }
15310
0076bf602969 start gear data group implementation
alfadur
parents:
diff changeset
    94
        Self {
15359
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
    95
            elements_count: 0,
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
    96
            max_elements,
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
    97
            data,
15363
b5e0a39856fd complete basic ecs
alfadur
parents: 15362
diff changeset
    98
            component_blocks: blocks,
15310
0076bf602969 start gear data group implementation
alfadur
parents:
diff changeset
    99
        }
0076bf602969 start gear data group implementation
alfadur
parents:
diff changeset
   100
    }
0076bf602969 start gear data group implementation
alfadur
parents:
diff changeset
   101
15359
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   102
    fn is_full(&self) -> bool {
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   103
        self.elements_count == self.max_elements
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   104
    }
15310
0076bf602969 start gear data group implementation
alfadur
parents:
diff changeset
   105
}
0076bf602969 start gear data group implementation
alfadur
parents:
diff changeset
   106
15359
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   107
#[derive(Clone, Copy, Debug, Default)]
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   108
pub struct LookupEntry {
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   109
    index: Option<NonZeroU16>,
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   110
    block_index: u16,
15310
0076bf602969 start gear data group implementation
alfadur
parents:
diff changeset
   111
}
0076bf602969 start gear data group implementation
alfadur
parents:
diff changeset
   112
0076bf602969 start gear data group implementation
alfadur
parents:
diff changeset
   113
pub struct GearDataManager {
0076bf602969 start gear data group implementation
alfadur
parents:
diff changeset
   114
    types: Vec<TypeId>,
15359
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   115
    blocks: Vec<DataBlock>,
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   116
    block_masks: Vec<u64>,
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   117
    element_sizes: Box<[u16; 64]>,
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   118
    lookup: Box<[LookupEntry]>,
15310
0076bf602969 start gear data group implementation
alfadur
parents:
diff changeset
   119
}
0076bf602969 start gear data group implementation
alfadur
parents:
diff changeset
   120
0076bf602969 start gear data group implementation
alfadur
parents:
diff changeset
   121
impl GearDataManager {
0076bf602969 start gear data group implementation
alfadur
parents:
diff changeset
   122
    pub fn new() -> Self {
0076bf602969 start gear data group implementation
alfadur
parents:
diff changeset
   123
        Self {
0076bf602969 start gear data group implementation
alfadur
parents:
diff changeset
   124
            types: vec![],
15359
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   125
            blocks: vec![],
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   126
            block_masks: vec![],
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   127
            element_sizes: Box::new([0; 64]),
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   128
            lookup: vec![LookupEntry::default(); u16::max_value() as usize].into_boxed_slice(),
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   129
        }
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   130
    }
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   131
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   132
    #[inline]
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   133
    fn get_type_index<T: 'static>(&self) -> Option<usize> {
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   134
        let type_id = TypeId::of::<T>();
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   135
        self.types.iter().position(|id| *id == type_id)
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   136
    }
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   137
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   138
    fn move_between_blocks(&mut self, from_block_index: u16, from_index: u16, to_block_index: u16) {
15362
135c29237a56 implement moving between blocks
alfadur
parents: 15361
diff changeset
   139
        debug_assert!(from_block_index != to_block_index);
15359
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   140
        let source_mask = self.block_masks[from_block_index as usize];
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   141
        let destination_mask = self.block_masks[to_block_index as usize];
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   142
        debug_assert!(source_mask & destination_mask == source_mask);
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   143
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   144
        let source = &self.blocks[from_block_index as usize];
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   145
        let destination = &self.blocks[to_block_index as usize];
15362
135c29237a56 implement moving between blocks
alfadur
parents: 15361
diff changeset
   146
        debug_assert!(from_index < source.elements_count);
135c29237a56 implement moving between blocks
alfadur
parents: 15361
diff changeset
   147
        debug_assert!(!destination.is_full());
135c29237a56 implement moving between blocks
alfadur
parents: 15361
diff changeset
   148
15359
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   149
        for i in 0..64 {
15363
b5e0a39856fd complete basic ecs
alfadur
parents: 15362
diff changeset
   150
            if source_mask & 1 << i != 0 {
15362
135c29237a56 implement moving between blocks
alfadur
parents: 15361
diff changeset
   151
                unsafe {
135c29237a56 implement moving between blocks
alfadur
parents: 15361
diff changeset
   152
                    copy_nonoverlapping(
15363
b5e0a39856fd complete basic ecs
alfadur
parents: 15362
diff changeset
   153
                        source.component_blocks[i].unwrap().as_ptr(),
b5e0a39856fd complete basic ecs
alfadur
parents: 15362
diff changeset
   154
                        destination.component_blocks[i].unwrap().as_ptr(),
15362
135c29237a56 implement moving between blocks
alfadur
parents: 15361
diff changeset
   155
                        self.element_sizes[i] as usize,
135c29237a56 implement moving between blocks
alfadur
parents: 15361
diff changeset
   156
                    );
135c29237a56 implement moving between blocks
alfadur
parents: 15361
diff changeset
   157
                }
135c29237a56 implement moving between blocks
alfadur
parents: 15361
diff changeset
   158
            }
15359
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   159
        }
15362
135c29237a56 implement moving between blocks
alfadur
parents: 15361
diff changeset
   160
        self.blocks[from_block_index as usize].elements_count -= 1;
135c29237a56 implement moving between blocks
alfadur
parents: 15361
diff changeset
   161
        self.blocks[to_block_index as usize].elements_count += 1;
15359
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   162
    }
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   163
15361
277acc9f9fcf implement addition to/removal from blocks
alfadur
parents: 15359
diff changeset
   164
    fn add_to_block<T: Clone>(&mut self, block_index: u16, value: &T) {
277acc9f9fcf implement addition to/removal from blocks
alfadur
parents: 15359
diff changeset
   165
        debug_assert!(self.block_masks[block_index as usize].count_ones() == 1);
277acc9f9fcf implement addition to/removal from blocks
alfadur
parents: 15359
diff changeset
   166
277acc9f9fcf implement addition to/removal from blocks
alfadur
parents: 15359
diff changeset
   167
        let block = &mut self.blocks[block_index as usize];
277acc9f9fcf implement addition to/removal from blocks
alfadur
parents: 15359
diff changeset
   168
        debug_assert!(block.elements_count < block.max_elements);
277acc9f9fcf implement addition to/removal from blocks
alfadur
parents: 15359
diff changeset
   169
277acc9f9fcf implement addition to/removal from blocks
alfadur
parents: 15359
diff changeset
   170
        unsafe {
277acc9f9fcf implement addition to/removal from blocks
alfadur
parents: 15359
diff changeset
   171
            let slice = slice::from_raw_parts_mut(
277acc9f9fcf implement addition to/removal from blocks
alfadur
parents: 15359
diff changeset
   172
                block.data.as_mut_ptr() as *mut T,
277acc9f9fcf implement addition to/removal from blocks
alfadur
parents: 15359
diff changeset
   173
                block.max_elements as usize,
277acc9f9fcf implement addition to/removal from blocks
alfadur
parents: 15359
diff changeset
   174
            );
277acc9f9fcf implement addition to/removal from blocks
alfadur
parents: 15359
diff changeset
   175
            *slice.get_unchecked_mut(block.elements_count as usize) = value.clone();
277acc9f9fcf implement addition to/removal from blocks
alfadur
parents: 15359
diff changeset
   176
        };
277acc9f9fcf implement addition to/removal from blocks
alfadur
parents: 15359
diff changeset
   177
        block.elements_count += 1;
15359
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   178
    }
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   179
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   180
    fn remove_from_block(&mut self, block_index: u16, index: u16) {
15361
277acc9f9fcf implement addition to/removal from blocks
alfadur
parents: 15359
diff changeset
   181
        let block = &mut self.blocks[block_index as usize];
277acc9f9fcf implement addition to/removal from blocks
alfadur
parents: 15359
diff changeset
   182
        debug_assert!(index < block.elements_count);
277acc9f9fcf implement addition to/removal from blocks
alfadur
parents: 15359
diff changeset
   183
277acc9f9fcf implement addition to/removal from blocks
alfadur
parents: 15359
diff changeset
   184
        for (i, size) in self.element_sizes.iter().cloned().enumerate() {
277acc9f9fcf implement addition to/removal from blocks
alfadur
parents: 15359
diff changeset
   185
            if index < block.elements_count - 1 {
15363
b5e0a39856fd complete basic ecs
alfadur
parents: 15362
diff changeset
   186
                if let Some(ptr) = block.component_blocks[i] {
15361
277acc9f9fcf implement addition to/removal from blocks
alfadur
parents: 15359
diff changeset
   187
                    unsafe {
15362
135c29237a56 implement moving between blocks
alfadur
parents: 15361
diff changeset
   188
                        copy_nonoverlapping(
15361
277acc9f9fcf implement addition to/removal from blocks
alfadur
parents: 15359
diff changeset
   189
                            ptr.as_ptr()
277acc9f9fcf implement addition to/removal from blocks
alfadur
parents: 15359
diff changeset
   190
                                .add((size * (block.elements_count - 1)) as usize),
277acc9f9fcf implement addition to/removal from blocks
alfadur
parents: 15359
diff changeset
   191
                            ptr.as_ptr().add((size * index) as usize),
277acc9f9fcf implement addition to/removal from blocks
alfadur
parents: 15359
diff changeset
   192
                            size as usize,
277acc9f9fcf implement addition to/removal from blocks
alfadur
parents: 15359
diff changeset
   193
                        );
277acc9f9fcf implement addition to/removal from blocks
alfadur
parents: 15359
diff changeset
   194
                    }
277acc9f9fcf implement addition to/removal from blocks
alfadur
parents: 15359
diff changeset
   195
                }
277acc9f9fcf implement addition to/removal from blocks
alfadur
parents: 15359
diff changeset
   196
            }
277acc9f9fcf implement addition to/removal from blocks
alfadur
parents: 15359
diff changeset
   197
        }
277acc9f9fcf implement addition to/removal from blocks
alfadur
parents: 15359
diff changeset
   198
        block.elements_count -= 1;
15359
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   199
    }
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   200
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   201
    #[inline]
15363
b5e0a39856fd complete basic ecs
alfadur
parents: 15362
diff changeset
   202
    fn ensure_block(&mut self, mask: u64) -> u16 {
15359
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   203
        if let Some(index) = self
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   204
            .block_masks
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   205
            .iter()
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   206
            .enumerate()
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   207
            .position(|(i, m)| *m == mask && !self.blocks[i].is_full())
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   208
        {
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   209
            index as u16
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   210
        } else {
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   211
            self.blocks.push(DataBlock::new(mask, &self.element_sizes));
15363
b5e0a39856fd complete basic ecs
alfadur
parents: 15362
diff changeset
   212
            self.block_masks.push(mask);
15359
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   213
            (self.blocks.len() - 1) as u16
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   214
        }
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   215
    }
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   216
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   217
    pub fn add<T: Clone + 'static>(&mut self, gear_id: GearId, value: &T) {
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   218
        if let Some(type_index) = self.get_type_index::<T>() {
15363
b5e0a39856fd complete basic ecs
alfadur
parents: 15362
diff changeset
   219
            let type_bit = 1 << type_index as u64;
15359
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   220
            let entry = self.lookup[gear_id.get() as usize - 1];
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   221
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   222
            if let Some(index) = entry.index {
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   223
                let mask = self.block_masks[entry.block_index as usize];
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   224
                let new_mask = mask | type_bit;
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   225
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   226
                if new_mask != mask {
15363
b5e0a39856fd complete basic ecs
alfadur
parents: 15362
diff changeset
   227
                    let dest_block_index = self.ensure_block(new_mask);
15359
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   228
                    self.move_between_blocks(entry.block_index, index.get() - 1, dest_block_index);
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   229
                }
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   230
            } else {
15363
b5e0a39856fd complete basic ecs
alfadur
parents: 15362
diff changeset
   231
                let dest_block_index = self.ensure_block(type_bit);
15359
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   232
                self.add_to_block(dest_block_index, value);
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   233
            }
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   234
        } else {
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   235
            panic!("Unregistered type")
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   236
        }
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   237
    }
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   238
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   239
    pub fn remove<T: 'static>(&mut self, gear_id: GearId) {
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   240
        if let Some(type_index) = self.get_type_index::<T>() {
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   241
            let entry = self.lookup[gear_id.get() as usize - 1];
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   242
            if let Some(index) = entry.index {
15362
135c29237a56 implement moving between blocks
alfadur
parents: 15361
diff changeset
   243
                let destination_mask =
15363
b5e0a39856fd complete basic ecs
alfadur
parents: 15362
diff changeset
   244
                    self.block_masks[entry.block_index as usize] & !(1 << type_index as u64);
15362
135c29237a56 implement moving between blocks
alfadur
parents: 15361
diff changeset
   245
135c29237a56 implement moving between blocks
alfadur
parents: 15361
diff changeset
   246
                if destination_mask == 0 {
135c29237a56 implement moving between blocks
alfadur
parents: 15361
diff changeset
   247
                    self.remove_all(gear_id)
135c29237a56 implement moving between blocks
alfadur
parents: 15361
diff changeset
   248
                } else {
15363
b5e0a39856fd complete basic ecs
alfadur
parents: 15362
diff changeset
   249
                    let destination_block_index = self.ensure_block(destination_mask);
15362
135c29237a56 implement moving between blocks
alfadur
parents: 15361
diff changeset
   250
                    self.move_between_blocks(
135c29237a56 implement moving between blocks
alfadur
parents: 15361
diff changeset
   251
                        entry.block_index,
135c29237a56 implement moving between blocks
alfadur
parents: 15361
diff changeset
   252
                        index.get() - 1,
135c29237a56 implement moving between blocks
alfadur
parents: 15361
diff changeset
   253
                        destination_block_index,
135c29237a56 implement moving between blocks
alfadur
parents: 15361
diff changeset
   254
                    );
135c29237a56 implement moving between blocks
alfadur
parents: 15361
diff changeset
   255
                }
15359
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   256
            }
15362
135c29237a56 implement moving between blocks
alfadur
parents: 15361
diff changeset
   257
        } else {
135c29237a56 implement moving between blocks
alfadur
parents: 15361
diff changeset
   258
            panic!("Unregistered type")
135c29237a56 implement moving between blocks
alfadur
parents: 15361
diff changeset
   259
        }
135c29237a56 implement moving between blocks
alfadur
parents: 15361
diff changeset
   260
    }
135c29237a56 implement moving between blocks
alfadur
parents: 15361
diff changeset
   261
135c29237a56 implement moving between blocks
alfadur
parents: 15361
diff changeset
   262
    pub fn remove_all(&mut self, gear_id: GearId) {
135c29237a56 implement moving between blocks
alfadur
parents: 15361
diff changeset
   263
        let entry = self.lookup[gear_id.get() as usize - 1];
135c29237a56 implement moving between blocks
alfadur
parents: 15361
diff changeset
   264
        if let Some(index) = entry.index {
135c29237a56 implement moving between blocks
alfadur
parents: 15361
diff changeset
   265
            self.remove_from_block(entry.block_index, index.get() - 1);
15310
0076bf602969 start gear data group implementation
alfadur
parents:
diff changeset
   266
        }
0076bf602969 start gear data group implementation
alfadur
parents:
diff changeset
   267
    }
0076bf602969 start gear data group implementation
alfadur
parents:
diff changeset
   268
0076bf602969 start gear data group implementation
alfadur
parents:
diff changeset
   269
    pub fn register<T: 'static>(&mut self) {
15361
277acc9f9fcf implement addition to/removal from blocks
alfadur
parents: 15359
diff changeset
   270
        debug_assert!(!std::mem::needs_drop::<T>());
277acc9f9fcf implement addition to/removal from blocks
alfadur
parents: 15359
diff changeset
   271
        debug_assert!(self.types.len() <= 64);
277acc9f9fcf implement addition to/removal from blocks
alfadur
parents: 15359
diff changeset
   272
        debug_assert!(size_of::<T>() <= u16::max_value() as usize);
15359
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   273
15310
0076bf602969 start gear data group implementation
alfadur
parents:
diff changeset
   274
        let id = TypeId::of::<T>();
0076bf602969 start gear data group implementation
alfadur
parents:
diff changeset
   275
        if !self.types.contains(&id) {
15359
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   276
            self.element_sizes[self.types.len()] = size_of::<T>() as u16;
15310
0076bf602969 start gear data group implementation
alfadur
parents:
diff changeset
   277
            self.types.push(id);
0076bf602969 start gear data group implementation
alfadur
parents:
diff changeset
   278
        }
0076bf602969 start gear data group implementation
alfadur
parents:
diff changeset
   279
    }
0076bf602969 start gear data group implementation
alfadur
parents:
diff changeset
   280
15372
d6b4586b271f make sure component slice order corresponds to the type args
alfadur
parents: 15363
diff changeset
   281
    pub fn iter<T: TypeTuple + 'static, F: FnMut(T)>(&self, mut f: F) {
d6b4586b271f make sure component slice order corresponds to the type args
alfadur
parents: 15363
diff changeset
   282
        let mut arg_types = Vec::with_capacity(64);
d6b4586b271f make sure component slice order corresponds to the type args
alfadur
parents: 15363
diff changeset
   283
        T::get_types(&mut arg_types);
d6b4586b271f make sure component slice order corresponds to the type args
alfadur
parents: 15363
diff changeset
   284
d6b4586b271f make sure component slice order corresponds to the type args
alfadur
parents: 15363
diff changeset
   285
        let mut type_indices = vec![-1i8; arg_types.len()];
d6b4586b271f make sure component slice order corresponds to the type args
alfadur
parents: 15363
diff changeset
   286
        let mut selector = 0u64;
d6b4586b271f make sure component slice order corresponds to the type args
alfadur
parents: 15363
diff changeset
   287
d6b4586b271f make sure component slice order corresponds to the type args
alfadur
parents: 15363
diff changeset
   288
        for (arg_index, type_id) in arg_types.iter().enumerate() {
d6b4586b271f make sure component slice order corresponds to the type args
alfadur
parents: 15363
diff changeset
   289
            match self.types.iter().position(|t| t == type_id) {
d6b4586b271f make sure component slice order corresponds to the type args
alfadur
parents: 15363
diff changeset
   290
                Some(i) if selector & 1 << i as u64 != 0 => panic!("Duplicate type"),
d6b4586b271f make sure component slice order corresponds to the type args
alfadur
parents: 15363
diff changeset
   291
                Some(i) => {
d6b4586b271f make sure component slice order corresponds to the type args
alfadur
parents: 15363
diff changeset
   292
                    type_indices[arg_index] = i as i8;
d6b4586b271f make sure component slice order corresponds to the type args
alfadur
parents: 15363
diff changeset
   293
                    selector &= 1 << i as u64;
15373
445138f388d4 expand iteration implementation to larger tuples
alfadur
parents: 15372
diff changeset
   294
                }
445138f388d4 expand iteration implementation to larger tuples
alfadur
parents: 15372
diff changeset
   295
                None => panic!("Unregistered type"),
15310
0076bf602969 start gear data group implementation
alfadur
parents:
diff changeset
   296
            }
0076bf602969 start gear data group implementation
alfadur
parents:
diff changeset
   297
        }
0076bf602969 start gear data group implementation
alfadur
parents:
diff changeset
   298
15372
d6b4586b271f make sure component slice order corresponds to the type args
alfadur
parents: 15363
diff changeset
   299
        let mut slices = vec![null_mut(); arg_types.len()];
15363
b5e0a39856fd complete basic ecs
alfadur
parents: 15362
diff changeset
   300
15359
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   301
        for (block_index, mask) in self.block_masks.iter().enumerate() {
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   302
            if mask & selector == selector {
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   303
                let block = &self.blocks[block_index];
15363
b5e0a39856fd complete basic ecs
alfadur
parents: 15362
diff changeset
   304
15372
d6b4586b271f make sure component slice order corresponds to the type args
alfadur
parents: 15363
diff changeset
   305
                for (arg_index, type_index) in type_indices.iter().cloned().enumerate() {
15373
445138f388d4 expand iteration implementation to larger tuples
alfadur
parents: 15372
diff changeset
   306
                    slices[arg_index as usize] = block.component_blocks[type_index as usize]
445138f388d4 expand iteration implementation to larger tuples
alfadur
parents: 15372
diff changeset
   307
                        .unwrap()
445138f388d4 expand iteration implementation to larger tuples
alfadur
parents: 15372
diff changeset
   308
                        .as_ptr()
15359
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   309
                }
15363
b5e0a39856fd complete basic ecs
alfadur
parents: 15362
diff changeset
   310
b5e0a39856fd complete basic ecs
alfadur
parents: 15362
diff changeset
   311
                unsafe {
b5e0a39856fd complete basic ecs
alfadur
parents: 15362
diff changeset
   312
                    T::iter(&slices[..], block.elements_count as usize, |x| f(x));
b5e0a39856fd complete basic ecs
alfadur
parents: 15362
diff changeset
   313
                }
15310
0076bf602969 start gear data group implementation
alfadur
parents:
diff changeset
   314
            }
0076bf602969 start gear data group implementation
alfadur
parents:
diff changeset
   315
        }
0076bf602969 start gear data group implementation
alfadur
parents:
diff changeset
   316
    }
0076bf602969 start gear data group implementation
alfadur
parents:
diff changeset
   317
}
15359
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   318
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   319
#[cfg(test)]
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   320
mod test {
15363
b5e0a39856fd complete basic ecs
alfadur
parents: 15362
diff changeset
   321
    use super::{super::common::GearId, GearDataManager};
15359
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   322
15363
b5e0a39856fd complete basic ecs
alfadur
parents: 15362
diff changeset
   323
    #[derive(Clone)]
15359
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   324
    struct Datum {
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   325
        value: u32,
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   326
    }
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   327
15376
24a9afbf33c6 add multicomponent iteration test
alfadur
parents: 15374
diff changeset
   328
    #[derive(Clone)]
24a9afbf33c6 add multicomponent iteration test
alfadur
parents: 15374
diff changeset
   329
    struct Tag {
24a9afbf33c6 add multicomponent iteration test
alfadur
parents: 15374
diff changeset
   330
        nothing: u8,
24a9afbf33c6 add multicomponent iteration test
alfadur
parents: 15374
diff changeset
   331
    }
24a9afbf33c6 add multicomponent iteration test
alfadur
parents: 15374
diff changeset
   332
15359
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   333
    #[test]
15363
b5e0a39856fd complete basic ecs
alfadur
parents: 15362
diff changeset
   334
    fn single_component_iteration() {
15359
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   335
        let mut manager = GearDataManager::new();
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   336
        manager.register::<Datum>();
15363
b5e0a39856fd complete basic ecs
alfadur
parents: 15362
diff changeset
   337
        for i in 1..=5 {
b5e0a39856fd complete basic ecs
alfadur
parents: 15362
diff changeset
   338
            manager.add(GearId::new(i as u16).unwrap(), &Datum { value: i });
b5e0a39856fd complete basic ecs
alfadur
parents: 15362
diff changeset
   339
        }
b5e0a39856fd complete basic ecs
alfadur
parents: 15362
diff changeset
   340
b5e0a39856fd complete basic ecs
alfadur
parents: 15362
diff changeset
   341
        let mut sum = 0;
b5e0a39856fd complete basic ecs
alfadur
parents: 15362
diff changeset
   342
        manager.iter(|(d,): (&Datum,)| sum += d.value);
15373
445138f388d4 expand iteration implementation to larger tuples
alfadur
parents: 15372
diff changeset
   343
        assert_eq!(sum, 15);
15363
b5e0a39856fd complete basic ecs
alfadur
parents: 15362
diff changeset
   344
15373
445138f388d4 expand iteration implementation to larger tuples
alfadur
parents: 15372
diff changeset
   345
        manager.iter(|(d,): (&mut Datum,)| d.value += 1);
445138f388d4 expand iteration implementation to larger tuples
alfadur
parents: 15372
diff changeset
   346
        manager.iter(|(d,): (&Datum,)| sum += d.value);
445138f388d4 expand iteration implementation to larger tuples
alfadur
parents: 15372
diff changeset
   347
        assert_eq!(sum, 35);
15359
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   348
    }
15376
24a9afbf33c6 add multicomponent iteration test
alfadur
parents: 15374
diff changeset
   349
24a9afbf33c6 add multicomponent iteration test
alfadur
parents: 15374
diff changeset
   350
    #[test]
24a9afbf33c6 add multicomponent iteration test
alfadur
parents: 15374
diff changeset
   351
    fn multiple_component_iteration() {
24a9afbf33c6 add multicomponent iteration test
alfadur
parents: 15374
diff changeset
   352
        let mut manager = GearDataManager::new();
24a9afbf33c6 add multicomponent iteration test
alfadur
parents: 15374
diff changeset
   353
        manager.register::<Datum>();
24a9afbf33c6 add multicomponent iteration test
alfadur
parents: 15374
diff changeset
   354
        manager.register::<Tag>();
24a9afbf33c6 add multicomponent iteration test
alfadur
parents: 15374
diff changeset
   355
        for i in 1..=10 {
24a9afbf33c6 add multicomponent iteration test
alfadur
parents: 15374
diff changeset
   356
            let gear_id = GearId::new(i as u16).unwrap();
24a9afbf33c6 add multicomponent iteration test
alfadur
parents: 15374
diff changeset
   357
            manager.add(gear_id, &Datum { value: i });
24a9afbf33c6 add multicomponent iteration test
alfadur
parents: 15374
diff changeset
   358
            if i & 1 == 0 {
24a9afbf33c6 add multicomponent iteration test
alfadur
parents: 15374
diff changeset
   359
                manager.add(gear_id, &Tag { nothing: 0 });
24a9afbf33c6 add multicomponent iteration test
alfadur
parents: 15374
diff changeset
   360
            }
24a9afbf33c6 add multicomponent iteration test
alfadur
parents: 15374
diff changeset
   361
        }
24a9afbf33c6 add multicomponent iteration test
alfadur
parents: 15374
diff changeset
   362
24a9afbf33c6 add multicomponent iteration test
alfadur
parents: 15374
diff changeset
   363
        let mut sum1 = 0;
24a9afbf33c6 add multicomponent iteration test
alfadur
parents: 15374
diff changeset
   364
        let mut sum2 = 0;
24a9afbf33c6 add multicomponent iteration test
alfadur
parents: 15374
diff changeset
   365
        manager.iter(|(d, _): (&Datum, &Tag)| sum1 += d.value);
24a9afbf33c6 add multicomponent iteration test
alfadur
parents: 15374
diff changeset
   366
        manager.iter(|(_, d): (&Tag, &Datum)| sum2 += d.value);
24a9afbf33c6 add multicomponent iteration test
alfadur
parents: 15374
diff changeset
   367
        assert_eq!(sum1, 30);
24a9afbf33c6 add multicomponent iteration test
alfadur
parents: 15374
diff changeset
   368
        assert_eq!(sum2, sum1);
24a9afbf33c6 add multicomponent iteration test
alfadur
parents: 15374
diff changeset
   369
    }
15359
dff37ac61dcf convert ecs storage to untyped
alfadur
parents: 15310
diff changeset
   370
}