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