28class CompoundTagVariant {
45 using Variant = Types::to<::std::variant>;
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>;
58 std::variant<CompoundTagVariant const*, CompoundTag::const_iterator, ListTag::const_iterator>,
59 std::variant<CompoundTagVariant*, CompoundTag::iterator, ListTag::iterator>>
62 static Iterator makeBegin(
auto& var)
noexcept {
64 switch (var.index()) {
66 res.iter.template emplace<2>(var.template get<ListTag>().begin());
69 res.iter.template emplace<1>(var.template get<CompoundTag>().begin());
72 res.iter.template emplace<0>(std::addressof(var) + 1);
75 res.iter.template emplace<0>(std::addressof(var));
80 static Iterator makeEnd(
auto& var)
noexcept {
82 switch (var.index()) {
84 res.iter.template emplace<2>(var.template get<ListTag>().end());
87 res.iter.template emplace<1>(var.template get<CompoundTag>().end());
90 res.iter.template emplace<0>(std::addressof(var) + 1);
95 [[nodiscard]] reference operator*()
const noexcept {
96 switch (iter.index()) {
98 return std::get<0>(iter)->get();
100 return std::get<1>(iter)->second.get();
102 return *std::get<2>(iter)->get();
109 [[nodiscard]] pointer operator->()
const noexcept {
return std::addressof(**
this); }
112 std::visit([](
auto& val) { ++val; }, iter);
123 std::visit([](
auto& val) { --val; }, iter);
133 [[nodiscard]]
bool operator==(
Iterator const& r)
const noexcept {
return this->iter == r.iter; }
150 LLNDAPI
static ll::Expected<CompoundTagVariant>
153 [[nodiscard]]
constexpr CompoundTagVariant() =
default;
155 [[nodiscard]]
constexpr CompoundTagVariant(CompoundTagVariant&&) =
default;
157 LL_MAY_CONSTEXPR CompoundTagVariant& operator=(CompoundTagVariant&&) =
default;
159 [[nodiscard]]
constexpr CompoundTagVariant(CompoundTagVariant
const&) =
default;
161 LL_MAY_CONSTEXPR CompoundTagVariant& operator=(CompoundTagVariant
const&) =
default;
164 requires(
requires(T o) { mTagStorage = std::move(o); })
166 mTagStorage = std::move(other);
170 [[nodiscard]]
constexpr CompoundTagVariant(std::nullptr_t) {}
172 [[nodiscard]]
bool operator==(CompoundTagVariant
const& other)
const {
return get() == other.get(); }
174 [[nodiscard]] CompoundTagVariant(Variant tag) : mTagStorage(std::move(tag)) {}
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)...) {}
180 [[nodiscard]]
constexpr CompoundTagVariant(std::initializer_list<CompoundTag::TagMap::value_type> tagPairs)
181 : mTagStorage(std::in_place_type<CompoundTag>, tagPairs) {}
183 [[nodiscard]] CompoundTagVariant(UniqueTagPtr&& tag) {
187 ::ll::meta::visitIndex<Types::size>(
static_cast<size_t>(tag->getId()), [&]<
size_t I> {
188 mTagStorage = std::move((Types::get<I>&)*tag);
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};
204 mTagStorage = Int64Tag{integer};
207 [[nodiscard]]
constexpr CompoundTagVariant(std::byte b) : mTagStorage(ByteTag{b}) {}
209 [[nodiscard]]
constexpr CompoundTagVariant(
float f) : mTagStorage(FloatTag{f}) {}
211 [[nodiscard]]
constexpr CompoundTagVariant(
double d) : mTagStorage(DoubleTag{d}) {}
213 [[nodiscard]]
constexpr CompoundTagVariant(std::string s)
214 : mTagStorage(std::in_place_type<StringTag>, std::move(s)) {}
216 [[nodiscard]]
constexpr CompoundTagVariant(std::string_view s) : mTagStorage(std::in_place_type<StringTag>, s) {}
219 [[nodiscard]]
constexpr CompoundTagVariant(
char const (&str)[N])
220 : CompoundTagVariant(std::string_view{str, N - 1}) {}
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); }
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); }
230 [[nodiscard]]
constexpr Tag::Type index() const noexcept {
return Tag::Type(mTagStorage.index()); }
231 [[nodiscard]]
constexpr Tag::Type getId() const noexcept {
return index(); }
233 template <std::derived_from<Tag> T>
234 [[nodiscard]]
constexpr bool hold() const noexcept {
235 return std::holds_alternative<T>(mTagStorage);
237 [[nodiscard]]
constexpr bool hold(::Tag::Type type)
const noexcept {
return getId() == type; }
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);
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();
254 [[nodiscard]]
constexpr bool is_structured() const noexcept {
return is_array() || is_object(); }
256 [[nodiscard]]
constexpr CompoundTag::TagMap
const& items()
const {
return get<CompoundTag>().mTags; }
257 [[nodiscard]]
constexpr CompoundTag::TagMap& items() {
return get<CompoundTag>().mTags; }
259 [[nodiscard]]
bool contains(std::string_view key)
const noexcept {
261 return get<CompoundTag>().contains(key);
266 [[nodiscard]]
bool contains(std::string_view key, Tag::Type type)
const noexcept {
268 return get<CompoundTag>().contains(key, type);
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);
279 [[nodiscard]]
constexpr size_t size() const noexcept {
290 return get<ListTag>().size();
292 return get<CompoundTag>().size();
294 return get<IntArrayTag>().size();
296 return get<ByteArrayTag>().size();
304 template <std::derived_from<Tag> T>
305 [[nodiscard]]
constexpr T& get() {
306 return std::get<T>(mTagStorage);
309 template <std::derived_from<Tag> T>
310 [[nodiscard]]
constexpr T
const& get()
const {
311 return std::get<T>(mTagStorage);
314 [[nodiscard]] Tag& get() {
return reinterpret_cast<Tag&
>(mTagStorage); }
316 [[nodiscard]] Tag
const& get()
const {
return reinterpret_cast<Tag const&
>(mTagStorage); }
318 template <std::derived_from<Tag> T>
319 constexpr T& emplace() {
320 return mTagStorage.emplace<T>();
323 [[nodiscard]] UniqueTagPtr& operator[](
size_t index) {
324 if (hold(Tag::List)) {
325 return get<ListTag>()[index];
327 throw std::runtime_error(
"tag not hold an array");
331 [[nodiscard]] UniqueTagPtr
const& operator[](
size_t index)
const {
332 if (hold(Tag::List)) {
333 return get<ListTag>()[index];
335 throw std::runtime_error(
"tag not hold an array");
339 [[nodiscard]] CompoundTagVariant& operator[](std::string_view index) {
341 mTagStorage = CompoundTag{};
343 if (!hold(Tag::Compound)) {
344 throw std::runtime_error(
"tag not hold an object");
346 return get<CompoundTag>()[index];
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");
353 return get<CompoundTag>()[index];
357 [[nodiscard]] CompoundTagVariant& operator[](
char const (&index)[N]) {
358 return operator[](std::string_view{index, N - 1});
362 [[nodiscard]] CompoundTagVariant
const& operator[](
char const (&index)[N])
const {
363 return operator[](std::string_view{index, N - 1});
366 [[nodiscard]] UniqueTagPtr toUniqueCopy() const& {
368 [](
auto& val) -> std::unique_ptr<Tag> {
return std::make_unique<std::decay_t<
decltype(val)>>(val); },
373 [[nodiscard]] UniqueTagPtr toUnique() && {
375 [](
auto&& val) -> std::unique_ptr<Tag> {
376 return std::make_unique<std::decay_t<
decltype(val)>>(std::move(val));
382 LLNDAPI std::string toSnbt(SnbtFormat snbtFormat = SnbtFormat::PrettyFilePrint, uchar indent = 4) const noexcept;
384 std::
string dump(uchar indent = 4, SnbtFormat snbtFormat = SnbtFormat::PrettyFilePrint) const noexcept {
385 return toSnbt(snbtFormat, indent);
388 void push_back(CompoundTagVariant val) {
390 mTagStorage = ListTag{};
392 if (!hold(Tag::List)) {
393 throw std::runtime_error(
"tag not hold an array");
395 get<ListTag>().add(std::move(val).toUnique());
399 requires(std::is_arithmetic_v<T> && !ll::traits::is_char_v<T>)
400 [[nodiscard]]
constexpr operator T()
const {
404 if constexpr (std::is_convertible_v<std::decay_t<
decltype(val)>, T>) {
413 throw std::runtime_error(
"tag not hold an number");
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};
423 static CompoundTagVariant array(std::initializer_list<CompoundTagVariant> init = {}) {
424 return CompoundTagVariant{std::in_place_type<ListTag>, init};