LeviLamina
Loading...
Searching...
No Matches
CompoundTagVariant.h
1#pragma once
2
3#include "mc/_HeaderOutputPredefine.h"
4#include "mc/nbt/ByteArrayTag.h"
5#include "mc/nbt/ByteTag.h"
6#include "mc/nbt/CompoundTag.h"
7#include "mc/nbt/DoubleTag.h"
8#include "mc/nbt/EndTag.h"
9#include "mc/nbt/FloatTag.h"
10#include "mc/nbt/Int64Tag.h"
11#include "mc/nbt/IntArrayTag.h"
12#include "mc/nbt/IntTag.h"
13#include "mc/nbt/ListTag.h"
14#include "mc/nbt/ShortTag.h"
15#include "mc/nbt/StringTag.h"
16
17#include "ll/api/Expected.h"
18#include "ll/api/base/Concepts.h"
19#include "ll/api/base/Meta.h"
20
21// auto generated forward declare list
22// clang-format off
23class ByteArrayTag;
24class ByteTag;
25class CompoundTag;
26class DoubleTag;
27class EndTag;
28class FloatTag;
29class Int64Tag;
30class IntArrayTag;
31class IntTag;
32class ListTag;
33class ShortTag;
34class StringTag;
35class Tag;
36// clang-format on
37
39public:
40 // CompoundTagVariant inner types define
54
55 using Variant = Types::to<::std::variant>;
56
57 template <bool Const>
58 class Iterator {
59 public:
60 using iterator_category = std::bidirectional_iterator_tag;
61 using difference_type = ptrdiff_t;
62 using value_type = Tag;
63 using reference = std::conditional_t<Const, value_type const, value_type>&;
64 using pointer = std::add_pointer_t<reference>;
65
66 std::conditional_t<
67 Const,
68 std::variant<CompoundTagVariant const*, CompoundTag::const_iterator, ListTag::const_iterator>,
69 std::variant<CompoundTagVariant*, CompoundTag::iterator, ListTag::iterator>>
70 iter;
71
72 static Iterator makeBegin(auto& var) noexcept {
73 Iterator res;
74 switch (var.index()) {
75 case Tag::List:
76 res.iter.emplace<2>(var.get<ListTag>().begin());
77 break;
78 case Tag::Compound:
79 res.iter.emplace<1>(var.get<CompoundTag>().begin());
80 break;
81 case Tag::End:
82 res.iter.emplace<0>(std::addressof(var) + 1);
83 break;
84 default:
85 res.iter.emplace<0>(std::addressof(var));
86 }
87 return res;
88 }
89
90 static Iterator makeEnd(auto& var) noexcept {
91 Iterator res;
92 switch (var.index()) {
93 case Tag::List:
94 res.iter.emplace<2>(var.get<ListTag>().end());
95 break;
96 case Tag::Compound:
97 res.iter.emplace<1>(var.get<CompoundTag>().end());
98 break;
99 default:
100 res.iter.emplace<0>(std::addressof(var) + 1);
101 }
102 return res;
103 }
104
105 [[nodiscard]] reference operator*() const noexcept {
106 switch (iter.index()) {
107 case 0:
108 return std::get<0>(iter)->get();
109 case 1:
110 return std::get<1>(iter)->second.get();
111 case 2:
112 return *std::get<2>(iter)->get();
113 default:
114 LL_UNREACHABLE;
115 }
116 LL_UNREACHABLE;
117 }
118
119 [[nodiscard]] pointer operator->() const noexcept { return std::addressof(**this); }
120
121 Iterator& operator++() noexcept {
122 std::visit([](auto& val) { ++val; }, iter);
123 return *this;
124 }
125
126 Iterator operator++(int) noexcept {
127 Iterator tmp = *this;
128 ++*this;
129 return tmp;
130 }
131
132 Iterator& operator--() noexcept {
133 std::visit([](auto& val) { --val; }, iter);
134 return *this;
135 }
136
137 Iterator operator--(int) noexcept {
138 Iterator tmp = *this;
139 --*this;
140 return tmp;
141 }
142
143 [[nodiscard]] bool operator==(Iterator const& r) const noexcept { return this->iter == r.iter; }
144 };
145
148
149public:
150 // member variables
151 Variant mTagStorage;
152
153public:
154 // destructor thunk
155 // NOLINTBEGIN
156 MCFOLD void $dtor();
157 // NOLINTEND
158
159public:
160 LLNDAPI static ll::Expected<CompoundTagVariant>
161 parse(std::string_view snbt, optional_ref<size_t> parsedLength = std::nullopt) noexcept;
162
163 [[nodiscard]] constexpr CompoundTagVariant() = default;
164
165 [[nodiscard]] constexpr CompoundTagVariant(CompoundTagVariant&&) = default;
166
167 LL_MAY_CONSTEXPR CompoundTagVariant& operator=(CompoundTagVariant&&) = default;
168
169 [[nodiscard]] constexpr CompoundTagVariant(CompoundTagVariant const&) = default;
170
171 LL_MAY_CONSTEXPR CompoundTagVariant& operator=(CompoundTagVariant const&) = default;
172
173 template <class T>
174 requires(requires(T o) { mTagStorage = std::move(o); })
175 constexpr CompoundTagVariant& operator=(T other) {
176 mTagStorage = std::move(other);
177 return *this;
178 }
179
180 [[nodiscard]] constexpr CompoundTagVariant(std::nullptr_t) {}
181
182 [[nodiscard]] bool operator==(CompoundTagVariant const& other) const { return get() == other.get(); }
183
184 [[nodiscard]] CompoundTagVariant(Variant tag) : mTagStorage(std::move(tag)) {}
185
186 template <class T, class... Args>
187 [[nodiscard]] constexpr CompoundTagVariant(std::in_place_type_t<T>, Args&&... args)
188 : mTagStorage(std::in_place_type<T>, std::forward<Args>(args)...) {}
189
190 [[nodiscard]] constexpr CompoundTagVariant(std::initializer_list<CompoundTag::TagMap::value_type> tagPairs)
191 : mTagStorage(std::in_place_type<CompoundTag>, tagPairs) {}
192
193 [[nodiscard]] CompoundTagVariant(UniqueTagPtr&& tag) {
194 if (!tag) {
195 return;
196 }
197 ::ll::meta::visitIndex<Types::size>(static_cast<size_t>(tag->getId()), [&]<size_t I> {
198 mTagStorage = std::move((Types::get<I>&)*tag);
199 });
200 }
201 [[nodiscard]] CompoundTagVariant(UniqueTagPtr const& tag) : CompoundTagVariant(tag ? tag->copy() : nullptr) {}
202 template <std::derived_from<Tag> T>
203 [[nodiscard]] constexpr CompoundTagVariant(T tag) : mTagStorage(std::move(tag)) {}
204 template <std::integral T>
205 [[nodiscard]] constexpr CompoundTagVariant(T integer) {
206 constexpr size_t size = sizeof(T);
207 if constexpr (size == 1) {
208 mTagStorage = ByteTag{integer};
209 } else if constexpr (size == 2) {
210 mTagStorage = ShortTag{integer};
211 } else if constexpr (size == 4) {
212 mTagStorage = IntTag{integer};
213 } else {
214 mTagStorage = Int64Tag{integer};
215 }
216 }
217 [[nodiscard]] constexpr CompoundTagVariant(std::byte b) : mTagStorage(ByteTag{b}) {}
218
219 [[nodiscard]] constexpr CompoundTagVariant(float f) : mTagStorage(FloatTag{f}) {}
220
221 [[nodiscard]] constexpr CompoundTagVariant(double d) : mTagStorage(DoubleTag{d}) {}
222
223 [[nodiscard]] constexpr CompoundTagVariant(std::string s)
224 : mTagStorage(std::in_place_type<StringTag>, std::move(s)) {}
225
226 [[nodiscard]] constexpr CompoundTagVariant(std::string_view s) : mTagStorage(std::in_place_type<StringTag>, s) {}
227
228 template <size_t N>
229 [[nodiscard]] constexpr CompoundTagVariant(char const (&str)[N])
230 : CompoundTagVariant(std::string_view{str, N - 1}) {}
231
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); }
235
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); }
239
240 [[nodiscard]] constexpr Tag::Type index() const noexcept { return Tag::Type(mTagStorage.index()); }
241 [[nodiscard]] constexpr Tag::Type getId() const noexcept { return index(); }
242
243 template <std::derived_from<Tag> T>
244 [[nodiscard]] constexpr bool hold() const noexcept {
245 return std::holds_alternative<T>(mTagStorage);
246 }
247 [[nodiscard]] constexpr bool hold(::Tag::Type type) const noexcept { return getId() == type; }
248
249 // consistency with json
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);
257 }
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();
263 }
264 [[nodiscard]] constexpr bool is_structured() const noexcept { return is_array() || is_object(); }
265
266 [[nodiscard]] constexpr CompoundTag::TagMap const& items() const { return get<CompoundTag>().mTags; }
267 [[nodiscard]] constexpr CompoundTag::TagMap& items() { return get<CompoundTag>().mTags; }
268
269 [[nodiscard]] bool contains(std::string_view key) const noexcept {
270 if (is_object()) {
271 return get<CompoundTag>().contains(key);
272 }
273 return false;
274 }
275
276 [[nodiscard]] bool contains(std::string_view key, Tag::Type type) const noexcept {
277 if (is_object()) {
278 return get<CompoundTag>().contains(key, type);
279 }
280 return false;
281 }
282
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);
287 }
288
289 [[nodiscard]] constexpr size_t size() const noexcept {
290 switch (index()) {
291 case Tag::Byte:
292 case Tag::Short:
293 case Tag::Int:
294 case Tag::Int64:
295 case Tag::Float:
296 case Tag::Double:
297 case Tag::String:
298 return 1;
299 case Tag::List:
300 return get<ListTag>().size();
301 case Tag::Compound:
302 return get<CompoundTag>().size();
303 case Tag::IntArray:
304 return get<IntArrayTag>().size();
305 case Tag::ByteArray:
306 return get<ByteArrayTag>().size();
307 case Tag::End:
308 return 0;
309 default:
310 LL_UNREACHABLE;
311 }
312 }
313
314 template <std::derived_from<Tag> T>
315 [[nodiscard]] constexpr T& get() {
316 return std::get<T>(mTagStorage);
317 }
318
319 template <std::derived_from<Tag> T>
320 [[nodiscard]] constexpr T const& get() const {
321 return std::get<T>(mTagStorage);
322 }
323
324 [[nodiscard]] Tag& get() { return reinterpret_cast<Tag&>(mTagStorage); }
325
326 [[nodiscard]] Tag const& get() const { return reinterpret_cast<Tag const&>(mTagStorage); }
327
328 template <std::derived_from<Tag> T>
329 constexpr T& emplace() {
330 return mTagStorage.emplace<T>();
331 }
332
333 [[nodiscard]] UniqueTagPtr& operator[](size_t index) {
334 if (hold(Tag::List)) {
335 return get<ListTag>()[index];
336 } else {
337 throw std::runtime_error("tag not hold an array");
338 }
339 }
340
341 [[nodiscard]] UniqueTagPtr const& operator[](size_t index) const {
342 if (hold(Tag::List)) {
343 return get<ListTag>()[index];
344 } else {
345 throw std::runtime_error("tag not hold an array");
346 }
347 }
348
349 [[nodiscard]] CompoundTagVariant& operator[](std::string_view index) {
350 if (is_null()) {
351 mTagStorage = CompoundTag{};
352 }
353 if (!hold(Tag::Compound)) {
354 throw std::runtime_error("tag not hold an object");
355 }
356 return get<CompoundTag>()[index];
357 }
358
359 [[nodiscard]] CompoundTagVariant const& operator[](std::string_view index) const {
360 if (!hold(Tag::Compound)) {
361 throw std::runtime_error("tag not hold an object");
362 }
363 return get<CompoundTag>()[index];
364 }
365
366 template <size_t N>
367 [[nodiscard]] CompoundTagVariant& operator[](char const (&index)[N]) { // make EDG happy
368 return operator[](std::string_view{index, N - 1});
369 }
370
371 template <size_t N>
372 [[nodiscard]] CompoundTagVariant const& operator[](char const (&index)[N]) const { // make EDG happy
373 return operator[](std::string_view{index, N - 1});
374 }
375
376 [[nodiscard]] UniqueTagPtr toUniqueCopy() const& {
377 return std::visit(
378 [](auto& val) -> std::unique_ptr<Tag> { return std::make_unique<std::decay_t<decltype(val)>>(val); },
379 mTagStorage
380 );
381 }
382
383 [[nodiscard]] UniqueTagPtr toUnique() && {
384 return std::visit(
385 [](auto&& val) -> std::unique_ptr<Tag> {
386 return std::make_unique<std::decay_t<decltype(val)>>(std::move(val));
387 },
388 mTagStorage
389 );
390 }
391
392 LLNDAPI std::string toSnbt(SnbtFormat snbtFormat = SnbtFormat::PrettyFilePrint, uchar indent = 4) const noexcept;
393
394 std::string dump(uchar indent = 4, SnbtFormat snbtFormat = SnbtFormat::PrettyFilePrint) const noexcept {
395 return toSnbt(snbtFormat, indent);
396 }
397
398 void push_back(CompoundTagVariant val) {
399 if (is_null()) {
400 mTagStorage = ListTag{};
401 }
402 if (!hold(Tag::List)) {
403 throw std::runtime_error("tag not hold an array");
404 }
405 get<ListTag>().add(std::move(val).toUnique());
406 }
407
408 template <class T>
409 requires(std::is_arithmetic_v<T> && !ll::traits::is_char_v<T>)
410 [[nodiscard]] constexpr operator T() const {
411 if (is_number()) {
412 return std::visit(
413 [](auto& val) -> T {
414 if constexpr (std::is_convertible_v<std::decay_t<decltype(val)>, T>) {
415 return (T)val;
416 } else {
417 return {};
418 }
419 },
420 mTagStorage
421 );
422 } else {
423 throw std::runtime_error("tag not hold an number");
424 }
425 }
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 = {}) {
431 return CompoundTagVariant{std::in_place_type<CompoundTag>, init};
432 }
433 static CompoundTagVariant array(std::initializer_list<CompoundTagVariant> init = {}) {
434 return CompoundTagVariant{std::in_place_type<ListTag>, init};
435 }
436};
437
438[[nodiscard]] inline auto CompoundTag::begin() noexcept { return mTags.begin(); }
439[[nodiscard]] inline auto CompoundTag::begin() const noexcept { return mTags.begin(); }
440[[nodiscard]] inline auto CompoundTag::end() noexcept { return mTags.end(); }
441[[nodiscard]] inline auto CompoundTag::end() const noexcept { return mTags.end(); }
442[[nodiscard]] inline auto CompoundTag::rbegin() noexcept { return mTags.rbegin(); }
443[[nodiscard]] inline auto CompoundTag::rbegin() const noexcept { return mTags.rbegin(); }
444[[nodiscard]] inline auto CompoundTag::rend() noexcept { return mTags.rend(); }
445[[nodiscard]] inline auto CompoundTag::rend() const noexcept { return mTags.rend(); }
446[[nodiscard]] inline auto CompoundTag::cbegin() const noexcept { return mTags.cbegin(); }
447[[nodiscard]] inline auto CompoundTag::cend() const noexcept { return mTags.cend(); }
448[[nodiscard]] inline auto CompoundTag::crbegin() const noexcept { return mTags.crbegin(); }
449[[nodiscard]] inline auto CompoundTag::crend() const noexcept { return mTags.crend(); }
450inline bool CompoundTag::erase(std::string_view name) {
451 if (auto it = mTags.find(name); it != mTags.end()) {
452 mTags.erase(it);
453 return true;
454 }
455 return false;
456}
457[[nodiscard]] inline CompoundTagVariant& CompoundTag::operator[](std::string_view index) {
458 if (auto it = mTags.find(index); it != mTags.end()) {
459 return it->second;
460 }
461 return mTags[std::string{index}];
462}
463[[nodiscard]] inline CompoundTagVariant const& CompoundTag::operator[](std::string_view index) const {
464 if (auto it = mTags.find(index); it != mTags.end()) {
465 return it->second;
466 }
467 throw std::out_of_range("invalid nbt key");
468}
469[[nodiscard]] inline void CompoundTag::rename(std::string_view name, std::string_view newName) {
470 if (auto it = mTags.find(name); it != mTags.end()) {
471 CompoundTagVariant tmp{std::move(it->second)};
472 mTags.erase(it);
473 mTags.try_emplace(std::string{newName}, std::move(tmp));
474 }
475}
476
477[[nodiscard]] constexpr ListTag::ListTag(std::vector<CompoundTagVariant> tags) {
478 if (tags.empty()) {
479 mType = Tag::End;
480 } else {
481 mType = tags.front().index();
482 reserve(tags.size());
483 for (auto& tag : tags) {
484 emplace_back(std::move(tag).toUnique());
485 }
486 }
487}
488[[nodiscard]] constexpr ListTag::ListTag(std::initializer_list<CompoundTagVariant> tags) {
489 if (tags.size() == 0) {
490 mType = Tag::End;
491 } else {
492 mType = tags.begin()->index();
493 reserve(tags.size());
494 for (auto& tag : tags) {
495 emplace_back(tag.toUniqueCopy());
496 }
497 }
498}
499[[nodiscard]] inline bool operator==(UniqueTagPtr const& l, CompoundTagVariant const& r) {
500 return l ? (*l == r.get()) : false;
501}
502[[nodiscard]] inline bool operator==(CompoundTagVariant const& l, UniqueTagPtr const& r) {
503 return r ? (l.get() == *r) : false;
504}
505
506[[nodiscard]] inline UniqueTagPtr::UniqueTagPtr(CompoundTagVariant&& r) : ptr(std::move(r).toUnique().release()) {}
507
508[[nodiscard]] inline UniqueTagPtr::UniqueTagPtr(CompoundTagVariant const& r) : ptr(r.toUniqueCopy().release()) {}
509
510inline UniqueTagPtr& UniqueTagPtr::operator=(CompoundTagVariant&& r) {
511 reset(std::move(r).toUnique().release());
512 return *this;
513}
514inline UniqueTagPtr& UniqueTagPtr::operator=(CompoundTagVariant const& r) {
515 reset(r.toUniqueCopy().release());
516 return *this;
517}
518
519template <std::derived_from<Tag> T>
520[[nodiscard]] inline T& UniqueTagPtr::get() const {
521 if (hold<T>()) {
522 return *static_cast<T*>(ptr);
523 }
524 throw std::runtime_error("not the expected type");
525}
526[[nodiscard]] inline bool UniqueTagPtr::contains(std::string_view key) const noexcept {
527 if (is_object()) {
528 return get<CompoundTag>().contains(key);
529 }
530 return false;
531}
532[[nodiscard]] inline bool UniqueTagPtr::contains(std::string_view key, Tag::Type type) const noexcept {
533 if (is_object()) {
534 return get<CompoundTag>().contains(key, type);
535 }
536 return false;
537}
538[[nodiscard]] inline size_t UniqueTagPtr::size() const noexcept {
539 switch (index()) {
540 case Tag::Byte:
541 case Tag::Short:
542 case Tag::Int:
543 case Tag::Int64:
544 case Tag::Float:
545 case Tag::Double:
546 case Tag::String:
547 return 1;
548 case Tag::List:
549 return get<ListTag>().size();
550 case Tag::Compound:
551 return get<CompoundTag>().size();
552 case Tag::IntArray:
553 return get<IntArrayTag>().size();
554 case Tag::ByteArray:
555 return get<ByteArrayTag>().size();
556 case Tag::End:
557 return 0;
558 default:
559 LL_UNREACHABLE;
560 }
561}
562[[nodiscard]] inline UniqueTagPtr::operator std::string const&() const { return get<StringTag>(); }
563[[nodiscard]] inline UniqueTagPtr::operator std::string&() & { return get<StringTag>(); }
564[[nodiscard]] inline UniqueTagPtr::operator std::string&&() && { return std::move(get<StringTag>()); }
565[[nodiscard]] inline UniqueTagPtr::operator std::string_view() const { return get<StringTag>(); }
566
567[[nodiscard]] inline UniqueTagPtr& UniqueTagPtr::operator[](size_t index) {
568 if (hold(Tag::List)) {
569 return get<ListTag>()[index];
570 } else {
571 throw std::runtime_error("tag not hold an array");
572 }
573}
574[[nodiscard]] inline UniqueTagPtr const& UniqueTagPtr::operator[](size_t index) const {
575 if (hold(Tag::List)) {
576 return get<ListTag>()[index];
577 } else {
578 throw std::runtime_error("tag not hold an array");
579 }
580}
581[[nodiscard]] inline CompoundTagVariant& UniqueTagPtr::operator[](std::string_view index) {
582 if (is_null()) {
583 emplace<CompoundTag>();
584 }
585 if (!hold(Tag::Compound)) {
586 throw std::runtime_error("tag not hold an object");
587 }
588 return get<CompoundTag>()[index];
589}
590[[nodiscard]] inline CompoundTagVariant const& UniqueTagPtr::operator[](std::string_view index) const {
591 if (!hold(Tag::Compound)) {
592 throw std::runtime_error("tag not hold an object");
593 }
594 return get<CompoundTag>()[index];
595}
596template <class T>
597 requires(std::is_arithmetic_v<T> && !ll::traits::is_char_v<T>)
598[[nodiscard]] inline UniqueTagPtr::operator T() const {
599 if (is_number()) {
600 return ll::meta::visitIndex<CompoundTagVariant::Types::size>((size_t)getId(), [&]<size_t I>() -> T {
601 auto& val = *static_cast<CompoundTagVariant::Types::get<I>*>(ptr);
602 if constexpr (std::is_convertible_v<std::decay_t<decltype(val)>, T>) {
603 return (T)val;
604 } else {
605 return {};
606 }
607 });
608 } else {
609 throw std::runtime_error("tag not hold an number");
610 }
611}
Definition ByteArrayTag.h:9
Definition ByteTag.h:9
Definition CompoundTagVariant.h:58
Definition CompoundTagVariant.h:38
Definition CompoundTag.h:13
Definition DoubleTag.h:9
Definition EndTag.h:9
Definition FloatTag.h:9
Definition Int64Tag.h:9
Definition IntArrayTag.h:9
Definition IntTag.h:9
Definition ListTag.h:12
Definition ShortTag.h:9
Definition StringTag.h:9
Definition Tag.h:39
Definition UniqueTagPtr.h:22
Definition Meta.h:197
Definition optional_ref.h:10
STL namespace.