1
0
Fork 0
mirror of https://github.com/azalea-rs/simdnbt.git synced 2025-08-02 15:36:03 +00:00

optimize writing

This commit is contained in:
mat 2023-09-21 01:02:23 -05:00
parent d2f3fdefc7
commit 40f38c34ef
13 changed files with 12659 additions and 129 deletions

View file

@ -24,11 +24,11 @@ hematite-nbt = { version = "0.5.2", default-features = false }
[profile.release]
lto = true
debug = true
debug = false
[profile.bench]
lto = true
debug = true
debug = false
[[bench]]
harness = false

View file

@ -91,13 +91,13 @@ pub fn bench_read_file(filename: &str, c: &mut Criterion) {
// black_box(nbt);
// })
// });
// let nbt = graphite_binary::nbt::decode::read(&mut &input[..]).unwrap();
// group.bench_function("graphite_write", |b| {
// b.iter(|| {
// let out = graphite_binary::nbt::encode::write(&nbt);
// black_box(out);
// })
// });
let nbt = graphite_binary::nbt::decode::read(&mut &input[..]).unwrap();
group.bench_function("graphite_write", |b| {
b.iter(|| {
let out = graphite_binary::nbt::encode::write(&nbt);
black_box(out);
})
});
// group.bench_function("valence_parse", |b| {
// b.iter(|| {
@ -129,7 +129,7 @@ fn bench(c: &mut Criterion) {
// bench_read_file("bigtest.nbt", c);
// bench_read_file("simple_player.dat", c);
bench_read_file("complex_player.dat", c);
// bench_read_file("level.dat", c);
bench_read_file("level.dat", c);
// bench_read_file("stringtest.nbt", c);
// bench_read_file("inttest1023.nbt", c);
}

12149
callgrind.out.1201671 Normal file

File diff suppressed because it is too large Load diff

261
callgrind.txt Normal file
View file

@ -0,0 +1,261 @@
--------------------------------------------------------------------------------
Profile data file 'callgrind.out.1201671' (creator: callgrind-3.21.0)
--------------------------------------------------------------------------------
I1 cache:
D1 cache:
LL cache:
Timerange: Basic block 0 - 226913
Trigger: Program termination
Profiled target: ./target/release/examples/read_and_write (PID 1201671, part 1)
Events recorded: Ir
Events shown: Ir
Event sort order: Ir
Thresholds: 99
Include dirs:
User annotated:
Auto-annotation: on
--------------------------------------------------------------------------------
Ir
--------------------------------------------------------------------------------
752,320 (100.0%) PROGRAM TOTALS
--------------------------------------------------------------------------------
Ir file:function
--------------------------------------------------------------------------------
86,883 (11.55%) /usr/src/debug/glibc/glibc/string/../sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S:__memset_avx2_unaligned_erms [/usr/lib/libc.so.6]
66,157 ( 8.79%) ???:miniz_oxide::inflate::core::decompress [/home/mat/code/simdnbt/target/release/examples/read_and_write]
59,020 ( 7.85%) /usr/src/debug/glibc/glibc/elf/dl-lookup.c:do_lookup_x [/usr/lib/ld-linux-x86-64.so.2]
53,059 ( 7.05%) /usr/src/debug/glibc/glibc/malloc/malloc.c:_int_malloc [/usr/lib/libc.so.6]
51,906 ( 6.90%) /usr/src/debug/glibc/glibc/stdio-common/vfscanf-internal.c:__vfscanf_internal [/usr/lib/libc.so.6]
34,022 ( 4.52%) /usr/src/debug/glibc/glibc/elf/dl-tunables.c:__GI___tunables_init [/usr/lib/ld-linux-x86-64.so.2]
25,637 ( 3.41%) /usr/src/debug/glibc/glibc/malloc/malloc.c:_int_free [/usr/lib/libc.so.6]
24,238 ( 3.22%) /usr/src/debug/glibc/glibc/stdlib/../stdlib/strtol_l.c:____strtoul_l_internal [/usr/lib/libc.so.6]
23,541 ( 3.13%) ???:miniz_oxide::inflate::core::init_tree [/home/mat/code/simdnbt/target/release/examples/read_and_write]
22,849 ( 3.04%) ???:simdnbt::owned::CompoundTag::new'2 [/home/mat/code/simdnbt/target/release/examples/read_and_write]
21,287 ( 2.83%) /usr/src/debug/glibc/glibc/elf/dl-reloc.c:_dl_relocate_object [/usr/lib/ld-linux-x86-64.so.2]
19,545 ( 2.60%) /usr/src/debug/glibc/glibc/elf/dl-lookup.c:_dl_lookup_symbol_x [/usr/lib/ld-linux-x86-64.so.2]
19,054 ( 2.53%) /usr/src/debug/glibc/glibc/elf/../sysdeps/generic/dl-new-hash.h:_dl_lookup_symbol_x
18,154 ( 2.41%) /usr/src/debug/glibc/glibc/string/../sysdeps/x86_64/multiarch/../multiarch/strcmp-sse2.S:strcmp [/usr/lib/ld-linux-x86-64.so.2]
14,879 ( 1.98%) /usr/src/debug/glibc/glibc/malloc/malloc.c:malloc [/usr/lib/libc.so.6]
14,065 ( 1.87%) /usr/src/debug/glibc/glibc/string/../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S:__memcpy_avx_unaligned_erms [/usr/lib/libc.so.6]
13,713 ( 1.82%) /usr/src/debug/glibc/glibc/malloc/malloc.c:malloc_consolidate [/usr/lib/libc.so.6]
12,356 ( 1.64%) /usr/src/debug/glibc/glibc/elf/../sysdeps/x86_64/dl-machine.h:_dl_relocate_object
11,810 ( 1.57%) /usr/src/debug/glibc/glibc/elf/dl-lookup.c:check_match [/usr/lib/ld-linux-x86-64.so.2]
11,469 ( 1.52%) /usr/src/debug/glibc/glibc/elf/do-rel.h:_dl_relocate_object
9,796 ( 1.30%) ???:simdnbt::owned::CompoundTag::write'2 [/home/mat/code/simdnbt/target/release/examples/read_and_write]
8,371 ( 1.11%) ???:miniz_oxide::inflate::core::apply_match [/home/mat/code/simdnbt/target/release/examples/read_and_write]
8,184 ( 1.09%) /usr/src/debug/glibc/glibc/malloc/malloc.c:free [/usr/lib/libc.so.6]
6,634 ( 0.88%) /usr/src/debug/glibc/glibc/malloc/malloc.c:unlink_chunk.isra.0 [/usr/lib/libc.so.6]
6,224 ( 0.83%) /usr/src/debug/glibc/glibc/elf/dl-version.c:_dl_check_map_versions [/usr/lib/ld-linux-x86-64.so.2]
5,267 ( 0.70%) ???:core::ptr::drop_in_place<simdnbt::owned::Tag>'2 [/home/mat/code/simdnbt/target/release/examples/read_and_write]
4,620 ( 0.61%) /usr/src/debug/glibc/glibc/elf/dl-tunables.h:__GI___tunables_init
3,956 ( 0.53%) ???:simdnbt::owned::CompoundTag::new [/home/mat/code/simdnbt/target/release/examples/read_and_write]
3,496 ( 0.46%) /usr/src/debug/glibc/glibc/libio/genops.c:_IO_sputbackc [/usr/lib/libc.so.6]
3,391 ( 0.45%) /usr/src/debug/glibc/glibc/libio/iogetdelim.c:getdelim [/usr/lib/libc.so.6]
3,119 ( 0.41%) /usr/src/debug/glibc/glibc/elf/../sysdeps/x86/dl-cacheinfo.h:intel_check_word.constprop.0 [/usr/lib/ld-linux-x86-64.so.2]
2,689 ( 0.36%) /usr/src/debug/glibc/glibc/malloc/malloc.c:_int_free_merge_chunk [/usr/lib/libc.so.6]
2,471 ( 0.33%) ???:core::ptr::drop_in_place<simdnbt::owned::list::ListTag> [/home/mat/code/simdnbt/target/release/examples/read_and_write]
2,413 ( 0.32%) /usr/src/debug/glibc/glibc/elf/../bits/stdlib-bsearch.h:intel_check_word.constprop.0
2,354 ( 0.31%) /usr/src/debug/glibc/glibc/malloc/malloc.c:realloc [/usr/lib/libc.so.6]
2,282 ( 0.30%) /usr/src/debug/glibc/glibc/elf/dl-load.c:_dl_map_object_from_fd [/usr/lib/ld-linux-x86-64.so.2]
2,157 ( 0.29%) /usr/src/debug/glibc/glibc/malloc/malloc.c:_int_realloc [/usr/lib/libc.so.6]
1,987 ( 0.26%) ???:<flate2::gz::read::GzDecoder<R> as std::io::Read>::read [/home/mat/code/simdnbt/target/release/examples/read_and_write]
1,944 ( 0.26%) /usr/src/debug/glibc/glibc/malloc/malloc.c:_int_free_create_chunk [/usr/lib/libc.so.6]
1,840 ( 0.24%) /usr/src/debug/glibc/glibc/elf/dl-cache.c:_dl_cache_libcmp [/usr/lib/ld-linux-x86-64.so.2]
1,794 ( 0.24%) /usr/src/debug/glibc/glibc/libio/strops.c:_IO_str_init_static_internal [/usr/lib/libc.so.6]
1,783 ( 0.24%) /usr/src/debug/glibc/glibc/string/../sysdeps/x86_64/multiarch/memchr-avx2.S:__memchr_avx2 [/usr/lib/libc.so.6]
1,647 ( 0.22%) ???:crc32fast::specialized::pclmulqdq::calculate [/home/mat/code/simdnbt/target/release/examples/read_and_write]
1,610 ( 0.21%) /usr/src/debug/glibc/glibc/stdio-common/isoc23_sscanf.c:__isoc23_sscanf [/usr/lib/libc.so.6]
1,577 ( 0.21%) ???:simdnbt::owned::list::ListTag::new [/home/mat/code/simdnbt/target/release/examples/read_and_write]
1,540 ( 0.20%) ???:simdnbt::owned::CompoundTag::write [/home/mat/code/simdnbt/target/release/examples/read_and_write]
1,500 ( 0.20%) /usr/src/debug/glibc/glibc/malloc/malloc.c:alloc_perturb [/usr/lib/libc.so.6]
1,368 ( 0.18%) /usr/src/debug/glibc/glibc/elf/dl-deps.c:_dl_map_object_deps [/usr/lib/ld-linux-x86-64.so.2]
1,349 ( 0.18%) /usr/src/debug/glibc/glibc/libio/genops.c:_IO_setb [/usr/lib/libc.so.6]
1,312 ( 0.17%) /usr/src/debug/glibc/glibc/string/../sysdeps/x86_64/multiarch/strlen-avx2.S:__strlen_avx2 [/usr/lib/libc.so.6]
1,246 ( 0.17%) /usr/src/debug/glibc/glibc/nptl/pthread_getattr_np.c:pthread_getattr_np@@GLIBC_2.32 [/usr/lib/libc.so.6]
1,173 ( 0.16%) ???:alloc::raw_vec::finish_grow [/home/mat/code/simdnbt/target/release/examples/read_and_write]
1,143 ( 0.15%) ???:core::ptr::drop_in_place<simdnbt::owned::Tag> [/home/mat/code/simdnbt/target/release/examples/read_and_write]
1,140 ( 0.15%) /usr/src/debug/glibc/glibc/elf/rtld.c:dl_main [/usr/lib/ld-linux-x86-64.so.2]
1,116 ( 0.15%) /usr/src/debug/glibc/glibc/malloc/arena.c:free
1,088 ( 0.14%) /usr/src/debug/glibc/glibc/libio/genops.c:_IO_no_init [/usr/lib/libc.so.6]
1,083 ( 0.14%) /usr/src/debug/glibc/glibc/libio/genops.c:_IO_old_init [/usr/lib/libc.so.6]
1,050 ( 0.14%) ???:simdnbt::owned::list::ListTag::new'2 [/home/mat/code/simdnbt/target/release/examples/read_and_write]
1,015 ( 0.13%) ???:core::ptr::drop_in_place<simdnbt::owned::list::ListTag>'2 [/home/mat/code/simdnbt/target/release/examples/read_and_write]
1,012 ( 0.13%) /usr/src/debug/glibc/glibc/stdio-common/../include/scratch_buffer.h:__vfscanf_internal
1,005 ( 0.13%) /usr/src/debug/glibc/glibc/elf/../sysdeps/generic/ldsodefs.h:do_lookup_x
934 ( 0.12%) /usr/src/debug/glibc/glibc/elf/get-dynamic-info.h:_dl_map_object_from_fd
899 ( 0.12%) /usr/src/debug/glibc/glibc/elf/dl-load.c:_dl_map_object [/usr/lib/ld-linux-x86-64.so.2]
862 ( 0.11%) /usr/src/debug/glibc/glibc/elf/dl-misc.c:_dl_name_match_p [/usr/lib/ld-linux-x86-64.so.2]
804 ( 0.11%) /usr/src/debug/glibc/glibc/elf/../sysdeps/generic/dl-protected.h:do_lookup_x
781 ( 0.10%) /usr/src/debug/glibc/glibc/elf/dl-object.c:_dl_new_object [/usr/lib/ld-linux-x86-64.so.2]
771 ( 0.10%) /usr/src/debug/glibc/glibc/malloc/malloc.c:ptmalloc_init.part.0
745 ( 0.10%) ???:crc32fast::baseline::update_fast_16 [/home/mat/code/simdnbt/target/release/examples/read_and_write]
741 ( 0.10%) /usr/src/debug/glibc/glibc/elf/dl-tunables.c:__tunable_get_val [/usr/lib/ld-linux-x86-64.so.2]
707 ( 0.09%) /usr/src/debug/glibc/glibc/malloc/arena.c:malloc
694 ( 0.09%) /usr/src/debug/glibc/glibc/elf/dl-minimal-malloc.c:__minimal_malloc [/usr/lib/ld-linux-x86-64.so.2]
690 ( 0.09%) /usr/src/debug/glibc/glibc/stdio-common/../libio/strfile.h:__isoc23_sscanf
683 ( 0.09%) ???:read_and_write::main [/home/mat/code/simdnbt/target/release/examples/read_and_write]
670 ( 0.09%) /usr/src/debug/glibc/glibc/elf/../sysdeps/generic/ldsodefs.h:_dl_relocate_object
650 ( 0.09%) /usr/src/debug/glibc/glibc/nptl/libc-cleanup.c:__libc_cleanup_push_defer [/usr/lib/libc.so.6]
645 ( 0.09%) ???:simdnbt::owned::list::ListTag::write [/home/mat/code/simdnbt/target/release/examples/read_and_write]
608 ( 0.08%) ???:alloc::raw_vec::RawVec<T,A>::reserve::do_reserve_and_handle [/home/mat/code/simdnbt/target/release/examples/read_and_write]
597 ( 0.08%) /usr/src/debug/glibc/glibc/elf/dl-cache.c:search_cache [/usr/lib/ld-linux-x86-64.so.2]
561 ( 0.07%) /usr/src/debug/glibc/glibc/elf/../sysdeps/x86/dl-cacheinfo.h:handle_intel.constprop.0 [/usr/lib/ld-linux-x86-64.so.2]
480 ( 0.06%) ???:core::ptr::drop_in_place<simdnbt::owned::Nbt> [/home/mat/code/simdnbt/target/release/examples/read_and_write]
460 ( 0.06%) /usr/src/debug/glibc/glibc/stdlib/../stdlib/strtol.c:__strtoul_internal [/usr/lib/libc.so.6]
456 ( 0.06%) /usr/src/debug/glibc/glibc/string/../sysdeps/x86_64/multiarch/../multiarch/strchr-sse2.S:index [/usr/lib/ld-linux-x86-64.so.2]
451 ( 0.06%) /usr/src/debug/glibc/glibc/string/../sysdeps/x86_64/multiarch/../multiarch/strlen-sse2.S:strlen [/usr/lib/ld-linux-x86-64.so.2]
450 ( 0.06%) /usr/src/debug/glibc/glibc/nptl/libc-cleanup.c:__libc_cleanup_pop_restore [/usr/lib/libc.so.6]
445 ( 0.06%) /usr/src/debug/glibc/glibc/elf/dl-environ.c:_dl_next_ld_env_entry [/usr/lib/ld-linux-x86-64.so.2]
439 ( 0.06%) /usr/src/debug/glibc/glibc/elf/./dl-map-segments.h:_dl_map_object_from_fd
410 ( 0.05%) /usr/src/debug/glibc/glibc/string/../sysdeps/x86_64/multiarch/../multiarch/memset-vec-unaligned-erms.S:memset [/usr/lib/ld-linux-x86-64.so.2]
410 ( 0.05%) ???:simdnbt::owned::list::ListTag::write'2 [/home/mat/code/simdnbt/target/release/examples/read_and_write]
408 ( 0.05%) /usr/src/debug/glibc/glibc/elf/dl-hwcaps_split.c:_dl_hwcaps_split [/usr/lib/ld-linux-x86-64.so.2]
373 ( 0.05%) /usr/src/debug/glibc/glibc/elf/dl-sort-maps.c:dfs_traversal.part.0 [/usr/lib/ld-linux-x86-64.so.2]
362 ( 0.05%) /usr/src/debug/glibc/glibc/elf/../sysdeps/x86/dl-prop.h:_dl_map_object_from_fd
360 ( 0.05%) /rustc/69e97df5ce571a777acd654ec3697ae8d25962ea/library/alloc/src/raw_vec.rs:alloc::raw_vec::RawVec<T,A>::reserve_for_push [/home/mat/code/simdnbt/target/release/examples/read_and_write]
359 ( 0.05%) /usr/src/debug/glibc/glibc/elf/./get-dynamic-info.h:dl_main
347 ( 0.05%) /usr/src/debug/glibc/glibc/misc/../sysdeps/unix/sysv/linux/mmap64.c:mmap [/usr/lib/libc.so.6]
346 ( 0.05%) /usr/src/debug/gcc/gcc/libgcc/../gcc/common/config/i386/cpuinfo.h:__cpu_indicator_init@GCC_4.8.0
332 ( 0.04%) /usr/src/debug/glibc/glibc/elf/../elf/dl-tls.c:_dl_allocate_tls_storage [/usr/lib/ld-linux-x86-64.so.2]
320 ( 0.04%) /usr/src/debug/glibc/glibc/elf/./dl-find_object.h:_dl_find_object_from_map [/usr/lib/ld-linux-x86-64.so.2]
312 ( 0.04%) /usr/src/debug/glibc/glibc/elf/dl-sort-maps.c:_dl_sort_maps [/usr/lib/ld-linux-x86-64.so.2]
294 ( 0.04%) /usr/src/debug/glibc/glibc/elf/../sysdeps/unix/sysv/linux/dl-sysdep.c:_dl_sysdep_parse_arguments [/usr/lib/ld-linux-x86-64.so.2]
273 ( 0.04%) /usr/src/debug/glibc/glibc/elf/dl-init.c:call_init [/usr/lib/ld-linux-x86-64.so.2]
264 ( 0.04%) /usr/src/debug/glibc/glibc/elf/dl-load.c:open_verify.constprop.0 [/usr/lib/ld-linux-x86-64.so.2]
260 ( 0.03%) /usr/src/debug/glibc/glibc/string/../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S:memcpy [/usr/lib/ld-linux-x86-64.so.2]
255 ( 0.03%) /usr/src/debug/glibc/glibc/elf/./get-dynamic-info.h:_dl_start
248 ( 0.03%) /usr/src/debug/glibc/glibc/elf/dl-fini.c:_dl_fini [/usr/lib/ld-linux-x86-64.so.2]
238 ( 0.03%) /usr/src/debug/glibc/glibc/string/../string/strcspn.c:strcspn [/usr/lib/ld-linux-x86-64.so.2]
235 ( 0.03%) ???:main [/home/mat/code/simdnbt/target/release/examples/read_and_write]
224 ( 0.03%) /usr/src/debug/glibc/glibc/malloc/arena.c:realloc
221 ( 0.03%) ???:miniz_oxide::inflate::core::transfer [/home/mat/code/simdnbt/target/release/examples/read_and_write]
219 ( 0.03%) /usr/src/debug/glibc/glibc/elf/../sysdeps/x86/dl-cacheinfo.h:get_common_cache_info.constprop.0 [/usr/lib/ld-linux-x86-64.so.2]
219 ( 0.03%) /usr/src/debug/glibc/glibc/elf/../sysdeps/x86/dl-cacheinfo.h:init_cpu_features.constprop.0
216 ( 0.03%) ???:alloc::raw_vec::RawVec<T,A>::allocate_in [/home/mat/code/simdnbt/target/release/examples/read_and_write]
212 ( 0.03%) /usr/src/debug/glibc/glibc/elf/dl-hwcaps_split.c:_dl_hwcaps_split_masked [/usr/lib/ld-linux-x86-64.so.2]
205 ( 0.03%) /usr/src/debug/glibc/glibc/elf/dl-catch.c:_dl_catch_exception [/usr/lib/ld-linux-x86-64.so.2]
204 ( 0.03%) /usr/src/debug/glibc/glibc/elf/dl-find_object.c:_dlfo_process_initial [/usr/lib/ld-linux-x86-64.so.2]
203 ( 0.03%) /usr/src/debug/glibc/glibc/elf/../sysdeps/unix/sysv/linux/dl-parse_auxv.h:_dl_sysdep_parse_arguments
198 ( 0.03%) /usr/src/debug/glibc/glibc/malloc/malloc.c:calloc [/usr/lib/libc.so.6]
191 ( 0.03%) /usr/src/debug/glibc/glibc/libio/fileops.c:_IO_file_underflow@@GLIBC_2.2.5 [/usr/lib/libc.so.6]
190 ( 0.03%) /usr/src/debug/glibc/glibc/elf/dl-hwcaps.c:_dl_important_hwcaps [/usr/lib/ld-linux-x86-64.so.2]
184 ( 0.02%) /usr/src/debug/glibc/glibc/libio/libioP.h:getdelim
184 ( 0.02%) /usr/src/debug/glibc/glibc/stdio-common/getline.c:getline [/usr/lib/libc.so.6]
182 ( 0.02%) /usr/src/debug/glibc/glibc/elf/../sysdeps/x86/dl-prop.h:dl_main
182 ( 0.02%) /usr/src/debug/glibc/glibc/elf/rtld.c:_dl_start [/usr/lib/ld-linux-x86-64.so.2]
180 ( 0.02%) ???:simdnbt::swap_endianness::swap_endianness_64bit [/home/mat/code/simdnbt/target/release/examples/read_and_write]
176 ( 0.02%) /usr/src/debug/glibc/glibc/signal/../sysdeps/unix/sysv/linux/libc_sigaction.c:__libc_sigaction [/usr/lib/libc.so.6]
175 ( 0.02%) /usr/src/debug/glibc/glibc/elf/dl-lookup-direct.c:_dl_lookup_direct [/usr/lib/ld-linux-x86-64.so.2]
173 ( 0.02%) /usr/src/debug/glibc/glibc/elf/../sysdeps/x86/cpu-features.c:init_cpu_features.constprop.0 [/usr/lib/ld-linux-x86-64.so.2]
171 ( 0.02%) /usr/src/debug/glibc/glibc/stdlib/cxa_finalize.c:__cxa_finalize [/usr/lib/libc.so.6]
163 ( 0.02%) /usr/src/debug/glibc/glibc/elf/dl-object.c:_dl_add_to_namespace_list [/usr/lib/ld-linux-x86-64.so.2]
159 ( 0.02%) /rustc/69e97df5ce571a777acd654ec3697ae8d25962ea/library/stdarch/crates/std_detect/src/detect/os/x86.rs:std_detect::detect::cache::detect_and_initialize
158 ( 0.02%) /usr/src/debug/glibc/glibc/libio/genops.c:_IO_flush_all [/usr/lib/libc.so.6]
157 ( 0.02%) /usr/src/debug/glibc/glibc/elf/../sysdeps/x86/cpu-features.c:update_active.constprop.0 [/usr/lib/ld-linux-x86-64.so.2]
153 ( 0.02%) /usr/src/debug/glibc/glibc/elf/dl-lookup-direct.c:check_match [/usr/lib/ld-linux-x86-64.so.2]
151 ( 0.02%) /usr/src/debug/glibc/glibc/malloc/malloc.c:sysmalloc [/usr/lib/libc.so.6]
150 ( 0.02%) /usr/src/debug/glibc/glibc/elf/../elf/dl-tls.c:_dl_allocate_tls_init [/usr/lib/ld-linux-x86-64.so.2]
150 ( 0.02%) /usr/src/debug/glibc/glibc/libio/genops.c:_IO_cleanup [/usr/lib/libc.so.6]
147 ( 0.02%) /usr/src/debug/glibc/glibc/libio/../string/bits/string_fortified.h:getdelim
145 ( 0.02%) /usr/src/debug/glibc/glibc/elf/dl-tunables.c:do_tunable_update_val [/usr/lib/ld-linux-x86-64.so.2]
144 ( 0.02%) /usr/src/debug/glibc/glibc/elf/dl-minimal.c:lookup_malloc_symbol [/usr/lib/ld-linux-x86-64.so.2]
143 ( 0.02%) /usr/src/debug/glibc/glibc/elf/dl-call_fini.c:_dl_call_fini [/usr/lib/ld-linux-x86-64.so.2]
142 ( 0.02%) /usr/src/debug/glibc/glibc/setjmp/../sysdeps/x86_64/setjmp.S:__sigsetjmp [/usr/lib/libc.so.6]
135 ( 0.02%) /rustc/69e97df5ce571a777acd654ec3697ae8d25962ea/library/core/src/cmp.rs:alloc::raw_vec::RawVec<T,A>::reserve_for_push
135 ( 0.02%) /usr/src/debug/glibc/glibc/elf/dl-cache.c:_dl_load_cache_lookup [/usr/lib/ld-linux-x86-64.so.2]
135 ( 0.02%) /usr/src/debug/glibc/glibc/elf/dl-setup_hash.c:_dl_setup_hash [/usr/lib/ld-linux-x86-64.so.2]
132 ( 0.02%) /usr/src/debug/glibc/glibc/posix/../sysdeps/unix/sysv/linux/x86/sysconf.c:sysconf [/usr/lib/libc.so.6]
130 ( 0.02%) ???:flate2::gz::GzHeaderParser::parse [/home/mat/code/simdnbt/target/release/examples/read_and_write]
128 ( 0.02%) /usr/src/debug/glibc/glibc/elf/dl-find_object.c:_dlfo_sort_mappings [/usr/lib/ld-linux-x86-64.so.2]
123 ( 0.02%) ???:<flate2::bufreader::BufReader<R> as std::io::Read>::read [/home/mat/code/simdnbt/target/release/examples/read_and_write]
115 ( 0.02%) /usr/src/debug/glibc/glibc/libio/genops.c:__underflow [/usr/lib/libc.so.6]
112 ( 0.01%) /usr/src/debug/glibc/glibc/elf/../elf/dl-tls.c:_dl_determine_tlsoffset [/usr/lib/ld-linux-x86-64.so.2]
108 ( 0.01%) ???:simdnbt::swap_endianness::swap_endianness [/home/mat/code/simdnbt/target/release/examples/read_and_write]
107 ( 0.01%) /usr/src/debug/glibc/glibc/string/../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S:mempcpy [/usr/lib/ld-linux-x86-64.so.2]
102 ( 0.01%) /usr/src/debug/glibc/glibc/posix/../sysdeps/posix/sysconf.c:sysconf
100 ( 0.01%) /usr/src/debug/glibc/glibc/elf/dl-minimal-malloc.c:__minimal_calloc [/usr/lib/ld-linux-x86-64.so.2]
100 ( 0.01%) /usr/src/debug/glibc/glibc/elf/dl-reloc.c:_dl_protect_relro [/usr/lib/ld-linux-x86-64.so.2]
100 ( 0.01%) /usr/src/debug/glibc/glibc/libio/genops.c:_IO_switch_to_get_mode [/usr/lib/libc.so.6]
--------------------------------------------------------------------------------
The following files chosen for auto-annotation could not be found:
--------------------------------------------------------------------------------
/rustc/69e97df5ce571a777acd654ec3697ae8d25962ea/library/alloc/src/raw_vec.rs
/rustc/69e97df5ce571a777acd654ec3697ae8d25962ea/library/core/src/cmp.rs
/rustc/69e97df5ce571a777acd654ec3697ae8d25962ea/library/stdarch/crates/std_detect/src/detect/os/x86.rs
/usr/src/debug/gcc/gcc/libgcc/../gcc/common/config/i386/cpuinfo.h
/usr/src/debug/glibc/glibc/elf/../bits/stdlib-bsearch.h
/usr/src/debug/glibc/glibc/elf/../elf/dl-tls.c
/usr/src/debug/glibc/glibc/elf/../sysdeps/generic/dl-new-hash.h
/usr/src/debug/glibc/glibc/elf/../sysdeps/generic/dl-protected.h
/usr/src/debug/glibc/glibc/elf/../sysdeps/generic/ldsodefs.h
/usr/src/debug/glibc/glibc/elf/../sysdeps/unix/sysv/linux/dl-parse_auxv.h
/usr/src/debug/glibc/glibc/elf/../sysdeps/unix/sysv/linux/dl-sysdep.c
/usr/src/debug/glibc/glibc/elf/../sysdeps/x86/cpu-features.c
/usr/src/debug/glibc/glibc/elf/../sysdeps/x86/dl-cacheinfo.h
/usr/src/debug/glibc/glibc/elf/../sysdeps/x86/dl-prop.h
/usr/src/debug/glibc/glibc/elf/../sysdeps/x86_64/dl-machine.h
/usr/src/debug/glibc/glibc/elf/./dl-find_object.h
/usr/src/debug/glibc/glibc/elf/./dl-map-segments.h
/usr/src/debug/glibc/glibc/elf/./get-dynamic-info.h
/usr/src/debug/glibc/glibc/elf/dl-cache.c
/usr/src/debug/glibc/glibc/elf/dl-call_fini.c
/usr/src/debug/glibc/glibc/elf/dl-catch.c
/usr/src/debug/glibc/glibc/elf/dl-deps.c
/usr/src/debug/glibc/glibc/elf/dl-environ.c
/usr/src/debug/glibc/glibc/elf/dl-find_object.c
/usr/src/debug/glibc/glibc/elf/dl-fini.c
/usr/src/debug/glibc/glibc/elf/dl-hwcaps.c
/usr/src/debug/glibc/glibc/elf/dl-hwcaps_split.c
/usr/src/debug/glibc/glibc/elf/dl-init.c
/usr/src/debug/glibc/glibc/elf/dl-load.c
/usr/src/debug/glibc/glibc/elf/dl-lookup-direct.c
/usr/src/debug/glibc/glibc/elf/dl-lookup.c
/usr/src/debug/glibc/glibc/elf/dl-minimal-malloc.c
/usr/src/debug/glibc/glibc/elf/dl-minimal.c
/usr/src/debug/glibc/glibc/elf/dl-misc.c
/usr/src/debug/glibc/glibc/elf/dl-object.c
/usr/src/debug/glibc/glibc/elf/dl-reloc.c
/usr/src/debug/glibc/glibc/elf/dl-setup_hash.c
/usr/src/debug/glibc/glibc/elf/dl-sort-maps.c
/usr/src/debug/glibc/glibc/elf/dl-tunables.c
/usr/src/debug/glibc/glibc/elf/dl-tunables.h
/usr/src/debug/glibc/glibc/elf/dl-version.c
/usr/src/debug/glibc/glibc/elf/do-rel.h
/usr/src/debug/glibc/glibc/elf/get-dynamic-info.h
/usr/src/debug/glibc/glibc/elf/rtld.c
/usr/src/debug/glibc/glibc/libio/../string/bits/string_fortified.h
/usr/src/debug/glibc/glibc/libio/fileops.c
/usr/src/debug/glibc/glibc/libio/genops.c
/usr/src/debug/glibc/glibc/libio/iogetdelim.c
/usr/src/debug/glibc/glibc/libio/libioP.h
/usr/src/debug/glibc/glibc/libio/strops.c
/usr/src/debug/glibc/glibc/malloc/arena.c
/usr/src/debug/glibc/glibc/malloc/malloc.c
/usr/src/debug/glibc/glibc/misc/../sysdeps/unix/sysv/linux/mmap64.c
/usr/src/debug/glibc/glibc/nptl/libc-cleanup.c
/usr/src/debug/glibc/glibc/nptl/pthread_getattr_np.c
/usr/src/debug/glibc/glibc/posix/../sysdeps/posix/sysconf.c
/usr/src/debug/glibc/glibc/posix/../sysdeps/unix/sysv/linux/x86/sysconf.c
/usr/src/debug/glibc/glibc/setjmp/../sysdeps/x86_64/setjmp.S
/usr/src/debug/glibc/glibc/signal/../sysdeps/unix/sysv/linux/libc_sigaction.c
/usr/src/debug/glibc/glibc/stdio-common/../include/scratch_buffer.h
/usr/src/debug/glibc/glibc/stdio-common/../libio/strfile.h
/usr/src/debug/glibc/glibc/stdio-common/getline.c
/usr/src/debug/glibc/glibc/stdio-common/isoc23_sscanf.c
/usr/src/debug/glibc/glibc/stdio-common/vfscanf-internal.c
/usr/src/debug/glibc/glibc/stdlib/../stdlib/strtol.c
/usr/src/debug/glibc/glibc/stdlib/../stdlib/strtol_l.c
/usr/src/debug/glibc/glibc/stdlib/cxa_finalize.c
/usr/src/debug/glibc/glibc/string/../string/strcspn.c
/usr/src/debug/glibc/glibc/string/../sysdeps/x86_64/multiarch/../multiarch/memset-vec-unaligned-erms.S
/usr/src/debug/glibc/glibc/string/../sysdeps/x86_64/multiarch/../multiarch/strchr-sse2.S
/usr/src/debug/glibc/glibc/string/../sysdeps/x86_64/multiarch/../multiarch/strcmp-sse2.S
/usr/src/debug/glibc/glibc/string/../sysdeps/x86_64/multiarch/../multiarch/strlen-sse2.S
/usr/src/debug/glibc/glibc/string/../sysdeps/x86_64/multiarch/memchr-avx2.S
/usr/src/debug/glibc/glibc/string/../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S
/usr/src/debug/glibc/glibc/string/../sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S
/usr/src/debug/glibc/glibc/string/../sysdeps/x86_64/multiarch/strlen-avx2.S

View file

@ -101,15 +101,10 @@ fn simdnbt_items_from_nbt(nbt: Nbt) -> Option<Vec<Option<Item>>> {
fn main() {
let input = black_box(include_bytes!("../tests/realworld.nbt"));
for _ in 0..10000 {
let nbt = Nbt::new(&mut Cursor::new(input));
let nbt = black_box(nbt.unwrap().unwrap());
black_box(simdnbt_items_from_nbt(nbt));
}
let nbt = Nbt::new(&mut Cursor::new(input)).unwrap().unwrap();
for _ in 0..100000 {
let mut out = Vec::new();
nbt.write(&mut out);
}
}

View file

@ -0,0 +1,20 @@
use std::{hint::black_box, io::Cursor};
fn main() {
let src = black_box(include_bytes!("../tests/complex_player.dat"));
let mut decoded_src_decoder = flate2::read::GzDecoder::new(&src[..]);
let mut input = Vec::new();
if std::io::Read::read_to_end(&mut decoded_src_decoder, &mut input).is_err() {
// oh probably wasn't gzipped then
input = src.to_vec();
}
let input = input.as_slice();
let nbt = simdnbt::owned::Nbt::new(&mut Cursor::new(input))
.unwrap()
.unwrap();
let mut out = Vec::new();
nbt.write(&mut out);
black_box(out);
}

View file

@ -5,9 +5,9 @@ use byteorder::ReadBytesExt;
use crate::{
common::{
read_i8_array, read_int_array, read_long_array, read_string, read_u8_array,
read_with_u32_length, write_i8_array, write_string, write_u32, BYTE_ARRAY_ID, BYTE_ID,
COMPOUND_ID, DOUBLE_ID, END_ID, FLOAT_ID, INT_ARRAY_ID, INT_ID, LIST_ID, LONG_ARRAY_ID,
LONG_ID, SHORT_ID, STRING_ID,
read_with_u32_length, slice_i8_into_u8, unchecked_extend, unchecked_push, write_string,
write_u32, write_with_u32_length, BYTE_ARRAY_ID, BYTE_ID, COMPOUND_ID, DOUBLE_ID, END_ID,
FLOAT_ID, INT_ARRAY_ID, INT_ID, LIST_ID, LONG_ARRAY_ID, LONG_ID, SHORT_ID, STRING_ID,
},
raw_list::RawList,
Mutf8Str, ReadError,
@ -27,7 +27,7 @@ pub enum ListTag<'a> {
Long(RawList<'a, i64>) = LONG_ID,
Float(RawList<'a, f32>) = FLOAT_ID,
Double(RawList<'a, f64>) = DOUBLE_ID,
ByteArray(&'a [u8]) = BYTE_ARRAY_ID,
ByteArray(Vec<&'a [u8]>) = BYTE_ARRAY_ID,
String(Vec<&'a Mutf8Str>) = STRING_ID,
List(Vec<ListTag<'a>>) = LIST_ID,
Compound(Vec<CompoundTag<'a>>) = COMPOUND_ID,
@ -51,7 +51,15 @@ impl<'a> ListTag<'a> {
LONG_ID => ListTag::Long(RawList::new(read_with_u32_length(data, 8)?)),
FLOAT_ID => ListTag::Float(RawList::new(read_with_u32_length(data, 4)?)),
DOUBLE_ID => ListTag::Double(RawList::new(read_with_u32_length(data, 8)?)),
BYTE_ARRAY_ID => ListTag::ByteArray(read_u8_array(data)?),
BYTE_ARRAY_ID => ListTag::ByteArray({
let length = read_u32(data)?;
// arbitrary number to prevent big allocations
let mut arrays = Vec::with_capacity(length.min(128) as usize);
for _ in 0..length {
arrays.push(read_u8_array(data)?)
}
arrays
}),
STRING_ID => ListTag::String({
let length = read_u32(data)?;
// arbitrary number to prevent big allocations
@ -102,42 +110,52 @@ impl<'a> ListTag<'a> {
}
pub fn write(&self, data: &mut Vec<u8>) {
// fast path for compound since it's very common to have lists of compounds
if let ListTag::Compound(compounds) = self {
data.reserve(5);
// SAFETY: we just reserved 5 bytes
unsafe {
unchecked_push(data, COMPOUND_ID);
unchecked_extend(data, &(compounds.len() as u32).to_be_bytes());
}
for compound in compounds {
compound.write(data);
}
return;
}
data.push(self.id());
match self {
ListTag::Empty => {
write_u32(data, 0);
data.extend(&0u32.to_be_bytes());
}
ListTag::Byte(bytes) => {
write_u32(data, bytes.len() as u32);
write_i8_array(data, bytes);
write_with_u32_length(data, 1, slice_i8_into_u8(bytes));
}
ListTag::Short(shorts) => {
write_u32(data, shorts.len() as u32);
data.extend_from_slice(&shorts.as_big_endian());
write_with_u32_length(data, 2, shorts.as_big_endian());
}
ListTag::Int(ints) => {
write_u32(data, ints.len() as u32);
data.extend_from_slice(&ints.as_big_endian());
write_with_u32_length(data, 4, ints.as_big_endian());
}
ListTag::Long(longs) => {
write_u32(data, longs.len() as u32);
data.extend_from_slice(&longs.as_big_endian());
write_with_u32_length(data, 8, longs.as_big_endian());
}
ListTag::Float(floats) => {
write_u32(data, floats.len() as u32);
data.extend_from_slice(&floats.as_big_endian());
write_with_u32_length(data, 4, floats.as_big_endian());
}
ListTag::Double(doubles) => {
write_u32(data, doubles.len() as u32);
data.extend_from_slice(&doubles.as_big_endian());
write_with_u32_length(data, 8, doubles.as_big_endian());
}
ListTag::ByteArray(byte_arrays) => {
write_u32(data, byte_arrays.len() as u32);
data.extend_from_slice(byte_arrays);
for array in byte_arrays.iter() {
write_with_u32_length(data, 1, array);
}
}
ListTag::String(strings) => {
write_u32(data, strings.len() as u32);
for &string in strings {
for string in strings {
write_string(data, string);
}
}
@ -147,24 +165,19 @@ impl<'a> ListTag<'a> {
list.write(data);
}
}
ListTag::Compound(compounds) => {
write_u32(data, compounds.len() as u32);
for compound in compounds {
compound.write(data);
}
ListTag::Compound(_) => {
unreachable!("fast path for compound should have been taken")
}
ListTag::IntArray(int_arrays) => {
write_u32(data, int_arrays.len() as u32);
for array in int_arrays {
write_u32(data, array.len() as u32);
data.extend_from_slice(&array.as_big_endian());
write_with_u32_length(data, 4, array.as_big_endian());
}
}
ListTag::LongArray(long_arrays) => {
write_u32(data, long_arrays.len() as u32);
for array in long_arrays {
write_u32(data, array.len() as u32);
data.extend_from_slice(&array.as_big_endian());
write_with_u32_length(data, 8, array.as_big_endian());
}
}
}
@ -216,7 +229,7 @@ impl<'a> ListTag<'a> {
_ => None,
}
}
pub fn byte_arrays(&self) -> Option<&[u8]> {
pub fn byte_arrays(&self) -> Option<&Vec<&[u8]>> {
match self {
ListTag::ByteArray(byte_arrays) => Some(byte_arrays),
_ => None,

View file

@ -8,9 +8,10 @@ use byteorder::{ReadBytesExt, BE};
use crate::{
common::{
read_int_array, read_long_array, read_string, read_u32, read_with_u32_length, write_i32,
write_string, BYTE_ARRAY_ID, BYTE_ID, COMPOUND_ID, DOUBLE_ID, END_ID, FLOAT_ID,
INT_ARRAY_ID, INT_ID, LIST_ID, LONG_ARRAY_ID, LONG_ID, MAX_DEPTH, SHORT_ID, STRING_ID,
read_int_array, read_long_array, read_string, read_u32, read_with_u32_length,
unchecked_extend, unchecked_push, unchecked_write_string, write_string, BYTE_ARRAY_ID,
BYTE_ID, COMPOUND_ID, DOUBLE_ID, END_ID, FLOAT_ID, INT_ARRAY_ID, INT_ID, LIST_ID,
LONG_ARRAY_ID, LONG_ID, MAX_DEPTH, SHORT_ID, STRING_ID,
},
raw_list::RawList,
Mutf8Str, ReadError,
@ -140,29 +141,37 @@ impl<'a> CompoundTag<'a> {
pub fn write(&self, data: &mut Vec<u8>) {
for (name, tag) in &self.values {
data.push(tag.id());
write_string(data, name);
// reserve 4 bytes extra so we can avoid reallocating for small tags
data.reserve(1 + 2 + name.len() + 4);
// SAFETY: We just reserved enough space for the tag ID, the name length, the name, and
// 4 bytes of tag data.
unsafe {
unchecked_push(data, tag.id());
unchecked_write_string(data, name);
}
match tag {
Tag::Byte(byte) => {
data.push(*byte as u8);
}
Tag::Short(short) => {
data.extend_from_slice(&short.to_be_bytes());
}
Tag::Int(int) => {
write_i32(data, *int);
}
Tag::Byte(byte) => unsafe {
unchecked_push(data, *byte as u8);
},
Tag::Short(short) => unsafe {
unchecked_extend(data, &short.to_be_bytes());
},
Tag::Int(int) => unsafe {
unchecked_extend(data, &int.to_be_bytes());
},
Tag::Long(long) => {
data.extend_from_slice(&long.to_be_bytes());
}
Tag::Float(float) => {
data.extend_from_slice(&float.to_be_bytes());
}
Tag::Float(float) => unsafe {
unchecked_extend(data, &float.to_be_bytes());
},
Tag::Double(double) => {
data.extend_from_slice(&double.to_be_bytes());
}
Tag::ByteArray(byte_array) => {
write_i32(data, byte_array.len() as i32);
unsafe {
unchecked_extend(data, &byte_array.len().to_be_bytes());
}
data.extend_from_slice(byte_array);
}
Tag::String(string) => {
@ -175,12 +184,16 @@ impl<'a> CompoundTag<'a> {
compound.write(data);
}
Tag::IntArray(int_array) => {
write_i32(data, int_array.len() as i32);
data.extend_from_slice(&int_array.to_little_endian());
unsafe {
unchecked_extend(data, &int_array.len().to_be_bytes());
}
data.extend_from_slice(&int_array.as_big_endian());
}
Tag::LongArray(long_array) => {
write_i32(data, long_array.len() as i32);
data.extend_from_slice(&long_array.to_little_endian());
unsafe {
unchecked_extend(data, &long_array.len().to_be_bytes());
}
data.extend_from_slice(&long_array.as_big_endian());
}
}
}

View file

@ -108,35 +108,75 @@ fn slice_u8_into_i8(s: &[u8]) -> &[i8] {
unsafe { slice::from_raw_parts(s.as_ptr() as *const i8, s.len()) }
}
fn slice_i8_into_u8(s: &[i8]) -> &[u8] {
pub fn slice_i8_into_u8(s: &[i8]) -> &[u8] {
unsafe { slice::from_raw_parts(s.as_ptr() as *const u8, s.len()) }
}
#[inline(always)]
pub fn write_with_u32_length<'a>(data: &mut Vec<u8>, width: usize, value: &'a [u8]) {
let length = value.len() / width;
data.reserve(4 + value.len());
unsafe {
unchecked_extend(data, &(length as u32).to_be_bytes());
unchecked_extend(data, value);
}
}
pub fn write_u32(data: &mut Vec<u8>, value: u32) {
data.extend_from_slice(&value.to_be_bytes());
}
pub fn write_i32(data: &mut Vec<u8>, value: i32) {
data.extend_from_slice(&value.to_be_bytes());
}
pub fn write_u16(data: &mut Vec<u8>, value: u16) {
data.extend_from_slice(&value.to_be_bytes());
}
pub fn write_i8_array(data: &mut Vec<u8>, value: &[i8]) {
data.extend_from_slice(slice_i8_into_u8(value));
}
pub fn write_string(data: &mut Vec<u8>, value: &Mutf8Str) {
write_u16(data, value.len() as u16);
data.extend_from_slice(value.as_bytes());
data.reserve(2 + value.len());
// SAFETY: We reserved enough capacity
unsafe {
unchecked_write_string(data, value);
}
}
/// Write a string to a Vec<u8> without checking if the Vec has enough capacity.
/// This is unsafe because it can cause a buffer overflow if the Vec doesn't have enough capacity.
///
/// # Safety
///
/// You must reserve enough capacity (2 + value.len()) in the Vec before calling this function.
#[inline]
pub unsafe fn unchecked_write_string(data: &mut Vec<u8>, value: &Mutf8Str) {
unchecked_extend(data, &(value.len() as u16).to_be_bytes());
unchecked_extend(data, value.as_bytes());
}
/// Extend a Vec<u8> with a slice of u8 without checking if the Vec has enough capacity.
///
/// This optimization is barely measurable, but it does make it slightly faster!
///
/// # Safety
///
/// You must reserve enough capacity in the Vec before calling this function.
#[inline]
pub unsafe fn unchecked_extend(data: &mut Vec<u8>, value: &[u8]) {
let ptr = data.as_mut_ptr();
let len = data.len();
std::ptr::copy_nonoverlapping(value.as_ptr(), ptr.add(len), value.len());
data.set_len(len + value.len());
}
#[inline]
pub unsafe fn unchecked_push(data: &mut Vec<u8>, value: u8) {
let ptr = data.as_mut_ptr();
let len = data.len();
std::ptr::write(ptr.add(len), value);
data.set_len(len + 1);
}
/// Convert a slice of any type into a slice of u8. This will probably return the data as little
/// endian! Use [`slice_into_u8_big_endian`] to get big endian (the endianness that's used in NBT).
#[inline]
pub fn slice_into_u8_native_endian<T>(s: &[T]) -> &[u8] {
unsafe { slice::from_raw_parts(s.as_ptr() as *const u8, s.len() * std::mem::size_of::<T>()) }
}
/// Convert a slice of any type into a Vec<u8>. This will return the data as big endian (the
/// endianness that's used in NBT).
#[inline]
pub fn slice_into_u8_big_endian<T: SwappableNumber>(s: &[T]) -> Vec<u8> {
swap_endianness_as_u8::<T>(slice_into_u8_native_endian(s))
}

View file

@ -76,6 +76,7 @@ fn is_plain_ascii(slice: &[u8]) -> bool {
}
impl Mutf8Str {
#[inline]
pub fn to_string_lossy(&self) -> Cow<str> {
String::from_utf8_lossy(&self.slice)
}
@ -88,6 +89,7 @@ impl Mutf8Str {
// we can't implement FromStr on Cow<Mutf8Str>
#[allow(clippy::should_implement_trait)]
#[inline]
pub fn from_str(s: &str) -> Cow<Mutf8Str> {
match mutf8::encode(s) {
Cow::Borrowed(b) => Cow::Borrowed(Mutf8Str::from_slice(b)),
@ -95,6 +97,7 @@ impl Mutf8Str {
}
}
#[inline]
pub fn to_str(&self) -> Cow<str> {
// fast check to skip if none of the bytes have the top bit set or are null
if is_plain_ascii(&self.slice) {
@ -108,10 +111,12 @@ impl Mutf8Str {
}
}
#[inline]
pub fn len(&self) -> usize {
self.slice.len()
}
#[inline]
pub fn as_bytes(&self) -> &[u8] {
&self.slice
}
@ -126,6 +131,7 @@ impl fmt::Display for Mutf8Str {
impl ToOwned for Mutf8Str {
type Owned = Mutf8String;
#[inline]
fn to_owned(&self) -> Self::Owned {
Mutf8String {
vec: self.slice.to_vec(),
@ -133,6 +139,7 @@ impl ToOwned for Mutf8Str {
}
}
impl Borrow<Mutf8Str> for Mutf8String {
#[inline]
fn borrow(&self) -> &Mutf8Str {
self.as_str()
}
@ -144,6 +151,7 @@ impl Mutf8String {
Mutf8Str::from_slice(self.vec.as_slice())
}
#[inline]
pub fn into_string(self) -> String {
if is_plain_ascii(&self.vec) {
// SAFETY: &[u8] and &str are the same layout.
@ -156,6 +164,7 @@ impl Mutf8String {
}
}
#[inline]
pub fn len(&self) -> usize {
self.vec.len()
}
@ -163,6 +172,7 @@ impl Mutf8String {
impl Deref for Mutf8String {
type Target = Mutf8Str;
#[inline]
fn deref(&self) -> &Self::Target {
self.as_str()
}

View file

@ -5,9 +5,10 @@ use byteorder::ReadBytesExt;
use crate::{
common::{
read_i8_array, read_int_array, read_long_array, read_string, read_u8_array,
read_with_u32_length, slice_into_u8_big_endian, write_i8_array, write_string, write_u32,
BYTE_ARRAY_ID, BYTE_ID, COMPOUND_ID, DOUBLE_ID, END_ID, FLOAT_ID, INT_ARRAY_ID, INT_ID,
LIST_ID, LONG_ARRAY_ID, LONG_ID, SHORT_ID, STRING_ID,
read_with_u32_length, slice_i8_into_u8, slice_into_u8_big_endian, unchecked_extend,
unchecked_push, write_string, write_u32, write_with_u32_length, BYTE_ARRAY_ID, BYTE_ID,
COMPOUND_ID, DOUBLE_ID, END_ID, FLOAT_ID, INT_ARRAY_ID, INT_ID, LIST_ID, LONG_ARRAY_ID,
LONG_ID, SHORT_ID, STRING_ID,
},
mutf8::Mutf8String,
swap_endianness::swap_endianness,
@ -28,7 +29,7 @@ pub enum ListTag {
Long(Vec<i64>) = LONG_ID,
Float(Vec<f32>) = FLOAT_ID,
Double(Vec<f64>) = DOUBLE_ID,
ByteArray(Vec<u8>) = BYTE_ARRAY_ID,
ByteArray(Vec<Vec<u8>>) = BYTE_ARRAY_ID,
String(Vec<Mutf8String>) = STRING_ID,
List(Vec<ListTag>) = LIST_ID,
Compound(Vec<CompoundTag>) = COMPOUND_ID,
@ -52,7 +53,15 @@ impl ListTag {
LONG_ID => ListTag::Long(swap_endianness(read_with_u32_length(data, 8)?)),
FLOAT_ID => ListTag::Float(swap_endianness(read_with_u32_length(data, 4)?)),
DOUBLE_ID => ListTag::Double(swap_endianness(read_with_u32_length(data, 8)?)),
BYTE_ARRAY_ID => ListTag::ByteArray(read_u8_array(data)?.to_owned()),
BYTE_ARRAY_ID => ListTag::ByteArray({
let length = read_u32(data)?;
// arbitrary number to prevent big allocations
let mut arrays = Vec::with_capacity(length.min(128) as usize);
for _ in 0..length {
arrays.push(read_u8_array(data)?.to_vec())
}
arrays
}),
STRING_ID => ListTag::String({
let length = read_u32(data)?;
// arbitrary number to prevent big allocations
@ -103,38 +112,48 @@ impl ListTag {
}
pub fn write(&self, data: &mut Vec<u8>) {
// fast path for compound since it's very common to have lists of compounds
if let ListTag::Compound(compounds) = self {
data.reserve(5);
// SAFETY: we just reserved 5 bytes
unsafe {
unchecked_push(data, COMPOUND_ID);
unchecked_extend(data, &(compounds.len() as u32).to_be_bytes());
}
for compound in compounds {
compound.write(data);
}
return;
}
data.push(self.id());
match self {
ListTag::Empty => {
write_u32(data, 0);
data.extend(&0u32.to_be_bytes());
}
ListTag::Byte(bytes) => {
write_u32(data, bytes.len() as u32);
write_i8_array(data, bytes);
write_with_u32_length(data, 1, slice_i8_into_u8(bytes));
}
ListTag::Short(shorts) => {
write_u32(data, shorts.len() as u32);
data.extend_from_slice(&slice_into_u8_big_endian(shorts));
write_with_u32_length(data, 2, &slice_into_u8_big_endian(shorts));
}
ListTag::Int(ints) => {
write_u32(data, ints.len() as u32);
data.extend_from_slice(&slice_into_u8_big_endian(ints));
write_with_u32_length(data, 4, &slice_into_u8_big_endian(ints));
}
ListTag::Long(longs) => {
write_u32(data, longs.len() as u32);
data.extend_from_slice(&slice_into_u8_big_endian(longs));
write_with_u32_length(data, 8, &slice_into_u8_big_endian(longs));
}
ListTag::Float(floats) => {
write_u32(data, floats.len() as u32);
data.extend_from_slice(&slice_into_u8_big_endian(floats));
write_with_u32_length(data, 4, &slice_into_u8_big_endian(floats));
}
ListTag::Double(doubles) => {
write_u32(data, doubles.len() as u32);
data.extend_from_slice(&slice_into_u8_big_endian(doubles));
write_with_u32_length(data, 8, &slice_into_u8_big_endian(doubles));
}
ListTag::ByteArray(byte_arrays) => {
write_u32(data, byte_arrays.len() as u32);
data.extend_from_slice(byte_arrays);
for array in byte_arrays {
write_with_u32_length(data, 1, array);
}
}
ListTag::String(strings) => {
write_u32(data, strings.len() as u32);
@ -148,24 +167,19 @@ impl ListTag {
list.write(data);
}
}
ListTag::Compound(compounds) => {
write_u32(data, compounds.len() as u32);
for compound in compounds {
compound.write(data);
}
ListTag::Compound(_) => {
unreachable!("fast path for compound should have been taken")
}
ListTag::IntArray(int_arrays) => {
write_u32(data, int_arrays.len() as u32);
for array in int_arrays {
write_u32(data, array.len() as u32);
data.extend_from_slice(&slice_into_u8_big_endian(array));
write_with_u32_length(data, 4, &slice_into_u8_big_endian(array));
}
}
ListTag::LongArray(long_arrays) => {
write_u32(data, long_arrays.len() as u32);
for array in long_arrays {
write_u32(data, array.len() as u32);
data.extend_from_slice(&slice_into_u8_big_endian(array));
write_with_u32_length(data, 8, &slice_into_u8_big_endian(array));
}
}
}
@ -217,7 +231,7 @@ impl ListTag {
_ => None,
}
}
pub fn byte_arrays(&self) -> Option<&[u8]> {
pub fn byte_arrays(&self) -> Option<&[Vec<u8>]> {
match self {
ListTag::ByteArray(byte_arrays) => Some(byte_arrays),
_ => None,

View file

@ -9,9 +9,9 @@ use byteorder::{ReadBytesExt, BE};
use crate::{
common::{
read_int_array, read_long_array, read_string, read_u32, read_with_u32_length,
slice_into_u8_big_endian, write_i32, write_string, BYTE_ARRAY_ID, BYTE_ID, COMPOUND_ID,
DOUBLE_ID, END_ID, FLOAT_ID, INT_ARRAY_ID, INT_ID, LIST_ID, LONG_ARRAY_ID, LONG_ID,
MAX_DEPTH, SHORT_ID, STRING_ID,
slice_into_u8_big_endian, unchecked_extend, unchecked_push, unchecked_write_string,
write_string, BYTE_ARRAY_ID, BYTE_ID, COMPOUND_ID, DOUBLE_ID, END_ID, FLOAT_ID,
INT_ARRAY_ID, INT_ID, LIST_ID, LONG_ARRAY_ID, LONG_ID, MAX_DEPTH, SHORT_ID, STRING_ID,
},
mutf8::Mutf8String,
Mutf8Str, ReadError,
@ -145,29 +145,37 @@ impl CompoundTag {
pub fn write(&self, data: &mut Vec<u8>) {
for (name, tag) in &self.values {
data.push(tag.id());
write_string(data, name);
// reserve 4 bytes extra so we can avoid reallocating for small tags
data.reserve(1 + 2 + name.len() + 4);
// SAFETY: We just reserved enough space for the tag ID, the name length, the name, and
// 4 bytes of tag data.
unsafe {
unchecked_push(data, tag.id());
unchecked_write_string(data, name);
}
match tag {
Tag::Byte(byte) => {
data.push(*byte as u8);
}
Tag::Short(short) => {
data.extend_from_slice(&short.to_be_bytes());
}
Tag::Int(int) => {
write_i32(data, *int);
}
Tag::Byte(byte) => unsafe {
unchecked_push(data, *byte as u8);
},
Tag::Short(short) => unsafe {
unchecked_extend(data, &short.to_be_bytes());
},
Tag::Int(int) => unsafe {
unchecked_extend(data, &int.to_be_bytes());
},
Tag::Long(long) => {
data.extend_from_slice(&long.to_be_bytes());
}
Tag::Float(float) => {
data.extend_from_slice(&float.to_be_bytes());
}
Tag::Float(float) => unsafe {
unchecked_extend(data, &float.to_be_bytes());
},
Tag::Double(double) => {
data.extend_from_slice(&double.to_be_bytes());
}
Tag::ByteArray(byte_array) => {
write_i32(data, byte_array.len() as i32);
unsafe {
unchecked_extend(data, &byte_array.len().to_be_bytes());
}
data.extend_from_slice(byte_array);
}
Tag::String(string) => {
@ -180,11 +188,15 @@ impl CompoundTag {
compound.write(data);
}
Tag::IntArray(int_array) => {
write_i32(data, int_array.len() as i32);
unsafe {
unchecked_extend(data, &int_array.len().to_be_bytes());
}
data.extend_from_slice(&slice_into_u8_big_endian(int_array));
}
Tag::LongArray(long_array) => {
write_i32(data, long_array.len() as i32);
unsafe {
unchecked_extend(data, &long_array.len().to_be_bytes());
}
data.extend_from_slice(&slice_into_u8_big_endian(long_array));
}
}

View file

@ -10,6 +10,7 @@ impl SwappableNumber for i64 {}
impl SwappableNumber for f32 {}
impl SwappableNumber for f64 {}
#[inline]
fn swap_endianness_16bit(bytes: &mut [u8], num: usize) {
for i in 0..num / 32 {
let simd: u8x64 = Simd::from_slice(bytes[i * 32 * 2..(i + 1) * 32 * 2].as_ref());
@ -124,6 +125,7 @@ fn swap_endianness_16bit(bytes: &mut [u8], num: usize) {
}
}
#[inline]
fn swap_endianness_32bit(bytes: &mut [u8], num: usize) {
for i in 0..num / 16 {
let simd: u8x64 = Simd::from_slice(bytes[i * 16 * 4..(i + 1) * 16 * 4].as_ref());
@ -198,6 +200,7 @@ fn swap_endianness_32bit(bytes: &mut [u8], num: usize) {
}
}
#[inline]
fn swap_endianness_64bit(bytes: &mut [u8], num: usize) {
for i in 0..num / 8 {
let simd: u8x64 = Simd::from_slice(bytes[i * 64..i * 64 + 64].as_ref());