flatten(): add quickfix to cover up race condition in diff notification

This commit is contained in:
Michael Sippel 2021-08-11 17:29:13 +02:00
parent b6f67c8ee3
commit 261bf15b70
Signed by: senvas
GPG key ID: F96CF119C34B64A6

View file

@ -19,7 +19,7 @@ use {
impl<Item> OuterViewPort<dyn GridView<Item = OuterViewPort<dyn GridView<Item = Item>>>> impl<Item> OuterViewPort<dyn GridView<Item = OuterViewPort<dyn GridView<Item = Item>>>>
where Item: 'static{ where Item: 'static{
pub fn flatten(&self) -> OuterViewPort<dyn GridView<Item = Item> + 'static> { pub fn flatten(&self) -> OuterViewPort<dyn GridView<Item = Item>> {
let port = ViewPort::new(); let port = ViewPort::new();
port.add_update_hook(Arc::new(self.0.clone())); port.add_update_hook(Arc::new(self.0.clone()));
Flatten::new(self.clone(), port.inner()); Flatten::new(self.clone(), port.inner());
@ -100,49 +100,61 @@ where Item: 'static
/// create a new observer for the contained sub sequence /// create a new observer for the contained sub sequence
fn update_chunk(&mut self, chunk_idx: Point2<i16>) { fn update_chunk(&mut self, chunk_idx: Point2<i16>) {
if let Some(chunk_port) = self.top.get(&chunk_idx) { if let Some(chunk_port) = self.top.get(&chunk_idx) {
self.chunks.insert( let view = self.proj_helper.new_index_arg(
chunk_idx,
Chunk {
offset: Vector2::new(0, 0),
limit: Point2::new(0, 0),
view: self.proj_helper.new_index_arg(
chunk_port.clone(), chunk_port.clone(),
move |s: &mut Self, idx| { move |s: &mut Self, idx| {
if let Some(chunk) = s.chunks.get(&chunk_idx) { if let Some(chunk) = s.chunks.get(&chunk_idx) {
let chunk_offset = chunk.offset; if chunk.limit != chunk.view.range().end {
let chunk_limit = chunk.view.range().end; s.update_all_offsets();
let mut dirty_idx = Vec::new();
if chunk.limit != chunk_limit {
dirty_idx = s.update_all_offsets();
}
s.cast.notify(&(idx + chunk_offset));
s.cast.notify_each(dirty_idx);
} }
} }
) if let Some(chunk) = s.chunks.get(&chunk_idx) {
s.cast.notify(&(idx + chunk.offset));
}
} }
); );
/*
if let Some(chunk) = self.chunks.get_mut(&chunk_idx) {
chunk.view = view;
} else {
*/
self.chunks.insert(
chunk_idx,
Chunk {
offset: Vector2::new(-1, -1),
limit: Point2::new(-1, -1),
view
}
);
/*
}
*/
chunk_port.0.update(); chunk_port.0.update();
self.update_all_offsets();
let dirty_idx = self.update_all_offsets(); chunk_port.0.update();
self.cast.notify_each(dirty_idx);
} else { } else {
// todo: // todo:
//self.proj_helper.remove_arg(); //self.proj_helper.remove_arg();
self.chunks.remove(&chunk_idx); let mut dirty_idx = Vec::new();
if let Some(chunk) = self.chunks.get_mut(&chunk_idx) {
dirty_idx.extend(
GridWindowIterator::from(
Point2::new(chunk.offset.x, chunk.offset.y)
.. Point2::new(chunk.offset.x + chunk.limit.x, chunk.offset.y + chunk.limit.y))
);
}
let dirty_idx = self.update_all_offsets(); self.chunks.remove(&chunk_idx);
self.cast.notify_each(dirty_idx); self.cast.notify_each(dirty_idx);
self.update_all_offsets();
} }
} }
/// recalculate all chunk offsets /// recalculate all chunk offsets
/// and update size of flattened grid /// and update size of flattened grid
fn update_all_offsets(&mut self) -> Vec<Point2<i16>> { fn update_all_offsets(&mut self) {
let mut dirty_idx = Vec::new(); let mut dirty_idx = Vec::new();
let top_range = self.top.range(); let top_range = self.top.range();
@ -168,34 +180,41 @@ where Item: 'static
GridWindowIterator::from( GridWindowIterator::from(
Point2::new(std::cmp::min(old_offset.x, chunk.offset.x), Point2::new(std::cmp::min(old_offset.x, chunk.offset.x),
std::cmp::min(old_offset.y, chunk.offset.y)) std::cmp::min(old_offset.y, chunk.offset.y))
.. Point2::new(std::cmp::max(old_offset.x, chunk.offset.x) + std::cmp::max(old_limit.x, chunk.limit.x), .. Point2::new(std::cmp::max(old_offset.x + old_limit.x, chunk.offset.x + chunk.limit.x),
std::cmp::max(old_offset.y, chunk.offset.y) + std::cmp::max(old_limit.y, chunk.limit.y))) std::cmp::max(old_offset.y + old_limit.y, chunk.offset.y + chunk.limit.y)))
); );
} }
} }
} }
//let old_limit = self.limit; let old_limit = self.limit;
self.limit = Point2::new( self.limit = Point2::new(
(0 .. top_range.end.x as usize).map(|x| col_widths[x]).sum(), (0 .. top_range.end.x as usize).map(|x| col_widths[x]).sum(),
(0 .. top_range.end.y as usize).map(|y| row_heights[y]).sum() (0 .. top_range.end.y as usize).map(|y| row_heights[y]).sum()
); );
dirty_idx // fixme: dirty hack to mitigate the buggy notifications, not efficien
dirty_idx.extend(
GridWindowIterator::from(
Point2::new(0, 0) .. Point2::new(
std::cmp::max(old_limit.x, self.limit.x),
std::cmp::max(old_limit.y, self.limit.y)
)
)
);
self.cast.notify_each(dirty_idx);
} }
/// given an index in the flattened sequence, /// given an index in the flattened sequence,
/// which sub-sequence does it belong to? /// which sub-sequence does it belong to?
fn get_chunk_idx(&self, glob_pos: Point2<i16>) -> Option<Point2<i16>> { fn get_chunk_idx(&self, glob_pos: Point2<i16>) -> Option<Point2<i16>> {
let mut offset = Point2::new(0, 0);
for chunk_idx in GridWindowIterator::from(self.top.range()) { for chunk_idx in GridWindowIterator::from(self.top.range()) {
if let Some(chunk) = self.chunks.get(&chunk_idx) { if let Some(chunk) = self.chunks.get(&chunk_idx) {
let chunk_range = chunk.view.range(); let chunk_range = chunk.view.range();
let end = chunk_range.end + chunk.offset;
offset += Vector2::new(chunk_range.end.x, chunk_range.end.y); if glob_pos.x < end.x && glob_pos.y < end.y {
if glob_pos.x < offset.x && glob_pos.y < offset.y {
return Some(chunk_idx); return Some(chunk_idx);
} }
} }