fix merge conflict

This commit is contained in:
mat 2023-03-24 13:55:11 +00:00
commit 4b387c320c
10 changed files with 222 additions and 26 deletions

17
Cargo.lock generated
View file

@ -345,6 +345,7 @@ dependencies = [
"flate2",
"graphite_binary",
"log",
"packed_simd_2",
"serde",
"valence_nbt",
]
@ -1514,6 +1515,12 @@ version = "0.2.140"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c"
[[package]]
name = "libm"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a"
[[package]]
name = "linked-hash-map"
version = "0.5.6"
@ -1740,6 +1747,16 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
[[package]]
name = "packed_simd_2"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1914cd452d8fccd6f9db48147b29fd4ae05bea9dc5d9ad578509f72415de282"
dependencies = [
"cfg-if",
"libm",
]
[[package]]
name = "parking"
version = "2.0.0"

View file

@ -15,6 +15,7 @@ compact_str = { version = "0.7.0", features = ["serde"] }
enum-as-inner = "0.5.1"
flate2 = "^1.0.25"
log = "0.4.17"
packed_simd_2 = "0.3.8"
serde = { version = "1.0.152", features = ["derive"], optional = true }
[dev-dependencies]

View file

@ -79,7 +79,7 @@ pub fn bench_read_file(filename: &str, c: &mut Criterion) {
}
fn bench(c: &mut Criterion) {
bench_read_file("tests/bigtest.nbt", c);
// 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/level.dat", c);

View file

@ -15,7 +15,10 @@ fn bench_file(filename: &str, c: &mut Criterion) {
// decode the original src so most of the time isn't spent on unzipping
let mut decoded_src_decoder = GzDecoder::new(&mut src);
let mut decoded_src = Vec::new();
decoded_src_decoder.read_to_end(&mut decoded_src).unwrap();
if decoded_src_decoder.read_to_end(&mut decoded_src).is_err() {
// oh probably wasn't gzipped then
decoded_src = contents;
}
let mut decoded_src_stream = Cursor::new(&decoded_src[..]);
@ -26,12 +29,12 @@ 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(Nbt::read(&mut decoded_src_stream).unwrap());
decoded_src_stream.set_position(0);
})
});
// group.bench_function("Decode", |b| {
// b.iter(|| {
// black_box(Nbt::read(&mut decoded_src_stream).unwrap());
// decoded_src_stream.set_position(0);
// })
// });
// group.bench_function("Encode", |b| {
// b.iter(|| {
@ -41,7 +44,16 @@ fn bench_file(filename: &str, c: &mut Criterion) {
group.bench_function("Get", |b| {
b.iter(|| {
black_box(nbt.as_compound().unwrap().get(""));
let level = nbt
.as_compound()
.unwrap()
.get("Level")
.unwrap()
.as_compound()
.unwrap();
for (k, _) in level.iter() {
black_box(level.get(black_box(k)));
}
})
});
group.finish();
@ -53,7 +65,10 @@ fn bench(c: &mut Criterion) {
// bench_file("tests/complex_player.dat", c);
// bench_file("tests/level.dat", c);
// bench_file("tests/stringtest.nbt", c);
// bench_file("tests/inttest.nbt", c);
// bench_file("tests/inttest16.nbt", c);
// bench_file("tests/inttest1023.nbt", c);
// bench_file("tests/inttest3.nbt", c);
}
criterion_group!(benches, bench);

View file

@ -2,6 +2,7 @@ use crate::tag::*;
use azalea_buf::McBufWritable;
use byteorder::{WriteBytesExt, BE};
use flate2::write::{GzEncoder, ZlibEncoder};
use packed_simd_2::{i32x16, i32x2, i32x4, i32x8, i64x2, i64x4, i64x8};
use std::io::Write;
#[inline(always)]
@ -81,14 +82,78 @@ fn write_list(writer: &mut impl Write, value: &NbtList) {
}
NbtList::Int(l) => {
writer.write_i32::<BE>(l.len() as i32).unwrap();
for &v in l {
writer.write_i32::<BE>(v).unwrap();
// flip the bits to big endian with simd
let l = l.as_slice();
let mut position = 0;
// x16
while l.len() - position >= 16 {
let l = unsafe { i32x16::from_slice_unaligned_unchecked(&l[position..]) };
l.to_be();
let l = unsafe { std::mem::transmute::<i32x16, [u8; 64]>(l) };
writer.write_all(&l).unwrap();
position += 16;
}
// x8
if l.len() - position >= 8 {
let l = unsafe { i32x8::from_slice_unaligned_unchecked(&l[position..]) };
l.to_be();
let l = unsafe { std::mem::transmute::<i32x8, [u8; 32]>(l) };
writer.write_all(&l).unwrap();
position += 8;
}
// x4
if l.len() - position >= 4 {
let l = unsafe { i32x4::from_slice_unaligned_unchecked(&l[position..]) };
l.to_be();
let l = unsafe { std::mem::transmute::<i32x4, [u8; 16]>(l) };
writer.write_all(&l).unwrap();
position += 4;
}
// x2
if l.len() - position >= 2 {
let l = unsafe { i32x2::from_slice_unaligned_unchecked(&l[position..]) };
l.to_be();
let l = unsafe { std::mem::transmute::<i32x2, [u8; 8]>(l) };
writer.write_all(&l).unwrap();
position += 2;
}
// x1 ... just a normal write_i32
if l.len() - position >= 1 {
writer.write_i32::<BE>(l[position]).unwrap();
}
}
NbtList::Long(l) => {
writer.write_i32::<BE>(l.len() as i32).unwrap();
for &v in l {
writer.write_i64::<BE>(v).unwrap();
// flip the bits to big endian with simd
let l = l.as_slice();
let mut position = 0;
// x16
while l.len() - position >= 8 {
let l = unsafe { i64x8::from_slice_unaligned_unchecked(&l[position..]) };
l.to_be();
let l = unsafe { std::mem::transmute::<i64x8, [u8; 64]>(l) };
writer.write_all(&l).unwrap();
position += 8;
}
// x4
if l.len() - position >= 4 {
let l = unsafe { i64x4::from_slice_unaligned_unchecked(&l[position..]) };
l.to_be();
let l = unsafe { std::mem::transmute::<i64x4, [u8; 32]>(l) };
writer.write_all(&l).unwrap();
position += 4;
}
// x2
if l.len() - position >= 2 {
let l = unsafe { i64x2::from_slice_unaligned_unchecked(&l[position..]) };
l.to_be();
let l = unsafe { std::mem::transmute::<i64x2, [u8; 16]>(l) };
writer.write_all(&l).unwrap();
position += 2;
}
// x1 ... just a normal write_i32
if l.len() - position >= 1 {
writer.write_i64::<BE>(l[position]).unwrap();
}
}
NbtList::Float(l) => {

View file

@ -48,6 +48,17 @@ pub enum Nbt {
IntArray(NbtIntArray) = INT_ARRAY_ID,
LongArray(NbtLongArray) = LONG_ARRAY_ID,
}
impl Nbt {
/// Get the numerical ID of the tag type.
#[inline]
pub fn id(&self) -> u8 {
// SAFETY: Because `Self` is marked `repr(u8)`, its layout is a `repr(C)`
// `union` between `repr(C)` structs, each of which has the `u8`
// discriminant as its first field, so we can read the discriminant
// without offsetting the pointer.
unsafe { *<*const _>::from(self).cast::<u8>() }
}
}
/// An NBT value.
#[derive(Clone, Debug, PartialEq)]
@ -69,7 +80,7 @@ pub enum NbtList {
LongArray(Vec<NbtLongArray>) = LONG_ARRAY_ID,
}
impl Nbt {
impl NbtList {
/// Get the numerical ID of the tag type.
#[inline]
pub fn id(&self) -> u8 {
@ -80,15 +91,64 @@ impl Nbt {
unsafe { *<*const _>::from(self).cast::<u8>() }
}
}
impl NbtList {
/// Get the numerical ID of the tag type.
#[inline]
pub fn id(&self) -> u8 {
// SAFETY: Because `Self` is marked `repr(u8)`, its layout is a `repr(C)`
// `union` between `repr(C)` structs, each of which has the `u8`
// discriminant as its first field, so we can read the discriminant
// without offsetting the pointer.
unsafe { *<*const _>::from(self).cast::<u8>() }
impl From<Vec<NbtByte>> for NbtList {
fn from(v: Vec<NbtByte>) -> Self {
Self::Byte(v)
}
}
impl From<Vec<NbtShort>> for NbtList {
fn from(v: Vec<NbtShort>) -> Self {
Self::Short(v)
}
}
impl From<Vec<NbtInt>> for NbtList {
fn from(v: Vec<NbtInt>) -> Self {
Self::Int(v)
}
}
impl From<Vec<NbtLong>> for NbtList {
fn from(v: Vec<NbtLong>) -> Self {
Self::Long(v)
}
}
impl From<Vec<NbtFloat>> for NbtList {
fn from(v: Vec<NbtFloat>) -> Self {
Self::Float(v)
}
}
impl From<Vec<NbtDouble>> for NbtList {
fn from(v: Vec<NbtDouble>) -> Self {
Self::Double(v)
}
}
impl From<Vec<NbtByteArray>> for NbtList {
fn from(v: Vec<NbtByteArray>) -> Self {
Self::ByteArray(v)
}
}
impl From<Vec<NbtString>> for NbtList {
fn from(v: Vec<NbtString>) -> Self {
Self::String(v)
}
}
impl From<Vec<NbtList>> for NbtList {
fn from(v: Vec<NbtList>) -> Self {
Self::List(v)
}
}
impl From<Vec<NbtCompound>> for NbtList {
fn from(v: Vec<NbtCompound>) -> Self {
Self::Compound(v)
}
}
impl From<Vec<NbtIntArray>> for NbtList {
fn from(v: Vec<NbtIntArray>) -> Self {
Self::IntArray(v)
}
}
impl From<Vec<NbtLongArray>> for NbtList {
fn from(v: Vec<NbtLongArray>) -> Self {
Self::LongArray(v)
}
}
@ -161,7 +221,9 @@ impl NbtCompound {
#[inline]
fn is_worth_sorting(&self) -> bool {
self.inner.len() >= 128
// i don't actually know when binary search starts being better, but it's at
// least more than 12
self.inner.len() >= 32
}
}
#[cfg(feature = "serde")]
@ -191,3 +253,9 @@ impl FromIterator<(NbtString, Nbt)> for NbtCompound {
Self { inner }
}
}
impl From<Vec<(NbtString, Nbt)>> for NbtCompound {
fn from(inner: Vec<(NbtString, Nbt)>) -> Self {
Self { inner }
}
}

Binary file not shown.

Binary file not shown.

View file

@ -1,4 +1,4 @@
use azalea_nbt::{NbtCompound, NbtList, Nbt};
use azalea_nbt::{Nbt, NbtCompound, NbtList};
use std::io::Cursor;
#[test]
@ -108,3 +108,33 @@ fn test_simple_player() {
assert_eq!(decoded_tag, original_tag);
}
// #[test]
// fn test_inttest() {
// let original = include_bytes!("inttest.nbt").to_vec();
// let mut original_stream = Cursor::new(original);
// let original_tag = Nbt::read_gzip(&mut original_stream).unwrap();
// let mut result = Vec::new();
// original_tag.write(&mut result);
// let decoded_tag = Nbt::read(&mut Cursor::new(&result)).unwrap();
// assert_eq!(decoded_tag, original_tag);
// }
#[test]
fn test_inttest1023() {
let original = include_bytes!("inttest1023.nbt").to_vec();
let mut original_stream = Cursor::new(original.as_slice());
let original_tag = Nbt::read(&mut original_stream).unwrap();
let mut result = Vec::new();
original_tag.write(&mut result);
let decoded_tag = Nbt::read(&mut Cursor::new(&result)).unwrap();
assert_eq!(decoded_tag, original_tag);
}