2437 lines
83 KiB
C++
2437 lines
83 KiB
C++
|
#pragma once
|
|||
|
#define use_fastio
|
|||
|
#ifdef use_fastio
|
|||
|
#include "./fast_io/include/fast_io.h"
|
|||
|
#endif
|
|||
|
|
|||
|
#include <bit>
|
|||
|
#include <cassert>
|
|||
|
#include <cmath>
|
|||
|
#include <concepts>
|
|||
|
#include <span>
|
|||
|
#include <string>
|
|||
|
#include <utility>
|
|||
|
|
|||
|
namespace na::nbt::v7 {
|
|||
|
namespace impl {
|
|||
|
enum class nbt_parse_error
|
|||
|
{
|
|||
|
end_of_file,
|
|||
|
invalid
|
|||
|
};
|
|||
|
|
|||
|
struct nbt_document;
|
|||
|
|
|||
|
namespace swapper {
|
|||
|
template<typename T>
|
|||
|
inline T& byte_as_type(std::byte* ptr) noexcept;
|
|||
|
|
|||
|
template<typename T, std::endian nbt_endian>
|
|||
|
requires(nbt_endian == std::endian::big || nbt_endian == std::endian::little) inline T endian_get(std::byte* ptr) noexcept;
|
|||
|
|
|||
|
template<typename T, std::endian nbt_endian>
|
|||
|
requires(nbt_endian == std::endian::big || nbt_endian == std::endian::little) inline T endian_make_native_get(std::byte* ptr) noexcept;
|
|||
|
|
|||
|
template<typename T, std::endian nbt_endian>
|
|||
|
requires(nbt_endian == std::endian::big || nbt_endian == std::endian::little) inline T endian_get_make_native(std::byte* ptr) noexcept;
|
|||
|
|
|||
|
template<typename T, std::endian nbt_endian>
|
|||
|
requires(nbt_endian == std::endian::big || nbt_endian == std::endian::little) inline void endian_make_native(std::byte* ptr) noexcept;
|
|||
|
|
|||
|
template<typename read_swapper, std::endian nbt_endian>
|
|||
|
concept read_swapper_for_endian = requires(std::byte * &t)
|
|||
|
{
|
|||
|
read_swapper::template tag_byte<nbt_endian>(t);
|
|||
|
read_swapper::template tag_short<nbt_endian>(t);
|
|||
|
read_swapper::template tag_int<nbt_endian>(t);
|
|||
|
read_swapper::template tag_long<nbt_endian>(t);
|
|||
|
read_swapper::template tag_float<nbt_endian>(t);
|
|||
|
read_swapper::template tag_double<nbt_endian>(t);
|
|||
|
read_swapper::template tag_byte_array<nbt_endian>(t);
|
|||
|
read_swapper::template tag_string<nbt_endian>(t);
|
|||
|
read_swapper::template tag_int_array<nbt_endian>(t);
|
|||
|
read_swapper::template tag_long_array<nbt_endian>(t);
|
|||
|
};
|
|||
|
template<typename read_swapper_t>
|
|||
|
concept read_swapper =
|
|||
|
read_swapper_for_endian<read_swapper_t, std::endian::big> &&
|
|||
|
read_swapper_for_endian<read_swapper_t, std::endian::little>;
|
|||
|
|
|||
|
template<typename write_swapper, std::endian nbt_endian>
|
|||
|
concept write_swapper_for_endian = requires(std::byte * &t)
|
|||
|
{
|
|||
|
write_swapper::template tag_byte<nbt_endian>(t);
|
|||
|
write_swapper::template tag_short<nbt_endian>(t);
|
|||
|
write_swapper::template tag_int<nbt_endian>(t);
|
|||
|
write_swapper::template tag_long<nbt_endian>(t);
|
|||
|
write_swapper::template tag_float<nbt_endian>(t);
|
|||
|
write_swapper::template tag_double<nbt_endian>(t);
|
|||
|
write_swapper::template tag_byte_array<nbt_endian>(t);
|
|||
|
write_swapper::template tag_string<nbt_endian>(t);
|
|||
|
write_swapper::template tag_int_array<nbt_endian>(t);
|
|||
|
write_swapper::template tag_long_array<nbt_endian>(t);
|
|||
|
};
|
|||
|
template<typename write_swapper_t>
|
|||
|
concept write_swapper =
|
|||
|
write_swapper_for_endian<write_swapper_t, std::endian::big> &&
|
|||
|
write_swapper_for_endian<write_swapper_t, std::endian::little>;
|
|||
|
|
|||
|
} // namespace swapper
|
|||
|
namespace read_write {
|
|||
|
template<bool in_place, bool bound_check, std::endian nbt_endian, swapper::read_swapper rswap>
|
|||
|
[[nodiscard]] inline auto read(std::byte* source, std::size_t source_len) -> nbt_document;
|
|||
|
|
|||
|
} // namespace read_write
|
|||
|
union mark_t
|
|||
|
{
|
|||
|
struct
|
|||
|
{
|
|||
|
uint32_t general_parrent_offset; // 4
|
|||
|
uint32_t list_current_length; // 4
|
|||
|
uint32_t list_total_length; // 4
|
|||
|
uint16_t list_type; // 2
|
|||
|
uint16_t general_is_compound; // 2
|
|||
|
} cache;
|
|||
|
struct
|
|||
|
{
|
|||
|
uint64_t flat_next_mark; // offset from this
|
|||
|
std::byte* end;
|
|||
|
} store;
|
|||
|
};
|
|||
|
|
|||
|
struct nbt_document
|
|||
|
{
|
|||
|
mark_t* mark_m;
|
|||
|
std::byte* source_m;
|
|||
|
|
|||
|
mark_t* mark;
|
|||
|
std::byte* source;
|
|||
|
std::size_t mark_len; //可能小于 mark_m 已分配内存
|
|||
|
std::size_t source_len; //可能小于 source_m 已分配内存
|
|||
|
};
|
|||
|
|
|||
|
enum class nbt_type : ::std::uint8_t
|
|||
|
{
|
|||
|
tag_end = 0,
|
|||
|
tag_byte = 1,
|
|||
|
tag_short = 2,
|
|||
|
tag_int = 3,
|
|||
|
tag_long = 4,
|
|||
|
tag_float = 5,
|
|||
|
tag_double = 6,
|
|||
|
tag_byte_array = 7,
|
|||
|
tag_string = 8,
|
|||
|
tag_list = 9,
|
|||
|
tag_compound = 10,
|
|||
|
tag_int_array = 11,
|
|||
|
tag_long_array = 12
|
|||
|
};
|
|||
|
|
|||
|
struct any_tag
|
|||
|
{
|
|||
|
mark_t* mark;
|
|||
|
std::byte* source;
|
|||
|
|
|||
|
#ifndef NDEBUG
|
|||
|
nbt_type type;
|
|||
|
#endif
|
|||
|
};
|
|||
|
|
|||
|
struct nbt_list
|
|||
|
{
|
|||
|
struct iterator
|
|||
|
{
|
|||
|
mark_t* mark;
|
|||
|
std::byte* source;
|
|||
|
|
|||
|
std::int32_t index;
|
|||
|
|
|||
|
#ifndef NDEBUG
|
|||
|
nbt_type type;
|
|||
|
#endif
|
|||
|
};
|
|||
|
#ifndef NDEBUG
|
|||
|
nbt_type element_type;
|
|||
|
#endif
|
|||
|
std::int32_t length;
|
|||
|
mark_t* mark;
|
|||
|
std::byte* source;
|
|||
|
};
|
|||
|
|
|||
|
struct nbt_compound
|
|||
|
{
|
|||
|
struct iterator
|
|||
|
{
|
|||
|
mark_t* mark;
|
|||
|
std::byte* source;
|
|||
|
};
|
|||
|
mark_t* mark;
|
|||
|
std::byte* source;
|
|||
|
};
|
|||
|
|
|||
|
namespace nbt_document_function {
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 释放 doc 所有的内存并置空所有指针.
|
|||
|
/// </summary>
|
|||
|
/// <param name="doc"></param>
|
|||
|
inline void nbt_document_free(nbt_document* doc) noexcept
|
|||
|
{
|
|||
|
doc->source = nullptr;
|
|||
|
doc->mark = nullptr;
|
|||
|
if (doc->source_m != nullptr)
|
|||
|
{
|
|||
|
#ifdef use_fastio
|
|||
|
fast_io::native_global_allocator::deallocate(doc->source_m);
|
|||
|
#else
|
|||
|
free(doc->source_m);
|
|||
|
#endif
|
|||
|
}
|
|||
|
if (doc->mark_m != nullptr)
|
|||
|
{
|
|||
|
#ifdef use_fastio
|
|||
|
fast_io::native_global_allocator::deallocate(doc->mark_m);
|
|||
|
#else
|
|||
|
free(doc->mark_m);
|
|||
|
#endif
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 将 from 中已分配内存的所有权转移到 to.
|
|||
|
/// to 中不能所有已分配内存,否则会导致泄漏.
|
|||
|
/// 移动之后,from 中所有指针被置空.
|
|||
|
/// </summary>
|
|||
|
/// <param name="from"></param>
|
|||
|
/// <param name="to"></param>
|
|||
|
inline void nbt_document_move(nbt_document* from, nbt_document* to) noexcept
|
|||
|
{
|
|||
|
*to = *from;
|
|||
|
from->mark_m = nullptr;
|
|||
|
from->source_m = nullptr;
|
|||
|
from->mark = nullptr;
|
|||
|
from->source = nullptr;
|
|||
|
}
|
|||
|
|
|||
|
inline const std::u8string_view nbt_document_root_key(const nbt_document* doc) noexcept
|
|||
|
{
|
|||
|
if (static_cast<nbt_type>(swapper::byte_as_type<std::uint8_t>(doc->source)) == nbt_type::tag_end) [[unlikely]]
|
|||
|
{
|
|||
|
return {};
|
|||
|
}
|
|||
|
return std::u8string_view(
|
|||
|
reinterpret_cast<char8_t*>(doc->source + sizeof(std::uint8_t)),
|
|||
|
swapper::byte_as_type<std::uint16_t>(doc->source + sizeof(std::uint8_t)));
|
|||
|
}
|
|||
|
|
|||
|
inline any_tag nbt_document_root_value(const nbt_document* doc) noexcept
|
|||
|
{
|
|||
|
return any_tag{
|
|||
|
.mark = doc->mark,
|
|||
|
.source = doc->source + sizeof(std::uint8_t) + sizeof(std::uint16_t) + swapper::byte_as_type<std::uint16_t>(doc->source + sizeof(std::uint8_t))
|
|||
|
#ifndef NDEBUG
|
|||
|
,
|
|||
|
.type = static_cast<nbt_type>(swapper::byte_as_type<std::uint8_t>(doc->source))
|
|||
|
#endif
|
|||
|
};
|
|||
|
}
|
|||
|
} // namespace nbt_document_function
|
|||
|
namespace any_tag_function {
|
|||
|
|
|||
|
inline auto any_tag_get_end(const any_tag* tag) noexcept
|
|||
|
{
|
|||
|
assert(tag->type == nbt_type::tag_end);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
inline auto any_tag_get_byte(const any_tag* tag) noexcept
|
|||
|
{
|
|||
|
assert(tag->type == nbt_type::tag_byte);
|
|||
|
return swapper::byte_as_type<std::int8_t>(tag->source);
|
|||
|
}
|
|||
|
|
|||
|
inline auto any_tag_get_short(const any_tag* tag) noexcept
|
|||
|
{
|
|||
|
assert(tag->type == nbt_type::tag_short);
|
|||
|
return swapper::byte_as_type<std::int16_t>(tag->source);
|
|||
|
}
|
|||
|
|
|||
|
inline auto any_tag_get_int(const any_tag* tag) noexcept
|
|||
|
{
|
|||
|
assert(tag->type == nbt_type::tag_int);
|
|||
|
return swapper::byte_as_type<std::int32_t>(tag->source);
|
|||
|
}
|
|||
|
|
|||
|
inline auto any_tag_get_long(const any_tag* tag) noexcept
|
|||
|
{
|
|||
|
assert(tag->type == nbt_type::tag_long);
|
|||
|
return swapper::byte_as_type<std::int64_t>(tag->source);
|
|||
|
}
|
|||
|
|
|||
|
inline auto any_tag_get_float(const any_tag* tag) noexcept
|
|||
|
{
|
|||
|
assert(tag->type == nbt_type::tag_float);
|
|||
|
return swapper::byte_as_type<std::float_t>(tag->source);
|
|||
|
}
|
|||
|
|
|||
|
inline auto any_tag_get_double(const any_tag* tag) noexcept
|
|||
|
{
|
|||
|
assert(tag->type == nbt_type::tag_double);
|
|||
|
return swapper::byte_as_type<std::double_t>(tag->source);
|
|||
|
}
|
|||
|
|
|||
|
inline auto any_tag_get_byte_array(const any_tag* tag) noexcept
|
|||
|
{
|
|||
|
assert(tag->type == nbt_type::tag_byte_array);
|
|||
|
return std::span<const std::int8_t, std::dynamic_extent>(reinterpret_cast<std::int8_t*>(tag->source + sizeof(std::int32_t)), swapper::byte_as_type<std::int32_t>(tag->source));
|
|||
|
}
|
|||
|
|
|||
|
inline auto any_tag_get_string(const any_tag* tag) noexcept
|
|||
|
{
|
|||
|
assert(tag->type == nbt_type::tag_string);
|
|||
|
return std::u8string_view(reinterpret_cast<char8_t*>(tag->source + sizeof(std::uint16_t)), swapper::byte_as_type<std::uint16_t>(tag->source));
|
|||
|
}
|
|||
|
|
|||
|
inline auto any_tag_get_list_end(const any_tag* tag) noexcept
|
|||
|
{
|
|||
|
assert(tag->type == nbt_type::tag_list);
|
|||
|
assert(static_cast<nbt_type>(swapper::byte_as_type<std::uint8_t>(tag->source)) == nbt_type::tag_end);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
inline auto any_tag_get_list_byte(const any_tag* tag) noexcept
|
|||
|
{
|
|||
|
assert(tag->type == nbt_type::tag_list);
|
|||
|
assert(static_cast<nbt_type>(swapper::byte_as_type<std::uint8_t>(tag->source)) == nbt_type::tag_byte);
|
|||
|
return std::span<std::int8_t, std::dynamic_extent>(
|
|||
|
reinterpret_cast<std::int8_t*>(tag->source + sizeof(std::uint8_t) + sizeof(std::int32_t)),
|
|||
|
swapper::byte_as_type<std::int32_t>(tag->source + sizeof(std::uint8_t)));
|
|||
|
}
|
|||
|
|
|||
|
inline auto any_tag_get_list_short(const any_tag* tag) noexcept
|
|||
|
{
|
|||
|
assert(tag->type == nbt_type::tag_list);
|
|||
|
assert(static_cast<nbt_type>(swapper::byte_as_type<std::uint8_t>(tag->source)) == nbt_type::tag_short);
|
|||
|
return std::span<std::int16_t, std::dynamic_extent>(
|
|||
|
reinterpret_cast<std::int16_t*>(tag->source + sizeof(std::uint8_t) + sizeof(std::int32_t)),
|
|||
|
swapper::byte_as_type<std::int32_t>(tag->source + sizeof(std::uint8_t)));
|
|||
|
}
|
|||
|
|
|||
|
inline auto any_tag_get_list_int(const any_tag* tag) noexcept
|
|||
|
{
|
|||
|
assert(tag->type == nbt_type::tag_list);
|
|||
|
assert(static_cast<nbt_type>(swapper::byte_as_type<std::uint8_t>(tag->source)) == nbt_type::tag_int);
|
|||
|
return std::span<std::int32_t, std::dynamic_extent>(
|
|||
|
reinterpret_cast<std::int32_t*>(tag->source + sizeof(std::uint8_t) + sizeof(std::int32_t)),
|
|||
|
swapper::byte_as_type<std::int32_t>(tag->source + sizeof(std::uint8_t)));
|
|||
|
}
|
|||
|
|
|||
|
inline auto any_tag_get_list_long(const any_tag* tag) noexcept
|
|||
|
{
|
|||
|
assert(tag->type == nbt_type::tag_list);
|
|||
|
assert(static_cast<nbt_type>(swapper::byte_as_type<std::uint8_t>(tag->source)) == nbt_type::tag_long);
|
|||
|
return std::span<std::int64_t, std::dynamic_extent>(
|
|||
|
reinterpret_cast<std::int64_t*>(tag->source + sizeof(std::uint8_t) + sizeof(std::int32_t)),
|
|||
|
swapper::byte_as_type<std::int32_t>(tag->source + sizeof(std::uint8_t)));
|
|||
|
}
|
|||
|
|
|||
|
inline auto any_tag_get_list_float(const any_tag* tag) noexcept
|
|||
|
{
|
|||
|
assert(tag->type == nbt_type::tag_list);
|
|||
|
assert(static_cast<nbt_type>(swapper::byte_as_type<std::uint8_t>(tag->source)) == nbt_type::tag_float);
|
|||
|
return std::span<std::float_t, std::dynamic_extent>(
|
|||
|
reinterpret_cast<std::float_t*>(tag->source + sizeof(std::uint8_t) + sizeof(std::int32_t)),
|
|||
|
swapper::byte_as_type<std::int32_t>(tag->source + sizeof(std::uint8_t)));
|
|||
|
}
|
|||
|
|
|||
|
inline auto any_tag_get_list_double(const any_tag* tag) noexcept
|
|||
|
{
|
|||
|
assert(tag->type == nbt_type::tag_list);
|
|||
|
assert(static_cast<nbt_type>(swapper::byte_as_type<std::uint8_t>(tag->source)) == nbt_type::tag_double);
|
|||
|
return std::span<std::double_t, std::dynamic_extent>(
|
|||
|
reinterpret_cast<std::double_t*>(tag->source + sizeof(std::uint8_t) + sizeof(std::int32_t)),
|
|||
|
swapper::byte_as_type<std::int32_t>(tag->source + sizeof(std::uint8_t)));
|
|||
|
}
|
|||
|
|
|||
|
inline auto any_tag_get_list_byte_array(const any_tag* tag) noexcept
|
|||
|
{
|
|||
|
assert(tag->type == nbt_type::tag_list);
|
|||
|
assert(static_cast<nbt_type>(swapper::byte_as_type<std::uint8_t>(tag->source)) == nbt_type::tag_byte_array);
|
|||
|
return nbt_list{
|
|||
|
#ifndef NDEBUG
|
|||
|
.element_type = nbt_type::tag_byte_array,
|
|||
|
#endif
|
|||
|
.length = swapper::byte_as_type<std::int32_t>(tag->source + sizeof(std::uint8_t)),
|
|||
|
.mark = tag->mark,
|
|||
|
.source = tag->source + sizeof(std::uint8_t) + sizeof(std::int32_t)};
|
|||
|
}
|
|||
|
|
|||
|
inline auto any_tag_get_list_string(const any_tag* tag) noexcept
|
|||
|
{
|
|||
|
assert(tag->type == nbt_type::tag_list);
|
|||
|
assert(static_cast<nbt_type>(swapper::byte_as_type<std::uint8_t>(tag->source)) == nbt_type::tag_string);
|
|||
|
return nbt_list{
|
|||
|
#ifndef NDEBUG
|
|||
|
.element_type = nbt_type::tag_string,
|
|||
|
#endif
|
|||
|
.length = swapper::byte_as_type<std::int32_t>(tag->source + sizeof(std::uint8_t)),
|
|||
|
.mark = tag->mark,
|
|||
|
.source = tag->source + sizeof(std::uint8_t) + sizeof(std::int32_t)};
|
|||
|
}
|
|||
|
|
|||
|
inline auto any_tag_get_list_list(const any_tag* tag) noexcept
|
|||
|
{
|
|||
|
assert(tag->type == nbt_type::tag_list);
|
|||
|
assert(static_cast<nbt_type>(swapper::byte_as_type<std::uint8_t>(tag->source)) == nbt_type::tag_list);
|
|||
|
return nbt_list{
|
|||
|
#ifndef NDEBUG
|
|||
|
.element_type = nbt_type::tag_list,
|
|||
|
#endif
|
|||
|
.length = swapper::byte_as_type<std::int32_t>(tag->source + sizeof(std::uint8_t)),
|
|||
|
.mark = tag->mark,
|
|||
|
.source = tag->source + sizeof(std::uint8_t) + sizeof(std::int32_t)};
|
|||
|
}
|
|||
|
|
|||
|
inline auto any_tag_get_list_compound(const any_tag* tag) noexcept
|
|||
|
{
|
|||
|
assert(tag->type == nbt_type::tag_list);
|
|||
|
assert(static_cast<nbt_type>(swapper::byte_as_type<std::uint8_t>(tag->source)) == nbt_type::tag_compound);
|
|||
|
return nbt_list{
|
|||
|
#ifndef NDEBUG
|
|||
|
.element_type = nbt_type::tag_compound,
|
|||
|
#endif
|
|||
|
.length = swapper::byte_as_type<std::int32_t>(tag->source + sizeof(std::uint8_t)),
|
|||
|
.mark = tag->mark,
|
|||
|
.source = tag->source + sizeof(std::uint8_t) + sizeof(std::int32_t)};
|
|||
|
}
|
|||
|
|
|||
|
inline auto any_tag_get_list_int_array(const any_tag* tag) noexcept
|
|||
|
{
|
|||
|
assert(tag->type == nbt_type::tag_list);
|
|||
|
assert(static_cast<nbt_type>(swapper::byte_as_type<std::uint8_t>(tag->source)) == nbt_type::tag_int_array);
|
|||
|
return nbt_list{
|
|||
|
#ifndef NDEBUG
|
|||
|
.element_type = nbt_type::tag_int_array,
|
|||
|
#endif
|
|||
|
.length = swapper::byte_as_type<std::int32_t>(tag->source + sizeof(std::uint8_t)),
|
|||
|
.mark = tag->mark,
|
|||
|
.source = tag->source + sizeof(std::uint8_t) + sizeof(std::int32_t)};
|
|||
|
}
|
|||
|
|
|||
|
inline auto any_tag_get_list_long_array(const any_tag* tag) noexcept
|
|||
|
{
|
|||
|
assert(tag->type == nbt_type::tag_list);
|
|||
|
assert(static_cast<nbt_type>(swapper::byte_as_type<std::uint8_t>(tag->source)) == nbt_type::tag_long_array);
|
|||
|
return nbt_list{
|
|||
|
#ifndef NDEBUG
|
|||
|
.element_type = nbt_type::tag_long_array,
|
|||
|
#endif
|
|||
|
.length = swapper::byte_as_type<std::int32_t>(tag->source + sizeof(std::uint8_t)),
|
|||
|
.mark = tag->mark,
|
|||
|
.source = tag->source + sizeof(std::uint8_t) + sizeof(std::int32_t)};
|
|||
|
}
|
|||
|
|
|||
|
inline auto any_tag_get_compound(const any_tag* tag) noexcept
|
|||
|
{
|
|||
|
assert(tag->type == nbt_type::tag_compound);
|
|||
|
return nbt_compound{
|
|||
|
.mark = tag->mark,
|
|||
|
.source = tag->source};
|
|||
|
}
|
|||
|
|
|||
|
inline auto any_tag_get_int_array(const any_tag* tag) noexcept
|
|||
|
{
|
|||
|
assert(tag->type == nbt_type::tag_int_array);
|
|||
|
return std::span<const std::int32_t, std::dynamic_extent>(reinterpret_cast<std::int32_t*>(tag->source + sizeof(std::int32_t)), swapper::byte_as_type<std::int32_t>(tag->source));
|
|||
|
}
|
|||
|
|
|||
|
inline auto any_tag_get_long_array(const any_tag* tag) noexcept
|
|||
|
{
|
|||
|
assert(tag->type == nbt_type::tag_long_array);
|
|||
|
return std::span<const std::int64_t, std::dynamic_extent>(reinterpret_cast<std::int64_t*>(tag->source + sizeof(std::int32_t)), swapper::byte_as_type<std::int32_t>(tag->source));
|
|||
|
}
|
|||
|
|
|||
|
inline auto any_tag_valid(const any_tag* tag) noexcept
|
|||
|
{
|
|||
|
return tag->mark != nullptr && tag->source != nullptr
|
|||
|
#ifndef NDEBUG
|
|||
|
&& tag->type == nbt_type::tag_end
|
|||
|
#endif
|
|||
|
;
|
|||
|
}
|
|||
|
|
|||
|
} // namespace any_tag_function
|
|||
|
namespace nbt_compound_function {
|
|||
|
inline auto nbt_compound_iterator_begin(const nbt_compound* comp) noexcept
|
|||
|
{
|
|||
|
return nbt_compound::iterator{
|
|||
|
.mark = comp->mark + 1,
|
|||
|
.source = comp->source};
|
|||
|
}
|
|||
|
inline auto nbt_compound_iterator_end(const nbt_compound* comp) noexcept
|
|||
|
{
|
|||
|
return nbt_compound::iterator{
|
|||
|
.mark = nullptr,
|
|||
|
.source = comp->mark->store.end - 1 //at tag_end
|
|||
|
};
|
|||
|
}
|
|||
|
inline void nbt_compound_iterator_next(nbt_compound::iterator* iter) noexcept
|
|||
|
{
|
|||
|
assert(iter->mark != nullptr);
|
|||
|
assert(iter->source != nullptr);
|
|||
|
auto type = static_cast<nbt_type>(swapper::byte_as_type<std::uint8_t>(iter->source));
|
|||
|
assert(type != nbt_type::tag_end);
|
|||
|
auto len = swapper::byte_as_type<::std::uint16_t>(iter->source + 1); //name length
|
|||
|
|
|||
|
switch (type)
|
|||
|
{
|
|||
|
case nbt_type::tag_byte:
|
|||
|
iter->source = iter->source + 1 + 2 + len + 1;
|
|||
|
return;
|
|||
|
case nbt_type::tag_short:
|
|||
|
iter->source = iter->source + 1 + 2 + len + 2;
|
|||
|
return;
|
|||
|
case nbt_type::tag_int:
|
|||
|
iter->source = iter->source + 1 + 2 + len + 4;
|
|||
|
return;
|
|||
|
case nbt_type::tag_long:
|
|||
|
iter->source = iter->source + 1 + 2 + len + 8;
|
|||
|
return;
|
|||
|
case nbt_type::tag_float:
|
|||
|
iter->source = iter->source + 1 + 2 + len + 4;
|
|||
|
return;
|
|||
|
case nbt_type::tag_double:
|
|||
|
iter->source = iter->source + 1 + 2 + len + 8;
|
|||
|
return;
|
|||
|
case nbt_type::tag_string:
|
|||
|
iter->source = iter->source + 1 + 2 + len; //payload begin
|
|||
|
iter->source = iter->source + 2 + swapper::byte_as_type<::std::uint16_t>(iter->source);
|
|||
|
return;
|
|||
|
case nbt_type::tag_byte_array:
|
|||
|
iter->source = iter->source + 1 + 2 + len; //payload begin
|
|||
|
iter->source = iter->source + 4 + swapper::byte_as_type<::std::int32_t>(iter->source);
|
|||
|
return;
|
|||
|
case nbt_type::tag_int_array:
|
|||
|
iter->source = iter->source + 1 + 2 + len; //payload begin
|
|||
|
iter->source = iter->source + 4 + static_cast<std::ptrdiff_t>(swapper::byte_as_type<::std::int32_t>(iter->source)) * 4;
|
|||
|
return;
|
|||
|
case nbt_type::tag_long_array:
|
|||
|
iter->source = iter->source + 1 + 2 + len; //payload begin
|
|||
|
iter->source = iter->source + 4 + static_cast<std::ptrdiff_t>(swapper::byte_as_type<::std::int32_t>(iter->source)) * 8;
|
|||
|
return;
|
|||
|
case nbt_type::tag_list:
|
|||
|
case nbt_type::tag_compound:
|
|||
|
iter->source = iter->mark->store.end;
|
|||
|
iter->mark = iter->mark + iter->mark->store.flat_next_mark;
|
|||
|
return;
|
|||
|
default:
|
|||
|
std::unreachable();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
inline bool nbt_compound_iter_equal(const nbt_compound::iterator* left, const nbt_compound::iterator* right)
|
|||
|
{
|
|||
|
assert(left->source != nullptr);
|
|||
|
assert(right->source != nullptr);
|
|||
|
return left->source == right->source;
|
|||
|
}
|
|||
|
inline const std::u8string_view nbt_compound_iter_key(const nbt_compound::iterator* iter) noexcept
|
|||
|
{
|
|||
|
assert(iter->mark != nullptr);
|
|||
|
assert(iter->source != nullptr);
|
|||
|
assert(static_cast<nbt_type>(swapper::byte_as_type<std::uint8_t>(iter->source)) != nbt_type::tag_end);
|
|||
|
return std::u8string_view(reinterpret_cast<char8_t*>(iter->source + sizeof(std::uint8_t) + sizeof(std::uint16_t)), swapper::byte_as_type<std::uint16_t>(iter->source + sizeof(std::uint8_t)));
|
|||
|
}
|
|||
|
inline any_tag nbt_compound_iter_value(const nbt_compound::iterator* iter) noexcept
|
|||
|
{
|
|||
|
assert(iter->mark != nullptr);
|
|||
|
assert(iter->source != nullptr);
|
|||
|
assert(static_cast<nbt_type>(swapper::byte_as_type<std::uint8_t>(iter->source)) != nbt_type::tag_end);
|
|||
|
return any_tag{
|
|||
|
.mark = iter->mark,
|
|||
|
.source = iter->source + sizeof(std::uint8_t) + sizeof(std::uint16_t) + swapper::byte_as_type<std::uint16_t>(iter->source + sizeof(std::uint8_t))
|
|||
|
#ifndef NDEBUG
|
|||
|
,
|
|||
|
.type = static_cast<nbt_type>(swapper::byte_as_type<std::uint8_t>(iter->source))
|
|||
|
#endif
|
|||
|
};
|
|||
|
}
|
|||
|
|
|||
|
inline auto nbt_compound_find_value(const std::u8string_view key, const nbt_compound::iterator* begin, const nbt_compound::iterator* end) noexcept
|
|||
|
{
|
|||
|
for (auto iter{*begin}; !nbt_compound_iter_equal(std::addressof(iter), end); nbt_compound_iterator_next(std::addressof(iter)))
|
|||
|
{
|
|||
|
if (nbt_compound_iter_key(std::addressof(iter)).compare(key) == 0)
|
|||
|
{
|
|||
|
return iter;
|
|||
|
}
|
|||
|
}
|
|||
|
return *end;
|
|||
|
}
|
|||
|
|
|||
|
inline auto nbt_compound_find_value(const nbt_compound* comp, const std::u8string_view key) noexcept
|
|||
|
{
|
|||
|
auto begin{nbt_compound_iterator_begin(comp)};
|
|||
|
auto end{nbt_compound_iterator_end(comp)};
|
|||
|
return nbt_compound_find_value(key, std::addressof(begin), std::addressof(end));
|
|||
|
}
|
|||
|
} // namespace nbt_compound_function
|
|||
|
namespace nbt_list_function {
|
|||
|
inline auto nbt_list_iterator_begin(const nbt_list* list) noexcept
|
|||
|
{
|
|||
|
return nbt_list::iterator{
|
|||
|
.mark = list->mark + 1,
|
|||
|
.source = list->source,
|
|||
|
.index = 0
|
|||
|
#ifndef NDEBUG
|
|||
|
,
|
|||
|
.type = list->element_type
|
|||
|
#endif
|
|||
|
};
|
|||
|
}
|
|||
|
inline auto nbt_list_iterator_end(const nbt_list* list) noexcept
|
|||
|
{
|
|||
|
return nbt_list::iterator{
|
|||
|
.mark = nullptr,
|
|||
|
.source = list->mark->store.end,
|
|||
|
.index = list->length};
|
|||
|
}
|
|||
|
|
|||
|
inline void nbt_list_iterator_next_end(nbt_list::iterator* iter) noexcept
|
|||
|
{
|
|||
|
assert(iter->mark != nullptr);
|
|||
|
assert(iter->source != nullptr);
|
|||
|
assert(iter->type == nbt_type::tag_end);
|
|||
|
|
|||
|
iter->index++;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
inline void nbt_list_iterator_next_byte(nbt_list::iterator* iter) noexcept
|
|||
|
{
|
|||
|
assert(iter->mark != nullptr);
|
|||
|
assert(iter->source != nullptr);
|
|||
|
assert(iter->type == nbt_type::tag_byte);
|
|||
|
|
|||
|
iter->index++;
|
|||
|
iter->source = iter->source + 1;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
inline void nbt_list_iterator_next_short(nbt_list::iterator* iter) noexcept
|
|||
|
{
|
|||
|
assert(iter->mark != nullptr);
|
|||
|
assert(iter->source != nullptr);
|
|||
|
assert(iter->type == nbt_type::tag_short);
|
|||
|
|
|||
|
iter->index++;
|
|||
|
iter->source = iter->source + 2;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
inline void nbt_list_iterator_next_int(nbt_list::iterator* iter) noexcept
|
|||
|
{
|
|||
|
assert(iter->mark != nullptr);
|
|||
|
assert(iter->source != nullptr);
|
|||
|
assert(iter->type == nbt_type::tag_int);
|
|||
|
|
|||
|
iter->index++;
|
|||
|
iter->source = iter->source + 4;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
inline void nbt_list_iterator_next_long(nbt_list::iterator* iter) noexcept
|
|||
|
{
|
|||
|
assert(iter->mark != nullptr);
|
|||
|
assert(iter->source != nullptr);
|
|||
|
assert(iter->type == nbt_type::tag_long);
|
|||
|
|
|||
|
iter->index++;
|
|||
|
iter->source = iter->source + 8;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
inline void nbt_list_iterator_next_float(nbt_list::iterator* iter) noexcept
|
|||
|
{
|
|||
|
assert(iter->mark != nullptr);
|
|||
|
assert(iter->source != nullptr);
|
|||
|
assert(iter->type == nbt_type::tag_float);
|
|||
|
|
|||
|
iter->index++;
|
|||
|
iter->source = iter->source + 4;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
inline void nbt_list_iterator_next_double(nbt_list::iterator* iter) noexcept
|
|||
|
{
|
|||
|
assert(iter->mark != nullptr);
|
|||
|
assert(iter->source != nullptr);
|
|||
|
assert(iter->type == nbt_type::tag_double);
|
|||
|
|
|||
|
iter->index++;
|
|||
|
iter->source = iter->source + 8;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
inline void nbt_list_iterator_next_string(nbt_list::iterator* iter) noexcept
|
|||
|
{
|
|||
|
assert(iter->mark != nullptr);
|
|||
|
assert(iter->source != nullptr);
|
|||
|
assert(iter->type == nbt_type::tag_string);
|
|||
|
|
|||
|
iter->index++;
|
|||
|
iter->source = iter->source + 2 + swapper::byte_as_type<::std::uint16_t>(iter->source);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
inline void nbt_list_iterator_next_byte_array(nbt_list::iterator* iter) noexcept
|
|||
|
{
|
|||
|
assert(iter->mark != nullptr);
|
|||
|
assert(iter->source != nullptr);
|
|||
|
assert(iter->type == nbt_type::tag_byte_array);
|
|||
|
|
|||
|
iter->index++;
|
|||
|
iter->source = iter->source + 4 + swapper::byte_as_type<::std::int32_t>(iter->source);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
inline void nbt_list_iterator_next_int_array(nbt_list::iterator* iter) noexcept
|
|||
|
{
|
|||
|
assert(iter->mark != nullptr);
|
|||
|
assert(iter->source != nullptr);
|
|||
|
assert(iter->type == nbt_type::tag_int_array);
|
|||
|
|
|||
|
iter->index++;
|
|||
|
iter->source = iter->source + 4 + swapper::byte_as_type<::std::int32_t>(iter->source) * 4;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
inline void nbt_list_iterator_next_long_array(nbt_list::iterator* iter) noexcept
|
|||
|
{
|
|||
|
assert(iter->mark != nullptr);
|
|||
|
assert(iter->source != nullptr);
|
|||
|
assert(iter->type == nbt_type::tag_long_array);
|
|||
|
|
|||
|
iter->index++;
|
|||
|
iter->source = iter->source + 4 + swapper::byte_as_type<::std::int32_t>(iter->source) * 8;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
inline void nbt_list_iterator_next_list(nbt_list::iterator* iter) noexcept
|
|||
|
{
|
|||
|
assert(iter->mark != nullptr);
|
|||
|
assert(iter->source != nullptr);
|
|||
|
assert(iter->type == nbt_type::tag_list);
|
|||
|
|
|||
|
iter->index++;
|
|||
|
iter->source = iter->mark->store.end;
|
|||
|
iter->mark = iter->mark + iter->mark->store.flat_next_mark;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
inline void nbt_list_iterator_next_compound(nbt_list::iterator* iter) noexcept
|
|||
|
{
|
|||
|
assert(iter->mark != nullptr);
|
|||
|
assert(iter->source != nullptr);
|
|||
|
assert(iter->type == nbt_type::tag_compound);
|
|||
|
|
|||
|
iter->index++;
|
|||
|
iter->source = iter->mark->store.end;
|
|||
|
iter->mark = iter->mark + iter->mark->store.flat_next_mark;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
inline bool nbt_list_iter_equal(const nbt_list::iterator* left, const nbt_list::iterator* right)
|
|||
|
{
|
|||
|
assert(left->source != nullptr);
|
|||
|
assert(right->source != nullptr);
|
|||
|
return left->source == right->source;
|
|||
|
}
|
|||
|
inline any_tag nbt_list_iter_value(const nbt_list::iterator* iter) noexcept
|
|||
|
{
|
|||
|
assert(iter->mark != nullptr);
|
|||
|
assert(iter->source != nullptr);
|
|||
|
return any_tag{
|
|||
|
.mark = iter->mark,
|
|||
|
.source = iter->source
|
|||
|
#ifndef NDEBUG
|
|||
|
,
|
|||
|
.type = iter->type
|
|||
|
#endif
|
|||
|
};
|
|||
|
}
|
|||
|
|
|||
|
inline auto nbt_list_find_value_end(std::int32_t index, const nbt_list::iterator* begin, const nbt_list::iterator* end) noexcept
|
|||
|
{
|
|||
|
auto iter{*begin};
|
|||
|
while (index--)
|
|||
|
{
|
|||
|
nbt_list_iterator_next_end(std::addressof(iter));
|
|||
|
}
|
|||
|
return iter;
|
|||
|
}
|
|||
|
|
|||
|
inline auto nbt_list_find_value_byte(std::int32_t index, const nbt_list::iterator* begin, const nbt_list::iterator* end) noexcept
|
|||
|
{
|
|||
|
auto iter{*begin};
|
|||
|
while (index--)
|
|||
|
{
|
|||
|
nbt_list_iterator_next_byte(std::addressof(iter));
|
|||
|
}
|
|||
|
return iter;
|
|||
|
}
|
|||
|
|
|||
|
inline auto nbt_list_find_value_short(std::int32_t index, const nbt_list::iterator* begin, const nbt_list::iterator* end) noexcept
|
|||
|
{
|
|||
|
auto iter{*begin};
|
|||
|
while (index--)
|
|||
|
{
|
|||
|
nbt_list_iterator_next_short(std::addressof(iter));
|
|||
|
}
|
|||
|
return iter;
|
|||
|
}
|
|||
|
|
|||
|
inline auto nbt_list_find_value_int(std::int32_t index, const nbt_list::iterator* begin, const nbt_list::iterator* end) noexcept
|
|||
|
{
|
|||
|
auto iter{*begin};
|
|||
|
while (index--)
|
|||
|
{
|
|||
|
nbt_list_iterator_next_int(std::addressof(iter));
|
|||
|
}
|
|||
|
return iter;
|
|||
|
}
|
|||
|
|
|||
|
inline auto nbt_list_find_value_long(std::int32_t index, const nbt_list::iterator* begin, const nbt_list::iterator* end) noexcept
|
|||
|
{
|
|||
|
auto iter{*begin};
|
|||
|
while (index--)
|
|||
|
{
|
|||
|
nbt_list_iterator_next_long(std::addressof(iter));
|
|||
|
}
|
|||
|
return iter;
|
|||
|
}
|
|||
|
|
|||
|
inline auto nbt_list_find_value_float(std::int32_t index, const nbt_list::iterator* begin, const nbt_list::iterator* end) noexcept
|
|||
|
{
|
|||
|
auto iter{*begin};
|
|||
|
while (index--)
|
|||
|
{
|
|||
|
nbt_list_iterator_next_float(std::addressof(iter));
|
|||
|
}
|
|||
|
return iter;
|
|||
|
}
|
|||
|
|
|||
|
inline auto nbt_list_find_value_double(std::int32_t index, const nbt_list::iterator* begin, const nbt_list::iterator* end) noexcept
|
|||
|
{
|
|||
|
auto iter{*begin};
|
|||
|
while (index--)
|
|||
|
{
|
|||
|
nbt_list_iterator_next_double(std::addressof(iter));
|
|||
|
}
|
|||
|
return iter;
|
|||
|
}
|
|||
|
|
|||
|
inline auto nbt_list_find_value_byte_array(std::int32_t index, const nbt_list::iterator* begin, const nbt_list::iterator* end) noexcept
|
|||
|
{
|
|||
|
auto iter{*begin};
|
|||
|
while (index--)
|
|||
|
{
|
|||
|
nbt_list_iterator_next_byte_array(std::addressof(iter));
|
|||
|
}
|
|||
|
return iter;
|
|||
|
}
|
|||
|
|
|||
|
inline auto nbt_list_find_value_string(std::int32_t index, const nbt_list::iterator* begin, const nbt_list::iterator* end) noexcept
|
|||
|
{
|
|||
|
auto iter{*begin};
|
|||
|
while (index--)
|
|||
|
{
|
|||
|
nbt_list_iterator_next_string(std::addressof(iter));
|
|||
|
}
|
|||
|
return iter;
|
|||
|
}
|
|||
|
|
|||
|
inline auto nbt_list_find_value_list(std::int32_t index, const nbt_list::iterator* begin, const nbt_list::iterator* end) noexcept
|
|||
|
{
|
|||
|
auto iter{*begin};
|
|||
|
while (index--)
|
|||
|
{
|
|||
|
nbt_list_iterator_next_list(std::addressof(iter));
|
|||
|
}
|
|||
|
return iter;
|
|||
|
}
|
|||
|
|
|||
|
inline auto nbt_list_find_value_compound(std::int32_t index, const nbt_list::iterator* begin, const nbt_list::iterator* end) noexcept
|
|||
|
{
|
|||
|
auto iter{*begin};
|
|||
|
while (index--)
|
|||
|
{
|
|||
|
nbt_list_iterator_next_compound(std::addressof(iter));
|
|||
|
}
|
|||
|
return iter;
|
|||
|
}
|
|||
|
|
|||
|
inline auto nbt_list_find_value_int_array(std::int32_t index, const nbt_list::iterator* begin, const nbt_list::iterator* end) noexcept
|
|||
|
{
|
|||
|
auto iter{*begin};
|
|||
|
while (index--)
|
|||
|
{
|
|||
|
nbt_list_iterator_next_int_array(std::addressof(iter));
|
|||
|
}
|
|||
|
return iter;
|
|||
|
}
|
|||
|
|
|||
|
inline auto nbt_list_find_value_long_array(std::int32_t index, const nbt_list::iterator* begin, const nbt_list::iterator* end) noexcept
|
|||
|
{
|
|||
|
auto iter{*begin};
|
|||
|
while (index--)
|
|||
|
{
|
|||
|
nbt_list_iterator_next_long_array(std::addressof(iter));
|
|||
|
}
|
|||
|
return iter;
|
|||
|
}
|
|||
|
|
|||
|
inline auto nbt_list_find_value_end(const nbt_list* list, std::int32_t index) noexcept
|
|||
|
{
|
|||
|
assert(list->mark != nullptr);
|
|||
|
assert(list->source != nullptr);
|
|||
|
assert(list->element_type == nbt_type::tag_end);
|
|||
|
auto begin{nbt_list_iterator_begin(list)};
|
|||
|
auto end{nbt_list_iterator_end(list)};
|
|||
|
if (index >= list->length)
|
|||
|
{
|
|||
|
return end;
|
|||
|
}
|
|||
|
return nbt_list_find_value_end(index, std::addressof(begin), std::addressof(end));
|
|||
|
}
|
|||
|
|
|||
|
inline auto nbt_list_find_value_byte(const nbt_list* list, std::int32_t index) noexcept
|
|||
|
{
|
|||
|
assert(list->mark != nullptr);
|
|||
|
assert(list->source != nullptr);
|
|||
|
assert(list->element_type == nbt_type::tag_byte);
|
|||
|
auto begin{nbt_list_iterator_begin(list)};
|
|||
|
auto end{nbt_list_iterator_end(list)};
|
|||
|
if (index >= list->length)
|
|||
|
{
|
|||
|
return end;
|
|||
|
}
|
|||
|
return nbt_list_find_value_byte(index, std::addressof(begin), std::addressof(end));
|
|||
|
}
|
|||
|
|
|||
|
inline auto nbt_list_find_value_short(const nbt_list* list, std::int32_t index) noexcept
|
|||
|
{
|
|||
|
assert(list->mark != nullptr);
|
|||
|
assert(list->source != nullptr);
|
|||
|
assert(list->element_type == nbt_type::tag_short);
|
|||
|
auto begin{nbt_list_iterator_begin(list)};
|
|||
|
auto end{nbt_list_iterator_end(list)};
|
|||
|
if (index >= list->length)
|
|||
|
{
|
|||
|
return end;
|
|||
|
}
|
|||
|
return nbt_list_find_value_short(index, std::addressof(begin), std::addressof(end));
|
|||
|
}
|
|||
|
|
|||
|
inline auto nbt_list_find_value_int(const nbt_list* list, std::int32_t index) noexcept
|
|||
|
{
|
|||
|
assert(list->mark != nullptr);
|
|||
|
assert(list->source != nullptr);
|
|||
|
assert(list->element_type == nbt_type::tag_int);
|
|||
|
auto begin{nbt_list_iterator_begin(list)};
|
|||
|
auto end{nbt_list_iterator_end(list)};
|
|||
|
if (index >= list->length)
|
|||
|
{
|
|||
|
return end;
|
|||
|
}
|
|||
|
return nbt_list_find_value_int(index, std::addressof(begin), std::addressof(end));
|
|||
|
}
|
|||
|
|
|||
|
inline auto nbt_list_find_value_long(const nbt_list* list, std::int32_t index) noexcept
|
|||
|
{
|
|||
|
assert(list->mark != nullptr);
|
|||
|
assert(list->source != nullptr);
|
|||
|
assert(list->element_type == nbt_type::tag_long);
|
|||
|
auto begin{nbt_list_iterator_begin(list)};
|
|||
|
auto end{nbt_list_iterator_end(list)};
|
|||
|
if (index >= list->length)
|
|||
|
{
|
|||
|
return end;
|
|||
|
}
|
|||
|
return nbt_list_find_value_long(index, std::addressof(begin), std::addressof(end));
|
|||
|
}
|
|||
|
|
|||
|
inline auto nbt_list_find_value_float(const nbt_list* list, std::int32_t index) noexcept
|
|||
|
{
|
|||
|
assert(list->mark != nullptr);
|
|||
|
assert(list->source != nullptr);
|
|||
|
assert(list->element_type == nbt_type::tag_float);
|
|||
|
auto begin{nbt_list_iterator_begin(list)};
|
|||
|
auto end{nbt_list_iterator_end(list)};
|
|||
|
if (index >= list->length)
|
|||
|
{
|
|||
|
return end;
|
|||
|
}
|
|||
|
return nbt_list_find_value_float(index, std::addressof(begin), std::addressof(end));
|
|||
|
}
|
|||
|
|
|||
|
inline auto nbt_list_find_value_double(const nbt_list* list, std::int32_t index) noexcept
|
|||
|
{
|
|||
|
assert(list->mark != nullptr);
|
|||
|
assert(list->source != nullptr);
|
|||
|
assert(list->element_type == nbt_type::tag_double);
|
|||
|
auto begin{nbt_list_iterator_begin(list)};
|
|||
|
auto end{nbt_list_iterator_end(list)};
|
|||
|
if (index >= list->length)
|
|||
|
{
|
|||
|
return end;
|
|||
|
}
|
|||
|
return nbt_list_find_value_double(index, std::addressof(begin), std::addressof(end));
|
|||
|
}
|
|||
|
|
|||
|
inline auto nbt_list_find_value_byte_array(const nbt_list* list, std::int32_t index) noexcept
|
|||
|
{
|
|||
|
assert(list->mark != nullptr);
|
|||
|
assert(list->source != nullptr);
|
|||
|
assert(list->element_type == nbt_type::tag_byte_array);
|
|||
|
auto begin{nbt_list_iterator_begin(list)};
|
|||
|
auto end{nbt_list_iterator_end(list)};
|
|||
|
if (index >= list->length)
|
|||
|
{
|
|||
|
return end;
|
|||
|
}
|
|||
|
return nbt_list_find_value_byte_array(index, std::addressof(begin), std::addressof(end));
|
|||
|
}
|
|||
|
|
|||
|
inline auto nbt_list_find_value_string(const nbt_list* list, std::int32_t index) noexcept
|
|||
|
{
|
|||
|
assert(list->mark != nullptr);
|
|||
|
assert(list->source != nullptr);
|
|||
|
assert(list->element_type == nbt_type::tag_string);
|
|||
|
auto begin{nbt_list_iterator_begin(list)};
|
|||
|
auto end{nbt_list_iterator_end(list)};
|
|||
|
if (index >= list->length)
|
|||
|
{
|
|||
|
return end;
|
|||
|
}
|
|||
|
return nbt_list_find_value_string(index, std::addressof(begin), std::addressof(end));
|
|||
|
}
|
|||
|
|
|||
|
inline auto nbt_list_find_value_list(const nbt_list* list, std::int32_t index) noexcept
|
|||
|
{
|
|||
|
assert(list->mark != nullptr);
|
|||
|
assert(list->source != nullptr);
|
|||
|
assert(list->element_type == nbt_type::tag_list);
|
|||
|
auto begin{nbt_list_iterator_begin(list)};
|
|||
|
auto end{nbt_list_iterator_end(list)};
|
|||
|
if (index >= list->length)
|
|||
|
{
|
|||
|
return end;
|
|||
|
}
|
|||
|
return nbt_list_find_value_list(index, std::addressof(begin), std::addressof(end));
|
|||
|
}
|
|||
|
|
|||
|
inline auto nbt_list_find_value_compound(const nbt_list* list, std::int32_t index) noexcept
|
|||
|
{
|
|||
|
assert(list->mark != nullptr);
|
|||
|
assert(list->source != nullptr);
|
|||
|
assert(list->element_type == nbt_type::tag_compound);
|
|||
|
auto begin{nbt_list_iterator_begin(list)};
|
|||
|
auto end{nbt_list_iterator_end(list)};
|
|||
|
if (index >= list->length)
|
|||
|
{
|
|||
|
return end;
|
|||
|
}
|
|||
|
return nbt_list_find_value_compound(index, std::addressof(begin), std::addressof(end));
|
|||
|
}
|
|||
|
|
|||
|
inline auto nbt_list_find_value_int_array(const nbt_list* list, std::int32_t index) noexcept
|
|||
|
{
|
|||
|
assert(list->mark != nullptr);
|
|||
|
assert(list->source != nullptr);
|
|||
|
assert(list->element_type == nbt_type::tag_int_array);
|
|||
|
auto begin{nbt_list_iterator_begin(list)};
|
|||
|
auto end{nbt_list_iterator_end(list)};
|
|||
|
if (index >= list->length)
|
|||
|
{
|
|||
|
return end;
|
|||
|
}
|
|||
|
return nbt_list_find_value_int_array(index, std::addressof(begin), std::addressof(end));
|
|||
|
}
|
|||
|
|
|||
|
inline auto nbt_list_find_value_long_array(const nbt_list* list, std::int32_t index) noexcept
|
|||
|
{
|
|||
|
assert(list->mark != nullptr);
|
|||
|
assert(list->source != nullptr);
|
|||
|
assert(list->element_type == nbt_type::tag_long_array);
|
|||
|
auto begin{nbt_list_iterator_begin(list)};
|
|||
|
auto end{nbt_list_iterator_end(list)};
|
|||
|
if (index >= list->length)
|
|||
|
{
|
|||
|
return end;
|
|||
|
}
|
|||
|
return nbt_list_find_value_long_array(index, std::addressof(begin), std::addressof(end));
|
|||
|
}
|
|||
|
|
|||
|
} // namespace nbt_list_function
|
|||
|
namespace swapper {
|
|||
|
|
|||
|
template<typename T>
|
|||
|
inline T& byte_as_type(std::byte* ptr) noexcept
|
|||
|
{
|
|||
|
return *reinterpret_cast<T*>(ptr);
|
|||
|
}
|
|||
|
|
|||
|
template<typename T, std::endian nbt_endian>
|
|||
|
requires(nbt_endian == std::endian::big || nbt_endian == std::endian::little) inline T endian_get(std::byte* ptr) noexcept
|
|||
|
{
|
|||
|
if constexpr (nbt_endian == std::endian::big)
|
|||
|
{
|
|||
|
return fast_io::big_endian(byte_as_type<std::make_unsigned_t<T>>(ptr));
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return fast_io::little_endian(byte_as_type<std::make_unsigned_t<T>>(ptr));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
template<typename T, std::endian nbt_endian>
|
|||
|
requires(nbt_endian == std::endian::big || nbt_endian == std::endian::little) inline T endian_make_native_get(std::byte* ptr) noexcept
|
|||
|
{
|
|||
|
using unsigned_T = std::make_unsigned_t<T>;
|
|||
|
T& t = byte_as_type<T>(ptr);
|
|||
|
if constexpr (nbt_endian == std::endian::big)
|
|||
|
{
|
|||
|
t = static_cast<T>(fast_io::big_endian(static_cast<unsigned_T>(t)));
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
t = static_cast<T>(fast_io::little_endian(static_cast<unsigned_T>(t)));
|
|||
|
}
|
|||
|
return t;
|
|||
|
}
|
|||
|
|
|||
|
template<typename T, std::endian nbt_endian>
|
|||
|
requires(nbt_endian == std::endian::big || nbt_endian == std::endian::little) inline T endian_get_make_native(std::byte* ptr) noexcept
|
|||
|
{
|
|||
|
using unsigned_T = std::make_unsigned_t<T>;
|
|||
|
T& t = byte_as_type<T>(ptr);
|
|||
|
T ret = t;
|
|||
|
if constexpr (nbt_endian == std::endian::big)
|
|||
|
{
|
|||
|
t = static_cast<T>(fast_io::big_endian(static_cast<unsigned_T>(t)));
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
t = static_cast<T>(fast_io::little_endian(static_cast<unsigned_T>(t)));
|
|||
|
}
|
|||
|
return ret;
|
|||
|
}
|
|||
|
|
|||
|
template<typename T, std::endian nbt_endian>
|
|||
|
requires(nbt_endian == std::endian::big || nbt_endian == std::endian::little) inline void endian_make_native(std::byte* ptr) noexcept
|
|||
|
{
|
|||
|
using unsigned_T = std::make_unsigned_t<T>;
|
|||
|
unsigned_T& t = byte_as_type<unsigned_T>(ptr);
|
|||
|
if constexpr (nbt_endian == std::endian::big)
|
|||
|
{
|
|||
|
t = fast_io::big_endian(t);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
t = fast_io::little_endian(t);
|
|||
|
}
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
struct default_read_swapper
|
|||
|
{
|
|||
|
template<std::endian nbt_endian>
|
|||
|
static constexpr inline void tag_byte(std::byte*& current_pos) noexcept
|
|||
|
{
|
|||
|
current_pos += (sizeof(std::int8_t));
|
|||
|
}
|
|||
|
template<std::endian nbt_endian>
|
|||
|
static constexpr inline void tag_short(std::byte*& current_pos) noexcept
|
|||
|
{
|
|||
|
endian_make_native<std::uint16_t, nbt_endian>(current_pos);
|
|||
|
current_pos += (sizeof(std::int16_t));
|
|||
|
}
|
|||
|
template<std::endian nbt_endian>
|
|||
|
static constexpr inline void tag_int(std::byte*& current_pos) noexcept
|
|||
|
{
|
|||
|
endian_make_native<std::uint32_t, nbt_endian>(current_pos);
|
|||
|
current_pos += (sizeof(std::int32_t));
|
|||
|
}
|
|||
|
template<std::endian nbt_endian>
|
|||
|
static constexpr inline void tag_long(std::byte*& current_pos) noexcept
|
|||
|
{
|
|||
|
endian_make_native<std::uint64_t, nbt_endian>(current_pos);
|
|||
|
current_pos += (sizeof(std::int64_t));
|
|||
|
}
|
|||
|
template<std::endian nbt_endian>
|
|||
|
static constexpr inline void tag_float(std::byte*& current_pos) noexcept
|
|||
|
{
|
|||
|
endian_make_native<std::uint32_t, nbt_endian>(current_pos);
|
|||
|
current_pos += (sizeof(std::float_t));
|
|||
|
}
|
|||
|
template<std::endian nbt_endian>
|
|||
|
static constexpr inline void tag_double(std::byte*& current_pos) noexcept
|
|||
|
{
|
|||
|
endian_make_native<std::uint64_t, nbt_endian>(current_pos);
|
|||
|
current_pos += (sizeof(std::double_t));
|
|||
|
}
|
|||
|
template<std::endian nbt_endian>
|
|||
|
static constexpr inline void tag_byte_array(std::byte*& current_pos) noexcept
|
|||
|
{
|
|||
|
auto len = endian_make_native_get<std::int32_t, nbt_endian>(current_pos);
|
|||
|
current_pos += sizeof(std::int32_t);
|
|||
|
current_pos += sizeof(std::int8_t) * len;
|
|||
|
}
|
|||
|
template<std::endian nbt_endian>
|
|||
|
static constexpr inline void tag_string(std::byte*& current_pos) noexcept
|
|||
|
{
|
|||
|
auto len = endian_make_native_get<std::uint16_t, nbt_endian>(current_pos);
|
|||
|
current_pos += sizeof(std::uint16_t);
|
|||
|
current_pos += sizeof(char) * len;
|
|||
|
}
|
|||
|
template<std::endian nbt_endian>
|
|||
|
static constexpr inline void tag_int_array(std::byte*& current_pos) noexcept
|
|||
|
{
|
|||
|
auto len = endian_make_native_get<std::int32_t, nbt_endian>(current_pos);
|
|||
|
current_pos += sizeof(std::int32_t);
|
|||
|
if constexpr (nbt_endian == std::endian::native)
|
|||
|
{
|
|||
|
current_pos += sizeof(std::int32_t) * len;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
for (std::int32_t _index = 0; _index < len; _index++)
|
|||
|
{
|
|||
|
endian_make_native<std::int32_t, nbt_endian>(current_pos);
|
|||
|
current_pos += sizeof(std::int32_t);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
template<std::endian nbt_endian>
|
|||
|
static constexpr inline void tag_long_array(std::byte*& current_pos) noexcept
|
|||
|
{
|
|||
|
auto len = endian_make_native_get<std::int32_t, nbt_endian>(current_pos);
|
|||
|
current_pos += sizeof(std::int32_t);
|
|||
|
current_pos += sizeof(std::int32_t);
|
|||
|
if constexpr (nbt_endian == std::endian::native)
|
|||
|
{
|
|||
|
current_pos += sizeof(std::int64_t) * len;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
for (std::int32_t _index = 0; _index < len; _index++)
|
|||
|
{
|
|||
|
endian_make_native<std::int64_t, nbt_endian>(current_pos);
|
|||
|
current_pos += sizeof(std::int64_t);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
struct default_write_swapper
|
|||
|
{
|
|||
|
template<std::endian nbt_endian>
|
|||
|
static constexpr inline void tag_byte(std::byte*& current_pos) noexcept
|
|||
|
{
|
|||
|
current_pos += (sizeof(std::int8_t));
|
|||
|
}
|
|||
|
template<std::endian nbt_endian>
|
|||
|
static constexpr inline void tag_short(std::byte*& current_pos) noexcept
|
|||
|
{
|
|||
|
endian_make_native<std::uint16_t, nbt_endian>(current_pos);
|
|||
|
current_pos += (sizeof(std::int16_t));
|
|||
|
}
|
|||
|
template<std::endian nbt_endian>
|
|||
|
static constexpr inline void tag_int(std::byte*& current_pos) noexcept
|
|||
|
{
|
|||
|
endian_make_native<std::uint32_t, nbt_endian>(current_pos);
|
|||
|
current_pos += (sizeof(std::int32_t));
|
|||
|
}
|
|||
|
template<std::endian nbt_endian>
|
|||
|
static constexpr inline void tag_long(std::byte*& current_pos) noexcept
|
|||
|
{
|
|||
|
endian_make_native<std::uint64_t, nbt_endian>(current_pos);
|
|||
|
current_pos += (sizeof(std::int64_t));
|
|||
|
}
|
|||
|
template<std::endian nbt_endian>
|
|||
|
static constexpr inline void tag_float(std::byte*& current_pos) noexcept
|
|||
|
{
|
|||
|
endian_make_native<std::uint32_t, nbt_endian>(current_pos);
|
|||
|
current_pos += (sizeof(std::float_t));
|
|||
|
}
|
|||
|
template<std::endian nbt_endian>
|
|||
|
static constexpr inline void tag_double(std::byte*& current_pos) noexcept
|
|||
|
{
|
|||
|
endian_make_native<std::uint64_t, nbt_endian>(current_pos);
|
|||
|
current_pos += (sizeof(std::double_t));
|
|||
|
}
|
|||
|
template<std::endian nbt_endian>
|
|||
|
static constexpr inline void tag_byte_array(std::byte*& current_pos) noexcept
|
|||
|
{
|
|||
|
auto len = endian_get_make_native<std::int32_t, nbt_endian>(current_pos);
|
|||
|
current_pos += sizeof(std::int32_t);
|
|||
|
current_pos += sizeof(std::int8_t) * len;
|
|||
|
}
|
|||
|
template<std::endian nbt_endian>
|
|||
|
static constexpr inline void tag_string(std::byte*& current_pos) noexcept
|
|||
|
{
|
|||
|
auto len = endian_get_make_native<std::uint16_t, nbt_endian>(current_pos);
|
|||
|
current_pos += sizeof(std::uint16_t);
|
|||
|
current_pos += sizeof(char) * len;
|
|||
|
}
|
|||
|
template<std::endian nbt_endian>
|
|||
|
static constexpr inline void tag_int_array(std::byte*& current_pos) noexcept
|
|||
|
{
|
|||
|
auto len = endian_get_make_native<std::int32_t, nbt_endian>(current_pos);
|
|||
|
current_pos += sizeof(std::int32_t);
|
|||
|
//current_pos += sizeof(std::int32_t) * len;
|
|||
|
for (std::int32_t _index = 0; _index < len; _index++)
|
|||
|
{
|
|||
|
endian_make_native<std::int32_t, nbt_endian>(current_pos);
|
|||
|
current_pos += sizeof(std::int32_t);
|
|||
|
}
|
|||
|
}
|
|||
|
template<std::endian nbt_endian>
|
|||
|
static constexpr inline void tag_long_array(std::byte*& current_pos) noexcept
|
|||
|
{
|
|||
|
auto len = endian_get_make_native<std::int32_t, nbt_endian>(current_pos);
|
|||
|
current_pos += sizeof(std::int32_t);
|
|||
|
//current_pos += sizeof(std::int64_t) * len;
|
|||
|
for (std::int32_t _index = 0; _index < len; _index++)
|
|||
|
{
|
|||
|
endian_make_native<std::int64_t, nbt_endian>(current_pos);
|
|||
|
current_pos += sizeof(std::int64_t);
|
|||
|
}
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
} // namespace swapper
|
|||
|
namespace read_write {
|
|||
|
|
|||
|
template<bool in_place = true, bool bound_check = false, std::endian nbt_endian = std::endian::big, swapper::read_swapper rswap = swapper::default_read_swapper>
|
|||
|
[[nodiscard]] inline auto read(std::byte* source, std::size_t source_len) -> nbt_document
|
|||
|
{
|
|||
|
#define bound_check_return(pos) \
|
|||
|
if ((pos) > source_len) [[unlikely]] \
|
|||
|
{ \
|
|||
|
throw nbt_parse_error::end_of_file; \
|
|||
|
}
|
|||
|
|
|||
|
nbt_document t{};
|
|||
|
if constexpr (in_place)
|
|||
|
{
|
|||
|
t.source_m = nullptr;
|
|||
|
t.source = source;
|
|||
|
t.source_len = source_len;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
t.source_m = static_cast<std::byte*>(fast_io::native_global_allocator::allocate(source_len));
|
|||
|
t.source = t.source_m;
|
|||
|
t.source_len = source_len;
|
|||
|
fast_io::freestanding::non_overlapped_copy_n(source, source_len, t.source);
|
|||
|
}
|
|||
|
auto src{t.source};
|
|||
|
std::size_t readed_length{0};
|
|||
|
|
|||
|
auto current_pos{src + 1}; //read first byte (id), +1
|
|||
|
if constexpr (bound_check)
|
|||
|
{
|
|||
|
readed_length += 1;
|
|||
|
bound_check_return(readed_length);
|
|||
|
}
|
|||
|
if (swapper::endian_get<std::uint8_t, nbt_endian>(src) != 0) [[likely]] //is tag_end, ignore tag name and payload
|
|||
|
{
|
|||
|
//read tag name
|
|||
|
{
|
|||
|
if constexpr (bound_check)
|
|||
|
{
|
|||
|
readed_length += sizeof(std::uint16_t);
|
|||
|
bound_check_return(readed_length);
|
|||
|
auto len = swapper::endian_get<std::uint16_t, nbt_endian>(src + 1);
|
|||
|
readed_length += len;
|
|||
|
bound_check_return(readed_length);
|
|||
|
}
|
|||
|
std::uint16_t len = swapper::endian_make_native_get<std::uint16_t, nbt_endian>(src + 1); //read name length
|
|||
|
current_pos += sizeof(std::uint16_t);
|
|||
|
current_pos += len; // read name, +2 +length*1
|
|||
|
}
|
|||
|
switch (swapper::endian_get<std::uint8_t, nbt_endian>(src))
|
|||
|
{
|
|||
|
case 1: //tag_byte
|
|||
|
if constexpr (bound_check)
|
|||
|
{
|
|||
|
readed_length += 1;
|
|||
|
bound_check_return(readed_length);
|
|||
|
}
|
|||
|
rswap::template tag_byte<nbt_endian>(current_pos);
|
|||
|
break;
|
|||
|
case 2: //tag_short
|
|||
|
if constexpr (bound_check)
|
|||
|
{
|
|||
|
readed_length += 2;
|
|||
|
bound_check_return(readed_length);
|
|||
|
}
|
|||
|
rswap::template tag_short<nbt_endian>(current_pos);
|
|||
|
break;
|
|||
|
case 3: //tag_int
|
|||
|
if constexpr (bound_check)
|
|||
|
{
|
|||
|
readed_length += 4;
|
|||
|
bound_check_return(readed_length);
|
|||
|
}
|
|||
|
rswap::template tag_int<nbt_endian>(current_pos);
|
|||
|
break;
|
|||
|
case 4: //tag_long
|
|||
|
if constexpr (bound_check)
|
|||
|
{
|
|||
|
readed_length += 8;
|
|||
|
bound_check_return(readed_length);
|
|||
|
}
|
|||
|
rswap::template tag_long<nbt_endian>(current_pos);
|
|||
|
break;
|
|||
|
case 5: //tag_float
|
|||
|
if constexpr (bound_check)
|
|||
|
{
|
|||
|
readed_length += 4;
|
|||
|
bound_check_return(readed_length);
|
|||
|
}
|
|||
|
rswap::template tag_float<nbt_endian>(current_pos);
|
|||
|
break;
|
|||
|
case 6: //tag_double
|
|||
|
if constexpr (bound_check)
|
|||
|
{
|
|||
|
readed_length += 8;
|
|||
|
bound_check_return(readed_length);
|
|||
|
}
|
|||
|
rswap::template tag_double<nbt_endian>(current_pos);
|
|||
|
break;
|
|||
|
case 7: //tag_byte_array
|
|||
|
if constexpr (bound_check)
|
|||
|
{
|
|||
|
readed_length += 4;
|
|||
|
bound_check_return(readed_length);
|
|||
|
auto len = swapper::endian_get<std::int32_t, nbt_endian>(current_pos);
|
|||
|
readed_length += len;
|
|||
|
bound_check_return(readed_length);
|
|||
|
}
|
|||
|
rswap::template tag_byte_array<nbt_endian>(current_pos);
|
|||
|
break;
|
|||
|
case 8: //tag_string
|
|||
|
|
|||
|
if constexpr (bound_check)
|
|||
|
{
|
|||
|
readed_length += 2;
|
|||
|
bound_check_return(readed_length);
|
|||
|
auto len = swapper::endian_get<std::uint16_t, nbt_endian>(current_pos);
|
|||
|
readed_length += len;
|
|||
|
bound_check_return(readed_length);
|
|||
|
}
|
|||
|
rswap::template tag_string<nbt_endian>(current_pos);
|
|||
|
break;
|
|||
|
case 9: //tag_list
|
|||
|
goto general_start;
|
|||
|
case 10: //tag_compound
|
|||
|
goto general_start;
|
|||
|
case 11: //tag_int_array
|
|||
|
if constexpr (bound_check)
|
|||
|
{
|
|||
|
readed_length += 4;
|
|||
|
bound_check_return(readed_length);
|
|||
|
auto len = swapper::endian_get<std::int32_t, nbt_endian>(current_pos);
|
|||
|
readed_length += len * sizeof(std::int32_t);
|
|||
|
bound_check_return(readed_length);
|
|||
|
}
|
|||
|
rswap::template tag_int_array<nbt_endian>(current_pos);
|
|||
|
break;
|
|||
|
case 12: //tag_long_array
|
|||
|
if constexpr (bound_check)
|
|||
|
{
|
|||
|
readed_length += 4;
|
|||
|
bound_check_return(readed_length);
|
|||
|
auto len = swapper::endian_get<std::int32_t, nbt_endian>(current_pos);
|
|||
|
readed_length += len * sizeof(std::int64_t);
|
|||
|
bound_check_return(readed_length);
|
|||
|
}
|
|||
|
rswap::template tag_long_array<nbt_endian>(current_pos);
|
|||
|
break;
|
|||
|
default:
|
|||
|
throw nbt_parse_error::invalid;
|
|||
|
}
|
|||
|
}
|
|||
|
t.mark_m = nullptr;
|
|||
|
t.mark = t.mark_m;
|
|||
|
t.mark_len = 0;
|
|||
|
return t;
|
|||
|
general_start:
|
|||
|
using mark = mark_t;
|
|||
|
std::size_t alc_len{static_cast<std::size_t>(t.source_len) / 32 /*todo: magic number*/ + 4 /*avoid zero*/};
|
|||
|
mark* mark_hdr{static_cast<mark*>(fast_io::native_global_allocator::allocate(alc_len * sizeof(mark)))}; //first element of mark array
|
|||
|
mark* mark_end{mark_hdr + alc_len}; //end+1 of mark array
|
|||
|
mark* use_end{mark_hdr}; //last element used
|
|||
|
mark* _mark_tmp{nullptr}; //tmp
|
|||
|
mark* current{use_end}; //current container
|
|||
|
mark* parent{use_end}; //parent container
|
|||
|
|
|||
|
current->cache.general_parrent_offset = 0;
|
|||
|
|
|||
|
if (swapper::endian_get<std::uint8_t, nbt_endian>(src) == 9) //list
|
|||
|
{
|
|||
|
goto list_general_begin;
|
|||
|
}
|
|||
|
else //compound
|
|||
|
{
|
|||
|
goto comp_general_begin;
|
|||
|
}
|
|||
|
|
|||
|
comp_begin:
|
|||
|
parent = current;
|
|||
|
use_end++;
|
|||
|
if (use_end > mark_end) [[unlikely]]
|
|||
|
{
|
|||
|
alc_len += alc_len / 2;
|
|||
|
if (std::is_constant_evaluated())
|
|||
|
{
|
|||
|
_mark_tmp = reinterpret_cast<mark*>(fast_io::native_global_allocator::reallocate_n(mark_hdr, (mark_end - mark_hdr) * sizeof(mark), alc_len * sizeof(mark)));
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
_mark_tmp = reinterpret_cast<mark*>(fast_io::native_global_allocator::reallocate(mark_hdr, alc_len * sizeof(mark))); //reallocate should make sure that the allocation is successful.
|
|||
|
}
|
|||
|
use_end = _mark_tmp + (use_end - mark_hdr);
|
|||
|
parent = _mark_tmp + (parent - mark_hdr);
|
|||
|
mark_hdr = _mark_tmp;
|
|||
|
mark_end = _mark_tmp + alc_len;
|
|||
|
}
|
|||
|
current = use_end;
|
|||
|
comp_general_begin:
|
|||
|
current->cache.general_parrent_offset = static_cast<std::uint32_t>(use_end - parent);
|
|||
|
current->cache.general_is_compound = 1;
|
|||
|
// goto comp_item_begin
|
|||
|
comp_item_begin:
|
|||
|
{
|
|||
|
if constexpr (bound_check)
|
|||
|
{
|
|||
|
readed_length++;
|
|||
|
bound_check_return(readed_length);
|
|||
|
}
|
|||
|
const std::uint8_t id{swapper::endian_get<std::uint8_t, nbt_endian>(current_pos)};
|
|||
|
current_pos++;
|
|||
|
if (id == 0) [[unlikely]]
|
|||
|
{
|
|||
|
goto comp_end;
|
|||
|
}
|
|||
|
if constexpr (bound_check)
|
|||
|
{
|
|||
|
readed_length += sizeof(std::uint16_t);
|
|||
|
bound_check_return(readed_length);
|
|||
|
auto len = swapper::endian_get<std::uint16_t, nbt_endian>(current_pos);
|
|||
|
readed_length += len;
|
|||
|
bound_check_return(readed_length);
|
|||
|
}
|
|||
|
auto len = swapper::endian_make_native_get<std::uint16_t, nbt_endian>(current_pos);
|
|||
|
current_pos += sizeof(std::uint16_t);
|
|||
|
current_pos += (len * sizeof(char));
|
|||
|
switch (id)
|
|||
|
{
|
|||
|
case 1:
|
|||
|
{
|
|||
|
if constexpr (bound_check)
|
|||
|
{
|
|||
|
readed_length += 1;
|
|||
|
bound_check_return(readed_length);
|
|||
|
}
|
|||
|
rswap::template tag_byte<nbt_endian>(current_pos);
|
|||
|
break;
|
|||
|
}
|
|||
|
case 2:
|
|||
|
{
|
|||
|
if constexpr (bound_check)
|
|||
|
{
|
|||
|
readed_length += 2;
|
|||
|
bound_check_return(readed_length);
|
|||
|
}
|
|||
|
rswap::template tag_short<nbt_endian>(current_pos);
|
|||
|
break;
|
|||
|
}
|
|||
|
case 3:
|
|||
|
{
|
|||
|
if constexpr (bound_check)
|
|||
|
{
|
|||
|
readed_length += 4;
|
|||
|
bound_check_return(readed_length);
|
|||
|
}
|
|||
|
rswap::template tag_int<nbt_endian>(current_pos);
|
|||
|
break;
|
|||
|
}
|
|||
|
case 4:
|
|||
|
{
|
|||
|
if constexpr (bound_check)
|
|||
|
{
|
|||
|
readed_length += 8;
|
|||
|
bound_check_return(readed_length);
|
|||
|
}
|
|||
|
rswap::template tag_long<nbt_endian>(current_pos);
|
|||
|
break;
|
|||
|
}
|
|||
|
case 5:
|
|||
|
{
|
|||
|
if constexpr (bound_check)
|
|||
|
{
|
|||
|
readed_length += 4;
|
|||
|
bound_check_return(readed_length);
|
|||
|
}
|
|||
|
rswap::template tag_float<nbt_endian>(current_pos);
|
|||
|
break;
|
|||
|
}
|
|||
|
case 6:
|
|||
|
{
|
|||
|
if constexpr (bound_check)
|
|||
|
{
|
|||
|
readed_length += 8;
|
|||
|
bound_check_return(readed_length);
|
|||
|
}
|
|||
|
rswap::template tag_double<nbt_endian>(current_pos);
|
|||
|
break;
|
|||
|
}
|
|||
|
case 7:
|
|||
|
{
|
|||
|
if constexpr (bound_check)
|
|||
|
{
|
|||
|
readed_length += 4;
|
|||
|
bound_check_return(readed_length);
|
|||
|
auto arrlen = swapper::endian_get<std::int32_t, nbt_endian>(current_pos);
|
|||
|
readed_length += arrlen;
|
|||
|
bound_check_return(readed_length);
|
|||
|
}
|
|||
|
rswap::template tag_byte_array<nbt_endian>(current_pos);
|
|||
|
break;
|
|||
|
}
|
|||
|
case 8:
|
|||
|
{
|
|||
|
if constexpr (bound_check)
|
|||
|
{
|
|||
|
readed_length += 2;
|
|||
|
bound_check_return(readed_length);
|
|||
|
auto arrlen = swapper::endian_get<std::uint16_t, nbt_endian>(current_pos);
|
|||
|
readed_length += arrlen;
|
|||
|
bound_check_return(readed_length);
|
|||
|
}
|
|||
|
rswap::template tag_string<nbt_endian>(current_pos);
|
|||
|
break;
|
|||
|
}
|
|||
|
case 9:
|
|||
|
{
|
|||
|
goto list_begin;
|
|||
|
}
|
|||
|
case 10:
|
|||
|
{
|
|||
|
goto comp_begin;
|
|||
|
}
|
|||
|
case 11:
|
|||
|
{
|
|||
|
if constexpr (bound_check)
|
|||
|
{
|
|||
|
readed_length += 4;
|
|||
|
bound_check_return(readed_length);
|
|||
|
std::size_t arrlen = swapper::endian_get<std::int32_t, nbt_endian>(current_pos);
|
|||
|
readed_length += arrlen * sizeof(std::int32_t);
|
|||
|
bound_check_return(readed_length);
|
|||
|
}
|
|||
|
rswap::template tag_int_array<nbt_endian>(current_pos);
|
|||
|
break;
|
|||
|
}
|
|||
|
case 12:
|
|||
|
{
|
|||
|
if constexpr (bound_check)
|
|||
|
{
|
|||
|
readed_length += 4;
|
|||
|
bound_check_return(readed_length);
|
|||
|
std::size_t arrlen = swapper::endian_get<std::int32_t, nbt_endian>(current_pos);
|
|||
|
readed_length += arrlen * sizeof(std::int64_t);
|
|||
|
bound_check_return(readed_length);
|
|||
|
}
|
|||
|
rswap::template tag_long_array<nbt_endian>(current_pos);
|
|||
|
break;
|
|||
|
}
|
|||
|
default:
|
|||
|
fast_io::native_global_allocator::deallocate_n(mark_hdr, alc_len * sizeof(mark));
|
|||
|
throw nbt_parse_error::invalid;
|
|||
|
};
|
|||
|
goto comp_item_begin;
|
|||
|
}
|
|||
|
comp_end:
|
|||
|
if (current->cache.general_parrent_offset == 0) [[unlikely]]
|
|||
|
{
|
|||
|
current->store.end = current_pos;
|
|||
|
current->store.flat_next_mark = use_end - current + 1;
|
|||
|
goto read_finish;
|
|||
|
}
|
|||
|
current->store.end = current_pos;
|
|||
|
current->store.flat_next_mark = use_end - current + 1;
|
|||
|
current = parent;
|
|||
|
parent = parent - (parent->cache.general_parrent_offset);
|
|||
|
if (current->cache.general_is_compound == 1)
|
|||
|
{
|
|||
|
goto comp_item_begin;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
goto list_item_begin;
|
|||
|
}
|
|||
|
list_begin:
|
|||
|
parent = current;
|
|||
|
use_end++;
|
|||
|
if (use_end > mark_end) [[unlikely]]
|
|||
|
{
|
|||
|
alc_len += alc_len / 2;
|
|||
|
if (std::is_constant_evaluated())
|
|||
|
{
|
|||
|
#ifdef use_fastio
|
|||
|
_mark_tmp = reinterpret_cast<mark*>(fast_io::native_global_allocator::reallocate_n(mark_hdr, (mark_end - mark_hdr) * sizeof(mark), alc_len * sizeof(mark)));
|
|||
|
#else
|
|||
|
_mark_tmp = reinterpret_cast<mark*>(realloc(mark_hdr, (mark_end - mark_hdr) * sizeof(mark), alc_len * sizeof(mark)));
|
|||
|
#endif
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
_mark_tmp = reinterpret_cast<mark*>(fast_io::native_global_allocator::reallocate(mark_hdr, alc_len * sizeof(mark))); //reallocate should make sure that the allocation is successful.
|
|||
|
}
|
|||
|
use_end = _mark_tmp + (use_end - mark_hdr);
|
|||
|
parent = _mark_tmp + (parent - mark_hdr);
|
|||
|
mark_hdr = _mark_tmp;
|
|||
|
mark_end = _mark_tmp + alc_len;
|
|||
|
}
|
|||
|
current = use_end;
|
|||
|
list_general_begin:
|
|||
|
if constexpr (bound_check)
|
|||
|
{
|
|||
|
readed_length++;
|
|||
|
readed_length += sizeof(std::uint32_t);
|
|||
|
bound_check_return(readed_length);
|
|||
|
auto id = swapper::endian_get<std::uint8_t, nbt_endian>(current_pos);
|
|||
|
if (id >= 0 && id <= 6)
|
|||
|
{
|
|||
|
const std::size_t len = swapper::endian_get<std::uint32_t, nbt_endian>(current_pos + 1);
|
|||
|
switch (id)
|
|||
|
{
|
|||
|
case 0:
|
|||
|
break;
|
|||
|
case 1:
|
|||
|
readed_length += len;
|
|||
|
break;
|
|||
|
case 2:
|
|||
|
readed_length += len * 2;
|
|||
|
break;
|
|||
|
case 3:
|
|||
|
readed_length += len * 4;
|
|||
|
break;
|
|||
|
case 4:
|
|||
|
readed_length += len * 8;
|
|||
|
break;
|
|||
|
case 5:
|
|||
|
readed_length += len * 4;
|
|||
|
break;
|
|||
|
case 6:
|
|||
|
readed_length += len * 8;
|
|||
|
break;
|
|||
|
default:
|
|||
|
break;
|
|||
|
}
|
|||
|
bound_check_return(readed_length);
|
|||
|
}
|
|||
|
}
|
|||
|
current->cache.list_type = swapper::endian_get<std::uint8_t, nbt_endian>(current_pos);
|
|||
|
current->cache.general_parrent_offset = static_cast<std::uint32_t>(current - parent);
|
|||
|
current->cache.general_is_compound = 0;
|
|||
|
current_pos++;
|
|||
|
current->cache.list_total_length = swapper::endian_make_native_get<std::uint32_t, nbt_endian>(current_pos);
|
|||
|
current->cache.list_current_length = 0;
|
|||
|
current_pos += sizeof(std::uint32_t);
|
|||
|
goto list_item_begin;
|
|||
|
list_item_begin:
|
|||
|
if (current->cache.list_current_length >= current->cache.list_total_length) [[unlikely]]
|
|||
|
{
|
|||
|
goto list_end;
|
|||
|
}
|
|||
|
|
|||
|
current->cache.list_current_length++;
|
|||
|
switch (current->cache.list_type)
|
|||
|
{
|
|||
|
case 0:
|
|||
|
{
|
|||
|
break;
|
|||
|
}
|
|||
|
case 1:
|
|||
|
{
|
|||
|
rswap::template tag_byte<nbt_endian>(current_pos);
|
|||
|
break;
|
|||
|
}
|
|||
|
case 2:
|
|||
|
{
|
|||
|
rswap::template tag_short<nbt_endian>(current_pos);
|
|||
|
break;
|
|||
|
}
|
|||
|
case 3:
|
|||
|
{
|
|||
|
rswap::template tag_int<nbt_endian>(current_pos);
|
|||
|
break;
|
|||
|
}
|
|||
|
case 4:
|
|||
|
{
|
|||
|
rswap::template tag_long<nbt_endian>(current_pos);
|
|||
|
break;
|
|||
|
}
|
|||
|
case 5:
|
|||
|
{
|
|||
|
rswap::template tag_float<nbt_endian>(current_pos);
|
|||
|
break;
|
|||
|
}
|
|||
|
case 6:
|
|||
|
{
|
|||
|
rswap::template tag_double<nbt_endian>(current_pos);
|
|||
|
break;
|
|||
|
}
|
|||
|
case 7:
|
|||
|
{
|
|||
|
if constexpr (bound_check)
|
|||
|
{
|
|||
|
readed_length += 4;
|
|||
|
bound_check_return(readed_length);
|
|||
|
auto len = swapper::endian_get<std::int32_t, nbt_endian>(current_pos);
|
|||
|
readed_length += len;
|
|||
|
bound_check_return(readed_length);
|
|||
|
}
|
|||
|
rswap::template tag_byte_array<nbt_endian>(current_pos);
|
|||
|
break;
|
|||
|
}
|
|||
|
case 8:
|
|||
|
{
|
|||
|
if constexpr (bound_check)
|
|||
|
{
|
|||
|
readed_length += 2;
|
|||
|
bound_check_return(readed_length);
|
|||
|
auto len = swapper::endian_get<std::uint16_t, nbt_endian>(current_pos);
|
|||
|
readed_length += len;
|
|||
|
bound_check_return(readed_length);
|
|||
|
}
|
|||
|
rswap::template tag_string<nbt_endian>(current_pos);
|
|||
|
break;
|
|||
|
}
|
|||
|
case 9:
|
|||
|
{
|
|||
|
goto list_begin;
|
|||
|
}
|
|||
|
case 10:
|
|||
|
{
|
|||
|
goto comp_begin;
|
|||
|
}
|
|||
|
case 11:
|
|||
|
{
|
|||
|
if constexpr (bound_check)
|
|||
|
{
|
|||
|
readed_length += 4;
|
|||
|
bound_check_return(readed_length);
|
|||
|
auto len = swapper::endian_get<std::int32_t, nbt_endian>(current_pos);
|
|||
|
readed_length += len * sizeof(std::int32_t);
|
|||
|
bound_check_return(readed_length);
|
|||
|
}
|
|||
|
rswap::template tag_int_array<nbt_endian>(current_pos);
|
|||
|
break;
|
|||
|
}
|
|||
|
case 12:
|
|||
|
{
|
|||
|
if constexpr (bound_check)
|
|||
|
{
|
|||
|
readed_length += 4;
|
|||
|
bound_check_return(readed_length);
|
|||
|
auto len = swapper::endian_get<std::int32_t, nbt_endian>(current_pos);
|
|||
|
readed_length += len * sizeof(std::int64_t);
|
|||
|
bound_check_return(readed_length);
|
|||
|
}
|
|||
|
rswap::template tag_long_array<nbt_endian>(current_pos);
|
|||
|
break;
|
|||
|
}
|
|||
|
default:
|
|||
|
fast_io::native_global_allocator::deallocate_n(mark_hdr, alc_len * sizeof(mark));
|
|||
|
throw nbt_parse_error::invalid;
|
|||
|
};
|
|||
|
goto list_item_begin;
|
|||
|
list_end:
|
|||
|
if (current->cache.general_parrent_offset == 0) [[unlikely]]
|
|||
|
{
|
|||
|
current->store.end = current_pos;
|
|||
|
current->store.flat_next_mark = use_end - current + 1;
|
|||
|
goto read_finish;
|
|||
|
}
|
|||
|
current->store.end = current_pos;
|
|||
|
current->store.flat_next_mark = use_end - current + 1;
|
|||
|
current = parent;
|
|||
|
parent = parent - (parent->cache.general_parrent_offset);
|
|||
|
if (current->cache.general_is_compound == 1)
|
|||
|
{
|
|||
|
goto comp_item_begin;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
goto list_item_begin;
|
|||
|
}
|
|||
|
|
|||
|
read_finish:
|
|||
|
t.mark_m = mark_hdr;
|
|||
|
t.mark = t.mark_m;
|
|||
|
t.mark_len = (mark_end - mark_hdr);
|
|||
|
return t;
|
|||
|
|
|||
|
#undef bound_check_return
|
|||
|
}
|
|||
|
} // namespace read_write
|
|||
|
} // namespace impl
|
|||
|
|
|||
|
using nbt_parse_error = impl::nbt_parse_error;
|
|||
|
using nbt_type = impl::nbt_type;
|
|||
|
struct nbt_type_error
|
|||
|
{
|
|||
|
nbt_type is;
|
|||
|
nbt_type as;
|
|||
|
};
|
|||
|
class nbt_document;
|
|||
|
template<nbt_type tag_type, nbt_type list_element_type>
|
|||
|
class nbt_any_tag;
|
|||
|
template<nbt_type list_element_type>
|
|||
|
class nbt_list;
|
|||
|
class nbt_compound;
|
|||
|
|
|||
|
template<bool in_place, bool bound_check, std::endian nbt_endian, impl::swapper::read_swapper rswap>
|
|||
|
[[nodiscard]] inline auto read(std::span<std::byte, std::dynamic_extent> source) -> nbt_document;
|
|||
|
|
|||
|
template<nbt_type list_element_type>
|
|||
|
class nbt_list
|
|||
|
{
|
|||
|
private:
|
|||
|
impl::nbt_list impl_list;
|
|||
|
|
|||
|
template<nbt_type tag_type, nbt_type list_element_type_>
|
|||
|
friend class nbt_any_tag;
|
|||
|
|
|||
|
public:
|
|||
|
class iterator
|
|||
|
{
|
|||
|
private:
|
|||
|
impl::nbt_list::iterator impl_iterator;
|
|||
|
|
|||
|
public:
|
|||
|
inline iterator& operator++() noexcept
|
|||
|
{
|
|||
|
if constexpr (list_element_type == nbt_type::tag_end)
|
|||
|
{
|
|||
|
impl::nbt_list_function::nbt_list_iterator_next_end(std::addressof(impl_iterator));
|
|||
|
}
|
|||
|
else if constexpr (list_element_type == nbt_type::tag_byte)
|
|||
|
{
|
|||
|
impl::nbt_list_function::nbt_list_iterator_next_byte(std::addressof(impl_iterator));
|
|||
|
}
|
|||
|
else if constexpr (list_element_type == nbt_type::tag_short)
|
|||
|
{
|
|||
|
impl::nbt_list_function::nbt_list_iterator_next_short(std::addressof(impl_iterator));
|
|||
|
}
|
|||
|
else if constexpr (list_element_type == nbt_type::tag_int)
|
|||
|
{
|
|||
|
impl::nbt_list_function::nbt_list_iterator_next_int(std::addressof(impl_iterator));
|
|||
|
}
|
|||
|
else if constexpr (list_element_type == nbt_type::tag_long)
|
|||
|
{
|
|||
|
impl::nbt_list_function::nbt_list_iterator_next_long(std::addressof(impl_iterator));
|
|||
|
}
|
|||
|
else if constexpr (list_element_type == nbt_type::tag_float)
|
|||
|
{
|
|||
|
impl::nbt_list_function::nbt_list_iterator_next_float(std::addressof(impl_iterator));
|
|||
|
}
|
|||
|
else if constexpr (list_element_type == nbt_type::tag_double)
|
|||
|
{
|
|||
|
impl::nbt_list_function::nbt_list_iterator_next_double(std::addressof(impl_iterator));
|
|||
|
}
|
|||
|
else if constexpr (list_element_type == nbt_type::tag_byte_array)
|
|||
|
{
|
|||
|
impl::nbt_list_function::nbt_list_iterator_next_byte_array(std::addressof(impl_iterator));
|
|||
|
}
|
|||
|
else if constexpr (list_element_type == nbt_type::tag_string)
|
|||
|
{
|
|||
|
impl::nbt_list_function::nbt_list_iterator_next_string(std::addressof(impl_iterator));
|
|||
|
}
|
|||
|
else if constexpr (list_element_type == nbt_type::tag_list)
|
|||
|
{
|
|||
|
impl::nbt_list_function::nbt_list_iterator_next_list(std::addressof(impl_iterator));
|
|||
|
}
|
|||
|
else if constexpr (list_element_type == nbt_type::tag_compound)
|
|||
|
{
|
|||
|
impl::nbt_list_function::nbt_list_iterator_next_compound(std::addressof(impl_iterator));
|
|||
|
}
|
|||
|
else if constexpr (list_element_type == nbt_type::tag_int_array)
|
|||
|
{
|
|||
|
impl::nbt_list_function::nbt_list_iterator_next_int_array(std::addressof(impl_iterator));
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
impl::nbt_list_function::nbt_list_iterator_next_long_array(std::addressof(impl_iterator));
|
|||
|
}
|
|||
|
return *this;
|
|||
|
}
|
|||
|
inline const iterator operator++(int) noexcept
|
|||
|
{
|
|||
|
auto old = *this;
|
|||
|
++(*this);
|
|||
|
return old;
|
|||
|
}
|
|||
|
[[nodiscard]] inline bool operator==(const iterator& x) const noexcept
|
|||
|
{
|
|||
|
return impl::nbt_list_function::nbt_list_iter_equal(std::addressof(impl_iterator), std::addressof(x.impl_iterator));
|
|||
|
}
|
|||
|
[[nodiscard]] inline bool operator!=(const iterator& x) const noexcept
|
|||
|
{
|
|||
|
return !impl::nbt_list_function::nbt_list_iter_equal(std::addressof(impl_iterator), std::addressof(x.impl_iterator));
|
|||
|
}
|
|||
|
|
|||
|
template<nbt_type element_type = nbt_type::tag_end>
|
|||
|
[[nodiscard]] inline auto value() const
|
|||
|
{
|
|||
|
nbt_any_tag<list_element_type, element_type> tag{};
|
|||
|
if constexpr (list_element_type == nbt_type::tag_list)
|
|||
|
{
|
|||
|
auto list_type{
|
|||
|
static_cast<nbt_type>(*impl_iterator.source)};
|
|||
|
if (list_type != element_type)
|
|||
|
{
|
|||
|
throw nbt_type_error{.is = list_type, .as = element_type};
|
|||
|
}
|
|||
|
}
|
|||
|
tag.impl_any_tag = impl::nbt_list_function::nbt_list_iter_value(std::addressof(impl_iterator));
|
|||
|
return tag.get();
|
|||
|
}
|
|||
|
|
|||
|
[[nodiscard]] inline consteval nbt_type type() const noexcept
|
|||
|
{
|
|||
|
return list_element_type;
|
|||
|
}
|
|||
|
|
|||
|
[[nodiscard]] inline nbt_type element_type() const noexcept
|
|||
|
{
|
|||
|
return static_cast<nbt_type>(*impl_iterator.source);
|
|||
|
}
|
|||
|
|
|||
|
friend class nbt_list<list_element_type>;
|
|||
|
};
|
|||
|
|
|||
|
[[nodiscard]] inline iterator begin() const noexcept
|
|||
|
{
|
|||
|
iterator iter{};
|
|||
|
iter.impl_iterator = impl::nbt_list_function::nbt_list_iterator_begin(std::addressof(impl_list));
|
|||
|
return iter;
|
|||
|
}
|
|||
|
|
|||
|
[[nodiscard]] inline iterator end() const noexcept
|
|||
|
{
|
|||
|
iterator iter{};
|
|||
|
iter.impl_iterator = impl::nbt_list_function::nbt_list_iterator_end(std::addressof(impl_list));
|
|||
|
return iter;
|
|||
|
}
|
|||
|
[[nodiscard]] inline std::size_t size() const noexcept
|
|||
|
{
|
|||
|
return impl_list.length;
|
|||
|
}
|
|||
|
[[nodiscard]] inline auto operator[](std::int32_t index) const noexcept
|
|||
|
{
|
|||
|
iterator iter{};
|
|||
|
if constexpr (list_element_type == nbt_type::tag_end)
|
|||
|
{
|
|||
|
iter.impl_iterator = (impl::nbt_list_function::nbt_list_find_value_end(std::addressof(impl_list), index));
|
|||
|
}
|
|||
|
else if constexpr (list_element_type == nbt_type::tag_byte)
|
|||
|
{
|
|||
|
iter.impl_iterator = (impl::nbt_list_function::nbt_list_find_value_byte(std::addressof(impl_list), index));
|
|||
|
}
|
|||
|
else if constexpr (list_element_type == nbt_type::tag_short)
|
|||
|
{
|
|||
|
iter.impl_iterator = (impl::nbt_list_function::nbt_list_find_value_short(std::addressof(impl_list), index));
|
|||
|
}
|
|||
|
else if constexpr (list_element_type == nbt_type::tag_int)
|
|||
|
{
|
|||
|
iter.impl_iterator = (impl::nbt_list_function::nbt_list_find_value_int(std::addressof(impl_list), index));
|
|||
|
}
|
|||
|
else if constexpr (list_element_type == nbt_type::tag_long)
|
|||
|
{
|
|||
|
iter.impl_iterator = (impl::nbt_list_function::nbt_list_find_value_long(std::addressof(impl_list), index));
|
|||
|
}
|
|||
|
else if constexpr (list_element_type == nbt_type::tag_float)
|
|||
|
{
|
|||
|
iter.impl_iterator = (impl::nbt_list_function::nbt_list_find_value_float(std::addressof(impl_list), index));
|
|||
|
}
|
|||
|
else if constexpr (list_element_type == nbt_type::tag_double)
|
|||
|
{
|
|||
|
iter.impl_iterator = (impl::nbt_list_function::nbt_list_find_value_double(std::addressof(impl_list), index));
|
|||
|
}
|
|||
|
else if constexpr (list_element_type == nbt_type::tag_byte_array)
|
|||
|
{
|
|||
|
iter.impl_iterator = (impl::nbt_list_function::nbt_list_find_value_byte_array(std::addressof(impl_list), index));
|
|||
|
}
|
|||
|
else if constexpr (list_element_type == nbt_type::tag_string)
|
|||
|
{
|
|||
|
iter.impl_iterator = (impl::nbt_list_function::nbt_list_find_value_string(std::addressof(impl_list), index));
|
|||
|
}
|
|||
|
else if constexpr (list_element_type == nbt_type::tag_list)
|
|||
|
{
|
|||
|
iter.impl_iterator = (impl::nbt_list_function::nbt_list_find_value_list(std::addressof(impl_list), index));
|
|||
|
}
|
|||
|
else if constexpr (list_element_type == nbt_type::tag_compound)
|
|||
|
{
|
|||
|
iter.impl_iterator = (impl::nbt_list_function::nbt_list_find_value_compound(std::addressof(impl_list), index));
|
|||
|
}
|
|||
|
else if constexpr (list_element_type == nbt_type::tag_int_array)
|
|||
|
{
|
|||
|
iter.impl_iterator = (impl::nbt_list_function::nbt_list_find_value_int_array(std::addressof(impl_list), index));
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
iter.impl_iterator = (impl::nbt_list_function::nbt_list_find_value_long_array(std::addressof(impl_list), index));
|
|||
|
}
|
|||
|
return iter;
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
class nbt_compound
|
|||
|
{
|
|||
|
private:
|
|||
|
impl::nbt_compound impl_compound;
|
|||
|
|
|||
|
template<nbt_type tag_type, nbt_type list_element_type>
|
|||
|
friend class nbt_any_tag;
|
|||
|
|
|||
|
public:
|
|||
|
class iterator
|
|||
|
{
|
|||
|
private:
|
|||
|
impl::nbt_compound::iterator impl_iterator;
|
|||
|
|
|||
|
public:
|
|||
|
inline iterator& operator++() noexcept
|
|||
|
{
|
|||
|
impl::nbt_compound_function::nbt_compound_iterator_next(std::addressof(impl_iterator));
|
|||
|
return *this;
|
|||
|
}
|
|||
|
inline const iterator operator++(int) noexcept
|
|||
|
{
|
|||
|
auto old = *this;
|
|||
|
++(*this);
|
|||
|
return old;
|
|||
|
}
|
|||
|
[[nodiscard]] inline bool operator==(const iterator& x) const noexcept
|
|||
|
{
|
|||
|
return impl::nbt_compound_function::nbt_compound_iter_equal(std::addressof(impl_iterator), std::addressof(x.impl_iterator));
|
|||
|
}
|
|||
|
[[nodiscard]] inline bool operator!=(const iterator& x) const noexcept
|
|||
|
{
|
|||
|
return !impl::nbt_compound_function::nbt_compound_iter_equal(std::addressof(impl_iterator), std::addressof(x.impl_iterator));
|
|||
|
}
|
|||
|
|
|||
|
template<nbt_type tag_type, nbt_type list_element_type = nbt_type::tag_end>
|
|||
|
[[nodiscard]] inline auto value() const
|
|||
|
{
|
|||
|
auto real_type{static_cast<nbt_type>(impl::swapper::byte_as_type<std::uint8_t>(impl_iterator.source))};
|
|||
|
if (real_type != tag_type)
|
|||
|
{
|
|||
|
throw nbt_type_error{.is = real_type, .as = tag_type};
|
|||
|
}
|
|||
|
if constexpr (tag_type == nbt_type::tag_list)
|
|||
|
{
|
|||
|
auto list_type{
|
|||
|
static_cast<nbt_type>(impl::swapper::byte_as_type<std::uint8_t>(
|
|||
|
impl_iterator.source + sizeof(std::uint8_t) + sizeof(std::uint16_t) +
|
|||
|
impl::swapper::byte_as_type<std::uint16_t>(
|
|||
|
impl_iterator.source + sizeof(std::uint8_t))))};
|
|||
|
if (list_type != list_element_type)
|
|||
|
{
|
|||
|
throw nbt_type_error{.is = list_type, .as = list_element_type};
|
|||
|
}
|
|||
|
}
|
|||
|
nbt_any_tag<tag_type, list_element_type> tag{};
|
|||
|
tag.impl_any_tag = impl::nbt_compound_function::nbt_compound_iter_value(std::addressof(impl_iterator));
|
|||
|
return tag.get();
|
|||
|
}
|
|||
|
|
|||
|
[[nodiscard]] inline std::u8string_view key() const noexcept
|
|||
|
{
|
|||
|
return impl::nbt_compound_function::nbt_compound_iter_key(std::addressof(impl_iterator));
|
|||
|
}
|
|||
|
|
|||
|
[[nodiscard]] inline nbt_type type() const noexcept
|
|||
|
{
|
|||
|
return static_cast<nbt_type>(impl::swapper::byte_as_type<std::uint8_t>(impl_iterator.source));
|
|||
|
}
|
|||
|
|
|||
|
[[nodiscard]] inline nbt_type element_type() const noexcept
|
|||
|
{
|
|||
|
return static_cast<nbt_type>(impl::swapper::byte_as_type<std::uint8_t>(
|
|||
|
impl_iterator.source + sizeof(std::uint8_t) + sizeof(std::uint16_t) +
|
|||
|
impl::swapper::byte_as_type<std::uint16_t>(
|
|||
|
impl_iterator.source + sizeof(std::uint8_t))));
|
|||
|
}
|
|||
|
|
|||
|
using difference_type = std::ptrdiff_t;
|
|||
|
|
|||
|
friend class nbt_compound;
|
|||
|
};
|
|||
|
|
|||
|
[[nodiscard]] inline iterator begin() const noexcept
|
|||
|
{
|
|||
|
iterator iter{};
|
|||
|
iter.impl_iterator = impl::nbt_compound_function::nbt_compound_iterator_begin(std::addressof(impl_compound));
|
|||
|
return iter;
|
|||
|
}
|
|||
|
|
|||
|
[[nodiscard]] inline iterator end() const noexcept
|
|||
|
{
|
|||
|
iterator iter{};
|
|||
|
iter.impl_iterator = impl::nbt_compound_function::nbt_compound_iterator_end(std::addressof(impl_compound));
|
|||
|
return iter;
|
|||
|
}
|
|||
|
|
|||
|
[[nodiscard]] inline iterator at(std::u8string_view key) const
|
|||
|
{
|
|||
|
iterator iter{};
|
|||
|
iter.impl_iterator = impl::nbt_compound_function::nbt_compound_find_value(std::addressof(impl_compound), key);
|
|||
|
return iter;
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
template<nbt_type tag_type, nbt_type list_element_type = nbt_type::tag_end>
|
|||
|
class nbt_any_tag
|
|||
|
{
|
|||
|
private:
|
|||
|
impl::any_tag impl_any_tag;
|
|||
|
|
|||
|
friend class nbt_document;
|
|||
|
template<nbt_type list_element_type_>
|
|||
|
friend class nbt_list;
|
|||
|
friend class nbt_compound;
|
|||
|
|
|||
|
public:
|
|||
|
[[nodiscard]] inline consteval nbt_type type() noexcept
|
|||
|
{
|
|||
|
return tag_type;
|
|||
|
}
|
|||
|
|
|||
|
[[nodiscard]] inline consteval nbt_type element_type() noexcept
|
|||
|
{
|
|||
|
return list_element_type;
|
|||
|
}
|
|||
|
|
|||
|
[[nodiscard]] inline auto get() noexcept
|
|||
|
{
|
|||
|
if constexpr (tag_type == nbt_type::tag_end)
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
else if constexpr (tag_type == nbt_type::tag_byte)
|
|||
|
{
|
|||
|
return impl::any_tag_function::any_tag_get_byte(std::addressof(impl_any_tag));
|
|||
|
}
|
|||
|
else if constexpr (tag_type == nbt_type::tag_short)
|
|||
|
{
|
|||
|
return impl::any_tag_function::any_tag_get_short(std::addressof(impl_any_tag));
|
|||
|
}
|
|||
|
else if constexpr (tag_type == nbt_type::tag_int)
|
|||
|
{
|
|||
|
return impl::any_tag_function::any_tag_get_int(std::addressof(impl_any_tag));
|
|||
|
}
|
|||
|
else if constexpr (tag_type == nbt_type::tag_long)
|
|||
|
{
|
|||
|
return impl::any_tag_function::any_tag_get_long(std::addressof(impl_any_tag));
|
|||
|
}
|
|||
|
else if constexpr (tag_type == nbt_type::tag_float)
|
|||
|
{
|
|||
|
return impl::any_tag_function::any_tag_get_float(std::addressof(impl_any_tag));
|
|||
|
}
|
|||
|
else if constexpr (tag_type == nbt_type::tag_double)
|
|||
|
{
|
|||
|
return impl::any_tag_function::any_tag_get_double(std::addressof(impl_any_tag));
|
|||
|
}
|
|||
|
else if constexpr (tag_type == nbt_type::tag_byte_array)
|
|||
|
{
|
|||
|
return impl::any_tag_function::any_tag_get_byte_array(std::addressof(impl_any_tag));
|
|||
|
}
|
|||
|
else if constexpr (tag_type == nbt_type::tag_string)
|
|||
|
{
|
|||
|
return impl::any_tag_function::any_tag_get_string(std::addressof(impl_any_tag));
|
|||
|
}
|
|||
|
else if constexpr (tag_type == nbt_type::tag_list)
|
|||
|
{
|
|||
|
if constexpr (list_element_type == nbt_type::tag_end)
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
else if constexpr (list_element_type == nbt_type::tag_byte)
|
|||
|
{
|
|||
|
return impl::any_tag_function::any_tag_get_list_byte(std::addressof(impl_any_tag));
|
|||
|
}
|
|||
|
else if constexpr (list_element_type == nbt_type::tag_short)
|
|||
|
{
|
|||
|
return impl::any_tag_function::any_tag_get_list_short(std::addressof(impl_any_tag));
|
|||
|
}
|
|||
|
else if constexpr (list_element_type == nbt_type::tag_int)
|
|||
|
{
|
|||
|
return impl::any_tag_function::any_tag_get_list_int(std::addressof(impl_any_tag));
|
|||
|
}
|
|||
|
else if constexpr (list_element_type == nbt_type::tag_long)
|
|||
|
{
|
|||
|
return impl::any_tag_function::any_tag_get_list_long(std::addressof(impl_any_tag));
|
|||
|
}
|
|||
|
else if constexpr (list_element_type == nbt_type::tag_float)
|
|||
|
{
|
|||
|
return impl::any_tag_function::any_tag_get_list_float(std::addressof(impl_any_tag));
|
|||
|
}
|
|||
|
else if constexpr (list_element_type == nbt_type::tag_double)
|
|||
|
{
|
|||
|
return impl::any_tag_function::any_tag_get_list_double(std::addressof(impl_any_tag));
|
|||
|
}
|
|||
|
else if constexpr (list_element_type == nbt_type::tag_byte_array)
|
|||
|
{
|
|||
|
nbt_list<list_element_type> list{};
|
|||
|
list.impl_list = impl::any_tag_function::any_tag_get_list_byte_array(std::addressof(impl_any_tag));
|
|||
|
return list;
|
|||
|
}
|
|||
|
else if constexpr (list_element_type == nbt_type::tag_string)
|
|||
|
{
|
|||
|
nbt_list<list_element_type> list{};
|
|||
|
list.impl_list = impl::any_tag_function::any_tag_get_list_string(std::addressof(impl_any_tag));
|
|||
|
return list;
|
|||
|
}
|
|||
|
else if constexpr (list_element_type == nbt_type::tag_list)
|
|||
|
{
|
|||
|
nbt_list<list_element_type> list{};
|
|||
|
list.impl_list = impl::any_tag_function::any_tag_get_list_list(std::addressof(impl_any_tag));
|
|||
|
return list;
|
|||
|
}
|
|||
|
else if constexpr (list_element_type == nbt_type::tag_compound)
|
|||
|
{
|
|||
|
nbt_list<list_element_type> list{};
|
|||
|
list.impl_list = impl::any_tag_function::any_tag_get_list_compound(std::addressof(impl_any_tag));
|
|||
|
return list;
|
|||
|
}
|
|||
|
else if constexpr (list_element_type == nbt_type::tag_int_array)
|
|||
|
{
|
|||
|
nbt_list<list_element_type> list{};
|
|||
|
list.impl_list = impl::any_tag_function::any_tag_get_list_int_array(std::addressof(impl_any_tag));
|
|||
|
return list;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
nbt_list<list_element_type> list{};
|
|||
|
list.impl_list = impl::any_tag_function::any_tag_get_list_long_array(std::addressof(impl_any_tag));
|
|||
|
return list;
|
|||
|
}
|
|||
|
}
|
|||
|
else if constexpr (tag_type == nbt_type::tag_compound)
|
|||
|
{
|
|||
|
nbt_compound comp{};
|
|||
|
comp.impl_compound = impl::any_tag_function::any_tag_get_compound(std::addressof(impl_any_tag));
|
|||
|
return comp;
|
|||
|
}
|
|||
|
else if constexpr (tag_type == nbt_type::tag_int_array)
|
|||
|
{
|
|||
|
return impl::any_tag_function::any_tag_get_int_array(std::addressof(impl_any_tag));
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return impl::any_tag_function::any_tag_get_long_array(std::addressof(impl_any_tag));
|
|||
|
}
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
class nbt_document
|
|||
|
{
|
|||
|
private:
|
|||
|
impl::nbt_document impl_document;
|
|||
|
|
|||
|
template<bool in_place, bool bound_check, std::endian nbt_endian, impl::swapper::read_swapper rswap>
|
|||
|
friend inline auto read(std::span<std::byte, std::dynamic_extent> source) -> nbt_document;
|
|||
|
|
|||
|
public:
|
|||
|
nbt_document(const nbt_document&) = delete;
|
|||
|
nbt_document& operator=(const nbt_document&) = delete;
|
|||
|
|
|||
|
inline nbt_document& operator=(nbt_document&& right) noexcept
|
|||
|
{
|
|||
|
impl::nbt_document_function::nbt_document_move(
|
|||
|
std::addressof(right.impl_document),
|
|||
|
std::addressof(this->impl_document));
|
|||
|
return *this;
|
|||
|
}
|
|||
|
inline ~nbt_document() noexcept
|
|||
|
{
|
|||
|
impl::nbt_document_function::nbt_document_free(
|
|||
|
std::addressof(this->impl_document));
|
|||
|
}
|
|||
|
inline nbt_document() noexcept = default;
|
|||
|
inline nbt_document(nbt_document&& right) noexcept
|
|||
|
{
|
|||
|
impl::nbt_document_function::nbt_document_move(
|
|||
|
std::addressof(right.impl_document),
|
|||
|
std::addressof(this->impl_document));
|
|||
|
}
|
|||
|
|
|||
|
public:
|
|||
|
[[nodiscard]] inline nbt_type type() noexcept
|
|||
|
{
|
|||
|
return static_cast<nbt_type>(impl::swapper::byte_as_type<std::uint8_t>(this->impl_document.source));
|
|||
|
}
|
|||
|
[[nodiscard]] inline nbt_type element_type() noexcept
|
|||
|
{
|
|||
|
return static_cast<nbt_type>(impl::swapper::byte_as_type<std::uint8_t>(
|
|||
|
this->impl_document.source + sizeof(std::uint8_t) + sizeof(std::uint16_t) +
|
|||
|
impl::swapper::byte_as_type<std::uint16_t>(
|
|||
|
this->impl_document.source + sizeof(std::uint8_t))));
|
|||
|
}
|
|||
|
[[nodiscard]] inline auto key() noexcept
|
|||
|
{
|
|||
|
return impl::nbt_document_function::nbt_document_root_key(std::addressof(this->impl_document));
|
|||
|
}
|
|||
|
template<nbt_type tag_type, nbt_type list_element_type = nbt_type::tag_end>
|
|||
|
[[nodiscard]] inline auto value()
|
|||
|
{
|
|||
|
auto real_type{static_cast<nbt_type>(impl::swapper::byte_as_type<std::uint8_t>(this->impl_document.source))};
|
|||
|
if (real_type != tag_type)
|
|||
|
{
|
|||
|
throw nbt_type_error{.is = real_type, .as = tag_type};
|
|||
|
}
|
|||
|
if constexpr (tag_type == nbt_type::tag_list)
|
|||
|
{
|
|||
|
auto list_type{
|
|||
|
static_cast<nbt_type>(impl::swapper::byte_as_type<std::uint8_t>(
|
|||
|
this->impl_document.source + sizeof(std::uint8_t) + sizeof(std::uint16_t) +
|
|||
|
impl::swapper::byte_as_type<std::uint16_t>(
|
|||
|
this->impl_document.source + sizeof(std::uint8_t))))};
|
|||
|
if (list_type != list_element_type)
|
|||
|
{
|
|||
|
throw nbt_type_error{.is = list_type, .as = list_element_type};
|
|||
|
}
|
|||
|
}
|
|||
|
nbt_any_tag<tag_type, list_element_type> tag{};
|
|||
|
tag.impl_any_tag = impl::nbt_document_function::nbt_document_root_value(std::addressof(this->impl_document));
|
|||
|
return tag.get();
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
template<bool in_place = true, bool bound_check = false, std::endian nbt_endian = std::endian::big, impl::swapper::read_swapper rswap = impl::swapper::default_read_swapper>
|
|||
|
[[nodiscard]] auto read(std::span<std::byte, std::dynamic_extent> source) -> nbt_document
|
|||
|
{
|
|||
|
nbt_document doc{};
|
|||
|
doc.impl_document = impl::read_write::read<in_place, bound_check, nbt_endian, rswap>(source.data(), source.size());
|
|||
|
return doc;
|
|||
|
}
|
|||
|
} // namespace na::nbt
|