1
Fork 0

hashmap cache

This commit is contained in:
Andy Killorin 2023-12-26 11:07:45 -06:00
parent 42ef46f2ff
commit 1a232d5c08
Signed by: ank
GPG key ID: B6241CA3B552BCA4
3 changed files with 76 additions and 12 deletions

View file

@ -1,3 +1,4 @@
extern crate test;
use std::{sync::Arc, ops::Sub, collections::HashMap}; use std::{sync::Arc, ops::Sub, collections::HashMap};
use anyhow::{Ok, anyhow}; use anyhow::{Ok, anyhow};
@ -8,16 +9,24 @@ use tokio::sync::{RwLock, OwnedRwLockReadGuard};
use crate::{turtle::TurtleCommand, paths::{self, TRANSPARENT}}; use crate::{turtle::TurtleCommand, paths::{self, TRANSPARENT}};
const CHUNK_SIZE: usize = 16; const CHUNK_SIZE: usize = 4;
const CHUNK_VOLUME: usize = CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE; const CHUNK_VOLUME: usize = CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE;
const CHUNK_VEC: Vec3 = Vec3::new(CHUNK_SIZE as i32, CHUNK_SIZE as i32, CHUNK_SIZE as i32); const CHUNK_VEC: Vec3 = Vec3::new(CHUNK_SIZE as i32, CHUNK_SIZE as i32, CHUNK_SIZE as i32);
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct World(HashMap<Vec3, Chunk>); // TODO: make r-trees faster than this, for my sanity pub struct World { // TODO: make r-trees faster than this, for my sanity
index: HashMap<Vec3, usize>,
data: Vec<Chunk>,
last: Option<usize>,
}
impl World { impl World {
pub fn new() -> Self { pub fn new() -> Self {
World(HashMap::new()) World{
index: HashMap::new(),
data: Vec::new(),
last: None,
}
} }
pub fn get(&self, block: Vec3) -> Option<Block> { pub fn get(&self, block: Vec3) -> Option<Block> {
let chunk = self.get_chunk(block)?; let chunk = self.get_chunk(block)?;
@ -25,22 +34,36 @@ impl World {
} }
pub fn set(&mut self, block: Block) { pub fn set(&mut self, block: Block) {
let chunk = block.pos.map(|n| i32::div_floor(n,CHUNK_SIZE as i32)); let chunk_coords = block.pos.map(|n| i32::div_floor(n,CHUNK_SIZE as i32));
match self.0.get_mut(&chunk) {
let chunk = self.last
.filter(|n| self.data[*n].contains(&block.pos))
.or_else(|| {
self.index.get(&chunk_coords).map(|c| *c)
})
.map(|n| *self.last.insert(n));
match chunk {
Some(chunk) => { Some(chunk) => {
chunk.set(block).unwrap(); self.data[chunk].set(block).unwrap();
}, },
None => { None => {
let mut new_chunk = Chunk::new(chunk); let mut new_chunk = Chunk::new(chunk_coords);
new_chunk.set(block).unwrap(); new_chunk.set(block).unwrap();
self.0.insert(chunk, new_chunk); self.data.push(new_chunk);
self.index.insert(chunk_coords, self.data.len() - 1);
}, },
} }
} }
fn get_chunk(&self, block: Vec3) -> Option<&Chunk> { fn get_chunk(&self, block: Vec3) -> Option<&Chunk> {
let block = block.map(|n| i32::div_floor(n,CHUNK_SIZE as i32)); let block = block.map(|n| i32::div_floor(n,CHUNK_SIZE as i32));
self.0.get(&block) if let Some(last) = self.last {
if self.data[last].contains(&block) {
return Some(&self.data[last])
}
}
self.index.get(&block).map(|i| &self.data[*i])
} }
} }
@ -127,7 +150,7 @@ impl Chunk {
fn contains(&self, pos:&Vec3) -> bool { fn contains(&self, pos:&Vec3) -> bool {
let chunk = self.pos.component_mul(&CHUNK_VEC); let chunk = self.pos.component_mul(&CHUNK_VEC);
let local = pos - chunk; let local = pos - chunk;
local >= Vec3::zeros() && local <= CHUNK_VEC local >= Vec3::zeros() && local < CHUNK_VEC
} }
} }
@ -281,6 +304,10 @@ pub fn nearest(from: Vec3, to: Vec3) -> Position {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use test::Bencher;
use crate::mine::fill;
use super::*; use super::*;
fn single_point(point: Vec3) { fn single_point(point: Vec3) {
@ -290,6 +317,19 @@ mod tests {
assert_eq!("a", world.get(point).unwrap().name); assert_eq!("a", world.get(point).unwrap().name);
} }
fn many(point: Vec3, size: Vec3) {
let mut world = World::new();
for i in 0..size.product() {
let block = fill(size, i) + point;
world.set(Block { name: i.to_string(), pos: block});
}
for i in 0..size.product() {
let block = fill(size, i) + point;
assert_eq!(i.to_string(), world.get(block).unwrap().name)
}
}
#[test] #[test]
fn origin() { fn origin() {
single_point(Vec3::zeros()) single_point(Vec3::zeros())
@ -302,4 +342,24 @@ mod tests {
fn small() { fn small() {
single_point(Vec3::new(-1212,100,-1292)) single_point(Vec3::new(-1212,100,-1292))
} }
#[test]
fn positive_many() {
many(Vec3::new(1212,100,1292), Vec3::new(100, 100, 100))
}
#[test]
fn negative_many() {
many(Vec3::new(-1212,100,-1292), Vec3::new(100, 100, 100))
}
#[bench]
fn positive_several(b: &mut Bencher) {
b.iter(||many(Vec3::new(1212,100,1292), Vec3::new(100, 1, 30)));
}
#[bench]
fn positive_many_bench(b: &mut Bencher) {
b.iter(||many(Vec3::new(1212,100,1292), Vec3::new(50, 50, 50)));
}
} }

View file

@ -1,4 +1,4 @@
#![feature(iter_map_windows, iter_collect_into, int_roundings)] #![feature(iter_map_windows, iter_collect_into, int_roundings, test)]
use std::{collections::VecDeque, io::ErrorKind, sync::Arc, env::args, path, borrow::BorrowMut, time::Duration}; use std::{collections::VecDeque, io::ErrorKind, sync::Arc, env::args, path, borrow::BorrowMut, time::Duration};

View file

@ -198,7 +198,11 @@ impl TurtleCommander {
// is left to read garbage // is left to read garbage
}; };
let resp = recv.await.unwrap(); let resp = recv.await.unwrap_or_else(|_| {
error!("server dissapering");
TurtleInfo::from_update(TurtleUpdate { fuel: self.fuel(), ahead: "".into(), above: "".into(), below: "".into(), ret: TurtleCommandResponse::Failure }, self.name(), Position::new(Vec3::zeros(), Direction::North))
});
let mut pos = self.pos.write().await; let mut pos = self.pos.write().await;
*pos = resp.pos; *pos = resp.pos;
self.fuel.store(resp.fuel, std::sync::atomic::Ordering::SeqCst); self.fuel.store(resp.fuel, std::sync::atomic::Ordering::SeqCst);