1
0
Fork 0
mirror of https://github.com/azalea-rs/simdnbt.git synced 2025-08-02 07:26:04 +00:00

keep track of depths for compounds and lists separately for 10% speedup

This commit is contained in:
mat 2024-05-14 01:54:39 +00:00
parent 740e7afbe9
commit f47749f7a8
3 changed files with 57 additions and 42 deletions

View file

@ -20,19 +20,20 @@ pub struct NbtCompound<'a> {
impl<'a> NbtCompound<'a> {
pub fn read(data: &mut Cursor<&'a [u8]>, alloc: &TagAllocator<'a>) -> Result<Self, Error> {
Self::read_with_depth(data, alloc, 0)
Self::read_with_depth(data, alloc, 0, 0)
}
pub fn read_with_depth(
data: &mut Cursor<&'a [u8]>,
alloc: &TagAllocator<'a>,
depth: usize,
compound_depth: usize,
list_depth: usize,
) -> Result<Self, Error> {
if depth > MAX_DEPTH {
if compound_depth + list_depth > MAX_DEPTH {
return Err(Error::MaxDepthExceeded);
}
let mut tags = alloc.get().named.start(depth);
let mut tags = alloc.get().named.start(compound_depth);
let mut tags_buffer = unsafe {
MaybeUninit::<[MaybeUninit<(&Mutf8Str, NbtTag<'a>)>; 4]>::uninit().assume_init()
@ -43,7 +44,7 @@ impl<'a> NbtCompound<'a> {
let tag_type = match data.read_u8() {
Ok(tag_type) => tag_type,
Err(_) => {
alloc.get().named.finish(tags, depth);
alloc.get().named.finish(tags, compound_depth);
return Err(Error::UnexpectedEof);
}
};
@ -54,16 +55,17 @@ impl<'a> NbtCompound<'a> {
let tag_name = match read_string(data) {
Ok(name) => name,
Err(_) => {
alloc.get().named.finish(tags, depth);
alloc.get().named.finish(tags, compound_depth);
// the only error read_string can return is UnexpectedEof, so this makes it
// slightly faster
return Err(Error::UnexpectedEof);
}
};
let tag = match NbtTag::read_with_type(data, alloc, tag_type, depth) {
let tag =
match NbtTag::read_with_type(data, alloc, tag_type, compound_depth, list_depth) {
Ok(tag) => tag,
Err(e) => {
alloc.get().named.finish(tags, depth);
alloc.get().named.finish(tags, compound_depth);
return Err(e);
}
};
@ -84,7 +86,7 @@ impl<'a> NbtCompound<'a> {
tags.push(unsafe { tags_buffer.get_unchecked(i).assume_init_read() });
}
let values = alloc.get().named.finish(tags, depth);
let values = alloc.get().named.finish(tags, compound_depth);
Ok(Self { values })
}

View file

@ -38,9 +38,10 @@ impl<'a> NbtList<'a> {
pub fn read(
data: &mut Cursor<&'a [u8]>,
alloc: &TagAllocator<'a>,
depth: usize,
compound_depth: usize,
list_depth: usize,
) -> Result<Self, Error> {
if depth > MAX_DEPTH {
if compound_depth + list_depth > MAX_DEPTH {
return Err(Error::MaxDepthExceeded);
}
let tag_type = data.read_u8().map_err(|_| Error::UnexpectedEof)?;
@ -57,93 +58,98 @@ impl<'a> NbtList<'a> {
DOUBLE_ID => NbtList::Double(RawList::new(read_with_u32_length(data, 8)?)),
BYTE_ARRAY_ID => NbtList::ByteArray({
let length = read_u32(data)?;
let mut tags = alloc.get().unnamed_bytearray.start(depth);
let mut tags = alloc.get().unnamed_bytearray.start(list_depth);
for _ in 0..length {
let tag = match read_u8_array(data) {
Ok(tag) => tag,
Err(e) => {
alloc.get().unnamed_bytearray.finish(tags, depth);
alloc.get().unnamed_bytearray.finish(tags, list_depth);
return Err(e);
}
};
tags.push(tag);
}
alloc.get().unnamed_bytearray.finish(tags, depth)
alloc.get().unnamed_bytearray.finish(tags, list_depth)
}),
STRING_ID => NbtList::String({
let length = read_u32(data)?;
let mut tags = alloc.get().unnamed_string.start(depth);
let mut tags = alloc.get().unnamed_string.start(list_depth);
for _ in 0..length {
let tag = match read_string(data) {
Ok(tag) => tag,
Err(e) => {
alloc.get().unnamed_string.finish(tags, depth);
alloc.get().unnamed_string.finish(tags, list_depth);
return Err(e);
}
};
tags.push(tag);
}
alloc.get().unnamed_string.finish(tags, depth)
alloc.get().unnamed_string.finish(tags, list_depth)
}),
LIST_ID => NbtList::List({
let length = read_u32(data)?;
let mut tags = alloc.get().unnamed_list.start(depth);
let mut tags = alloc.get().unnamed_list.start(list_depth);
for _ in 0..length {
let tag = match NbtList::read(data, alloc, depth + 1) {
let tag = match NbtList::read(data, alloc, compound_depth, list_depth + 1) {
Ok(tag) => tag,
Err(e) => {
alloc.get().unnamed_list.finish(tags, depth);
alloc.get().unnamed_list.finish(tags, list_depth);
return Err(e);
}
};
tags.push(tag)
}
alloc.get().unnamed_list.finish(tags, depth)
alloc.get().unnamed_list.finish(tags, list_depth)
}),
COMPOUND_ID => NbtList::Compound({
let length = read_u32(data)?;
let mut tags = alloc.get().unnamed_compound.start(depth);
let mut tags = alloc.get().unnamed_compound.start(list_depth);
for _ in 0..length {
let tag = match NbtCompound::read_with_depth(data, alloc, depth + 1) {
let tag = match NbtCompound::read_with_depth(
data,
alloc,
compound_depth + 1,
list_depth,
) {
Ok(tag) => tag,
Err(e) => {
alloc.get().unnamed_compound.finish(tags, depth);
alloc.get().unnamed_compound.finish(tags, list_depth);
return Err(e);
}
};
tags.push(tag);
}
alloc.get().unnamed_compound.finish(tags, depth)
alloc.get().unnamed_compound.finish(tags, list_depth)
}),
INT_ARRAY_ID => NbtList::IntArray({
let length = read_u32(data)?;
let mut tags = alloc.get().unnamed_intarray.start(depth);
let mut tags = alloc.get().unnamed_intarray.start(list_depth);
for _ in 0..length {
let tag = match read_int_array(data) {
Ok(tag) => tag,
Err(e) => {
alloc.get().unnamed_intarray.finish(tags, depth);
alloc.get().unnamed_intarray.finish(tags, list_depth);
return Err(e);
}
};
tags.push(tag);
}
alloc.get().unnamed_intarray.finish(tags, depth)
alloc.get().unnamed_intarray.finish(tags, list_depth)
}),
LONG_ARRAY_ID => NbtList::LongArray({
let length = read_u32(data)?;
let mut tags = alloc.get().unnamed_longarray.start(depth);
let mut tags = alloc.get().unnamed_longarray.start(list_depth);
for _ in 0..length {
let tag = match read_long_array(data) {
Ok(tag) => tag,
Err(e) => {
alloc.get().unnamed_longarray.finish(tags, depth);
alloc.get().unnamed_longarray.finish(tags, list_depth);
return Err(e);
}
};
tags.push(tag);
}
alloc.get().unnamed_longarray.finish(tags, depth)
alloc.get().unnamed_longarray.finish(tags, list_depth)
}),
_ => return Err(Error::UnknownTagId(tag_type)),
})

View file

@ -50,7 +50,7 @@ impl<'a> Nbt<'a> {
let tag_alloc = TagAllocator::new();
let name = read_string(data)?;
let tag = NbtCompound::read_with_depth(data, &tag_alloc, 0)?;
let tag = NbtCompound::read_with_depth(data, &tag_alloc, 0, 0)?;
Ok(Nbt::Some(BaseNbt {
name,
@ -160,7 +160,8 @@ impl<'a> NbtTag<'a> {
data: &mut Cursor<&'a [u8]>,
alloc: &TagAllocator<'a>,
tag_type: u8,
depth: usize,
compound_depth: usize,
list_depth: usize,
) -> Result<Self, Error> {
match tag_type {
BYTE_ID => Ok(NbtTag::Byte(
@ -183,11 +184,17 @@ impl<'a> NbtTag<'a> {
)),
BYTE_ARRAY_ID => Ok(NbtTag::ByteArray(read_with_u32_length(data, 1)?)),
STRING_ID => Ok(NbtTag::String(read_string(data)?)),
LIST_ID => Ok(NbtTag::List(NbtList::read(data, alloc, depth + 1)?)),
LIST_ID => Ok(NbtTag::List(NbtList::read(
data,
alloc,
compound_depth,
list_depth + 1,
)?)),
COMPOUND_ID => Ok(NbtTag::Compound(NbtCompound::read_with_depth(
data,
alloc,
depth + 1,
compound_depth + 1,
list_depth,
)?)),
INT_ARRAY_ID => Ok(NbtTag::IntArray(read_int_array(data)?)),
LONG_ARRAY_ID => Ok(NbtTag::LongArray(read_long_array(data)?)),
@ -197,7 +204,7 @@ impl<'a> NbtTag<'a> {
pub fn read(data: &mut Cursor<&'a [u8]>, alloc: &TagAllocator<'a>) -> Result<Self, Error> {
let tag_type = data.read_u8().map_err(|_| Error::UnexpectedEof)?;
Self::read_with_type(data, alloc, tag_type, 0)
Self::read_with_type(data, alloc, tag_type, 0, 0)
}
pub fn read_optional(
@ -208,7 +215,7 @@ impl<'a> NbtTag<'a> {
if tag_type == END_ID {
return Ok(None);
}
Ok(Some(Self::read_with_type(data, alloc, tag_type, 0)?))
Ok(Some(Self::read_with_type(data, alloc, tag_type, 0, 0)?))
}
pub fn byte(&self) -> Option<i8> {