57 using Variant = Types::to<::std::variant>;
62 using iterator_category = std::bidirectional_iterator_tag;
63 using difference_type = ptrdiff_t;
65 using reference = std::conditional_t<Const, value_type const, value_type>&;
66 using pointer = std::add_pointer_t<reference>;
70 std::variant<CompoundTagVariant const*, CompoundTag::const_iterator, ListTag::const_iterator>,
71 std::variant<CompoundTagVariant*, CompoundTag::iterator, ListTag::iterator>>
74 static Iterator makeBegin(
auto& var)
noexcept {
76 switch (var.index()) {
78 res.iter.template emplace<2>(var.get<
ListTag>().begin());
81 res.iter.template emplace<1>(var.get<
CompoundTag>().begin());
84 res.iter.template emplace<0>(std::addressof(var) + 1);
87 res.iter.template emplace<0>(std::addressof(var));
92 static Iterator makeEnd(
auto& var)
noexcept {
94 switch (var.index()) {
96 res.iter.template emplace<2>(var.get<
ListTag>().end());
99 res.iter.template emplace<1>(var.get<
CompoundTag>().end());
102 res.iter.template emplace<0>(std::addressof(var) + 1);
107 [[nodiscard]] reference operator*()
const noexcept {
108 switch (iter.index()) {
110 return std::get<0>(iter)->get();
112 return std::get<1>(iter)->second.get();
114 return *std::get<2>(iter)->get();
121 [[nodiscard]] pointer operator->()
const noexcept {
return std::addressof(**
this); }
124 std::visit([](
auto& val) { ++val; }, iter);
135 std::visit([](
auto& val) { --val; }, iter);
145 [[nodiscard]]
bool operator==(
Iterator const& r)
const noexcept {
return this->iter == r.iter; }
162 LLNDAPI
static ll::Expected<CompoundTagVariant>
176 requires(
requires(T o) { mTagStorage = std::move(o); })
178 mTagStorage = std::move(other);
184 [[nodiscard]]
bool operator==(
CompoundTagVariant const& other)
const {
return get() == other.get(); }
188 template <
class T,
class... Args>
190 : mTagStorage(
std::in_place_type<T>,
std::forward<Args>(args)...) {}
192 [[nodiscard]]
constexpr CompoundTagVariant(std::initializer_list<CompoundTag::TagMap::value_type> tagPairs)
199 ::ll::meta::visitIndex<Types::size>(
static_cast<size_t>(tag->getId()), [&]<
size_t I> {
200 mTagStorage = std::move((Types::get<I>&)*tag);
204 template <std::derived_from<Tag> T>
206 template <std::
integral T>
208 constexpr size_t size =
sizeof(T);
209 if constexpr (size == 1) {
210 mTagStorage =
ByteTag{integer};
211 }
else if constexpr (size == 2) {
213 }
else if constexpr (size == 4) {
214 mTagStorage =
IntTag{integer};
234 [[nodiscard]] iterator begin() noexcept {
return iterator::makeBegin(*
this); }
235 [[nodiscard]] const_iterator begin() const noexcept {
return cbegin(); }
236 [[nodiscard]] const_iterator cbegin() const noexcept {
return const_iterator::makeBegin(*
this); }
238 [[nodiscard]] iterator end() noexcept {
return iterator::makeEnd(*
this); }
239 [[nodiscard]] const_iterator end() const noexcept {
return cend(); }
240 [[nodiscard]] const_iterator cend() const noexcept {
return const_iterator::makeEnd(*
this); }
242 [[nodiscard]]
constexpr Tag::Type index() const noexcept {
return Tag::Type(mTagStorage.index()); }
243 [[nodiscard]]
constexpr Tag::Type getId() const noexcept {
return index(); }
245 template <std::derived_from<Tag> T>
246 [[nodiscard]]
constexpr bool hold() const noexcept {
247 return std::holds_alternative<T>(mTagStorage);
249 [[nodiscard]]
constexpr bool hold(::Tag::Type type)
const noexcept {
return getId() == type; }
252 [[nodiscard]]
constexpr bool is_array() const noexcept {
return hold(Tag::List); }
253 [[nodiscard]]
constexpr bool is_binary() const noexcept {
return hold(Tag::ByteArray) || hold(Tag::IntArray); }
254 [[nodiscard]]
constexpr bool is_boolean() const noexcept {
return hold(Tag::Byte); }
255 [[nodiscard]]
constexpr bool is_null() const noexcept {
return hold(Tag::End); }
256 [[nodiscard]]
constexpr bool is_number_float() const noexcept {
return hold(Tag::Float) || hold(Tag::Double); }
257 [[nodiscard]]
constexpr bool is_number_integer() const noexcept {
258 return hold(Tag::Byte) || hold(Tag::Short) || hold(Tag::Int) || hold(Tag::Int64);
260 [[nodiscard]]
constexpr bool is_object() const noexcept {
return hold(Tag::Compound); }
261 [[nodiscard]]
constexpr bool is_string() const noexcept {
return hold(Tag::String); }
262 [[nodiscard]]
constexpr bool is_number() const noexcept {
return is_number_float() || is_number_integer(); }
263 [[nodiscard]]
constexpr bool is_primitive() const noexcept {
264 return is_null() || is_string() || is_number() || is_binary();
266 [[nodiscard]]
constexpr bool is_structured() const noexcept {
return is_array() || is_object(); }
268 [[nodiscard]]
constexpr CompoundTag::TagMap
const& items()
const {
return get<CompoundTag>().mTags; }
269 [[nodiscard]]
constexpr CompoundTag::TagMap& items() {
return get<CompoundTag>().mTags; }
271 [[nodiscard]]
bool contains(std::string_view key)
const noexcept {
273 return get<CompoundTag>().contains(key);
278 [[nodiscard]]
bool contains(std::string_view key, Tag::Type type)
const noexcept {
280 return get<CompoundTag>().contains(key, type);
285 template <std::derived_from<Tag> T>
286 [[nodiscard]]
bool contains(std::string_view key)
const noexcept {
287 constexpr size_t idx = Types::index<T>;
288 return contains(key, (Tag::Type)idx);
291 [[nodiscard]]
constexpr size_t size() const noexcept {
302 return get<ListTag>().size();
304 return get<CompoundTag>().size();
306 return get<IntArrayTag>().size();
308 return get<ByteArrayTag>().size();
316 template <std::derived_from<Tag> T>
317 [[nodiscard]]
constexpr T& get() {
318 return std::get<T>(mTagStorage);
321 template <std::derived_from<Tag> T>
322 [[nodiscard]]
constexpr T
const& get()
const {
323 return std::get<T>(mTagStorage);
326 [[nodiscard]]
Tag& get() {
return reinterpret_cast<Tag&
>(mTagStorage); }
328 [[nodiscard]]
Tag const& get()
const {
return reinterpret_cast<Tag const&
>(mTagStorage); }
330 template <std::derived_from<Tag> T>
331 constexpr T& emplace() {
332 return mTagStorage.emplace<T>();
336 if (hold(Tag::List)) {
337 return get<ListTag>()[index];
339 throw std::runtime_error(
"tag not hold an array");
343 [[nodiscard]]
UniqueTagPtr const& operator[](
size_t index)
const {
344 if (hold(Tag::List)) {
345 return get<ListTag>()[index];
347 throw std::runtime_error(
"tag not hold an array");
355 if (!hold(Tag::Compound)) {
356 throw std::runtime_error(
"tag not hold an object");
358 return get<CompoundTag>()[index];
362 if (!hold(Tag::Compound)) {
363 throw std::runtime_error(
"tag not hold an object");
365 return get<CompoundTag>()[index];
370 return operator[](std::string_view{index, N - 1});
375 return operator[](std::string_view{index, N - 1});
380 [](
auto& val) -> std::unique_ptr<Tag> {
return std::make_unique<std::decay_t<
decltype(val)>>(val); },
387 [](
auto&& val) -> std::unique_ptr<Tag> {
388 return std::make_unique<std::decay_t<
decltype(val)>>(std::move(val));
394 LLNDAPI std::string toSnbt(SnbtFormat snbtFormat = SnbtFormat::PrettyFilePrint, uchar indent = 4) const noexcept;
396 std::
string dump(uchar indent = 4, SnbtFormat snbtFormat = SnbtFormat::PrettyFilePrint) const noexcept {
397 return toSnbt(snbtFormat, indent);
404 if (!hold(Tag::List)) {
405 throw std::runtime_error(
"tag not hold an array");
407 get<ListTag>().add(std::move(val).toUnique());
411 requires(std::is_arithmetic_v<T> && !ll::traits::is_char_v<T>)
412 [[nodiscard]]
constexpr operator T()
const {
416 if constexpr (std::is_convertible_v<std::decay_t<
decltype(val)>, T>) {
425 throw std::runtime_error(
"tag not hold an number");
428 [[nodiscard]]
operator std::string
const&()
const {
return get<StringTag>(); }
429 [[nodiscard]]
operator std::string&() {
return get<StringTag>(); }
430 [[nodiscard]]
operator std::string&&() && {
return std::move(get<StringTag>()); }
431 [[nodiscard]]
operator std::string_view()
const {
return get<StringTag>(); }
432 static CompoundTagVariant object(std::initializer_list<CompoundTag::TagMap::value_type> init = {}) {
435 static CompoundTagVariant array(std::initializer_list<CompoundTagVariant> init = {}) {