mirror of
https://github.com/mat-1/azalea.git
synced 2025-08-02 14:26:04 +00:00
binary search map
This commit is contained in:
parent
350bbac282
commit
c3b63ad129
10 changed files with 122 additions and 75 deletions
18
Cargo.lock
generated
18
Cargo.lock
generated
|
@ -39,19 +39,6 @@ dependencies = [
|
|||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"getrandom",
|
||||
"once_cell",
|
||||
"serde",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.7.20"
|
||||
|
@ -349,7 +336,6 @@ dependencies = [
|
|||
name = "azalea-nbt"
|
||||
version = "0.6.0"
|
||||
dependencies = [
|
||||
"ahash 0.8.3",
|
||||
"azalea-buf",
|
||||
"byteorder",
|
||||
"compact_str",
|
||||
|
@ -656,7 +642,7 @@ version = "0.10.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04d90ce493910ad9af3b4220ea6864c7d1472761086a98230ecac59c8d547e95"
|
||||
dependencies = [
|
||||
"ahash 0.7.6",
|
||||
"ahash",
|
||||
"bevy_utils_proc_macros",
|
||||
"getrandom",
|
||||
"hashbrown",
|
||||
|
@ -1329,7 +1315,7 @@ version = "0.12.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
dependencies = [
|
||||
"ahash 0.7.6",
|
||||
"ahash",
|
||||
"serde",
|
||||
]
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@ repository = "https://github.com/mat-1/azalea/tree/main/azalea-nbt"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
ahash = { version = "^0.8.3" }
|
||||
azalea-buf = { path = "../azalea-buf", version = "^0.6.0" }
|
||||
byteorder = "^1.4.3"
|
||||
compact_str = { version = "0.7.0", features = ["serde"] }
|
||||
|
@ -26,7 +25,7 @@ fastnbt = "2.4.3"
|
|||
|
||||
[features]
|
||||
default = []
|
||||
serde = ["dep:serde", "ahash/serde"]
|
||||
serde = ["dep:serde"]
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
|
|
|
@ -7,17 +7,16 @@ Note: Running your code with `RUSTFLAGS="-C target-cpu=native"` will result in s
|
|||
# Examples
|
||||
|
||||
```
|
||||
use ahash::AHashMap;
|
||||
use azalea_nbt::Tag;
|
||||
use azalea_nbt::{Tag, NbtCompound};
|
||||
use std::io::Cursor;
|
||||
|
||||
let buf = include_bytes!("../tests/hello_world.nbt");
|
||||
let tag = Tag::read(&mut Cursor::new(&buf[..])).unwrap();
|
||||
assert_eq!(
|
||||
tag,
|
||||
Tag::Compound(AHashMap::from_iter(vec![(
|
||||
Tag::Compound(NbtCompound::from_iter(vec![(
|
||||
"hello world".into(),
|
||||
Tag::Compound(AHashMap::from_iter(vec![(
|
||||
Tag::Compound(NbtCompound::from_iter(vec![(
|
||||
"name".into(),
|
||||
Tag::String("Bananrama".into()),
|
||||
)]))
|
||||
|
|
|
@ -48,40 +48,40 @@ pub fn bench_read_file(filename: &str, c: &mut Criterion) {
|
|||
|
||||
// // writing
|
||||
|
||||
// let nbt = azalea_nbt::Tag::read_from(&mut Cursor::new(input)).unwrap();
|
||||
// group.bench_function("azalea_write", |b| {
|
||||
// b.iter(|| {
|
||||
// let nbt = black_box(&nbt);
|
||||
// let mut written = Vec::new();
|
||||
// nbt.write(&mut written).unwrap();
|
||||
// black_box(written);
|
||||
// })
|
||||
// });
|
||||
let nbt = azalea_nbt::Tag::read_from(&mut Cursor::new(input)).unwrap();
|
||||
group.bench_function("azalea_write", |b| {
|
||||
b.iter(|| {
|
||||
let nbt = black_box(&nbt);
|
||||
let mut written = Vec::new();
|
||||
nbt.write(&mut written).unwrap();
|
||||
black_box(written);
|
||||
})
|
||||
});
|
||||
|
||||
// let nbt = graphite_binary::nbt::decode::read(&mut &input[..]).unwrap();
|
||||
// group.bench_function("graphite_write", |b| {
|
||||
// b.iter(|| {
|
||||
// let nbt = black_box(&nbt);
|
||||
// let written = graphite_binary::nbt::encode::write(nbt);
|
||||
// black_box(written);
|
||||
// })
|
||||
// });
|
||||
let nbt = graphite_binary::nbt::decode::read(&mut &input[..]).unwrap();
|
||||
group.bench_function("graphite_write", |b| {
|
||||
b.iter(|| {
|
||||
let nbt = black_box(&nbt);
|
||||
let written = graphite_binary::nbt::encode::write(nbt);
|
||||
black_box(written);
|
||||
})
|
||||
});
|
||||
|
||||
// let nbt = valence_nbt::from_binary_slice(&mut &input[..]).unwrap();
|
||||
// group.bench_function("valence_write", |b| {
|
||||
// b.iter(|| {
|
||||
// let nbt = black_box(&nbt);
|
||||
// let mut written = Vec::new();
|
||||
// valence_nbt::to_binary_writer(&mut written, &nbt.0,
|
||||
// &nbt.1).unwrap(); black_box(written);
|
||||
// })
|
||||
// });
|
||||
let nbt = valence_nbt::from_binary_slice(&mut &input[..]).unwrap();
|
||||
group.bench_function("valence_write", |b| {
|
||||
b.iter(|| {
|
||||
let nbt = black_box(&nbt);
|
||||
let mut written = Vec::new();
|
||||
valence_nbt::to_binary_writer(&mut written, &nbt.0, &nbt.1).unwrap();
|
||||
black_box(written);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn bench(c: &mut Criterion) {
|
||||
bench_read_file("tests/bigtest.nbt", c);
|
||||
// bench_read_file("tests/simple_player.dat", c);
|
||||
// bench_read_file("tests/complex_player.dat", c);
|
||||
bench_read_file("tests/complex_player.dat", c);
|
||||
// bench_read_file("tests/level.dat", c);
|
||||
// bench_read_file("tests/stringtest.nbt", c);
|
||||
// bench_read_file("tests/inttest.nbt", c);
|
||||
|
|
|
@ -26,16 +26,16 @@ fn bench_file(filename: &str, c: &mut Criterion) {
|
|||
|
||||
group.throughput(Throughput::Bytes(decoded_src.len() as u64));
|
||||
|
||||
// group.bench_function("Decode", |b| {
|
||||
// b.iter(|| {
|
||||
// black_box(Tag::read(&mut decoded_src_stream).unwrap());
|
||||
// decoded_src_stream.set_position(0);
|
||||
// })
|
||||
// });
|
||||
group.bench_function("Decode", |b| {
|
||||
b.iter(|| {
|
||||
black_box(Tag::read(&mut decoded_src_stream).unwrap());
|
||||
decoded_src_stream.set_position(0);
|
||||
})
|
||||
});
|
||||
|
||||
group.bench_function("Encode", |b| {
|
||||
b.iter(|| {
|
||||
nbt.write(&mut io::sink()).unwrap();
|
||||
nbt.write(&mut black_box(Vec::new())).unwrap();
|
||||
})
|
||||
});
|
||||
group.finish();
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use crate::tag::*;
|
||||
use crate::Error;
|
||||
use ahash::AHashMap;
|
||||
use azalea_buf::{BufReadError, McBufReadable};
|
||||
use byteorder::{ReadBytesExt, BE};
|
||||
use flate2::read::{GzDecoder, ZlibDecoder};
|
||||
|
@ -265,7 +264,7 @@ impl Tag {
|
|||
}
|
||||
let name = read_string(stream)?;
|
||||
let tag = Tag::read_known(stream, tag_id)?;
|
||||
let mut map = AHashMap::with_capacity(1);
|
||||
let mut map = NbtCompound::with_capacity(1);
|
||||
map.insert(name, tag);
|
||||
|
||||
Ok(Tag::Compound(map))
|
||||
|
|
|
@ -15,7 +15,7 @@ fn write_string(writer: &mut dyn Write, string: &str) -> Result<(), Error> {
|
|||
|
||||
#[inline]
|
||||
fn write_compound(writer: &mut dyn Write, value: &NbtCompound, end_tag: bool) -> Result<(), Error> {
|
||||
for (key, tag) in value {
|
||||
for (key, tag) in value.inner() {
|
||||
match tag {
|
||||
Tag::End => {}
|
||||
Tag::Byte(value) => {
|
||||
|
|
|
@ -6,23 +6,23 @@ mod error;
|
|||
mod tag;
|
||||
|
||||
pub use error::Error;
|
||||
pub use tag::NbtList;
|
||||
pub use tag::Tag;
|
||||
pub use tag::{NbtCompound, NbtList, Tag};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::io::Cursor;
|
||||
|
||||
use crate::tag::NbtCompound;
|
||||
|
||||
use super::*;
|
||||
use ahash::AHashMap;
|
||||
use azalea_buf::{McBufReadable, McBufWritable};
|
||||
|
||||
#[test]
|
||||
fn mcbuf_nbt() {
|
||||
let mut buf = Vec::new();
|
||||
let tag = Tag::Compound(AHashMap::from_iter(vec![(
|
||||
let tag = Tag::Compound(NbtCompound::from_iter(vec![(
|
||||
"hello world".into(),
|
||||
Tag::Compound(AHashMap::from_iter(vec![(
|
||||
Tag::Compound(NbtCompound::from_iter(vec![(
|
||||
"name".into(),
|
||||
Tag::String("Bananrama".into()),
|
||||
)])),
|
||||
|
@ -34,9 +34,9 @@ mod tests {
|
|||
let result = Tag::read_from(&mut buf).unwrap();
|
||||
assert_eq!(
|
||||
result,
|
||||
Tag::Compound(AHashMap::from_iter(vec![(
|
||||
Tag::Compound(NbtCompound::from_iter(vec![(
|
||||
"hello world".into(),
|
||||
Tag::Compound(AHashMap::from_iter(vec![(
|
||||
Tag::Compound(NbtCompound::from_iter(vec![(
|
||||
"name".into(),
|
||||
Tag::String("Bananrama".into()),
|
||||
)])),
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
use ahash::AHashMap;
|
||||
|
||||
use compact_str::CompactString;
|
||||
use enum_as_inner::EnumAsInner;
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde::{ser::SerializeMap, Deserialize, Serialize};
|
||||
|
||||
pub type NbtByte = i8;
|
||||
pub type NbtShort = i16;
|
||||
|
@ -13,7 +11,6 @@ pub type NbtFloat = f32;
|
|||
pub type NbtDouble = f64;
|
||||
pub type NbtByteArray = Vec<u8>;
|
||||
pub type NbtString = CompactString;
|
||||
pub type NbtCompound = AHashMap<CompactString, Tag>;
|
||||
pub type NbtIntArray = Vec<i32>;
|
||||
pub type NbtLongArray = Vec<i64>;
|
||||
|
||||
|
@ -94,3 +91,71 @@ impl NbtList {
|
|||
unsafe { *<*const _>::from(self).cast::<u8>() }
|
||||
}
|
||||
}
|
||||
|
||||
// thanks to Moulberry/Graphite for the idea to use a vec and binary search
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct NbtCompound {
|
||||
inner: Vec<(NbtString, Tag)>,
|
||||
}
|
||||
impl NbtCompound {
|
||||
#[inline]
|
||||
pub fn with_capacity(capacity: usize) -> Self {
|
||||
Self {
|
||||
inner: Vec::with_capacity(capacity),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn binary_search(&self, key: &NbtString) -> Result<usize, usize> {
|
||||
self.inner.binary_search_by(|(k, _)| k.cmp(key))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get(&self, key: &NbtString) -> Option<&Tag> {
|
||||
self.binary_search(key).ok().map(|i| &self.inner[i].1)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn insert(&mut self, key: NbtString, value: Tag) -> Option<Tag> {
|
||||
match self.binary_search(&key) {
|
||||
Ok(i) => Some(std::mem::replace(&mut self.inner[i].1, value)),
|
||||
Err(i) => {
|
||||
self.inner.insert(i, (key, value));
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn inner(&self) -> &Vec<(NbtString, Tag)> {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "serde")]
|
||||
impl Serialize for NbtCompound {
|
||||
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
let mut map = serializer.serialize_map(Some(self.inner.len()))?;
|
||||
for (key, value) in &self.inner {
|
||||
map.serialize_entry(key, value)?;
|
||||
}
|
||||
map.end()
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "serde")]
|
||||
impl<'de> Deserialize<'de> for NbtCompound {
|
||||
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
|
||||
use std::collections::BTreeMap;
|
||||
let map = <BTreeMap<NbtString, Tag> as Deserialize>::deserialize(deserializer)?;
|
||||
Ok(Self {
|
||||
inner: map.into_iter().collect(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl FromIterator<(NbtString, Tag)> for NbtCompound {
|
||||
fn from_iter<T: IntoIterator<Item = (NbtString, Tag)>>(iter: T) -> Self {
|
||||
let mut inner = iter.into_iter().collect::<Vec<_>>();
|
||||
inner.sort_unstable_by_key(|(k, _)| k.clone());
|
||||
Self { inner }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use ahash::AHashMap;
|
||||
use azalea_nbt::{NbtList, Tag};
|
||||
use azalea_nbt::{NbtCompound, NbtList, Tag};
|
||||
use std::io::Cursor;
|
||||
|
||||
#[test]
|
||||
|
@ -9,9 +8,9 @@ fn test_decode_hello_world() {
|
|||
let tag = Tag::read(&mut Cursor::new(&buf[..])).unwrap();
|
||||
assert_eq!(
|
||||
tag,
|
||||
Tag::Compound(AHashMap::from_iter(vec![(
|
||||
Tag::Compound(NbtCompound::from_iter(vec![(
|
||||
"hello world".into(),
|
||||
Tag::Compound(AHashMap::from_iter(vec![(
|
||||
Tag::Compound(NbtCompound::from_iter(vec![(
|
||||
"name".into(),
|
||||
Tag::String("Bananrama".into()),
|
||||
)]))
|
||||
|
@ -51,7 +50,7 @@ fn test_bigtest() {
|
|||
|
||||
#[test]
|
||||
fn test_stringtest() {
|
||||
let correct_tag = Tag::Compound(AHashMap::from_iter(vec![(
|
||||
let correct_tag = Tag::Compound(NbtCompound::from_iter(vec![(
|
||||
"😃".into(),
|
||||
Tag::List(NbtList::String(vec![
|
||||
"asdfkghasfjgihsdfogjsndfg".into(),
|
||||
|
|
Loading…
Add table
Reference in a new issue