hashmap cache
This commit is contained in:
parent
42ef46f2ff
commit
1a232d5c08
3 changed files with 76 additions and 12 deletions
|
@ -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)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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};
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue