55 using Variant = Types::to<::std::variant>;
60 using iterator_category = std::bidirectional_iterator_tag;
61 using difference_type = ptrdiff_t;
63 using reference = std::conditional_t<Const, value_type const, value_type>&;
64 using pointer = std::add_pointer_t<reference>;
68 std::variant<CompoundTagVariant const*, CompoundTag::const_iterator, ListTag::const_iterator>,
69 std::variant<CompoundTagVariant*, CompoundTag::iterator, ListTag::iterator>>
72 static Iterator makeBegin(
auto& var)
noexcept {
74 switch (var.index()) {
76 res.iter.emplace<2>(var.get<
ListTag>().begin());
79 res.iter.emplace<1>(var.get<
CompoundTag>().begin());
82 res.iter.emplace<0>(std::addressof(var) + 1);
85 res.iter.emplace<0>(std::addressof(var));
90 static Iterator makeEnd(
auto& var)
noexcept {
92 switch (var.index()) {
94 res.iter.emplace<2>(var.get<
ListTag>().end());
100 res.iter.emplace<0>(std::addressof(var) + 1);
105 [[nodiscard]] reference operator*()
const noexcept {
106 switch (iter.index()) {
108 return std::get<0>(iter)->get();
110 return std::get<1>(iter)->second.get();
112 return *std::get<2>(iter)->get();
119 [[nodiscard]] pointer operator->()
const noexcept {
return std::addressof(**
this); }
122 std::visit([](
auto& val) { ++val; }, iter);
133 std::visit([](
auto& val) { --val; }, iter);
143 [[nodiscard]]
bool operator==(
Iterator const& r)
const noexcept {
return this->iter == r.iter; }
160 LLNDAPI
static ll::Expected<CompoundTagVariant>
174 requires(
requires(T o) { mTagStorage = std::move(o); })
176 mTagStorage = std::move(other);
182 [[nodiscard]]
bool operator==(
CompoundTagVariant const& other)
const {
return get() == other.get(); }
186 template <
class T,
class... Args>
188 : mTagStorage(
std::in_place_type<T>,
std::forward<Args>(args)...) {}
190 [[nodiscard]]
constexpr CompoundTagVariant(std::initializer_list<CompoundTag::TagMap::value_type> tagPairs)
197 ::ll::meta::visitIndex<Types::size>(
static_cast<size_t>(tag->getId()), [&]<
size_t I> {
198 mTagStorage = std::move((Types::get<I>&)*tag);
202 template <std::derived_from<Tag> T>
204 template <std::
integral T>
206 constexpr size_t size =
sizeof(T);
207 if constexpr (size == 1) {
208 mTagStorage =
ByteTag{integer};
209 }
else if constexpr (size == 2) {
211 }
else if constexpr (size == 4) {
212 mTagStorage =
IntTag{integer};
232 [[nodiscard]] iterator begin() noexcept {
return iterator::makeBegin(*
this); }
233 [[nodiscard]] const_iterator begin() const noexcept {
return cbegin(); }
234 [[nodiscard]] const_iterator cbegin() const noexcept {
return const_iterator::makeBegin(*
this); }
236 [[nodiscard]] iterator end() noexcept {
return iterator::makeEnd(*
this); }
237 [[nodiscard]] const_iterator end() const noexcept {
return cend(); }
238 [[nodiscard]] const_iterator cend() const noexcept {
return const_iterator::makeEnd(*
this); }
240 [[nodiscard]]
constexpr Tag::Type index() const noexcept {
return Tag::Type(mTagStorage.index()); }
241 [[nodiscard]]
constexpr Tag::Type getId() const noexcept {
return index(); }
243 template <std::derived_from<Tag> T>
244 [[nodiscard]]
constexpr bool hold() const noexcept {
245 return std::holds_alternative<T>(mTagStorage);
247 [[nodiscard]]
constexpr bool hold(::Tag::Type type)
const noexcept {
return getId() == type; }
250 [[nodiscard]]
constexpr bool is_array() const noexcept {
return hold(Tag::List); }
251 [[nodiscard]]
constexpr bool is_binary() const noexcept {
return hold(Tag::ByteArray) || hold(Tag::IntArray); }
252 [[nodiscard]]
constexpr bool is_boolean() const noexcept {
return hold(Tag::Byte); }
253 [[nodiscard]]
constexpr bool is_null() const noexcept {
return hold(Tag::End); }
254 [[nodiscard]]
constexpr bool is_number_float() const noexcept {
return hold(Tag::Float) || hold(Tag::Double); }
255 [[nodiscard]]
constexpr bool is_number_integer() const noexcept {
256 return hold(Tag::Byte) || hold(Tag::Short) || hold(Tag::Int) || hold(Tag::Int64);
258 [[nodiscard]]
constexpr bool is_object() const noexcept {
return hold(Tag::Compound); }
259 [[nodiscard]]
constexpr bool is_string() const noexcept {
return hold(Tag::String); }
260 [[nodiscard]]
constexpr bool is_number() const noexcept {
return is_number_float() || is_number_integer(); }
261 [[nodiscard]]
constexpr bool is_primitive() const noexcept {
262 return is_null() || is_string() || is_number() || is_binary();
264 [[nodiscard]]
constexpr bool is_structured() const noexcept {
return is_array() || is_object(); }
266 [[nodiscard]]
constexpr CompoundTag::TagMap
const& items()
const {
return get<CompoundTag>().mTags; }
267 [[nodiscard]]
constexpr CompoundTag::TagMap& items() {
return get<CompoundTag>().mTags; }
269 [[nodiscard]]
bool contains(std::string_view key)
const noexcept {
271 return get<CompoundTag>().contains(key);
276 [[nodiscard]]
bool contains(std::string_view key, Tag::Type type)
const noexcept {
278 return get<CompoundTag>().contains(key, type);
283 template <std::derived_from<Tag> T>
284 [[nodiscard]]
bool contains(std::string_view key)
const noexcept {
285 constexpr size_t idx = Types::index<T>;
286 return contains(key, (Tag::Type)idx);
289 [[nodiscard]]
constexpr size_t size() const noexcept {
300 return get<ListTag>().size();
302 return get<CompoundTag>().size();
304 return get<IntArrayTag>().size();
306 return get<ByteArrayTag>().size();
314 template <std::derived_from<Tag> T>
315 [[nodiscard]]
constexpr T& get() {
316 return std::get<T>(mTagStorage);
319 template <std::derived_from<Tag> T>
320 [[nodiscard]]
constexpr T
const& get()
const {
321 return std::get<T>(mTagStorage);
324 [[nodiscard]]
Tag& get() {
return reinterpret_cast<Tag&
>(mTagStorage); }
326 [[nodiscard]]
Tag const& get()
const {
return reinterpret_cast<Tag const&
>(mTagStorage); }
328 template <std::derived_from<Tag> T>
329 constexpr T& emplace() {
330 return mTagStorage.emplace<T>();
334 if (hold(Tag::List)) {
335 return get<ListTag>()[index];
337 throw std::runtime_error(
"tag not hold an array");
341 [[nodiscard]]
UniqueTagPtr const& operator[](
size_t index)
const {
342 if (hold(Tag::List)) {
343 return get<ListTag>()[index];
345 throw std::runtime_error(
"tag not hold an array");
353 if (!hold(Tag::Compound)) {
354 throw std::runtime_error(
"tag not hold an object");
356 return get<CompoundTag>()[index];
360 if (!hold(Tag::Compound)) {
361 throw std::runtime_error(
"tag not hold an object");
363 return get<CompoundTag>()[index];
368 return operator[](std::string_view{index, N - 1});
373 return operator[](std::string_view{index, N - 1});
378 [](
auto& val) -> std::unique_ptr<Tag> {
return std::make_unique<std::decay_t<
decltype(val)>>(val); },
385 [](
auto&& val) -> std::unique_ptr<Tag> {
386 return std::make_unique<std::decay_t<
decltype(val)>>(std::move(val));
392 LLNDAPI std::string toSnbt(SnbtFormat snbtFormat = SnbtFormat::PrettyFilePrint, uchar indent = 4) const noexcept;
394 std::
string dump(uchar indent = 4, SnbtFormat snbtFormat = SnbtFormat::PrettyFilePrint) const noexcept {
395 return toSnbt(snbtFormat, indent);
402 if (!hold(Tag::List)) {
403 throw std::runtime_error(
"tag not hold an array");
405 get<ListTag>().add(std::move(val).toUnique());
409 requires(std::is_arithmetic_v<T> && !ll::traits::is_char_v<T>)
410 [[nodiscard]]
constexpr operator T()
const {
414 if constexpr (std::is_convertible_v<std::decay_t<
decltype(val)>, T>) {
423 throw std::runtime_error(
"tag not hold an number");
426 [[nodiscard]]
operator std::string
const&()
const {
return get<StringTag>(); }
427 [[nodiscard]]
operator std::string&() {
return get<StringTag>(); }
428 [[nodiscard]]
operator std::string&&() && {
return std::move(get<StringTag>()); }
429 [[nodiscard]]
operator std::string_view()
const {
return get<StringTag>(); }
430 static CompoundTagVariant object(std::initializer_list<CompoundTag::TagMap::value_type> init = {}) {
433 static CompoundTagVariant array(std::initializer_list<CompoundTagVariant> init = {}) {