28class CompoundTagVariant {
45 using Variant = Types::to<::std::variant>;
46 using string_t = std::string;
51 using iterator_category = std::bidirectional_iterator_tag;
52 using difference_type = ptrdiff_t;
53 using value_type =
Tag;
54 using reference = std::conditional_t<Const, value_type const, value_type>&;
55 using pointer = std::add_pointer_t<reference>;
59 std::variant<CompoundTagVariant const*, CompoundTag::const_iterator, ListTag::const_iterator>,
60 std::variant<CompoundTagVariant*, CompoundTag::iterator, ListTag::iterator>>
63 static Iterator makeBegin(
auto& var)
noexcept {
65 switch (var.index()) {
67 res.iter.template emplace<2>(var.template get<ListTag>().begin());
70 res.iter.template emplace<1>(var.template get<CompoundTag>().begin());
73 res.iter.template emplace<0>(std::addressof(var) + 1);
76 res.iter.template emplace<0>(std::addressof(var));
81 static Iterator makeEnd(
auto& var)
noexcept {
83 switch (var.index()) {
85 res.iter.template emplace<2>(var.template get<ListTag>().end());
88 res.iter.template emplace<1>(var.template get<CompoundTag>().end());
91 res.iter.template emplace<0>(std::addressof(var) + 1);
96 [[nodiscard]] reference operator*()
const noexcept {
97 switch (iter.index()) {
99 return std::get<0>(iter)->get();
101 return std::get<1>(iter)->second.get();
103 return *std::get<2>(iter)->get();
110 [[nodiscard]] pointer operator->()
const noexcept {
return std::addressof(**
this); }
113 std::visit([](
auto& val) { ++val; }, iter);
124 std::visit([](
auto& val) { --val; }, iter);
134 [[nodiscard]]
bool operator==(
Iterator const& r)
const noexcept {
return this->iter == r.iter; }
145 LLNDAPI
static ll::Expected<CompoundTagVariant>
148 [[nodiscard]]
constexpr CompoundTagVariant() =
default;
150 [[nodiscard]]
constexpr CompoundTagVariant(CompoundTagVariant&&) =
default;
152 LL_MAY_CONSTEXPR CompoundTagVariant& operator=(CompoundTagVariant&&) =
default;
154 [[nodiscard]]
constexpr CompoundTagVariant(CompoundTagVariant
const&) =
default;
156 LL_MAY_CONSTEXPR CompoundTagVariant& operator=(CompoundTagVariant
const&) =
default;
159 requires(
requires(T o) { mTagStorage = std::move(o); })
161 mTagStorage = std::move(other);
165 [[nodiscard]]
constexpr CompoundTagVariant(std::nullptr_t) {}
167 [[nodiscard]]
bool operator==(CompoundTagVariant
const& other)
const {
return get() == other.get(); }
169 [[nodiscard]] CompoundTagVariant(Variant tag) : mTagStorage(std::move(tag)) {}
171 template <
class T,
class... Args>
172 [[nodiscard]]
constexpr CompoundTagVariant(std::in_place_type_t<T>, Args&&... args)
173 : mTagStorage(std::in_place_type<T>, std::forward<Args>(args)...) {}
175 [[nodiscard]]
constexpr CompoundTagVariant(std::initializer_list<CompoundTag::TagMap::value_type> tagPairs)
176 : mTagStorage(std::in_place_type<CompoundTag>, tagPairs) {}
178 [[nodiscard]] CompoundTagVariant(UniqueTagPtr&& tag) {
182 ::ll::meta::visitIndex<Types::size>(
static_cast<size_t>(tag->getId()), [&]<
size_t I> {
183 mTagStorage = std::move((Types::get<I>&)*tag);
186 [[nodiscard]] CompoundTagVariant(UniqueTagPtr
const& tag) : CompoundTagVariant(tag ? tag->copy() : nullptr) {}
187 template <std::derived_from<Tag> T>
188 [[nodiscard]]
constexpr CompoundTagVariant(T tag) : mTagStorage(std::move(tag)) {}
189 template <std::
integral T>
190 [[nodiscard]]
constexpr CompoundTagVariant(T integer) {
191 constexpr size_t size =
sizeof(T);
192 if constexpr (size == 1) {
193 mTagStorage = ByteTag{integer};
194 }
else if constexpr (size == 2) {
195 mTagStorage = ShortTag{integer};
196 }
else if constexpr (size == 4) {
197 mTagStorage = IntTag{integer};
199 mTagStorage = Int64Tag{integer};
202 [[nodiscard]] CompoundTagVariant(std::byte b) : mTagStorage(ByteTag{b}) {}
204 [[nodiscard]] CompoundTagVariant(
float f) : mTagStorage(FloatTag{f}) {}
206 [[nodiscard]] CompoundTagVariant(
double d) : mTagStorage(DoubleTag{d}) {}
208 [[nodiscard]]
constexpr CompoundTagVariant(std::string s)
209 : mTagStorage(std::in_place_type<StringTag>, std::move(s)) {}
211 [[nodiscard]]
constexpr CompoundTagVariant(std::string_view s) : mTagStorage(std::in_place_type<StringTag>, s) {}
214 [[nodiscard]]
constexpr CompoundTagVariant(
char const (&str)[N])
215 : CompoundTagVariant(std::string_view{str, N - 1}) {}
217 [[nodiscard]] iterator begin() noexcept {
return iterator::makeBegin(*
this); }
218 [[nodiscard]] const_iterator begin() const noexcept {
return cbegin(); }
219 [[nodiscard]] const_iterator cbegin() const noexcept {
return const_iterator::makeBegin(*
this); }
221 [[nodiscard]] iterator end() noexcept {
return iterator::makeEnd(*
this); }
222 [[nodiscard]] const_iterator end() const noexcept {
return cend(); }
223 [[nodiscard]] const_iterator cend() const noexcept {
return const_iterator::makeEnd(*
this); }
225 [[nodiscard]]
constexpr Tag::Type index() const noexcept {
return Tag::Type(mTagStorage.index()); }
226 [[nodiscard]]
constexpr Tag::Type getId() const noexcept {
return index(); }
228 template <std::derived_from<Tag> T>
229 [[nodiscard]]
constexpr bool hold() const noexcept {
230 return std::holds_alternative<T>(mTagStorage);
232 [[nodiscard]]
constexpr bool hold(::Tag::Type type)
const noexcept {
return getId() == type; }
235 [[nodiscard]]
constexpr bool is_array() const noexcept {
return hold(Tag::List); }
236 [[nodiscard]]
constexpr bool is_binary() const noexcept {
return hold(Tag::ByteArray) || hold(Tag::IntArray); }
237 [[nodiscard]]
constexpr bool is_boolean() const noexcept {
return hold(Tag::Byte); }
238 [[nodiscard]]
constexpr bool is_null() const noexcept {
return hold(Tag::End); }
239 [[nodiscard]]
constexpr bool is_number_float() const noexcept {
return hold(Tag::Float) || hold(Tag::Double); }
240 [[nodiscard]]
constexpr bool is_number_integer() const noexcept {
241 return hold(Tag::Byte) || hold(Tag::Short) || hold(Tag::Int) || hold(Tag::Int64);
243 [[nodiscard]]
constexpr bool is_number_signed() const noexcept {
return is_number_integer(); }
244 [[nodiscard]]
constexpr bool is_number_unsigned() const noexcept {
return false; }
245 [[nodiscard]]
constexpr bool is_object() const noexcept {
return hold(Tag::Compound); }
246 [[nodiscard]]
constexpr bool is_string() const noexcept {
return hold(Tag::String); }
247 [[nodiscard]]
constexpr bool is_number() const noexcept {
return is_number_float() || is_number_integer(); }
248 [[nodiscard]]
constexpr bool is_primitive() const noexcept {
249 return is_null() || is_string() || is_number() || is_binary();
251 [[nodiscard]]
constexpr bool is_structured() const noexcept {
return is_array() || is_object(); }
253 [[nodiscard]]
constexpr std::string_view type_name() const noexcept {
254 if (is_null())
return "null";
255 if (is_object())
return "object";
256 if (is_array())
return "array";
257 if (is_string())
return "string";
258 if (is_boolean())
return "boolean";
259 if (is_number())
return "number";
260 if (is_binary())
return "binary";
264 [[nodiscard]]
constexpr CompoundTag::TagMap
const& items()
const {
return get<CompoundTag>().mTags; }
265 [[nodiscard]]
constexpr CompoundTag::TagMap& items() {
return get<CompoundTag>().mTags; }
267 [[nodiscard]]
bool contains(std::string_view key)
const noexcept {
269 return get<CompoundTag>().contains(key);
274 [[nodiscard]]
bool contains(std::string_view key, Tag::Type type)
const noexcept {
276 return get<CompoundTag>().contains(key, type);
281 template <std::derived_from<Tag> T>
282 [[nodiscard]]
bool contains(std::string_view key)
const noexcept {
283 constexpr size_t idx = Types::index<T>;
284 return contains(key, (Tag::Type)idx);
287 [[nodiscard]]
constexpr size_t size() const noexcept {
298 return get<ListTag>().size();
300 return get<CompoundTag>().size();
302 return get<IntArrayTag>().size();
304 return get<ByteArrayTag>().size();
312 template <std::derived_from<Tag> T>
313 [[nodiscard]]
constexpr T& get() {
314 return std::get<T>(mTagStorage);
317 template <std::derived_from<Tag> T>
318 [[nodiscard]]
constexpr T
const& get()
const {
319 return std::get<T>(mTagStorage);
323 [[nodiscard]]
constexpr Ref get_ref() &
324 requires(std::same_as<Ref, string_t&>)
326 return static_cast<string_t&
>(get<StringTag>());
330 [[nodiscard]]
constexpr Ref get_ref() const&
331 requires(std::same_as<Ref, string_t const&>)
333 return static_cast<string_t const&
>(get<StringTag>());
337 requires(std::is_arithmetic_v<T> && !ll::traits::is_char_v<T>)
338 [[nodiscard]]
constexpr T get()
const {
339 return static_cast<T
>(*this);
342 [[nodiscard]] Tag& get() {
return reinterpret_cast<Tag&
>(mTagStorage); }
344 [[nodiscard]] Tag
const& get()
const {
return reinterpret_cast<Tag const&
>(mTagStorage); }
346 template <std::derived_from<Tag> T>
347 constexpr T& emplace() {
348 return mTagStorage.emplace<T>();
351 [[nodiscard]] UniqueTagPtr& operator[](
size_t index) {
352 if (hold(Tag::List)) {
353 return get<ListTag>()[index];
355 throw std::runtime_error(
"tag not hold an array");
359 [[nodiscard]] UniqueTagPtr
const& operator[](
size_t index)
const {
360 if (hold(Tag::List)) {
361 return get<ListTag>()[index];
363 throw std::runtime_error(
"tag not hold an array");
367 [[nodiscard]] CompoundTagVariant& operator[](std::string_view index) {
369 mTagStorage = CompoundTag{};
371 if (!hold(Tag::Compound)) {
372 throw std::runtime_error(
"tag not hold an object");
374 return get<CompoundTag>()[index];
377 [[nodiscard]] CompoundTagVariant
const& operator[](std::string_view index)
const {
378 if (!hold(Tag::Compound)) {
379 throw std::runtime_error(
"tag not hold an object");
381 return get<CompoundTag>()[index];
385 [[nodiscard]] CompoundTagVariant& operator[](
char const (&index)[N]) {
386 return operator[](std::string_view{index, N - 1});
390 [[nodiscard]] CompoundTagVariant
const& operator[](
char const (&index)[N])
const {
391 return operator[](std::string_view{index, N - 1});
394 [[nodiscard]] UniqueTagPtr toUniqueCopy() const& {
396 [](
auto& val) -> std::unique_ptr<Tag> {
return std::make_unique<std::decay_t<
decltype(val)>>(val); },
401 [[nodiscard]] UniqueTagPtr toUnique() && {
403 [](
auto&& val) -> std::unique_ptr<Tag> {
404 return std::make_unique<std::decay_t<
decltype(val)>>(std::move(val));
410 LLNDAPI std::string toSnbt(SnbtFormat snbtFormat = SnbtFormat::PrettyFilePrint, uchar indent = 4) const noexcept;
412 std::
string dump(uchar indent = 4, SnbtFormat snbtFormat = SnbtFormat::PrettyFilePrint) const noexcept {
413 return toSnbt(snbtFormat, indent);
416 void push_back(CompoundTagVariant val) {
418 mTagStorage = ListTag{};
420 if (!hold(Tag::List)) {
421 throw std::runtime_error(
"tag not hold an array");
423 get<ListTag>().add(std::move(val).toUnique());
427 requires(std::is_arithmetic_v<T> && !ll::traits::is_char_v<T>)
428 [[nodiscard]]
constexpr operator T()
const {
432 if constexpr (std::is_convertible_v<std::decay_t<
decltype(val)>, T>) {
441 throw std::runtime_error(
"tag not hold an number");
444 [[nodiscard]]
operator std::string
const&()
const {
return get<StringTag>(); }
445 [[nodiscard]]
operator std::string&() {
return get<StringTag>(); }
446 [[nodiscard]]
operator std::string&&() && {
return std::move(get<StringTag>()); }
447 [[nodiscard]]
operator std::string_view()
const {
return get<StringTag>(); }
448 static CompoundTagVariant object(std::initializer_list<CompoundTag::TagMap::value_type> init = {}) {
449 return CompoundTagVariant{std::in_place_type<CompoundTag>, init};
451 static CompoundTagVariant array(std::initializer_list<CompoundTagVariant> init = {}) {
452 return CompoundTagVariant{std::in_place_type<ListTag>, init};