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

View file

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

View file

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