From 9f3178c5c0b61ab2ac8b063fe1ff4f4512d5f3df Mon Sep 17 00:00:00 2001 From: gentlegiantJGC Date: Thu, 18 Jul 2024 16:09:32 +0100 Subject: [PATCH 1/6] Prototype a native class structure --- src/amulet_nbt/cpp/tag2/float.cpp | 12 ++++++ src/amulet_nbt/cpp/tag2/int.cpp | 15 +++++++ src/amulet_nbt/cpp/tag2/string.cpp | 6 +++ .../include/amulet_nbt/tag2/abc.hpp | 42 +++++++++++++++++++ .../include/amulet_nbt/tag2/array.hpp | 18 ++++++++ .../include/amulet_nbt/tag2/compound.hpp | 37 ++++++++++++++++ .../include/amulet_nbt/tag2/float.hpp | 19 +++++++++ .../include/amulet_nbt/tag2/int.hpp | 21 ++++++++++ .../include/amulet_nbt/tag2/list.hpp | 15 +++++++ .../include/amulet_nbt/tag2/named_tag.hpp | 15 +++++++ .../include/amulet_nbt/tag2/string.hpp | 15 +++++++ 11 files changed, 215 insertions(+) create mode 100644 src/amulet_nbt/cpp/tag2/float.cpp create mode 100644 src/amulet_nbt/cpp/tag2/int.cpp create mode 100644 src/amulet_nbt/cpp/tag2/string.cpp create mode 100644 src/amulet_nbt/include/amulet_nbt/tag2/abc.hpp create mode 100644 src/amulet_nbt/include/amulet_nbt/tag2/array.hpp create mode 100644 src/amulet_nbt/include/amulet_nbt/tag2/compound.hpp create mode 100644 src/amulet_nbt/include/amulet_nbt/tag2/float.hpp create mode 100644 src/amulet_nbt/include/amulet_nbt/tag2/int.hpp create mode 100644 src/amulet_nbt/include/amulet_nbt/tag2/list.hpp create mode 100644 src/amulet_nbt/include/amulet_nbt/tag2/named_tag.hpp create mode 100644 src/amulet_nbt/include/amulet_nbt/tag2/string.hpp diff --git a/src/amulet_nbt/cpp/tag2/float.cpp b/src/amulet_nbt/cpp/tag2/float.cpp new file mode 100644 index 00000000..63088e20 --- /dev/null +++ b/src/amulet_nbt/cpp/tag2/float.cpp @@ -0,0 +1,12 @@ +#include + +namespace AmuletNBT { + template + FloatTagTemplate::FloatTagTemplate(): value(0.0){} + + template + FloatTagTemplate::FloatTagTemplate(T& value): value(value){} + + template class FloatTagTemplate; + template class FloatTagTemplate; +} diff --git a/src/amulet_nbt/cpp/tag2/int.cpp b/src/amulet_nbt/cpp/tag2/int.cpp new file mode 100644 index 00000000..dbdacdeb --- /dev/null +++ b/src/amulet_nbt/cpp/tag2/int.cpp @@ -0,0 +1,15 @@ +#include +#include + +namespace AmuletNBT { + template + IntTagTemplate::IntTagTemplate(): value(0){} + + template + IntTagTemplate::IntTagTemplate(T& value): value(value){} + + template class IntTagTemplate; + template class IntTagTemplate; + template class IntTagTemplate; + template class IntTagTemplate; +} diff --git a/src/amulet_nbt/cpp/tag2/string.cpp b/src/amulet_nbt/cpp/tag2/string.cpp new file mode 100644 index 00000000..25627068 --- /dev/null +++ b/src/amulet_nbt/cpp/tag2/string.cpp @@ -0,0 +1,6 @@ +#include + +namespace AmuletNBT { + StringTag::StringTag(): value(""){} + StringTag::StringTag(std::string& value): value(value){} +} diff --git a/src/amulet_nbt/include/amulet_nbt/tag2/abc.hpp b/src/amulet_nbt/include/amulet_nbt/tag2/abc.hpp new file mode 100644 index 00000000..26cb79d7 --- /dev/null +++ b/src/amulet_nbt/include/amulet_nbt/tag2/abc.hpp @@ -0,0 +1,42 @@ +#pragma once + +#include +#include + +#include + +namespace AmuletNBT { + + class AbstractBaseTag { + public: + virtual ~AbstractBaseTag(){}; + virtual std::string to_nbt(std::string, std::endian, AmuletNBT::StringEncode) const = 0; + virtual std::string to_snbt() const = 0; + virtual std::string to_snbt(const std::string& indent) const = 0; + }; + + class AbstractBaseImmutableTag: public AbstractBaseTag { + public: + virtual ~AbstractBaseImmutableTag(){}; + }; + class AbstractBaseMutableTag: public AbstractBaseTag { + public: + virtual ~AbstractBaseMutableTag(){}; + }; + class AbstractBaseNumericTag: public AbstractBaseImmutableTag { + public: + virtual ~AbstractBaseNumericTag(){}; + }; + class AbstractBaseIntTag: public AbstractBaseNumericTag { + public: + virtual ~AbstractBaseIntTag(){}; + }; + class AbstractBaseFloatTag: public AbstractBaseNumericTag { + public: + virtual ~AbstractBaseFloatTag(){}; + }; + class AbstractBaseArrayTag: public AbstractBaseMutableTag { + public: + virtual ~AbstractBaseArrayTag(){}; + }; +} diff --git a/src/amulet_nbt/include/amulet_nbt/tag2/array.hpp b/src/amulet_nbt/include/amulet_nbt/tag2/array.hpp new file mode 100644 index 00000000..645ac1f2 --- /dev/null +++ b/src/amulet_nbt/include/amulet_nbt/tag2/array.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include + +#include + +namespace AmuletNBT { + template + class ArrayTagTemplate: public AbstractBaseArrayTag { + public: + const std::string value; + + StringTag(); + StringTag(std::string&); + }; + + +} diff --git a/src/amulet_nbt/include/amulet_nbt/tag2/compound.hpp b/src/amulet_nbt/include/amulet_nbt/tag2/compound.hpp new file mode 100644 index 00000000..b0f77309 --- /dev/null +++ b/src/amulet_nbt/include/amulet_nbt/tag2/compound.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include +#include +#include + +#include +#include +#include +#include + +namespace AmuletNBT { + class CompoundTag; + + typedef std::variant< + ByteTag, + ShortTag, + IntTag, + LongTag, + FloatTag, + DoubleTag, + ByteArrayTagPtr, + StringTag, + ListTagPtr, + CompoundTagPtr, + IntArrayTagPtr, + LongArrayTagPtr + > TagNode; + + class CompoundTag: public AbstractBaseMutableTag { + public: + const std::string value; + + StringTag(); + StringTag(std::string&); + } +} diff --git a/src/amulet_nbt/include/amulet_nbt/tag2/float.hpp b/src/amulet_nbt/include/amulet_nbt/tag2/float.hpp new file mode 100644 index 00000000..1bf461ed --- /dev/null +++ b/src/amulet_nbt/include/amulet_nbt/tag2/float.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include + +#include + +namespace AmuletNBT { + template + class FloatTagTemplate: public AbstractBaseFloatTag { + public: + const T value; + + FloatTagTemplate(); + FloatTagTemplate(T&); + }; + + typedef IntTagTemplate FloatTag; + typedef IntTagTemplate DoubleTag; +} diff --git a/src/amulet_nbt/include/amulet_nbt/tag2/int.hpp b/src/amulet_nbt/include/amulet_nbt/tag2/int.hpp new file mode 100644 index 00000000..8b892730 --- /dev/null +++ b/src/amulet_nbt/include/amulet_nbt/tag2/int.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include + +#include + +namespace AmuletNBT { + template + class IntTagTemplate: public AbstractBaseIntTag { + public: + const T value; + + IntTagTemplate(); + IntTagTemplate(T&); + }; + + typedef IntTagTemplate ByteTag; + typedef IntTagTemplate ShortTag; + typedef IntTagTemplate IntTag; + typedef IntTagTemplate LongTag; +} diff --git a/src/amulet_nbt/include/amulet_nbt/tag2/list.hpp b/src/amulet_nbt/include/amulet_nbt/tag2/list.hpp new file mode 100644 index 00000000..a58220a6 --- /dev/null +++ b/src/amulet_nbt/include/amulet_nbt/tag2/list.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include + +#include + +namespace AmuletNBT { + class StringTag: public AbstractBaseImmutableTag { + public: + const std::string value; + + StringTag(); + StringTag(std::string&); + } +} diff --git a/src/amulet_nbt/include/amulet_nbt/tag2/named_tag.hpp b/src/amulet_nbt/include/amulet_nbt/tag2/named_tag.hpp new file mode 100644 index 00000000..5dd89447 --- /dev/null +++ b/src/amulet_nbt/include/amulet_nbt/tag2/named_tag.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include + +#include + +namespace AmuletNBT { + class NamedTag { + public: + std::string name; + TagNode tag_node; + + NamedTag(const std::string& name, const TagNode& tag_node): name(name), tag_node(tag_node) {} + } +} diff --git a/src/amulet_nbt/include/amulet_nbt/tag2/string.hpp b/src/amulet_nbt/include/amulet_nbt/tag2/string.hpp new file mode 100644 index 00000000..a58220a6 --- /dev/null +++ b/src/amulet_nbt/include/amulet_nbt/tag2/string.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include + +#include + +namespace AmuletNBT { + class StringTag: public AbstractBaseImmutableTag { + public: + const std::string value; + + StringTag(); + StringTag(std::string&); + } +} From ba2a4df7df9dbca9000972fc7d78b05402d222b7 Mon Sep 17 00:00:00 2001 From: gentlegiantJGC Date: Wed, 24 Jul 2024 11:46:49 +0100 Subject: [PATCH 2/6] Refactored NBT storage Storing the NBT tags as native types seemed like a good idea on the C++ side but it made it difficult to integrate with Python. The NBT tags are now their own classes so a wrapper class is not needed. --- .../cpp/nbt_encoding/binary/read_binary.cpp | 139 ++++----- .../cpp/nbt_encoding/binary/write_binary.cpp | 229 ++++++++------- .../cpp/nbt_encoding/string/read_string.cpp | 78 +++-- .../cpp/nbt_encoding/string/write_string.cpp | 208 +++++++------- src/amulet_nbt/cpp/tag/compound.cpp | 29 -- src/amulet_nbt/cpp/tag/copy.cpp | 123 ++++---- src/amulet_nbt/cpp/tag/eq.cpp | 71 ++--- src/amulet_nbt/cpp/tag/list.cpp | 42 --- src/amulet_nbt/cpp/tag/wrapper.cpp | 24 -- src/amulet_nbt/cpp/tag2/float.cpp | 12 - src/amulet_nbt/cpp/tag2/int.cpp | 15 - src/amulet_nbt/cpp/tag2/string.cpp | 6 - src/amulet_nbt/include/amulet_nbt/common.hpp | 6 + .../amulet_nbt/nbt_encoding/binary.hpp | 44 +-- .../amulet_nbt/nbt_encoding/string.hpp | 115 ++++---- .../include/amulet_nbt/{tag2 => tag}/abc.hpp | 8 - .../include/amulet_nbt/tag/array.hpp | 50 +++- .../include/amulet_nbt/tag/compound.hpp | 64 ++++- .../include/amulet_nbt/tag/copy.hpp | 36 ++- src/amulet_nbt/include/amulet_nbt/tag/eq.hpp | 33 ++- .../include/amulet_nbt/tag/float.hpp | 42 +++ src/amulet_nbt/include/amulet_nbt/tag/int.hpp | 55 ++++ .../include/amulet_nbt/tag/list.hpp | 271 ++++++++++++------ .../amulet_nbt/{tag2 => tag}/named_tag.hpp | 6 +- src/amulet_nbt/include/amulet_nbt/tag/nbt.hpp | 85 ------ .../include/amulet_nbt/tag/string.hpp | 19 ++ .../include/amulet_nbt/tag/wrapper.hpp | 119 -------- .../include/amulet_nbt/tag2/array.hpp | 18 -- .../include/amulet_nbt/tag2/compound.hpp | 37 --- .../include/amulet_nbt/tag2/float.hpp | 19 -- .../include/amulet_nbt/tag2/int.hpp | 21 -- .../include/amulet_nbt/tag2/list.hpp | 15 - .../include/amulet_nbt/tag2/string.hpp | 15 - 33 files changed, 1005 insertions(+), 1049 deletions(-) delete mode 100644 src/amulet_nbt/cpp/tag/compound.cpp delete mode 100644 src/amulet_nbt/cpp/tag/list.cpp delete mode 100644 src/amulet_nbt/cpp/tag/wrapper.cpp delete mode 100644 src/amulet_nbt/cpp/tag2/float.cpp delete mode 100644 src/amulet_nbt/cpp/tag2/int.cpp delete mode 100644 src/amulet_nbt/cpp/tag2/string.cpp rename src/amulet_nbt/include/amulet_nbt/{tag2 => tag}/abc.hpp (75%) create mode 100644 src/amulet_nbt/include/amulet_nbt/tag/float.hpp create mode 100644 src/amulet_nbt/include/amulet_nbt/tag/int.hpp rename src/amulet_nbt/include/amulet_nbt/{tag2 => tag}/named_tag.hpp (72%) create mode 100644 src/amulet_nbt/include/amulet_nbt/tag/string.hpp delete mode 100644 src/amulet_nbt/include/amulet_nbt/tag/wrapper.hpp delete mode 100644 src/amulet_nbt/include/amulet_nbt/tag2/array.hpp delete mode 100644 src/amulet_nbt/include/amulet_nbt/tag2/compound.hpp delete mode 100644 src/amulet_nbt/include/amulet_nbt/tag2/float.hpp delete mode 100644 src/amulet_nbt/include/amulet_nbt/tag2/int.hpp delete mode 100644 src/amulet_nbt/include/amulet_nbt/tag2/list.hpp delete mode 100644 src/amulet_nbt/include/amulet_nbt/tag2/string.hpp diff --git a/src/amulet_nbt/cpp/nbt_encoding/binary/read_binary.cpp b/src/amulet_nbt/cpp/nbt_encoding/binary/read_binary.cpp index ada821e5..df235055 100644 --- a/src/amulet_nbt/cpp/nbt_encoding/binary/read_binary.cpp +++ b/src/amulet_nbt/cpp/nbt_encoding/binary/read_binary.cpp @@ -6,37 +6,54 @@ #include #include +#include +#include +#include +#include +#include +#include +#include #include -AmuletNBT::StringTag read_string_tag(AmuletNBT::BinaryReader& reader){ +template +inline T read_numeric_tag(AmuletNBT::BinaryReader& reader) { + return T(reader.readNumeric()); +} + +inline std::string read_string(AmuletNBT::BinaryReader& reader) { std::uint16_t length = reader.readNumeric(); return reader.readString(length); }; +inline AmuletNBT::StringTag read_string_tag(AmuletNBT::BinaryReader& reader){ + return AmuletNBT::StringTag(read_string(reader)); +}; + -AmuletNBT::TagNode read_node(AmuletNBT::BinaryReader& reader, std::uint8_t tag_id); +inline AmuletNBT::TagNode read_node(AmuletNBT::BinaryReader& reader, std::uint8_t tag_id); -AmuletNBT::CompoundTagPtr read_compound_tag(AmuletNBT::BinaryReader& reader){ - AmuletNBT::CompoundTagPtr tag = std::make_shared(); +inline AmuletNBT::CompoundTagPtr read_compound_tag(AmuletNBT::BinaryReader& reader){ + AmuletNBT::CompoundTagPtr tag_ptr = std::make_shared(); + AmuletNBT::CompoundTag& tag = *tag_ptr; while (true){ std::uint8_t tag_id = reader.readNumeric(); if (tag_id == 0){ break; } - AmuletNBT::StringTag name = read_string_tag(reader); + std::string name = read_string(reader); AmuletNBT::TagNode node = read_node(reader, tag_id); - (*tag)[name] = node; + tag[name] = node; } - return tag; + return tag_ptr; }; template -std::shared_ptr> read_array_tag(AmuletNBT::BinaryReader& reader){ +inline std::shared_ptr read_array_tag(AmuletNBT::BinaryReader& reader){ std::int32_t length = reader.readNumeric(); if (length < 0){length = 0;} - std::shared_ptr> tag = std::make_shared>(length); + std::shared_ptr tag = std::make_shared(length); for (std::int32_t i = 0; i < length; i++){ reader.readNumericInto((*tag)[i]); } @@ -45,7 +62,7 @@ std::shared_ptr> read_array_tag(AmuletNBT::BinaryReader& template -AmuletNBT::ListTagPtr read_numeric_list_tag(AmuletNBT::BinaryReader& reader){ +inline AmuletNBT::ListTagPtr read_numeric_list_tag(AmuletNBT::BinaryReader& reader){ std::int32_t length = reader.readNumeric(); if (length < 0){length = 0;} AmuletNBT::ListTagPtr tag = std::make_shared(std::vector(length)); @@ -58,7 +75,7 @@ AmuletNBT::ListTagPtr read_numeric_list_tag(AmuletNBT::BinaryReader& reader){ template -AmuletNBT::ListTagPtr read_template_list_tag(AmuletNBT::BinaryReader& reader){ +inline AmuletNBT::ListTagPtr read_template_list_tag(AmuletNBT::BinaryReader& reader){ std::int32_t length = reader.readNumeric(); if (length < 0){length = 0;} AmuletNBT::ListTagPtr tag = std::make_shared(std::vector(length)); @@ -70,7 +87,7 @@ AmuletNBT::ListTagPtr read_template_list_tag(AmuletNBT::BinaryReader& reader){ } -AmuletNBT::ListTagPtr read_void_list_tag(AmuletNBT::BinaryReader& reader){ +inline AmuletNBT::ListTagPtr read_void_list_tag(AmuletNBT::BinaryReader& reader){ std::int32_t length = reader.readNumeric(); if (length < 0){length = 0;} if (length != 0){throw std::runtime_error("Void list tag must have a length of 0");} @@ -78,84 +95,70 @@ AmuletNBT::ListTagPtr read_void_list_tag(AmuletNBT::BinaryReader& reader){ } -AmuletNBT::ListTagPtr read_list_tag(AmuletNBT::BinaryReader& reader){ +inline AmuletNBT::ListTagPtr read_list_tag(AmuletNBT::BinaryReader& reader){ std::uint8_t tag_type = reader.readNumeric(); switch(tag_type){ case 0: return read_void_list_tag(reader); - case 1: + case AmuletNBT::tag_id_v: return read_numeric_list_tag(reader); - case 2: + case AmuletNBT::tag_id_v: return read_numeric_list_tag(reader); - case 3: + case AmuletNBT::tag_id_v: return read_numeric_list_tag(reader); - case 4: + case AmuletNBT::tag_id_v: return read_numeric_list_tag(reader); - case 5: + case AmuletNBT::tag_id_v: return read_numeric_list_tag(reader); - case 6: + case AmuletNBT::tag_id_v: return read_numeric_list_tag(reader); - case 7: - return read_template_list_tag>(reader); - case 8: + case AmuletNBT::tag_id_v: + return read_template_list_tag>(reader); + case AmuletNBT::tag_id_v: return read_template_list_tag(reader); - case 9: + case AmuletNBT::tag_id_v: return read_template_list_tag(reader); - case 10: + case AmuletNBT::tag_id_v: return read_template_list_tag(reader); - case 11: - return read_template_list_tag>(reader); - case 12: - return read_template_list_tag>(reader); + case AmuletNBT::tag_id_v: + return read_template_list_tag>(reader); + case AmuletNBT::tag_id_v: + return read_template_list_tag>(reader); default: throw std::runtime_error("This shouldn't happen"); } }; -AmuletNBT::TagNode read_node(AmuletNBT::BinaryReader& reader, std::uint8_t tag_id){ - AmuletNBT::TagNode node; +inline AmuletNBT::TagNode read_node(AmuletNBT::BinaryReader& reader, std::uint8_t tag_id){ switch(tag_id){ - case 1: - node = reader.readNumeric(); - break; - case 2: - node = reader.readNumeric(); - break; - case 3: - node = reader.readNumeric(); - break; - case 4: - node = reader.readNumeric(); - break; - case 5: - node = reader.readNumeric(); - break; - case 6: - node = reader.readNumeric(); - break; - case 8: - node = read_string_tag(reader); - break; - case 9: - node = read_list_tag(reader); - break; - case 10: - node = read_compound_tag(reader); - break; - case 7: - node = read_array_tag(reader); - break; - case 11: - node = read_array_tag(reader); - break; - case 12: - node = read_array_tag(reader); - break; + case AmuletNBT::tag_id_v: + return read_numeric_tag(reader); + case AmuletNBT::tag_id_v: + return read_numeric_tag(reader); + case AmuletNBT::tag_id_v: + return read_numeric_tag(reader); + case AmuletNBT::tag_id_v: + return read_numeric_tag(reader); + case AmuletNBT::tag_id_v: + return read_numeric_tag(reader); + case AmuletNBT::tag_id_v: + return read_numeric_tag(reader); + case AmuletNBT::tag_id_v: + return read_array_tag(reader); + case AmuletNBT::tag_id_v: + return read_string_tag(reader); + case AmuletNBT::tag_id_v: + return read_list_tag(reader); + case AmuletNBT::tag_id_v: + return read_compound_tag(reader); + case AmuletNBT::tag_id_v: + return read_array_tag(reader); + case AmuletNBT::tag_id_v: + return read_array_tag(reader); default: - throw std::runtime_error("Unsupported tag type"); + throw std::runtime_error("Unsupported tag type " + std::to_string(tag_id)); } - return node; }; diff --git a/src/amulet_nbt/cpp/nbt_encoding/binary/write_binary.cpp b/src/amulet_nbt/cpp/nbt_encoding/binary/write_binary.cpp index 3b1b6bf6..90907359 100644 --- a/src/amulet_nbt/cpp/nbt_encoding/binary/write_binary.cpp +++ b/src/amulet_nbt/cpp/nbt_encoding/binary/write_binary.cpp @@ -9,46 +9,99 @@ #include #include -#include +#include +#include +#include +#include +#include +#include #include #include -// I wanted to use templates to reduce code duplication but I can't get this to work -// The template version compiled and passed all tests on my computer but it just wasn't working on the remote servers - -template -void write_numeric_payload(AmuletNBT::BinaryWriter& writer, const T& value){ - writer.writeNumeric(value); +template < + class T, + std::enable_if_t< + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v, + bool + > = true> +inline void write_payload(AmuletNBT::BinaryWriter& writer, const T& value){ + writer.writeNumeric(value); }; -void write_string_payload(AmuletNBT::BinaryWriter& writer, const AmuletNBT::StringTag& value){ +inline void write_string(AmuletNBT::BinaryWriter& writer, const std::string& value){ std::string encoded_string = writer.encodeString(value); if (encoded_string.size() > static_cast(std::numeric_limits::max())){ throw std::overflow_error("String of length " + std::to_string(encoded_string.size()) + " is too long."); } - std::uint16_t length = static_cast(encoded_string.size()); - writer.writeNumeric(length); + writer.writeNumeric(static_cast(encoded_string.size())); writer.writeString(encoded_string); } +template < + typename T, + std::enable_if_t< + std::is_same_v, + bool +> = true> +inline void write_payload(AmuletNBT::BinaryWriter& writer, const T& value) { + write_string(writer, value); +}; -template -void write_array_payload(AmuletNBT::BinaryWriter& writer, const std::shared_ptr> value){ - if (value->size() > static_cast(std::numeric_limits::max())){ - throw std::overflow_error("Array of length " + std::to_string(value->size()) + " is too long."); +template < + class T, + std::enable_if_t< + std::is_same_v || + std::is_same_v || + std::is_same_v, + bool + > = true +> +inline void write_payload(AmuletNBT::BinaryWriter& writer, const T& value){ + if (value.size() > static_cast(std::numeric_limits::max())){ + throw std::overflow_error("Array of length " + std::to_string(value.size()) + " is too long."); } - std::int32_t length = static_cast(value->size()); + std::int32_t length = static_cast(value.size()); writer.writeNumeric(length); - for (const T& element: *value){ - writer.writeNumeric(element); + for (const T::value_type& element: value){ + writer.writeNumeric(element); } } -void write_list_payload(AmuletNBT::BinaryWriter& writer, const AmuletNBT::ListTagPtr& value); -void write_compound_payload(AmuletNBT::BinaryWriter& writer, const AmuletNBT::CompoundTagPtr& value); +template < + class T, + std::enable_if_t, bool> = true +> +inline void write_payload(AmuletNBT::BinaryWriter& writer, const T& value); + +template < + class T, + std::enable_if_t, bool> = true +> +inline void write_payload(AmuletNBT::BinaryWriter& writer, const T& value); + + +template < + class T, + std::enable_if_t< + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v, + bool + > = true +> +inline void write_payload(AmuletNBT::BinaryWriter & writer, const T value) { + write_payload(writer, *value); +} template < @@ -69,50 +122,30 @@ template < bool > = true > -void write_list_tag_payload(AmuletNBT::BinaryWriter& writer, const AmuletNBT::ListTagPtr& value){ - const std::vector& list = std::get>(*value); +inline void write_list_tag_payload(AmuletNBT::BinaryWriter& writer, const std::vector& list){ if (list.size() > static_cast(std::numeric_limits::max())){ throw std::overflow_error("List of length " + std::to_string(list.size()) + " is too long."); } - writer.writeNumeric(variant_index()); - std::int32_t length = static_cast(list.size()); - writer.writeNumeric(length); + writer.writeNumeric(AmuletNBT::tag_id_v); + writer.writeNumeric(static_cast(list.size())); for (const T& element: list){ - if constexpr (std::is_same_v){write_numeric_payload(writer, element);} else - if constexpr (std::is_same_v){write_numeric_payload(writer, element);} else - if constexpr (std::is_same_v){write_numeric_payload(writer, element);} else - if constexpr (std::is_same_v){write_numeric_payload(writer, element);} else - if constexpr (std::is_same_v){write_numeric_payload(writer, element);} else - if constexpr (std::is_same_v){write_numeric_payload(writer, element);} else - if constexpr (std::is_same_v){write_array_payload(writer, element);} else - if constexpr (std::is_same_v){write_string_payload(writer, element);} else - if constexpr (std::is_same_v){write_list_payload(writer, element);} else - if constexpr (std::is_same_v){write_compound_payload(writer, element);} else - if constexpr (std::is_same_v){write_array_payload(writer, element);} else - if constexpr (std::is_same_v){write_array_payload(writer, element);} + write_payload(writer, element); } } -void write_list_payload(AmuletNBT::BinaryWriter& writer, const AmuletNBT::ListTagPtr& value){ - switch (value->index()){ - case 0: +template <> +inline void write_payload(AmuletNBT::BinaryWriter& writer, const AmuletNBT::ListTag& value){ + std::visit([&writer](auto&& tag) { + using T = std::decay_t; + if constexpr (std::is_same_v) { writer.writeNumeric(0); writer.writeNumeric(0); - break; - case 1: write_list_tag_payload(writer, value); break; - case 2: write_list_tag_payload(writer, value); break; - case 3: write_list_tag_payload(writer, value); break; - case 4: write_list_tag_payload(writer, value); break; - case 5: write_list_tag_payload(writer, value); break; - case 6: write_list_tag_payload(writer, value); break; - case 7: write_list_tag_payload(writer, value); break; - case 8: write_list_tag_payload(writer, value); break; - case 9: write_list_tag_payload(writer, value); break; - case 10: write_list_tag_payload(writer, value); break; - case 11: write_list_tag_payload(writer, value); break; - case 12: write_list_tag_payload(writer, value); break; - } + } + else { + write_list_tag_payload(writer, tag); + } + }, value); } @@ -125,30 +158,34 @@ template < std::is_same_v || std::is_same_v || std::is_same_v || - std::is_same_v || + std::is_same_v || std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v, + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v, bool > = true > -void write_name_and_tag(AmuletNBT::BinaryWriter& writer, const std::string& name, const T& tag){ - writer.writeNumeric(variant_index()); - write_string_payload(writer, name); - if constexpr (std::is_same_v){write_numeric_payload(writer, tag);} else - if constexpr (std::is_same_v){write_numeric_payload(writer, tag);} else - if constexpr (std::is_same_v){write_numeric_payload(writer, tag);} else - if constexpr (std::is_same_v){write_numeric_payload(writer, tag);} else - if constexpr (std::is_same_v){write_numeric_payload(writer, tag);} else - if constexpr (std::is_same_v){write_numeric_payload(writer, tag);} else - if constexpr (std::is_same_v){write_array_payload(writer, tag);} else - if constexpr (std::is_same_v){write_string_payload(writer, tag);} else - if constexpr (std::is_same_v){write_list_payload(writer, tag);} else - if constexpr (std::is_same_v){write_compound_payload(writer, tag);} else - if constexpr (std::is_same_v){write_array_payload(writer, tag);} else - if constexpr (std::is_same_v){write_array_payload(writer, tag);} +inline void write_name_and_tag(AmuletNBT::BinaryWriter& writer, const std::string& name, const T& tag){ + writer.writeNumeric(AmuletNBT::tag_id_v); + write_string(writer, name); + write_payload(writer, tag); +} + +template < + typename T, + std::enable_if_t< + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v, + bool + > = true +> +inline void write_name_and_tag(AmuletNBT::BinaryWriter & writer, const std::string & name, const T tag) { + write_name_and_tag(writer, name, *tag); } @@ -156,27 +193,17 @@ template < typename T, std::enable_if_t, bool> = true > -void write_name_and_tag(AmuletNBT::BinaryWriter& writer, const std::string& name, const AmuletNBT::TagNode& node){ - switch (node.index()){ - case 1: write_name_and_tag(writer, name, std::get(node)); break; - case 2: write_name_and_tag(writer, name, std::get(node)); break; - case 3: write_name_and_tag(writer, name, std::get(node)); break; - case 4: write_name_and_tag(writer, name, std::get(node)); break; - case 5: write_name_and_tag(writer, name, std::get(node)); break; - case 6: write_name_and_tag(writer, name, std::get(node)); break; - case 7: write_name_and_tag(writer, name, std::get(node)); break; - case 8: write_name_and_tag(writer, name, std::get(node)); break; - case 9: write_name_and_tag(writer, name, std::get(node)); break; - case 10: write_name_and_tag(writer, name, std::get(node)); break; - case 11: write_name_and_tag(writer, name, std::get(node)); break; - case 12: write_name_and_tag(writer, name, std::get(node)); break; - default: throw std::runtime_error("TagNode cannot be in null state when writing."); - } +inline void write_name_and_tag(AmuletNBT::BinaryWriter& writer, const std::string& name, const AmuletNBT::TagNode& node){ + std::visit([&writer, &name](auto&& tag) { + using T = std::decay_t; + write_name_and_tag(writer, name, tag); + }, node); } -void write_compound_payload(AmuletNBT::BinaryWriter& writer, const AmuletNBT::CompoundTagPtr& value){ - for (auto it = value->begin(); it != value->end(); it++){ +template <> +inline void write_payload(AmuletNBT::BinaryWriter& writer, const AmuletNBT::CompoundTag& value){ + for (auto it = value.begin(); it != value.end(); it++){ write_name_and_tag(writer, it->first, it->second); } writer.writeNumeric(0); @@ -184,11 +211,11 @@ void write_compound_payload(AmuletNBT::BinaryWriter& writer, const AmuletNBT::Co template - std::string _write_nbt(const std::string& name, const T& tag, std::endian endianness, AmuletNBT::StringEncode string_encode){ - AmuletNBT::BinaryWriter writer(endianness, string_encode); - write_name_and_tag(writer, name, tag); - return writer.getBuffer(); - } +inline std::string _write_nbt(const std::string& name, const T& tag, std::endian endianness, AmuletNBT::StringEncode string_encode){ + AmuletNBT::BinaryWriter writer(endianness, string_encode); + write_name_and_tag(writer, name, tag); + return writer.getBuffer(); +} namespace AmuletNBT { std::string write_nbt(const std::string& name, const AmuletNBT::ByteTag& tag, std::endian endianness, AmuletNBT::StringEncode string_encode){ @@ -209,22 +236,22 @@ namespace AmuletNBT { std::string write_nbt(const std::string& name, const AmuletNBT::DoubleTag& tag, std::endian endianness, AmuletNBT::StringEncode string_encode){ return _write_nbt(name, tag, endianness, string_encode); }; - std::string write_nbt(const std::string& name, const AmuletNBT::ByteArrayTagPtr& tag, std::endian endianness, AmuletNBT::StringEncode string_encode){ + std::string write_nbt(const std::string& name, const AmuletNBT::ByteArrayTag& tag, std::endian endianness, AmuletNBT::StringEncode string_encode){ return _write_nbt(name, tag, endianness, string_encode); }; std::string write_nbt(const std::string& name, const AmuletNBT::StringTag& tag, std::endian endianness, AmuletNBT::StringEncode string_encode){ return _write_nbt(name, tag, endianness, string_encode); }; - std::string write_nbt(const std::string& name, const AmuletNBT::ListTagPtr& tag, std::endian endianness, AmuletNBT::StringEncode string_encode){ + std::string write_nbt(const std::string& name, const AmuletNBT::ListTag& tag, std::endian endianness, AmuletNBT::StringEncode string_encode){ return _write_nbt(name, tag, endianness, string_encode); }; - std::string write_nbt(const std::string& name, const AmuletNBT::CompoundTagPtr& tag, std::endian endianness, AmuletNBT::StringEncode string_encode){ + std::string write_nbt(const std::string& name, const AmuletNBT::CompoundTag& tag, std::endian endianness, AmuletNBT::StringEncode string_encode){ return _write_nbt(name, tag, endianness, string_encode); }; - std::string write_nbt(const std::string& name, const AmuletNBT::IntArrayTagPtr& tag, std::endian endianness, AmuletNBT::StringEncode string_encode){ + std::string write_nbt(const std::string& name, const AmuletNBT::IntArrayTag& tag, std::endian endianness, AmuletNBT::StringEncode string_encode){ return _write_nbt(name, tag, endianness, string_encode); }; - std::string write_nbt(const std::string& name, const AmuletNBT::LongArrayTagPtr& tag, std::endian endianness, AmuletNBT::StringEncode string_encode){ + std::string write_nbt(const std::string& name, const AmuletNBT::LongArrayTag& tag, std::endian endianness, AmuletNBT::StringEncode string_encode){ return _write_nbt(name, tag, endianness, string_encode); }; std::string write_nbt(const std::string& name, const AmuletNBT::TagNode& tag, std::endian endianness, AmuletNBT::StringEncode string_encode){ diff --git a/src/amulet_nbt/cpp/nbt_encoding/string/read_string.cpp b/src/amulet_nbt/cpp/nbt_encoding/string/read_string.cpp index f4bf6504..f02828bc 100644 --- a/src/amulet_nbt/cpp/nbt_encoding/string/read_string.cpp +++ b/src/amulet_nbt/cpp/nbt_encoding/string/read_string.cpp @@ -138,14 +138,38 @@ inline std::pair find_int(const AmuletNBT::CodePointVector& snbt } -template -inline T read_int(const AmuletNBT::CodePointVector& snbt, size_t start, size_t stop){ +template < + typename T, + std::enable_if_t< + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v, + bool + > = true +> +inline T read_int(const AmuletNBT::CodePointVector& snbt, const size_t& start, const size_t& stop){ std::string text; AmuletNBT::write_utf8(text, AmuletNBT::CodePointVector(snbt.begin() + start, snbt.begin() + stop)); return static_cast(std::stoll(text)); } +template < + typename T, + std::enable_if_t< + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v, + bool + > = true +> +inline T read_int_tag(const AmuletNBT::CodePointVector& snbt, const size_t & start, const size_t & stop) { + return T(read_int(snbt, start, stop)); +} + + inline std::tuple find_float(const AmuletNBT::CodePointVector& snbt, const size_t& index){ // Find a float at position index. // If an float is found, the return value will be the start and end position of the float @@ -199,7 +223,14 @@ inline std::tuple find_float(const AmuletNBT::CodePointVec } -template +template < + typename T, + std::enable_if_t< + std::is_same_v || + std::is_same_v, + bool + > = true +> inline T read_float(const AmuletNBT::CodePointVector& snbt, size_t start, size_t stop){ std::string text; AmuletNBT::write_utf8(text, AmuletNBT::CodePointVector(snbt.begin() + start, snbt.begin() + stop)); @@ -211,26 +242,34 @@ inline T read_float(const AmuletNBT::CodePointVector& snbt, size_t start, size_t } -template +template < + typename T, + std::enable_if_t< + std::is_same_v || + std::is_same_v || + std::is_same_v, + bool + > = true +> inline AmuletNBT::TagNode read_array(const AmuletNBT::CodePointVector& snbt, size_t& index){ //The caller must have read [ and validated B; but not read it (index must be after "[") // read past B; index += 2; read_whitespace(snbt, index); - std::vector arr; + std::vector arr; while (read_code_point(snbt, index) != ']'){ // read the number auto [start, stop] = find_int(snbt, index); if (start == stop){ throw std::invalid_argument("Expected a ] or int at position " + std::to_string(index) + " but got ->" + read_error(snbt, index) + " instead"); } - if constexpr (std::is_same_v){ + if constexpr (std::is_same_v){ if ((read_code_point(snbt, stop) | 32) != 'b'){ throw std::invalid_argument("Expected 'B' position " + std::to_string(stop) + " but got ->" + read_error(snbt, stop) + " instead"); } index = stop + 1; - } else if constexpr (std::is_same_v){ + } else if constexpr (std::is_same_v){ if ((read_code_point(snbt, stop) | 32) != 'l'){ throw std::invalid_argument("Expected 'L' position " + std::to_string(stop) + " but got ->" + read_error(snbt, stop) + " instead"); } @@ -240,13 +279,13 @@ inline AmuletNBT::TagNode read_array(const AmuletNBT::CodePointVector& snbt, siz } // read and append the value - arr.push_back(read_int(snbt, start, stop)); + arr.push_back(read_int(snbt, start, stop)); // Read past the comma read_comma(snbt, index, ']'); } index++; // seek past ']' - return std::make_shared>(arr.begin(), arr.end()); + return std::make_shared(arr.begin(), arr.end()); } @@ -267,7 +306,10 @@ AmuletNBT::TagNode _read_snbt(const AmuletNBT::CodePointVector& snbt, size_t& in read_colon(snbt, index); // Read the nested value - (*tag)[key] = _read_snbt(snbt, index); + AmuletNBT::TagNode node = _read_snbt(snbt, index); + + // Write to the map + tag->insert_or_assign(key, node); // Read past the comma read_comma(snbt, index, '}'); @@ -281,13 +323,13 @@ AmuletNBT::TagNode _read_snbt(const AmuletNBT::CodePointVector& snbt, size_t& in if (snbt.size() >= index + 2){ if (snbt[index] == 'B' && snbt[index+1] == ';'){ // byte array - return read_array(snbt, index); + return read_array(snbt, index); } else if (snbt[index] == 'I' && snbt[index+1] == ';'){ // int array - return read_array(snbt, index); + return read_array(snbt, index); } else if (snbt[index] == 'L' && snbt[index+1] == ';'){ // long array - return read_array(snbt, index); + return read_array(snbt, index); } else { // list auto tag = std::make_shared(); @@ -299,7 +341,7 @@ AmuletNBT::TagNode _read_snbt(const AmuletNBT::CodePointVector& snbt, size_t& in throw std::invalid_argument("All elements of a list tag must have the same type."); } - AmuletNBT::ListTag_append(*tag, value); + AmuletNBT::ListTag_append(*tag, value); // Read past the comma read_comma(snbt, index, ']'); @@ -345,15 +387,15 @@ AmuletNBT::TagNode _read_snbt(const AmuletNBT::CodePointVector& snbt, size_t& in auto [int_start, int_stop] = find_int(string, 0); if (int_stop == string.size()){ // found an int that takes the whole string - return read_int(string, int_start, int_stop); + return read_int_tag(string, int_start, int_stop); } else if (int_start != int_stop && int_stop == string.size() - 1) { switch (string[string.size() - 1] | 32){ case 'b': - return read_int(string, int_start, int_stop); + return read_int_tag(string, int_start, int_stop); case 's': - return read_int(string, int_start, int_stop); + return read_int_tag(string, int_start, int_stop); case 'l': - return read_int(string, int_start, int_stop); + return read_int_tag(string, int_start, int_stop); } } diff --git a/src/amulet_nbt/cpp/nbt_encoding/string/write_string.cpp b/src/amulet_nbt/cpp/nbt_encoding/string/write_string.cpp index 871e833f..6acc47a7 100644 --- a/src/amulet_nbt/cpp/nbt_encoding/string/write_string.cpp +++ b/src/amulet_nbt/cpp/nbt_encoding/string/write_string.cpp @@ -15,75 +15,66 @@ #include #include -#include +#include +#include +#include +#include +#include +#include +#include #include #include namespace AmuletNBT { // Forward declarations - void write_formatted_snbt(std::string&, const AmuletNBT::TagNode&, const std::string&, size_t); - void write_formatted_snbt(std::string&, const AmuletNBT::ListTag&, const std::string&, size_t); - void write_formatted_snbt(std::string&, const AmuletNBT::CompoundTag&, const std::string&, size_t); + void write_formatted_snbt(std::string& snbt, const AmuletNBT::TagNode& node, const std::string& indent, const size_t& indent_count); + void write_formatted_snbt(std::string& snbt, const AmuletNBT::ListTag& tag, const std::string& indent, const size_t& indent_count); + void write_formatted_snbt(std::string& snbt, const AmuletNBT::CompoundTag& tag, const std::string& indent, const size_t& indent_count); - inline void write_indent(std::string& snbt, const std::string& indent, size_t indent_count){ + inline void write_indent(std::string& snbt, const std::string& indent, const size_t& indent_count){ for (size_t i = 0; i < indent_count; i++){ snbt.append(indent); } } - void write_snbt(std::string& snbt, const TagNode& tag){ - switch (tag.index()){ - case 1: write_snbt(snbt, std::get(tag)); break; - case 2: write_snbt(snbt, std::get(tag)); break; - case 3: write_snbt(snbt, std::get(tag)); break; - case 4: write_snbt(snbt, std::get(tag)); break; - case 5: write_snbt(snbt, std::get(tag)); break; - case 6: write_snbt(snbt, std::get(tag)); break; - case 7: write_snbt(snbt, *std::get(tag)); break; - case 8: write_snbt(snbt, std::get(tag)); break; - case 9: write_snbt(snbt, *std::get(tag)); break; - case 10: write_snbt(snbt, *std::get(tag)); break; - case 11: write_snbt(snbt, *std::get(tag)); break; - case 12: write_snbt(snbt, *std::get(tag)); break; - default: throw std::runtime_error("TagNode cannot be in null state when writing."); - } + inline void write_snbt(std::string& snbt, const TagNode& node){ + std::visit([&snbt](auto&& tag){ + write_snbt(snbt, tag); + }, node); } - void write_formatted_snbt(std::string& snbt, const TagNode& tag, const std::string& indent, size_t indent_count){ - switch (tag.index()){ - case 1: write_snbt(snbt, std::get(tag)); break; - case 2: write_snbt(snbt, std::get(tag)); break; - case 3: write_snbt(snbt, std::get(tag)); break; - case 4: write_snbt(snbt, std::get(tag)); break; - case 5: write_snbt(snbt, std::get(tag)); break; - case 6: write_snbt(snbt, std::get(tag)); break; - case 7: write_snbt(snbt, *std::get(tag)); break; - case 8: write_snbt(snbt, std::get(tag)); break; - case 9: write_formatted_snbt(snbt, *std::get(tag), indent, indent_count); break; - case 10: write_formatted_snbt(snbt, *std::get(tag), indent, indent_count); break; - case 11: write_snbt(snbt, *std::get(tag)); break; - case 12: write_snbt(snbt, *std::get(tag)); break; - default: throw std::runtime_error("TagNode cannot be in null state when writing."); - } + inline void write_formatted_snbt(std::string& snbt, const TagNode& node, const std::string& indent, const size_t& indent_count){ + std::visit([&snbt, &indent, &indent_count](auto&& tag) { + using T = std::decay_t; + if constexpr (std::is_same_v || std::is_same_v) { + write_formatted_snbt(snbt, *tag, indent, indent_count); + } + else if constexpr (is_shared_ptr()) { + write_snbt(snbt, *tag); + } + else { + write_snbt(snbt, tag); + } + }, node); } - void write_snbt(std::string& snbt, const ByteTag& tag){ - snbt.append(std::to_string(tag)); + inline void write_snbt(std::string& snbt, const ByteTag& tag){ + snbt.append(std::to_string(static_cast(tag))); snbt.push_back('b'); } - void write_snbt(std::string& snbt, const ShortTag& tag){ - snbt.append(std::to_string(tag)); + inline void write_snbt(std::string& snbt, const ShortTag& tag){ + snbt.append(std::to_string(static_cast(tag))); snbt.push_back('s'); } - void write_snbt(std::string& snbt, const IntTag& tag){ - snbt.append(std::to_string(tag)); + inline void write_snbt(std::string& snbt, const IntTag& tag){ + snbt.append(std::to_string(static_cast(tag))); } - void write_snbt(std::string& snbt, const LongTag& tag){ - snbt.append(std::to_string(tag)); + inline void write_snbt(std::string& snbt, const LongTag& tag){ + snbt.append(std::to_string(static_cast(tag))); snbt.push_back('L'); } @@ -94,26 +85,26 @@ namespace AmuletNBT { return oss.str(); } - void write_snbt(std::string& snbt, const FloatTag& tag){ + inline void write_snbt(std::string& snbt, const FloatTag& tag){ if (std::isfinite(tag)){ - snbt.append(encode_float(tag)); + snbt.append(encode_float(tag)); snbt.push_back('f'); - } else if (tag == std::numeric_limits::infinity()){ + } else if (tag == std::numeric_limits::infinity()){ snbt.append("Infinityf"); - } else if (tag == -std::numeric_limits::infinity()){ + } else if (tag == -std::numeric_limits::infinity()){ snbt.append("-Infinityf"); } else { snbt.append("NaNf"); } } - void write_snbt(std::string& snbt, const DoubleTag& tag){ + inline void write_snbt(std::string& snbt, const DoubleTag& tag){ if (std::isfinite(tag)){ - snbt.append(encode_float(tag)); + snbt.append(encode_float(tag)); snbt.push_back('d'); - } else if (tag == std::numeric_limits::infinity()){ + } else if (tag == std::numeric_limits::infinity()){ snbt.append("Infinityd"); - } else if (tag == -std::numeric_limits::infinity()){ + } else if (tag == -std::numeric_limits::infinity()){ snbt.append("-Infinityd"); } else { snbt.append("NaNd"); @@ -121,7 +112,7 @@ namespace AmuletNBT { } - void write_snbt(std::string& snbt, const StringTag& tag){ + inline void write_snbt(std::string& snbt, const StringTag& tag){ std::string result = tag; size_t pos = 0; @@ -143,7 +134,7 @@ namespace AmuletNBT { template - void write_snbt_list(std::string& snbt, const ListTag& tag){ + inline void write_snbt_list(std::string& snbt, const ListTag& tag){ const std::vector& list = std::get>(tag); snbt.append("["); for (size_t i = 0; i < list.size(); i++){ @@ -160,7 +151,7 @@ namespace AmuletNBT { } - void write_snbt(std::string& snbt, const ListTag& tag){ + inline void write_snbt(std::string& snbt, const ListTag& tag){ switch (tag.index()){ case 0: snbt.append("[]"); break; case 1: write_snbt_list(snbt, tag); break; @@ -179,7 +170,7 @@ namespace AmuletNBT { } template - void write_formatted_snbt_list(std::string& snbt, const ListTag& tag, const std::string& indent, size_t indent_count){ + inline void write_formatted_snbt_list(std::string& snbt, const ListTag& tag, const std::string& indent, const size_t& indent_count){ const std::vector& list = std::get>(tag); snbt.append("["); for (size_t i = 0; i < list.size(); i++){ @@ -203,7 +194,7 @@ namespace AmuletNBT { snbt.append("]"); } - void write_formatted_snbt(std::string& snbt, const ListTag& tag, const std::string& indent, size_t indent_count){ + inline void write_formatted_snbt(std::string& snbt, const ListTag& tag, const std::string& indent, const size_t& indent_count){ switch (tag.index()){ case 0: snbt.append("[]"); break; case 1: write_formatted_snbt_list(snbt, tag, indent, indent_count); break; @@ -222,7 +213,7 @@ namespace AmuletNBT { } - void write_key(std::string& snbt, const StringTag& key){ + inline void write_key(std::string& snbt, const StringTag& key){ if (std::all_of(key.begin(), key.end(), [](char c) { return std::isalnum(c) || c == '.' || c == '_' || c == '+' || c == '-'; })){ @@ -233,7 +224,7 @@ namespace AmuletNBT { } - std::vector> sort_compound(const CompoundTag& tag){ + inline std::vector> sort_compound(const CompoundTag& tag){ std::vector> keys(tag.begin(), tag.end()); std::locale locale; try { @@ -251,7 +242,7 @@ namespace AmuletNBT { } - void write_snbt(std::string& snbt, const CompoundTag& tag){ + inline void write_snbt(std::string& snbt, const CompoundTag& tag){ auto sorted = sort_compound(tag); snbt.append("{"); for (size_t i = 0; i < sorted.size(); i++){ @@ -266,7 +257,7 @@ namespace AmuletNBT { } - void write_formatted_snbt(std::string& snbt, const CompoundTag& tag, const std::string& indent, size_t indent_count){ + inline void write_formatted_snbt(std::string& snbt, const CompoundTag& tag, const std::string& indent, const size_t& indent_count){ auto sorted = sort_compound(tag); snbt.append("{"); for (auto it = sorted.begin(); it != sorted.end(); it++){ @@ -286,7 +277,7 @@ namespace AmuletNBT { } - void write_snbt(std::string& snbt, const ByteArrayTag& tag){ + inline void write_snbt(std::string& snbt, const ByteArrayTag& tag){ snbt.append("[B;"); for (size_t i = 0; i < tag.size(); i++){ snbt.append(std::to_string(tag[i])); @@ -299,7 +290,7 @@ namespace AmuletNBT { } - void write_snbt(std::string& snbt, const IntArrayTag& tag){ + inline void write_snbt(std::string& snbt, const IntArrayTag& tag){ snbt.append("[I;"); for (size_t i = 0; i < tag.size(); i++){ snbt.append(std::to_string(tag[i])); @@ -311,7 +302,7 @@ namespace AmuletNBT { } - void write_snbt(std::string& snbt, const LongArrayTag& tag){ + inline void write_snbt(std::string& snbt, const LongArrayTag& tag){ snbt.append("[L;"); for (size_t i = 0; i < tag.size(); i++){ snbt.append(std::to_string(tag[i])); @@ -324,158 +315,155 @@ namespace AmuletNBT { } - std::string write_snbt(const TagNode& tag){ + inline std::string write_snbt(const TagNode& tag){ std::string snbt; write_snbt(snbt, tag); return snbt; } - std::string write_snbt(const ByteTag& tag){ + inline std::string write_snbt(const ByteTag& tag){ std::string snbt; write_snbt(snbt, tag); return snbt; } - std::string write_snbt(const ShortTag& tag){ + inline std::string write_snbt(const ShortTag& tag){ std::string snbt; write_snbt(snbt, tag); return snbt; } - std::string write_snbt(const IntTag& tag){ + inline std::string write_snbt(const IntTag& tag){ std::string snbt; write_snbt(snbt, tag); return snbt; } - std::string write_snbt(const LongTag& tag){ + inline std::string write_snbt(const LongTag& tag){ std::string snbt; write_snbt(snbt, tag); return snbt; } - std::string write_snbt(const FloatTag& tag){ + inline std::string write_snbt(const FloatTag& tag){ std::string snbt; write_snbt(snbt, tag); return snbt; } - std::string write_snbt(const DoubleTag& tag){ + inline std::string write_snbt(const DoubleTag& tag){ std::string snbt; write_snbt(snbt, tag); return snbt; } - std::string write_snbt(const ByteArrayTag& tag){ + inline std::string write_snbt(const ByteArrayTag& tag){ std::string snbt; write_snbt(snbt, tag); return snbt; } - std::string write_snbt(const StringTag& tag){ + inline std::string write_snbt(const StringTag& tag){ std::string snbt; write_snbt(snbt, tag); return snbt; } - std::string write_snbt(const ListTag& tag){ + inline std::string write_snbt(const ListTag& tag){ std::string snbt; write_snbt(snbt, tag); return snbt; } - std::string write_snbt(const CompoundTag& tag){ + inline std::string write_snbt(const CompoundTag& tag){ std::string snbt; write_snbt(snbt, tag); return snbt; } - std::string write_snbt(const IntArrayTag& tag){ + inline std::string write_snbt(const IntArrayTag& tag){ std::string snbt; write_snbt(snbt, tag); return snbt; } - std::string write_snbt(const LongArrayTag& tag){ + inline std::string write_snbt(const LongArrayTag& tag){ std::string snbt; write_snbt(snbt, tag); return snbt; } - void write_formatted_snbt(std::string& snbt, const TagNode& tag, const std::string& indent){ - size_t indent_count = 0; - return write_formatted_snbt(snbt, tag, indent, indent_count); + inline void write_formatted_snbt(std::string& snbt, const TagNode& tag, const std::string& indent){ + return write_formatted_snbt(snbt, tag, indent, 0); } - void write_formatted_snbt(std::string& snbt, const ByteTag& tag, const std::string& indent){ + inline void write_formatted_snbt(std::string& snbt, const ByteTag& tag, const std::string& indent){ write_snbt(snbt, tag); } - void write_formatted_snbt(std::string& snbt, const ShortTag& tag, const std::string& indent){ + inline void write_formatted_snbt(std::string& snbt, const ShortTag& tag, const std::string& indent){ write_snbt(snbt, tag); } - void write_formatted_snbt(std::string& snbt, const IntTag& tag, const std::string& indent){ + inline void write_formatted_snbt(std::string& snbt, const IntTag& tag, const std::string& indent){ write_snbt(snbt, tag); } - void write_formatted_snbt(std::string& snbt, const LongTag& tag, const std::string& indent){ + inline void write_formatted_snbt(std::string& snbt, const LongTag& tag, const std::string& indent){ write_snbt(snbt, tag); } - void write_formatted_snbt(std::string& snbt, const FloatTag& tag, const std::string& indent){ + inline void write_formatted_snbt(std::string& snbt, const FloatTag& tag, const std::string& indent){ write_snbt(snbt, tag); } - void write_formatted_snbt(std::string& snbt, const DoubleTag& tag, const std::string& indent){ + inline void write_formatted_snbt(std::string& snbt, const DoubleTag& tag, const std::string& indent){ write_snbt(snbt, tag); } - void write_formatted_snbt(std::string& snbt, const ByteArrayTag& tag, const std::string& indent){ + inline void write_formatted_snbt(std::string& snbt, const ByteArrayTag& tag, const std::string& indent){ write_snbt(snbt, tag); } - void write_formatted_snbt(std::string& snbt, const StringTag& tag, const std::string& indent){ + inline void write_formatted_snbt(std::string& snbt, const StringTag& tag, const std::string& indent){ write_snbt(snbt, tag); } - void write_formatted_snbt(std::string& snbt, const ListTag& tag, const std::string& indent){ - size_t indent_count = 0; - return write_formatted_snbt(snbt, tag, indent, indent_count); + inline void write_formatted_snbt(std::string& snbt, const ListTag& tag, const std::string& indent){ + return write_formatted_snbt(snbt, tag, indent, 0); } - void write_formatted_snbt(std::string& snbt, const CompoundTag& tag, const std::string& indent){ - size_t indent_count = 0; - return write_formatted_snbt(snbt, tag, indent, indent_count); + inline void write_formatted_snbt(std::string& snbt, const CompoundTag& tag, const std::string& indent){ + return write_formatted_snbt(snbt, tag, indent, 0); } - void write_formatted_snbt(std::string& snbt, const IntArrayTag& tag, const std::string& indent){ + inline void write_formatted_snbt(std::string& snbt, const IntArrayTag& tag, const std::string& indent){ write_snbt(snbt, tag); } - void write_formatted_snbt(std::string& snbt, const LongArrayTag& tag, const std::string& indent){ + inline void write_formatted_snbt(std::string& snbt, const LongArrayTag& tag, const std::string& indent){ write_snbt(snbt, tag); } - std::string write_formatted_snbt(const TagNode& tag, const std::string& indent){ + inline std::string write_formatted_snbt(const TagNode& tag, const std::string& indent){ std::string snbt; write_formatted_snbt(snbt, tag, indent); return snbt; } - std::string write_formatted_snbt(const ByteTag& tag, const std::string& indent){ + inline std::string write_formatted_snbt(const ByteTag& tag, const std::string& indent){ return write_snbt(tag); } - std::string write_formatted_snbt(const ShortTag& tag, const std::string& indent){ + inline std::string write_formatted_snbt(const ShortTag& tag, const std::string& indent){ return write_snbt(tag); } - std::string write_formatted_snbt(const IntTag& tag, const std::string& indent){ + inline std::string write_formatted_snbt(const IntTag& tag, const std::string& indent){ return write_snbt(tag); } - std::string write_formatted_snbt(const LongTag& tag, const std::string& indent){ + inline std::string write_formatted_snbt(const LongTag& tag, const std::string& indent){ return write_snbt(tag); } - std::string write_formatted_snbt(const FloatTag& tag, const std::string& indent){ + inline std::string write_formatted_snbt(const FloatTag& tag, const std::string& indent){ return write_snbt(tag); } - std::string write_formatted_snbt(const DoubleTag& tag, const std::string& indent){ + inline std::string write_formatted_snbt(const DoubleTag& tag, const std::string& indent){ return write_snbt(tag); } - std::string write_formatted_snbt(const ByteArrayTag& tag, const std::string& indent){ + inline std::string write_formatted_snbt(const ByteArrayTag& tag, const std::string& indent){ return write_snbt(tag); } - std::string write_formatted_snbt(const StringTag& tag, const std::string& indent){ + inline std::string write_formatted_snbt(const StringTag& tag, const std::string& indent){ return write_snbt(tag); } - std::string write_formatted_snbt(const ListTag& tag, const std::string& indent){ + inline std::string write_formatted_snbt(const ListTag& tag, const std::string& indent){ std::string snbt; write_formatted_snbt(snbt, tag, indent); return snbt; } - std::string write_formatted_snbt(const CompoundTag& tag, const std::string& indent){ + inline std::string write_formatted_snbt(const CompoundTag& tag, const std::string& indent){ std::string snbt; write_formatted_snbt(snbt, tag, indent); return snbt; } - std::string write_formatted_snbt(const IntArrayTag& tag, const std::string& indent){ + inline std::string write_formatted_snbt(const IntArrayTag& tag, const std::string& indent){ return write_snbt(tag); } - std::string write_formatted_snbt(const LongArrayTag& tag, const std::string& indent){ + inline std::string write_formatted_snbt(const LongArrayTag& tag, const std::string& indent){ return write_snbt(tag); } } diff --git a/src/amulet_nbt/cpp/tag/compound.cpp b/src/amulet_nbt/cpp/tag/compound.cpp deleted file mode 100644 index 83ea426f..00000000 --- a/src/amulet_nbt/cpp/tag/compound.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include -#include -#include - -#include - -namespace AmuletNBT { - CompoundTagIterator::CompoundTagIterator( - AmuletNBT::CompoundTagPtr tag - ): tag(tag), begin(tag->begin()), end(tag->end()), pos(tag->begin()), size(tag->size()) {}; - - std::string CompoundTagIterator::next(){ - if (!is_valid()){ - throw std::runtime_error("CompoundTag changed size during iteration."); - } - return (pos++)->first; - }; - - bool CompoundTagIterator::has_next(){ - return pos != end; - }; - - bool CompoundTagIterator::is_valid(){ - // This is not fool proof. - // There are cases where this is true but the iterator is invalid. - // The programmer should write good code and this will catch some of the bad cases. - return size == tag->size() && begin == tag->begin() && end == tag->end(); - }; -} diff --git a/src/amulet_nbt/cpp/tag/copy.cpp b/src/amulet_nbt/cpp/tag/copy.cpp index 3398ae88..793d9a76 100644 --- a/src/amulet_nbt/cpp/tag/copy.cpp +++ b/src/amulet_nbt/cpp/tag/copy.cpp @@ -4,86 +4,87 @@ #include #include #include +#include + +#include +#include +#include +#include +#include +#include #include + namespace AmuletNBT { - template - AmuletNBT::ListTagPtr NBTTag_deep_copy_list_vector(const std::vector& tag){ + template < + typename T, + std::enable_if_t< + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v, + bool + > = true + > + AmuletNBT::ListTagPtr NBTTag_deep_copy_list_vector(const std::vector&tag) { AmuletNBT::ListTagPtr new_tag = std::make_shared(std::in_place_type>); std::vector& new_vector = std::get>(*new_tag); - for (T value: tag){ - if constexpr (std::is_same_v){ + for (T value : tag) { + if constexpr (std::is_same_v) { new_vector.push_back(NBTTag_deep_copy_list(*value)); - } else if constexpr (std::is_same_v){ + } + else if constexpr (std::is_same_v) { new_vector.push_back(NBTTag_deep_copy_compound(*value)); - } else if constexpr (std::is_same_v){ - new_vector.push_back(NBTTag_copy(*value)); - } else if constexpr (std::is_same_v){ - new_vector.push_back(NBTTag_copy(*value)); - } else { - static_assert(std::is_same_v); - new_vector.push_back(NBTTag_copy(*value)); + } + else { + new_vector.push_back(NBTTag_copy(*value)); } } return new_tag; } - AmuletNBT::ListTagPtr NBTTag_deep_copy_list(const AmuletNBT::ListTag& tag){ - switch (tag.index()){ - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 8: - return std::make_shared(tag); - case 7: - return NBTTag_deep_copy_list_vector(std::get(tag)); - case 9: - return NBTTag_deep_copy_list_vector(std::get(tag)); - case 10: - return NBTTag_deep_copy_list_vector(std::get(tag)); - case 11: - return NBTTag_deep_copy_list_vector(std::get(tag)); - case 12: - return NBTTag_deep_copy_list_vector(std::get(tag)); - default: - throw std::runtime_error(""); - } + AmuletNBT::ListTagPtr NBTTag_deep_copy_list(const AmuletNBT::ListTag& tag) { + return std::visit([](auto&& list) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + return std::make_shared(); + } + else if constexpr (is_shared_ptr::value) { + return NBTTag_deep_copy_list_vector(list); + } + else { + return std::make_shared(list); + } + }, tag); } - AmuletNBT::TagNode NBTTag_deep_copy_node(const AmuletNBT::TagNode& tag) { - switch (tag.index()){ - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 8: + AmuletNBT::TagNode NBTTag_deep_copy_node(const AmuletNBT::TagNode& node) { + return std::visit([](auto&& tag) -> AmuletNBT::TagNode { + using T = std::decay_t; + if constexpr (std::is_same_v) { + return NBTTag_deep_copy_list(*tag); + } + else if constexpr (std::is_same_v) { + return NBTTag_deep_copy_compound(*tag); + } + else if constexpr ( + std::is_same_v || + std::is_same_v || + std::is_same_v + ) { + return NBTTag_copy(*tag); + } + else { return tag; - case 7: - return NBTTag_copy(*std::get(tag)); - case 9: - return NBTTag_deep_copy_list(*std::get(tag)); - case 10: - return NBTTag_deep_copy_compound(*std::get(tag)); - case 11: - return NBTTag_copy(*std::get(tag)); - case 12: - return NBTTag_copy(*std::get(tag)); - default: - throw std::runtime_error(""); - } + } + }, node); } - AmuletNBT::CompoundTagPtr NBTTag_deep_copy_compound(const AmuletNBT::CompoundTag& tag){ + AmuletNBT::CompoundTagPtr NBTTag_deep_copy_compound(const AmuletNBT::CompoundTag& tag) { auto new_tag = std::make_shared(); - for (auto& [key, value]: tag){ + for (auto& [key, value] : tag) { (*new_tag)[key] = NBTTag_deep_copy_node(value); } return new_tag; diff --git a/src/amulet_nbt/cpp/tag/eq.cpp b/src/amulet_nbt/cpp/tag/eq.cpp index 6555f918..7919a979 100644 --- a/src/amulet_nbt/cpp/tag/eq.cpp +++ b/src/amulet_nbt/cpp/tag/eq.cpp @@ -4,29 +4,33 @@ #include #include +#include +#include +#include #include +#include +#include #include namespace AmuletNBT{ - bool NBTTag_eq(const AmuletNBT::ByteTag a, const AmuletNBT::ByteTag b){return a == b;}; - bool NBTTag_eq(const AmuletNBT::ShortTag a, const AmuletNBT::ShortTag b){return a == b;}; - bool NBTTag_eq(const AmuletNBT::IntTag a, const AmuletNBT::IntTag b){return a == b;}; - bool NBTTag_eq(const AmuletNBT::LongTag a, const AmuletNBT::LongTag b){return a == b;}; - bool NBTTag_eq(const AmuletNBT::FloatTag a, const AmuletNBT::FloatTag b){return a == b;}; - bool NBTTag_eq(const AmuletNBT::DoubleTag a, const AmuletNBT::DoubleTag b){return a == b;}; - bool NBTTag_eq(const AmuletNBT::StringTag a, const AmuletNBT::StringTag b){return a == b;}; + bool NBTTag_eq(const AmuletNBT::ByteTag& a, const AmuletNBT::ByteTag& b){return a == b;}; + bool NBTTag_eq(const AmuletNBT::ShortTag& a, const AmuletNBT::ShortTag& b){return a == b;}; + bool NBTTag_eq(const AmuletNBT::IntTag& a, const AmuletNBT::IntTag& b){return a == b;}; + bool NBTTag_eq(const AmuletNBT::LongTag& a, const AmuletNBT::LongTag& b){return a == b;}; + bool NBTTag_eq(const AmuletNBT::FloatTag& a, const AmuletNBT::FloatTag& b){return a == b;}; + bool NBTTag_eq(const AmuletNBT::DoubleTag& a, const AmuletNBT::DoubleTag& b){return a == b;}; + bool NBTTag_eq(const AmuletNBT::StringTag& a, const AmuletNBT::StringTag& b){return a == b;}; bool NBTTag_eq(const AmuletNBT::ByteArrayTagPtr a, const AmuletNBT::ByteArrayTagPtr b){return *a == *b;}; bool NBTTag_eq(const AmuletNBT::IntArrayTagPtr a, const AmuletNBT::IntArrayTagPtr b){return *a == *b;}; bool NBTTag_eq(const AmuletNBT::LongArrayTagPtr a, const AmuletNBT::LongArrayTagPtr b){return *a == *b;}; template - inline bool ListTag_eq(const AmuletNBT::ListTagPtr a, const AmuletNBT::ListTagPtr b){ - const std::vector& a_vec = std::get>(*a); - if (b->index() != variant_index>()){ - return a_vec.size() == 0 && ListTag_size(*b) == 0; + inline bool ListTag_eq(const std::vector& a_vec, const AmuletNBT::ListTag& b){ + if (b.index() != variant_index>()){ + return a_vec.size() == 0 && ListTag_size(b) == 0; } - const std::vector& b_vec = std::get>(*b); + const std::vector& b_vec = std::get>(b); if constexpr (is_shared_ptr::value){ // Values are shared pointers @@ -44,24 +48,25 @@ namespace AmuletNBT{ return a_vec == b_vec; } } - bool NBTTag_eq(const AmuletNBT::ListTagPtr a, const AmuletNBT::ListTagPtr b){ - switch(a->index()){ - #define CASE(ID, TAG_NAME, TAG, TAG_STORAGE, LIST_TAG) case ID: return ListTag_eq(a, b); - case 0: - return ListTag_size(*b) == 0; - FOR_EACH_LIST_TAG(CASE) - #undef CASE - } - return false; + bool NBTTag_eq(const AmuletNBT::ListTag& a, const AmuletNBT::ListTag b){ + return std::visit([&b](auto&& list) -> bool { + using T = std::decay_t; + if constexpr (std::is_same_v) { + return ListTag_size(b) == 0; + } + else { + return ListTag_eq(list, b); + } + }, a); }; - bool NBTTag_eq(const AmuletNBT::CompoundTagPtr a, const AmuletNBT::CompoundTagPtr b){ - if (a->size() != b->size()){ + bool NBTTag_eq(const AmuletNBT::CompoundTag& a, const AmuletNBT::CompoundTag& b){ + if (a.size() != b.size()){ // Size does not match return false; } - for (auto& [key, value]: *a){ - AmuletNBT::CompoundTag::iterator it = b->find(key); - if (it == b->end()){ + for (auto& [key, value]: a){ + auto it = b.find(key); + if (it == b.end()){ // Key not in b return false; } @@ -72,14 +77,10 @@ namespace AmuletNBT{ } return true; }; - bool NBTTag_eq(const AmuletNBT::TagNode a, const AmuletNBT::TagNode b){ - switch(a.index()){ - #define CASE(ID, TAG_NAME, TAG, TAG_STORAGE, LIST_TAG) case ID: return b.index() == ID && NBTTag_eq(std::get(a), std::get(b)); - case 0: - return b.index() == 0; - FOR_EACH_LIST_TAG(CASE) - #undef CASE - } - return false; + bool NBTTag_eq(const AmuletNBT::TagNode& a, const AmuletNBT::TagNode& b){ + return std::visit([&b](auto&& tag) -> bool { + using T = std::decay_t; + return b.index() == variant_index() && NBTTag_eq(tag, std::get(b)); + }, a); }; } diff --git a/src/amulet_nbt/cpp/tag/list.cpp b/src/amulet_nbt/cpp/tag/list.cpp deleted file mode 100644 index 73c61b75..00000000 --- a/src/amulet_nbt/cpp/tag/list.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include -#include -#include - -#include -#include -#include -#include - -namespace AmuletNBT { - size_t ListTag_size(const AmuletNBT::ListTag& self){ - switch(self.index()){ - #define CASE(ID, TAG_NAME, TAG, TAG_STORAGE, LIST_TAG) case ID: return std::get(self).size(); - FOR_EACH_LIST_TAG(CASE) - #undef CASE - } - return 0; - }; - - void ListTag_append(AmuletNBT::ListTag& self, AmuletNBT::TagNode tag){ - switch(tag.index()){ - #define CASE(ID, TAG_NAME, TAG, TAG_STORAGE, LIST_TAG)\ - case ID:\ - ListTag_append(self, std::get(tag));\ - break; - case 0: - throw AmuletNBT::type_error("Cannot append null TagNode"); - FOR_EACH_LIST_TAG(CASE) - #undef CASE - } - } - - ListTagIterator::ListTagIterator(AmuletNBT::ListTagPtr tag, size_t start, std::ptrdiff_t step): tag(tag), index(start), step(step) {}; - AmuletNBT::TagNode ListTagIterator::next() { - auto node = AmuletNBT::ListTag_get_node(*tag, index); - index += step; - return node; - } - bool ListTagIterator::has_next(){ - return index >= 0 && index < ListTag_size(*tag); - } -} diff --git a/src/amulet_nbt/cpp/tag/wrapper.cpp b/src/amulet_nbt/cpp/tag/wrapper.cpp deleted file mode 100644 index 60109ea6..00000000 --- a/src/amulet_nbt/cpp/tag/wrapper.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include - -#include - -namespace AmuletNBT { - AmuletNBT::WrapperNode wrap_node(AmuletNBT::TagNode node){ - switch(node.index()){ - #define CASE(ID, TAG_NAME, TAG, TAG_STORAGE, LIST_TAG) case ID: return AmuletNBT::WrapperNode(TagWrapper(std::get(node))); - FOR_EACH_LIST_TAG(CASE) - default: - return AmuletNBT::WrapperNode(); - #undef CASE - } - } - AmuletNBT::TagNode unwrap_node(AmuletNBT::WrapperNode node){ - switch(node.index()){ - #define CASE(ID, TAG_NAME, TAG, TAG_STORAGE, LIST_TAG) case ID: return AmuletNBT::TagNode(std::get>(node).tag); - FOR_EACH_LIST_TAG(CASE) - default: - return AmuletNBT::TagNode(); - #undef CASE - } - } -} diff --git a/src/amulet_nbt/cpp/tag2/float.cpp b/src/amulet_nbt/cpp/tag2/float.cpp deleted file mode 100644 index 63088e20..00000000 --- a/src/amulet_nbt/cpp/tag2/float.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include - -namespace AmuletNBT { - template - FloatTagTemplate::FloatTagTemplate(): value(0.0){} - - template - FloatTagTemplate::FloatTagTemplate(T& value): value(value){} - - template class FloatTagTemplate; - template class FloatTagTemplate; -} diff --git a/src/amulet_nbt/cpp/tag2/int.cpp b/src/amulet_nbt/cpp/tag2/int.cpp deleted file mode 100644 index dbdacdeb..00000000 --- a/src/amulet_nbt/cpp/tag2/int.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include -#include - -namespace AmuletNBT { - template - IntTagTemplate::IntTagTemplate(): value(0){} - - template - IntTagTemplate::IntTagTemplate(T& value): value(value){} - - template class IntTagTemplate; - template class IntTagTemplate; - template class IntTagTemplate; - template class IntTagTemplate; -} diff --git a/src/amulet_nbt/cpp/tag2/string.cpp b/src/amulet_nbt/cpp/tag2/string.cpp deleted file mode 100644 index 25627068..00000000 --- a/src/amulet_nbt/cpp/tag2/string.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include - -namespace AmuletNBT { - StringTag::StringTag(): value(""){} - StringTag::StringTag(std::string& value): value(value){} -} diff --git a/src/amulet_nbt/include/amulet_nbt/common.hpp b/src/amulet_nbt/include/amulet_nbt/common.hpp index 56ee04b8..844a0f18 100644 --- a/src/amulet_nbt/include/amulet_nbt/common.hpp +++ b/src/amulet_nbt/include/amulet_nbt/common.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -26,4 +27,9 @@ namespace AmuletNBT { public: using std::runtime_error::runtime_error; }; + template + struct tag_id; + + template + inline constexpr std::uint8_t tag_id_v = tag_id::value; } diff --git a/src/amulet_nbt/include/amulet_nbt/nbt_encoding/binary.hpp b/src/amulet_nbt/include/amulet_nbt/nbt_encoding/binary.hpp index 9ceb7d25..bae2421c 100644 --- a/src/amulet_nbt/include/amulet_nbt/nbt_encoding/binary.hpp +++ b/src/amulet_nbt/include/amulet_nbt/nbt_encoding/binary.hpp @@ -4,29 +4,35 @@ #include #include #include -#include +#include +#include +#include +#include +#include +#include +#include #include #include #include namespace AmuletNBT { - AmuletNBT::NamedTag read_nbt(const std::string&, std::endian, AmuletNBT::StringDecode, size_t& offset); - AmuletNBT::NamedTag read_nbt(const std::string&, std::endian, AmuletNBT::StringDecode); - std::vector read_nbt_array(const std::string&, std::endian, AmuletNBT::StringDecode, size_t& offset); - std::vector read_nbt_array(const std::string&, std::endian, AmuletNBT::StringDecode, size_t& offset, size_t count); + NamedTag read_nbt(const std::string&, std::endian, StringDecode, size_t& offset); + NamedTag read_nbt(const std::string&, std::endian, StringDecode); + std::vector read_nbt_array(const std::string&, std::endian, StringDecode, size_t& offset); + std::vector read_nbt_array(const std::string&, std::endian, StringDecode, size_t& offset, size_t count); - std::string write_nbt(const std::string& name, const AmuletNBT::ByteTag&, std::endian, AmuletNBT::StringEncode); - std::string write_nbt(const std::string& name, const AmuletNBT::ShortTag&, std::endian, AmuletNBT::StringEncode); - std::string write_nbt(const std::string& name, const AmuletNBT::IntTag&, std::endian, AmuletNBT::StringEncode); - std::string write_nbt(const std::string& name, const AmuletNBT::LongTag&, std::endian, AmuletNBT::StringEncode); - std::string write_nbt(const std::string& name, const AmuletNBT::FloatTag&, std::endian, AmuletNBT::StringEncode); - std::string write_nbt(const std::string& name, const AmuletNBT::DoubleTag&, std::endian, AmuletNBT::StringEncode); - std::string write_nbt(const std::string& name, const AmuletNBT::ByteArrayTagPtr&, std::endian, AmuletNBT::StringEncode); - std::string write_nbt(const std::string& name, const AmuletNBT::StringTag&, std::endian, AmuletNBT::StringEncode); - std::string write_nbt(const std::string& name, const AmuletNBT::ListTagPtr&, std::endian, AmuletNBT::StringEncode); - std::string write_nbt(const std::string& name, const AmuletNBT::CompoundTagPtr&, std::endian, AmuletNBT::StringEncode); - std::string write_nbt(const std::string& name, const AmuletNBT::IntArrayTagPtr&, std::endian, AmuletNBT::StringEncode); - std::string write_nbt(const std::string& name, const AmuletNBT::LongArrayTagPtr&, std::endian, AmuletNBT::StringEncode); - std::string write_nbt(const std::string& name, const AmuletNBT::TagNode&, std::endian, AmuletNBT::StringEncode); - std::string write_nbt(const AmuletNBT::NamedTag& tag, std::endian, AmuletNBT::StringEncode); + std::string write_nbt(const std::string& name, const ByteTag&, std::endian, StringEncode); + std::string write_nbt(const std::string& name, const ShortTag&, std::endian, StringEncode); + std::string write_nbt(const std::string& name, const IntTag&, std::endian, StringEncode); + std::string write_nbt(const std::string& name, const LongTag&, std::endian, StringEncode); + std::string write_nbt(const std::string& name, const FloatTag&, std::endian, StringEncode); + std::string write_nbt(const std::string& name, const DoubleTag&, std::endian, StringEncode); + std::string write_nbt(const std::string& name, const ByteArrayTag&, std::endian, StringEncode); + std::string write_nbt(const std::string& name, const StringTag&, std::endian, StringEncode); + std::string write_nbt(const std::string& name, const ListTag&, std::endian, StringEncode); + std::string write_nbt(const std::string& name, const CompoundTag&, std::endian, StringEncode); + std::string write_nbt(const std::string& name, const IntArrayTag&, std::endian, StringEncode); + std::string write_nbt(const std::string& name, const LongArrayTag&, std::endian, StringEncode); + std::string write_nbt(const std::string& name, const TagNode&, std::endian, StringEncode); + std::string write_nbt(const NamedTag& tag, std::endian, StringEncode); } diff --git a/src/amulet_nbt/include/amulet_nbt/nbt_encoding/string.hpp b/src/amulet_nbt/include/amulet_nbt/nbt_encoding/string.hpp index 6a30d299..ebeb9145 100644 --- a/src/amulet_nbt/include/amulet_nbt/nbt_encoding/string.hpp +++ b/src/amulet_nbt/include/amulet_nbt/nbt_encoding/string.hpp @@ -2,67 +2,72 @@ #include -#include +#include +#include +#include +#include +#include +#include #include namespace AmuletNBT { - void write_snbt(std::string&, const AmuletNBT::TagNode&); - void write_snbt(std::string&, const AmuletNBT::ByteTag&); - void write_snbt(std::string&, const AmuletNBT::ShortTag&); - void write_snbt(std::string&, const AmuletNBT::IntTag&); - void write_snbt(std::string&, const AmuletNBT::LongTag&); - void write_snbt(std::string&, const AmuletNBT::FloatTag&); - void write_snbt(std::string&, const AmuletNBT::DoubleTag&); - void write_snbt(std::string&, const AmuletNBT::ByteArrayTag&); - void write_snbt(std::string&, const AmuletNBT::StringTag&); - void write_snbt(std::string&, const AmuletNBT::ListTag&); - void write_snbt(std::string&, const AmuletNBT::CompoundTag&); - void write_snbt(std::string&, const AmuletNBT::IntArrayTag&); - void write_snbt(std::string&, const AmuletNBT::LongArrayTag&); + void write_snbt(std::string&, const TagNode&); + void write_snbt(std::string&, const ByteTag&); + void write_snbt(std::string&, const ShortTag&); + void write_snbt(std::string&, const IntTag&); + void write_snbt(std::string&, const LongTag&); + void write_snbt(std::string&, const FloatTag&); + void write_snbt(std::string&, const DoubleTag&); + void write_snbt(std::string&, const ByteArrayTag&); + void write_snbt(std::string&, const StringTag&); + void write_snbt(std::string&, const ListTag&); + void write_snbt(std::string&, const CompoundTag&); + void write_snbt(std::string&, const IntArrayTag&); + void write_snbt(std::string&, const LongArrayTag&); - std::string write_snbt(const AmuletNBT::TagNode&); - std::string write_snbt(const AmuletNBT::ByteTag&); - std::string write_snbt(const AmuletNBT::ShortTag&); - std::string write_snbt(const AmuletNBT::IntTag&); - std::string write_snbt(const AmuletNBT::LongTag&); - std::string write_snbt(const AmuletNBT::FloatTag&); - std::string write_snbt(const AmuletNBT::DoubleTag&); - std::string write_snbt(const AmuletNBT::ByteArrayTag&); - std::string write_snbt(const AmuletNBT::StringTag&); - std::string write_snbt(const AmuletNBT::ListTag&); - std::string write_snbt(const AmuletNBT::CompoundTag&); - std::string write_snbt(const AmuletNBT::IntArrayTag&); - std::string write_snbt(const AmuletNBT::LongArrayTag&); + std::string write_snbt(const TagNode&); + std::string write_snbt(const ByteTag&); + std::string write_snbt(const ShortTag&); + std::string write_snbt(const IntTag&); + std::string write_snbt(const LongTag&); + std::string write_snbt(const FloatTag&); + std::string write_snbt(const DoubleTag&); + std::string write_snbt(const ByteArrayTag&); + std::string write_snbt(const StringTag&); + std::string write_snbt(const ListTag&); + std::string write_snbt(const CompoundTag&); + std::string write_snbt(const IntArrayTag&); + std::string write_snbt(const LongArrayTag&); // Multi-line variants - void write_formatted_snbt(std::string&, const AmuletNBT::TagNode&, const std::string& indent); - void write_formatted_snbt(std::string&, const AmuletNBT::ByteTag&, const std::string& indent); - void write_formatted_snbt(std::string&, const AmuletNBT::ShortTag&, const std::string& indent); - void write_formatted_snbt(std::string&, const AmuletNBT::IntTag&, const std::string& indent); - void write_formatted_snbt(std::string&, const AmuletNBT::LongTag&, const std::string& indent); - void write_formatted_snbt(std::string&, const AmuletNBT::FloatTag&, const std::string& indent); - void write_formatted_snbt(std::string&, const AmuletNBT::DoubleTag&, const std::string& indent); - void write_formatted_snbt(std::string&, const AmuletNBT::ByteArrayTag&, const std::string& indent); - void write_formatted_snbt(std::string&, const AmuletNBT::StringTag&, const std::string& indent); - void write_formatted_snbt(std::string&, const AmuletNBT::ListTag&, const std::string& indent); - void write_formatted_snbt(std::string&, const AmuletNBT::CompoundTag&, const std::string& indent); - void write_formatted_snbt(std::string&, const AmuletNBT::IntArrayTag&, const std::string& indent); - void write_formatted_snbt(std::string&, const AmuletNBT::LongArrayTag&, const std::string& indent); + void write_formatted_snbt(std::string&, const TagNode&, const std::string& indent); + void write_formatted_snbt(std::string&, const ByteTag&, const std::string& indent); + void write_formatted_snbt(std::string&, const ShortTag&, const std::string& indent); + void write_formatted_snbt(std::string&, const IntTag&, const std::string& indent); + void write_formatted_snbt(std::string&, const LongTag&, const std::string& indent); + void write_formatted_snbt(std::string&, const FloatTag&, const std::string& indent); + void write_formatted_snbt(std::string&, const DoubleTag&, const std::string& indent); + void write_formatted_snbt(std::string&, const ByteArrayTag&, const std::string& indent); + void write_formatted_snbt(std::string&, const StringTag&, const std::string& indent); + void write_formatted_snbt(std::string&, const ListTag&, const std::string& indent); + void write_formatted_snbt(std::string&, const CompoundTag&, const std::string& indent); + void write_formatted_snbt(std::string&, const IntArrayTag&, const std::string& indent); + void write_formatted_snbt(std::string&, const LongArrayTag&, const std::string& indent); - std::string write_formatted_snbt(const AmuletNBT::TagNode&, const std::string& indent); - std::string write_formatted_snbt(const AmuletNBT::ByteTag&, const std::string& indent); - std::string write_formatted_snbt(const AmuletNBT::ShortTag&, const std::string& indent); - std::string write_formatted_snbt(const AmuletNBT::IntTag&, const std::string& indent); - std::string write_formatted_snbt(const AmuletNBT::LongTag&, const std::string& indent); - std::string write_formatted_snbt(const AmuletNBT::FloatTag&, const std::string& indent); - std::string write_formatted_snbt(const AmuletNBT::DoubleTag&, const std::string& indent); - std::string write_formatted_snbt(const AmuletNBT::ByteArrayTag&, const std::string& indent); - std::string write_formatted_snbt(const AmuletNBT::StringTag&, const std::string& indent); - std::string write_formatted_snbt(const AmuletNBT::ListTag&, const std::string& indent); - std::string write_formatted_snbt(const AmuletNBT::CompoundTag&, const std::string& indent); - std::string write_formatted_snbt(const AmuletNBT::IntArrayTag&, const std::string& indent); - std::string write_formatted_snbt(const AmuletNBT::LongArrayTag&, const std::string& indent); + std::string write_formatted_snbt(const TagNode&, const std::string& indent); + std::string write_formatted_snbt(const ByteTag&, const std::string& indent); + std::string write_formatted_snbt(const ShortTag&, const std::string& indent); + std::string write_formatted_snbt(const IntTag&, const std::string& indent); + std::string write_formatted_snbt(const LongTag&, const std::string& indent); + std::string write_formatted_snbt(const FloatTag&, const std::string& indent); + std::string write_formatted_snbt(const DoubleTag&, const std::string& indent); + std::string write_formatted_snbt(const ByteArrayTag&, const std::string& indent); + std::string write_formatted_snbt(const StringTag&, const std::string& indent); + std::string write_formatted_snbt(const ListTag&, const std::string& indent); + std::string write_formatted_snbt(const CompoundTag&, const std::string& indent); + std::string write_formatted_snbt(const IntArrayTag&, const std::string& indent); + std::string write_formatted_snbt(const LongArrayTag&, const std::string& indent); - AmuletNBT::TagNode read_snbt(const AmuletNBT::CodePointVector& snbt); - AmuletNBT::TagNode read_snbt(const std::string& snbt); + TagNode read_snbt(const CodePointVector& snbt); + TagNode read_snbt(const std::string& snbt); } diff --git a/src/amulet_nbt/include/amulet_nbt/tag2/abc.hpp b/src/amulet_nbt/include/amulet_nbt/tag/abc.hpp similarity index 75% rename from src/amulet_nbt/include/amulet_nbt/tag2/abc.hpp rename to src/amulet_nbt/include/amulet_nbt/tag/abc.hpp index 26cb79d7..de6d08df 100644 --- a/src/amulet_nbt/include/amulet_nbt/tag2/abc.hpp +++ b/src/amulet_nbt/include/amulet_nbt/tag/abc.hpp @@ -1,18 +1,10 @@ #pragma once -#include -#include - -#include - namespace AmuletNBT { class AbstractBaseTag { public: virtual ~AbstractBaseTag(){}; - virtual std::string to_nbt(std::string, std::endian, AmuletNBT::StringEncode) const = 0; - virtual std::string to_snbt() const = 0; - virtual std::string to_snbt(const std::string& indent) const = 0; }; class AbstractBaseImmutableTag: public AbstractBaseTag { diff --git a/src/amulet_nbt/include/amulet_nbt/tag/array.hpp b/src/amulet_nbt/include/amulet_nbt/tag/array.hpp index 29c808ff..f960c33f 100644 --- a/src/amulet_nbt/include/amulet_nbt/tag/array.hpp +++ b/src/amulet_nbt/include/amulet_nbt/tag/array.hpp @@ -1,13 +1,23 @@ #pragma once +#include +#include #include +#include + +#include +#include namespace AmuletNBT { - // The standard vector class can be resized. - // To make wrapping in numpy easier we will make the size fixed at runtime. - template - class ArrayTag : private std::vector - { + template + class ArrayTagTemplate: private std::vector, public AbstractBaseArrayTag{ + static_assert( + std::is_same_v || + std::is_same_v || + std::is_same_v, + "T must be int 8, 32 or 64" + ); + public: // only methods that do not change the buffer size should be exposed here using std::vector::vector; @@ -42,9 +52,35 @@ namespace AmuletNBT { using std::vector::empty; using std::vector::size; - bool operator==(const ArrayTag& other) const - { + bool operator==(const ArrayTagTemplate& other) const { return static_cast&>(*this) == static_cast&>(other); } + + // Cast + explicit operator std::vector() const { + return static_cast&>(*this); + }; }; + + typedef ArrayTagTemplate ByteArrayTag; + typedef ArrayTagTemplate IntArrayTag; + typedef ArrayTagTemplate LongArrayTag; + + static_assert(std::is_copy_constructible_v, "ByteArrayTag is not copy constructible"); + static_assert(std::is_copy_assignable_v, "ByteArrayTag is not copy assignable"); + static_assert(std::is_copy_constructible_v, "IntArrayTag is not copy constructible"); + static_assert(std::is_copy_assignable_v, "IntArrayTag is not copy assignable"); + static_assert(std::is_copy_constructible_v, "LongArrayTag is not copy constructible"); + static_assert(std::is_copy_assignable_v, "LongArrayTag is not copy assignable"); + + typedef std::shared_ptr ByteArrayTagPtr; + typedef std::shared_ptr IntArrayTagPtr; + typedef std::shared_ptr LongArrayTagPtr; + + template<> struct tag_id { static constexpr std::uint8_t value = 7; }; + template<> struct tag_id { static constexpr std::uint8_t value = 7; }; + template<> struct tag_id { static constexpr std::uint8_t value = 11; }; + template<> struct tag_id { static constexpr std::uint8_t value = 11; }; + template<> struct tag_id { static constexpr std::uint8_t value = 12; }; + template<> struct tag_id { static constexpr std::uint8_t value = 12; }; } diff --git a/src/amulet_nbt/include/amulet_nbt/tag/compound.hpp b/src/amulet_nbt/include/amulet_nbt/tag/compound.hpp index c9018bed..f2d063b2 100644 --- a/src/amulet_nbt/include/amulet_nbt/tag/compound.hpp +++ b/src/amulet_nbt/include/amulet_nbt/tag/compound.hpp @@ -1,11 +1,49 @@ #pragma once -// Utility functions for the CompoundTag +#include +#include +#include #include -#include +#include +#include +#include +#include +#include +#include +#include namespace AmuletNBT { + class ListTag; + typedef std::shared_ptr ListTagPtr; + class CompoundTag; + typedef std::shared_ptr CompoundTagPtr; + + typedef std::variant< + ByteTag, + ShortTag, + IntTag, + LongTag, + FloatTag, + DoubleTag, + ByteArrayTagPtr, + StringTag, + ListTagPtr, + CompoundTagPtr, + IntArrayTagPtr, + LongArrayTagPtr + > TagNode; + + class CompoundTag: public std::unordered_map, public AbstractBaseMutableTag{ + using unordered_map::unordered_map; + }; + + static_assert(std::is_copy_constructible_v, "CompoundTag is not copy constructible"); + static_assert(std::is_copy_assignable_v, "CompoundTag is not copy assignable"); + + template<> struct tag_id { static constexpr std::uint8_t value = 10; }; + template<> struct tag_id { static constexpr std::uint8_t value = 10; }; + class CompoundTagIterator { private: AmuletNBT::CompoundTagPtr tag; @@ -14,9 +52,23 @@ namespace AmuletNBT { AmuletNBT::CompoundTag::iterator pos; size_t size; public: - CompoundTagIterator(AmuletNBT::CompoundTagPtr tag); - std::string next(); - bool has_next(); - bool is_valid(); + CompoundTagIterator( + AmuletNBT::CompoundTagPtr tag + ) : tag(tag), begin(tag->begin()), end(tag->end()), pos(tag->begin()), size(tag->size()) {}; + std::string next() { + if (!is_valid()) { + throw std::runtime_error("CompoundTag changed size during iteration."); + } + return (pos++)->first; + }; + bool has_next() { + return pos != end; + }; + bool is_valid() { + // This is not fool proof. + // There are cases where this is true but the iterator is invalid. + // The programmer should write good code and this will catch some of the bad cases. + return size == tag->size() && begin == tag->begin() && end == tag->end(); + }; }; } diff --git a/src/amulet_nbt/include/amulet_nbt/tag/copy.hpp b/src/amulet_nbt/include/amulet_nbt/tag/copy.hpp index 54b8d65e..3e1390c9 100644 --- a/src/amulet_nbt/include/amulet_nbt/tag/copy.hpp +++ b/src/amulet_nbt/include/amulet_nbt/tag/copy.hpp @@ -5,11 +5,43 @@ #include #include +#include +#include +#include #include +#include +#include namespace AmuletNBT { - template - std::shared_ptr NBTTag_copy(const T& tag){ + template < + typename T, + std::enable_if_t< + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v, + bool + > = true + > + inline T NBTTag_copy(const T & tag) { + return tag; + } + + template < + typename T, + std::enable_if_t< + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v, + bool + > = true + > + inline std::shared_ptr NBTTag_copy(const T& tag){ return std::make_shared(tag); } diff --git a/src/amulet_nbt/include/amulet_nbt/tag/eq.hpp b/src/amulet_nbt/include/amulet_nbt/tag/eq.hpp index 3eef4c81..a7a3c19b 100644 --- a/src/amulet_nbt/include/amulet_nbt/tag/eq.hpp +++ b/src/amulet_nbt/include/amulet_nbt/tag/eq.hpp @@ -2,20 +2,25 @@ // All of the NBT equal functions -#include +#include +#include +#include +#include +#include +#include namespace AmuletNBT { - bool NBTTag_eq(const AmuletNBT::ByteTag a, const AmuletNBT::ByteTag b); - bool NBTTag_eq(const AmuletNBT::ShortTag a, const AmuletNBT::ShortTag b); - bool NBTTag_eq(const AmuletNBT::IntTag a, const AmuletNBT::IntTag b); - bool NBTTag_eq(const AmuletNBT::LongTag a, const AmuletNBT::LongTag b); - bool NBTTag_eq(const AmuletNBT::FloatTag a, const AmuletNBT::FloatTag b); - bool NBTTag_eq(const AmuletNBT::DoubleTag a, const AmuletNBT::DoubleTag b); - bool NBTTag_eq(const AmuletNBT::ByteArrayTagPtr a, const AmuletNBT::ByteArrayTagPtr b); - bool NBTTag_eq(const AmuletNBT::StringTag a, const AmuletNBT::StringTag b); - bool NBTTag_eq(const AmuletNBT::ListTagPtr a, const AmuletNBT::ListTagPtr b); - bool NBTTag_eq(const AmuletNBT::CompoundTagPtr a, const AmuletNBT::CompoundTagPtr b); - bool NBTTag_eq(const AmuletNBT::IntArrayTagPtr a, const AmuletNBT::IntArrayTagPtr b); - bool NBTTag_eq(const AmuletNBT::LongArrayTagPtr a, const AmuletNBT::LongArrayTagPtr b); - bool NBTTag_eq(const AmuletNBT::TagNode a, const AmuletNBT::TagNode b); + bool NBTTag_eq(const AmuletNBT::ByteTag& a, const AmuletNBT::ByteTag& b); + bool NBTTag_eq(const AmuletNBT::ShortTag& a, const AmuletNBT::ShortTag& b); + bool NBTTag_eq(const AmuletNBT::IntTag& a, const AmuletNBT::IntTag& b); + bool NBTTag_eq(const AmuletNBT::LongTag& a, const AmuletNBT::LongTag& b); + bool NBTTag_eq(const AmuletNBT::FloatTag& a, const AmuletNBT::FloatTag& b); + bool NBTTag_eq(const AmuletNBT::DoubleTag& a, const AmuletNBT::DoubleTag& b); + bool NBTTag_eq(const AmuletNBT::ByteArrayTag& a, const AmuletNBT::ByteArrayTag& b); + bool NBTTag_eq(const AmuletNBT::StringTag& a, const AmuletNBT::StringTag& b); + bool NBTTag_eq(const AmuletNBT::ListTag& a, const AmuletNBT::ListTag& b); + bool NBTTag_eq(const AmuletNBT::CompoundTag& a, const AmuletNBT::CompoundTag& b); + bool NBTTag_eq(const AmuletNBT::IntArrayTag& a, const AmuletNBT::IntArrayTag& b); + bool NBTTag_eq(const AmuletNBT::LongArrayTag& a, const AmuletNBT::LongArrayTag& b); + bool NBTTag_eq(const AmuletNBT::TagNode& a, const AmuletNBT::TagNode& b); } diff --git a/src/amulet_nbt/include/amulet_nbt/tag/float.hpp b/src/amulet_nbt/include/amulet_nbt/tag/float.hpp new file mode 100644 index 00000000..06a259e6 --- /dev/null +++ b/src/amulet_nbt/include/amulet_nbt/tag/float.hpp @@ -0,0 +1,42 @@ +#pragma once + +#include + +#include +#include + +namespace AmuletNBT { + template + class FloatTagTemplate: public AbstractBaseFloatTag { + static_assert( + std::is_same_v || + std::is_same_v, + "T must be float or double" + ); + private: + const T value; + public: + typedef T native_type; + FloatTagTemplate() : value(0.0) {}; + FloatTagTemplate(const T& value) : value(value) {}; + FloatTagTemplate(const FloatTagTemplate& other) : value(other.value) {}; + FloatTagTemplate operator=(const FloatTagTemplate& other) { return other.value; }; + operator const T&() const { + return value; + }; + }; + + typedef float FloatTagNative; + typedef double DoubleTagNative; + + typedef FloatTagTemplate FloatTag; + typedef FloatTagTemplate DoubleTag; + + static_assert(std::is_copy_constructible_v, "FloatTag is not copy constructible"); + static_assert(std::is_copy_assignable_v, "FloatTag is not copy assignable"); + static_assert(std::is_copy_constructible_v, "DoubleTag is not copy constructible"); + static_assert(std::is_copy_assignable_v, "DoubleTag is not copy assignable"); + + template<> struct tag_id { static constexpr std::uint8_t value = 5; }; + template<> struct tag_id { static constexpr std::uint8_t value = 6; }; +} diff --git a/src/amulet_nbt/include/amulet_nbt/tag/int.hpp b/src/amulet_nbt/include/amulet_nbt/tag/int.hpp new file mode 100644 index 00000000..41eed8e1 --- /dev/null +++ b/src/amulet_nbt/include/amulet_nbt/tag/int.hpp @@ -0,0 +1,55 @@ +#pragma once + +#include +#include + +#include +#include + +namespace AmuletNBT { + template + class IntTagTemplate: public AbstractBaseIntTag { + static_assert( + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v, + "T must be int 8, 16, 32 or 64" + ); + private: + const T value; + public: + typedef T native_type; + IntTagTemplate() : value(0) {}; + IntTagTemplate(const T& value) : value(value) {}; + IntTagTemplate(const IntTagTemplate& other) : value(other.value) {}; + IntTagTemplate operator=(const IntTagTemplate& other) { return other.value; }; + operator const T&() const { + return value; + }; + }; + + typedef std::int8_t ByteTagNative; + typedef std::int16_t ShortTagNative; + typedef std::int32_t IntTagNative; + typedef std::int64_t LongTagNative; + + typedef IntTagTemplate ByteTag; + typedef IntTagTemplate ShortTag; + typedef IntTagTemplate IntTag; + typedef IntTagTemplate LongTag; + + static_assert(std::is_copy_constructible_v, "ByteTag is not copy constructible"); + static_assert(std::is_copy_assignable_v, "ByteTag is not copy assignable"); + static_assert(std::is_copy_constructible_v, "ShortTag is not copy constructible"); + static_assert(std::is_copy_assignable_v, "ShortTag is not copy assignable"); + static_assert(std::is_copy_constructible_v, "IntTag is not copy constructible"); + static_assert(std::is_copy_assignable_v, "IntTag is not copy assignable"); + static_assert(std::is_copy_constructible_v, "LongTag is not copy constructible"); + static_assert(std::is_copy_assignable_v, "LongTag is not copy assignable"); + + template<> struct tag_id {static constexpr std::uint8_t value = 1;}; + template<> struct tag_id {static constexpr std::uint8_t value = 2;}; + template<> struct tag_id {static constexpr std::uint8_t value = 3;}; + template<> struct tag_id {static constexpr std::uint8_t value = 4;}; +} diff --git a/src/amulet_nbt/include/amulet_nbt/tag/list.hpp b/src/amulet_nbt/include/amulet_nbt/tag/list.hpp index 670d12a5..d2225aff 100644 --- a/src/amulet_nbt/include/amulet_nbt/tag/list.hpp +++ b/src/amulet_nbt/include/amulet_nbt/tag/list.hpp @@ -1,41 +1,118 @@ #pragma once -// Utility functions for the ListTag - -#include -#include -#include -#include -#include +#include +#include #include -#include -#include -#include -#include #include -#include +#include +#include +#include +#include +#include +#include namespace AmuletNBT { - size_t ListTag_size(const AmuletNBT::ListTag&); + class ListTag; + typedef std::shared_ptr ListTagPtr; + class CompoundTag; + typedef std::shared_ptr CompoundTagPtr; - template - void ListTag_append(AmuletNBT::ListTag& self, tagT tag){ - if (self.index() == variant_index>()){ + // List types + typedef std::vector ByteListTag; + typedef std::vector ShortListTag; + typedef std::vector IntListTag; + typedef std::vector LongListTag; + typedef std::vector FloatListTag; + typedef std::vector DoubleListTag; + typedef std::vector ByteArrayListTag; + typedef std::vector StringListTag; + typedef std::vector ListListTag; + typedef std::vector CompoundListTag; + typedef std::vector IntArrayListTag; + typedef std::vector LongArrayListTag; + + typedef std::variant< + std::monostate, + ByteListTag, + ShortListTag, + IntListTag, + LongListTag, + FloatListTag, + DoubleListTag, + ByteArrayListTag, + StringListTag, + ListListTag, + CompoundListTag, + IntArrayListTag, + LongArrayListTag + > ListTagNative; + + class ListTag: public ListTagNative, public AbstractBaseImmutableTag{ + using variant::variant; + }; + + static_assert(std::is_copy_constructible_v, "ListTag is not copy constructible"); + static_assert(std::is_copy_assignable_v, "ListTag is not copy assignable"); + + inline size_t ListTag_size(const ListTag& self) { + return std::visit([](auto&& list) -> size_t { + using T = std::decay_t; + if constexpr (std::is_same_v) { + return 0; + } + else { + return list.size(); + } + }, self); + }; + + template < + typename tagT, + std::enable_if_t< + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v, + bool + > = true + > + inline void ListTag_append(ListTag& self, const tagT& tag) { + if (self.index() == variant_index>()) { std::get>(self).push_back(tag); - } else if (ListTag_size(self) == 0){ + } else if (ListTag_size(self) == 0) { self.emplace>().push_back(tag); } else { - throw AmuletNBT::type_error( + throw type_error( "ListTag has element type " + std::to_string(self.index()) + " but the tag has type " + - std::to_string(variant_index>()) + std::to_string(variant_index>()) ); } }; - void ListTag_append(AmuletNBT::ListTag& self, AmuletNBT::TagNode tag); + template < + typename tagT, + std::enable_if_t< + std::is_same_v, + bool + > = true + > + inline void ListTag_append(ListTag& self, const TagNode& node) { + std::visit([&self](auto&& tag) { + using T = std::decay_t; + ListTag_append(self, tag); + }, node); + } template size_t ListTag_bounds_check(size_t size, indexT index){ @@ -66,30 +143,48 @@ namespace AmuletNBT { return abs_index; }; - template - tagT ListTag_get(const AmuletNBT::ListTag& self, indexT index){ + template < + typename tagT, + typename indexT, + std::enable_if_t< + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v, + bool + > = true + > + tagT ListTag_get(const ListTag& self, indexT index){ auto& list_tag = std::get>(self); - return list_tag[AmuletNBT::ListTag_bounds_check(list_tag.size(), index)]; + return list_tag[ListTag_bounds_check(list_tag.size(), index)]; } template - AmuletNBT::TagNode ListTag_get_node(const AmuletNBT::ListTag& self, indexT index){ - switch(self.index()){ - #define CASE(ID, TAG_NAME, TAG, TAG_STORAGE, LIST_TAG)\ - case ID:\ - return AmuletNBT::TagNode(ListTag_get(self, index)); - FOR_EACH_LIST_TAG(CASE) - default: - throw AmuletNBT::type_error("Cannot get from null ListTag."); - #undef CASE - } + TagNode ListTag_get_node(const ListTag& self, indexT index){ + return std::visit([&self, &index](auto&& list) -> TagNode { + using T = std::decay_t; + if constexpr (std::is_same_v) { + throw type_error("Cannot get from null ListTag."); + } + else { + return list[ListTag_bounds_check(list.size(), index)]; + } + }, self); } template - void ListTag_set(AmuletNBT::ListTag& self, indexT index, tagT tag){ + void ListTag_set(ListTag& self, indexT index, tagT tag){ // Get the unsigned index. Also do bounds checking. size_t abs_index = ListTag_bounds_check(ListTag_size(self), index); - if (self.index() == variant_index>()){ + if (self.index() == variant_index>()){ // If the list type is the same as the tag auto& list_tag = std::get>(self); list_tag[abs_index] = tag; @@ -97,55 +192,49 @@ namespace AmuletNBT { // Overwriting the only value self.emplace>({tag}); } else { - throw AmuletNBT::type_error("NBT ListTag item mismatch."); + throw type_error("NBT ListTag item mismatch."); } } template - void ListTag_del(AmuletNBT::ListTag& self, indexT index){ - switch(self.index()){ - #define CASE(ID, TAG_NAME, TAG, TAG_STORAGE, LIST_TAG)\ - case ID:\ - {\ - LIST_TAG& list_tag = std::get(self);\ - size_t abs_index = AmuletNBT::ListTag_bounds_check(list_tag.size(), index);\ - list_tag.erase(list_tag.begin() + abs_index);\ - break;\ - } - FOR_EACH_LIST_TAG(CASE) - #undef CASE - } + void ListTag_del(ListTag& self, indexT index){ + std::visit([&index](auto&& list) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + // do nothing + } else { + size_t abs_index = ListTag_bounds_check(list.size(), index); + list.erase(list.begin() + abs_index); + } + }, self); } - + template - AmuletNBT::TagNode ListTag_pop(AmuletNBT::ListTag& self, indexT index){ - switch(self.index()){ - #define CASE(ID, TAG_NAME, TAG, TAG_STORAGE, LIST_TAG)\ - case ID:\ - {\ - LIST_TAG& list_tag = std::get(self);\ - size_t abs_index = AmuletNBT::ListTag_bounds_check(list_tag.size(), index);\ - TAG_STORAGE tag = list_tag[abs_index];\ - list_tag.erase(list_tag.begin() + abs_index);\ - return tag;\ - } - FOR_EACH_LIST_TAG(CASE) - #undef CASE - } - throw std::out_of_range("ListTag index is out of range."); + inline TagNode ListTag_pop(ListTag& self, const indexT& index){ + return std::visit([&index](auto&& list) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + throw std::out_of_range("ListTag index is out of range."); + } else { + size_t abs_index = ListTag_bounds_check(list.size(), index); + typename T::value_type tag = list[abs_index]; + list.erase(list.begin() + abs_index); + return tag; + } + }, self); } template - void ListTag_insert(AmuletNBT::ListTag& self, indexT index, tagT tag){ - if (self.index() != variant_index>()){ + void ListTag_insert(ListTag& self, indexT index, const tagT& tag){ + if (self.index() != variant_index>()){ if (ListTag_size(self) == 0) { self.emplace>(); } else { - throw AmuletNBT::type_error( + throw type_error( "ListTag has element type " + std::to_string(self.index()) + " but the tag has type " + - std::to_string(variant_index>()) + std::to_string(variant_index>()) ); } } @@ -155,20 +244,16 @@ namespace AmuletNBT { } template - void ListTag_insert(AmuletNBT::ListTag& self, indexT index, AmuletNBT::TagNode node){ - switch(self.index()){ - #define CASE(ID, TAG_NAME, TAG, TAG_STORAGE, LIST_TAG)\ - case ID:\ - ListTag_insert(self, index, std::get(node));\ - break; - FOR_EACH_LIST_TAG(CASE) - #undef CASE - } + void ListTag_insert(ListTag& self, indexT index, const TagNode& node){ + std::visit([&self, &index](auto&& tag) { + using T = std::decay_t; + ListTag_insert(self, index, tag); + }, node); } template - size_t ListTag_index(AmuletNBT::ListTag& self, tagT tag, indexT start=0, indexT stop=std::numeric_limits::max()){ - if (self.index() != variant_index>()){ + size_t ListTag_index(ListTag& self, tagT tag, indexT start=0, indexT stop=std::numeric_limits::max()){ + if (self.index() != variant_index>()){ throw std::invalid_argument("item is not in the ListTag"); } auto& list_tag = std::get>(self); @@ -184,8 +269,8 @@ namespace AmuletNBT { } template - size_t ListTag_count(AmuletNBT::ListTag& self, tagT tag){ - if (self.index() != variant_index>()){ + size_t ListTag_count(ListTag& self, tagT tag){ + if (self.index() != variant_index>()){ return 0; } auto& list_tag = std::get>(self); @@ -198,15 +283,29 @@ namespace AmuletNBT { return count; } + template<> struct tag_id { static constexpr std::uint8_t value = 9; }; + template<> struct tag_id { static constexpr std::uint8_t value = 9; }; + // A class to emulate python's iteration mechanic class ListTagIterator { private: - AmuletNBT::ListTagPtr tag; + ListTagPtr tag; size_t index; std::ptrdiff_t step; public: - ListTagIterator(AmuletNBT::ListTagPtr, size_t start, std::ptrdiff_t step); - AmuletNBT::TagNode next(); - bool has_next(); + ListTagIterator(ListTagPtr tag, size_t start, std::ptrdiff_t step) : tag(tag), index(start), step(step) {}; + TagNode next() { + auto node = ListTag_get_node(*tag, index); + index += step; + return node; + } + bool has_next() { + return index >= 0 && index < ListTag_size(*tag); + } }; } + +namespace std { + template <> struct variant_size : std::variant_size {}; + template struct variant_alternative : variant_alternative {}; +} diff --git a/src/amulet_nbt/include/amulet_nbt/tag2/named_tag.hpp b/src/amulet_nbt/include/amulet_nbt/tag/named_tag.hpp similarity index 72% rename from src/amulet_nbt/include/amulet_nbt/tag2/named_tag.hpp rename to src/amulet_nbt/include/amulet_nbt/tag/named_tag.hpp index 5dd89447..6ad67d0b 100644 --- a/src/amulet_nbt/include/amulet_nbt/tag2/named_tag.hpp +++ b/src/amulet_nbt/include/amulet_nbt/tag/named_tag.hpp @@ -1,8 +1,10 @@ #pragma once #include +#include -#include +#include +#include namespace AmuletNBT { class NamedTag { @@ -11,5 +13,5 @@ namespace AmuletNBT { TagNode tag_node; NamedTag(const std::string& name, const TagNode& tag_node): name(name), tag_node(tag_node) {} - } + }; } diff --git a/src/amulet_nbt/include/amulet_nbt/tag/nbt.hpp b/src/amulet_nbt/include/amulet_nbt/tag/nbt.hpp index c524db3e..adbcc4d8 100644 --- a/src/amulet_nbt/include/amulet_nbt/tag/nbt.hpp +++ b/src/amulet_nbt/include/amulet_nbt/tag/nbt.hpp @@ -10,86 +10,6 @@ #include "array.hpp" namespace AmuletNBT { - // Base types - typedef std::int8_t ByteTag; - typedef std::int16_t ShortTag; - typedef std::int32_t IntTag; - typedef std::int64_t LongTag; - typedef float FloatTag; - typedef double DoubleTag; - typedef ArrayTag ByteArrayTag; - typedef std::string StringTag; - class ListTag; - class CompoundTag; - typedef ArrayTag IntArrayTag; - typedef ArrayTag LongArrayTag; - - // Pointer types - typedef std::shared_ptr ListTagPtr; - typedef std::shared_ptr CompoundTagPtr; - typedef std::shared_ptr ByteArrayTagPtr; - typedef std::shared_ptr IntArrayTagPtr; - typedef std::shared_ptr LongArrayTagPtr; - - // List types - typedef std::vector ByteListTag; - typedef std::vector ShortListTag; - typedef std::vector IntListTag; - typedef std::vector LongListTag; - typedef std::vector FloatListTag; - typedef std::vector DoubleListTag; - typedef std::vector ByteArrayListTag; - typedef std::vector StringListTag; - typedef std::vector ListListTag; - typedef std::vector CompoundListTag; - typedef std::vector IntArrayListTag; - typedef std::vector LongArrayListTag; - - class ListTag : public std::variant< - std::monostate, - ByteListTag, - ShortListTag, - IntListTag, - LongListTag, - FloatListTag, - DoubleListTag, - ByteArrayListTag, - StringListTag, - ListListTag, - CompoundListTag, - IntArrayListTag, - LongArrayListTag - > { - using variant::variant; - }; - - typedef std::variant< - std::monostate, - ByteTag, - ShortTag, - IntTag, - LongTag, - FloatTag, - DoubleTag, - ByteArrayTagPtr, - StringTag, - ListTagPtr, - CompoundTagPtr, - IntArrayTagPtr, - LongArrayTagPtr - > TagNode; - - class CompoundTag : public std::unordered_map { - using unordered_map::unordered_map; - }; - - class NamedTag { - public: - std::string name; - TagNode tag_node; - - NamedTag(const std::string& name, const TagNode& tag_node): name(name), tag_node(tag_node) {} - }; #define FOR_EACH_LIST_TAG(MACRO)\ MACRO(1, "byte", ByteTag, AmuletNBT::ByteTag, AmuletNBT::ByteListTag)\ @@ -109,8 +29,3 @@ namespace AmuletNBT { MACRO(0, "end", std::monostate, std::monostate, std::monostate)\ FOR_EACH_LIST_TAG(MACRO) } - -namespace std { - template <> struct variant_size: std::variant_size {}; - template struct variant_alternative : variant_alternative {}; -} diff --git a/src/amulet_nbt/include/amulet_nbt/tag/string.hpp b/src/amulet_nbt/include/amulet_nbt/tag/string.hpp new file mode 100644 index 00000000..ceaed9da --- /dev/null +++ b/src/amulet_nbt/include/amulet_nbt/tag/string.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include + +#include +#include + +namespace AmuletNBT { + class StringTag: public std::string, public AbstractBaseImmutableTag { + public: + using std::string::string; + StringTag(const std::string& value): std::string(value.begin(), value.end()) {}; + }; + + static_assert(std::is_copy_constructible_v, "StringTag is not copy constructible"); + static_assert(std::is_copy_assignable_v, "StringTag is not copy assignable"); + + template<> struct tag_id { static constexpr std::uint8_t value = 8; }; +} diff --git a/src/amulet_nbt/include/amulet_nbt/tag/wrapper.hpp b/src/amulet_nbt/include/amulet_nbt/tag/wrapper.hpp deleted file mode 100644 index a16b5452..00000000 --- a/src/amulet_nbt/include/amulet_nbt/tag/wrapper.hpp +++ /dev/null @@ -1,119 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -namespace AmuletNBT { - - class AbstractBaseTag { - public: - virtual ~AbstractBaseTag(){}; - virtual std::string to_nbt(std::string, std::endian, AmuletNBT::StringEncode) const = 0; - virtual std::string to_snbt() const = 0; - virtual std::string to_snbt(const std::string& indent) const = 0; - }; - - class AbstractBaseImmutableTag: public AbstractBaseTag { - public: - virtual ~AbstractBaseImmutableTag(){}; - }; - class AbstractBaseMutableTag: public AbstractBaseTag { - public: - virtual ~AbstractBaseMutableTag(){}; - }; - class AbstractBaseNumericTag: public AbstractBaseImmutableTag { - public: - virtual ~AbstractBaseNumericTag(){}; - }; - class AbstractBaseIntTag: public AbstractBaseNumericTag { - public: - virtual ~AbstractBaseIntTag(){}; - }; - class AbstractBaseFloatTag: public AbstractBaseNumericTag { - public: - virtual ~AbstractBaseFloatTag(){}; - }; - class AbstractBaseArrayTag: public AbstractBaseMutableTag { - public: - virtual ~AbstractBaseArrayTag(){}; - }; - - // pybind cannot directly store fundamental types - // This wrapper exists to allow pybind to store fundamental types - template - class TagWrapper: public - std::conditional_t, AbstractBaseIntTag, - std::conditional_t, AbstractBaseIntTag, - std::conditional_t, AbstractBaseIntTag, - std::conditional_t, AbstractBaseIntTag, - std::conditional_t, AbstractBaseFloatTag, - std::conditional_t, AbstractBaseFloatTag, - std::conditional_t, AbstractBaseArrayTag, - std::conditional_t, AbstractBaseImmutableTag, - std::conditional_t, AbstractBaseMutableTag, - std::conditional_t, AbstractBaseMutableTag, - std::conditional_t, AbstractBaseArrayTag, - std::conditional_t, AbstractBaseArrayTag, - void - >>>>>>>>>>>> { - public: - T tag; - TagWrapper(T tag): tag(tag) {}; - virtual std::string to_nbt(std::string name, std::endian endianness, AmuletNBT::StringEncode string_encode) const { - return AmuletNBT::write_nbt(name, tag, endianness, string_encode); - } - virtual std::string to_snbt() const { - if constexpr (is_shared_ptr::value){ - return AmuletNBT::write_snbt(*tag); - } else { - return AmuletNBT::write_snbt(tag); - } - } - virtual std::string to_snbt(const std::string& indent) const { - if constexpr (is_shared_ptr::value){ - return AmuletNBT::write_formatted_snbt(*tag, indent); - } else { - return AmuletNBT::write_formatted_snbt(tag, indent); - } - } - }; - typedef TagWrapper ByteTagWrapper; - typedef TagWrapper ShortTagWrapper; - typedef TagWrapper IntTagWrapper; - typedef TagWrapper LongTagWrapper; - typedef TagWrapper FloatTagWrapper; - typedef TagWrapper DoubleTagWrapper; - typedef TagWrapper ByteArrayTagWrapper; - typedef TagWrapper StringTagWrapper; - typedef TagWrapper ListTagWrapper; - typedef TagWrapper CompoundTagWrapper; - typedef TagWrapper IntArrayTagWrapper; - typedef TagWrapper LongArrayTagWrapper; - - typedef std::variant< - std::monostate, - ByteTagWrapper, - ShortTagWrapper, - IntTagWrapper, - LongTagWrapper, - FloatTagWrapper, - DoubleTagWrapper, - ByteArrayTagWrapper, - StringTagWrapper, - ListTagWrapper, - CompoundTagWrapper, - IntArrayTagWrapper, - LongArrayTagWrapper - > WrapperNode; - - WrapperNode wrap_node(AmuletNBT::TagNode node); - AmuletNBT::TagNode unwrap_node(WrapperNode node); -} diff --git a/src/amulet_nbt/include/amulet_nbt/tag2/array.hpp b/src/amulet_nbt/include/amulet_nbt/tag2/array.hpp deleted file mode 100644 index 645ac1f2..00000000 --- a/src/amulet_nbt/include/amulet_nbt/tag2/array.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include - -#include - -namespace AmuletNBT { - template - class ArrayTagTemplate: public AbstractBaseArrayTag { - public: - const std::string value; - - StringTag(); - StringTag(std::string&); - }; - - -} diff --git a/src/amulet_nbt/include/amulet_nbt/tag2/compound.hpp b/src/amulet_nbt/include/amulet_nbt/tag2/compound.hpp deleted file mode 100644 index b0f77309..00000000 --- a/src/amulet_nbt/include/amulet_nbt/tag2/compound.hpp +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include -#include -#include - -#include -#include -#include -#include - -namespace AmuletNBT { - class CompoundTag; - - typedef std::variant< - ByteTag, - ShortTag, - IntTag, - LongTag, - FloatTag, - DoubleTag, - ByteArrayTagPtr, - StringTag, - ListTagPtr, - CompoundTagPtr, - IntArrayTagPtr, - LongArrayTagPtr - > TagNode; - - class CompoundTag: public AbstractBaseMutableTag { - public: - const std::string value; - - StringTag(); - StringTag(std::string&); - } -} diff --git a/src/amulet_nbt/include/amulet_nbt/tag2/float.hpp b/src/amulet_nbt/include/amulet_nbt/tag2/float.hpp deleted file mode 100644 index 1bf461ed..00000000 --- a/src/amulet_nbt/include/amulet_nbt/tag2/float.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include - -#include - -namespace AmuletNBT { - template - class FloatTagTemplate: public AbstractBaseFloatTag { - public: - const T value; - - FloatTagTemplate(); - FloatTagTemplate(T&); - }; - - typedef IntTagTemplate FloatTag; - typedef IntTagTemplate DoubleTag; -} diff --git a/src/amulet_nbt/include/amulet_nbt/tag2/int.hpp b/src/amulet_nbt/include/amulet_nbt/tag2/int.hpp deleted file mode 100644 index 8b892730..00000000 --- a/src/amulet_nbt/include/amulet_nbt/tag2/int.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include - -#include - -namespace AmuletNBT { - template - class IntTagTemplate: public AbstractBaseIntTag { - public: - const T value; - - IntTagTemplate(); - IntTagTemplate(T&); - }; - - typedef IntTagTemplate ByteTag; - typedef IntTagTemplate ShortTag; - typedef IntTagTemplate IntTag; - typedef IntTagTemplate LongTag; -} diff --git a/src/amulet_nbt/include/amulet_nbt/tag2/list.hpp b/src/amulet_nbt/include/amulet_nbt/tag2/list.hpp deleted file mode 100644 index a58220a6..00000000 --- a/src/amulet_nbt/include/amulet_nbt/tag2/list.hpp +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include - -#include - -namespace AmuletNBT { - class StringTag: public AbstractBaseImmutableTag { - public: - const std::string value; - - StringTag(); - StringTag(std::string&); - } -} diff --git a/src/amulet_nbt/include/amulet_nbt/tag2/string.hpp b/src/amulet_nbt/include/amulet_nbt/tag2/string.hpp deleted file mode 100644 index a58220a6..00000000 --- a/src/amulet_nbt/include/amulet_nbt/tag2/string.hpp +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include - -#include - -namespace AmuletNBT { - class StringTag: public AbstractBaseImmutableTag { - public: - const std::string value; - - StringTag(); - StringTag(std::string&); - } -} From 20c0bcfc591e22636f5085a57a5ecacff22afcfd Mon Sep 17 00:00:00 2001 From: gentlegiantJGC Date: Fri, 26 Jul 2024 10:59:12 +0100 Subject: [PATCH 3/6] Removed wrapper class and refactored Replaced variant.index switches with variant::visit and holds_alternative. --- .../cpp/nbt_encoding/binary/read_binary.cpp | 2 +- .../cpp/nbt_encoding/string/read_string.cpp | 9 +- .../cpp/nbt_encoding/string/write_string.cpp | 156 +++--- src/amulet_nbt/cpp/tag/eq.cpp | 20 +- .../amulet_nbt/pybind/serialisation.hpp | 144 ++++++ src/amulet_nbt/include/amulet_nbt/tag/abc.hpp | 18 + .../include/amulet_nbt/tag/compound.hpp | 35 +- .../include/amulet_nbt/tag/float.hpp | 4 +- src/amulet_nbt/include/amulet_nbt/tag/int.hpp | 4 +- .../include/amulet_nbt/tag/list.hpp | 34 +- src/amulet_nbt/include/amulet_nbt/tag/nbt.hpp | 31 -- src/amulet_nbt/pybind/bnbt.cpp | 1 - src/amulet_nbt/pybind/encoding.cpp | 1 - src/amulet_nbt/pybind/snbt.cpp | 3 +- src/amulet_nbt/pybind/tag/py_abc_tag.cpp | 93 +--- src/amulet_nbt/pybind/tag/py_array_tag.cpp | 91 ++-- src/amulet_nbt/pybind/tag/py_compound_tag.cpp | 291 ++++++----- src/amulet_nbt/pybind/tag/py_float_tag.cpp | 90 ++-- src/amulet_nbt/pybind/tag/py_int_tag.cpp | 96 ++-- src/amulet_nbt/pybind/tag/py_list_tag.cpp | 452 ++++++++---------- src/amulet_nbt/pybind/tag/py_named_tag.cpp | 35 +- src/amulet_nbt/pybind/tag/py_string_tag.cpp | 91 ++-- tests/test_amulet_nbt/test_tag/test_list.py | 4 +- 23 files changed, 899 insertions(+), 806 deletions(-) create mode 100644 src/amulet_nbt/include/amulet_nbt/pybind/serialisation.hpp delete mode 100644 src/amulet_nbt/include/amulet_nbt/tag/nbt.hpp diff --git a/src/amulet_nbt/cpp/nbt_encoding/binary/read_binary.cpp b/src/amulet_nbt/cpp/nbt_encoding/binary/read_binary.cpp index df235055..6557b444 100644 --- a/src/amulet_nbt/cpp/nbt_encoding/binary/read_binary.cpp +++ b/src/amulet_nbt/cpp/nbt_encoding/binary/read_binary.cpp @@ -68,7 +68,7 @@ inline AmuletNBT::ListTagPtr read_numeric_list_tag(AmuletNBT::BinaryReader& read AmuletNBT::ListTagPtr tag = std::make_shared(std::vector(length)); std::vector& list = std::get>(*tag); for (std::int32_t i = 0; i < length; i++){ - reader.readNumericInto(list[i]); + list[i] = T(reader.readNumeric()); } return tag; } diff --git a/src/amulet_nbt/cpp/nbt_encoding/string/read_string.cpp b/src/amulet_nbt/cpp/nbt_encoding/string/read_string.cpp index f02828bc..f561b4e7 100644 --- a/src/amulet_nbt/cpp/nbt_encoding/string/read_string.cpp +++ b/src/amulet_nbt/cpp/nbt_encoding/string/read_string.cpp @@ -297,7 +297,8 @@ AmuletNBT::TagNode _read_snbt(const AmuletNBT::CodePointVector& snbt, size_t& in { index++; read_whitespace(snbt, index); - auto tag = std::make_shared(); + AmuletNBT::CompoundTagPtr tag_ptr = std::make_shared(); + AmuletNBT::CompoundTag& tag = *tag_ptr; while (read_code_point(snbt, index) != '}'){ // read the key std::string key = AmuletNBT::write_utf8(read_string(snbt, index).first); @@ -309,13 +310,13 @@ AmuletNBT::TagNode _read_snbt(const AmuletNBT::CodePointVector& snbt, size_t& in AmuletNBT::TagNode node = _read_snbt(snbt, index); // Write to the map - tag->insert_or_assign(key, node); + tag[key] = node; // Read past the comma read_comma(snbt, index, '}'); } index++; // seek past '}' - return tag; + return tag_ptr; } case '[': index++; @@ -337,7 +338,7 @@ AmuletNBT::TagNode _read_snbt(const AmuletNBT::CodePointVector& snbt, size_t& in // read the value auto value = _read_snbt(snbt, index); - if (tag->index() != 0 && tag->index() != value.index()){ + if (tag->index() != 0 && tag->index() != value.index() + 1){ throw std::invalid_argument("All elements of a list tag must have the same type."); } diff --git a/src/amulet_nbt/cpp/nbt_encoding/string/write_string.cpp b/src/amulet_nbt/cpp/nbt_encoding/string/write_string.cpp index 6acc47a7..d9045269 100644 --- a/src/amulet_nbt/cpp/nbt_encoding/string/write_string.cpp +++ b/src/amulet_nbt/cpp/nbt_encoding/string/write_string.cpp @@ -40,7 +40,13 @@ namespace AmuletNBT { inline void write_snbt(std::string& snbt, const TagNode& node){ std::visit([&snbt](auto&& tag){ - write_snbt(snbt, tag); + using T = std::decay_t; + if constexpr (is_shared_ptr()) { + write_snbt(snbt, *tag); + } + else { + write_snbt(snbt, tag); + } }, node); } @@ -133,7 +139,24 @@ namespace AmuletNBT { } - template + template < + typename T, + std::enable_if_t< + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v, + bool + > = true + > inline void write_snbt_list(std::string& snbt, const ListTag& tag){ const std::vector& list = std::get>(tag); snbt.append("["); @@ -152,26 +175,19 @@ namespace AmuletNBT { inline void write_snbt(std::string& snbt, const ListTag& tag){ - switch (tag.index()){ - case 0: snbt.append("[]"); break; - case 1: write_snbt_list(snbt, tag); break; - case 2: write_snbt_list(snbt, tag); break; - case 3: write_snbt_list(snbt, tag); break; - case 4: write_snbt_list(snbt, tag); break; - case 5: write_snbt_list(snbt, tag); break; - case 6: write_snbt_list(snbt, tag); break; - case 7: write_snbt_list(snbt, tag); break; - case 8: write_snbt_list(snbt, tag); break; - case 9: write_snbt_list(snbt, tag); break; - case 10: write_snbt_list(snbt, tag); break; - case 11: write_snbt_list(snbt, tag); break; - case 12: write_snbt_list(snbt, tag); break; - } + std::visit([&snbt](auto&& list_tag) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + snbt.append("[]"); + } + else { + write_snbt_list(snbt, list_tag); + } + }, tag); } template - inline void write_formatted_snbt_list(std::string& snbt, const ListTag& tag, const std::string& indent, const size_t& indent_count){ - const std::vector& list = std::get>(tag); + inline void write_formatted_snbt_list(std::string& snbt, const std::vector& list, const std::string& indent, const size_t& indent_count){ snbt.append("["); for (size_t i = 0; i < list.size(); i++){ snbt.append("\n"); @@ -195,21 +211,15 @@ namespace AmuletNBT { } inline void write_formatted_snbt(std::string& snbt, const ListTag& tag, const std::string& indent, const size_t& indent_count){ - switch (tag.index()){ - case 0: snbt.append("[]"); break; - case 1: write_formatted_snbt_list(snbt, tag, indent, indent_count); break; - case 2: write_formatted_snbt_list(snbt, tag, indent, indent_count); break; - case 3: write_formatted_snbt_list(snbt, tag, indent, indent_count); break; - case 4: write_formatted_snbt_list(snbt, tag, indent, indent_count); break; - case 5: write_formatted_snbt_list(snbt, tag, indent, indent_count); break; - case 6: write_formatted_snbt_list(snbt, tag, indent, indent_count); break; - case 7: write_formatted_snbt_list(snbt, tag, indent, indent_count); break; - case 8: write_formatted_snbt_list(snbt, tag, indent, indent_count); break; - case 9: write_formatted_snbt_list(snbt, tag, indent, indent_count); break; - case 10: write_formatted_snbt_list(snbt, tag, indent, indent_count); break; - case 11: write_formatted_snbt_list(snbt, tag, indent, indent_count); break; - case 12: write_formatted_snbt_list(snbt, tag, indent, indent_count); break; - } + std::visit([&snbt, &indent, &indent_count](auto&& list_tag) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + snbt.append("[]"); + } + else { + write_formatted_snbt_list(snbt, list_tag, indent, indent_count); + } + }, tag); } @@ -315,155 +325,155 @@ namespace AmuletNBT { } - inline std::string write_snbt(const TagNode& tag){ + std::string write_snbt(const TagNode& tag){ std::string snbt; write_snbt(snbt, tag); return snbt; } - inline std::string write_snbt(const ByteTag& tag){ + std::string write_snbt(const ByteTag& tag){ std::string snbt; write_snbt(snbt, tag); return snbt; } - inline std::string write_snbt(const ShortTag& tag){ + std::string write_snbt(const ShortTag& tag){ std::string snbt; write_snbt(snbt, tag); return snbt; } - inline std::string write_snbt(const IntTag& tag){ + std::string write_snbt(const IntTag& tag){ std::string snbt; write_snbt(snbt, tag); return snbt; } - inline std::string write_snbt(const LongTag& tag){ + std::string write_snbt(const LongTag& tag){ std::string snbt; write_snbt(snbt, tag); return snbt; } - inline std::string write_snbt(const FloatTag& tag){ + std::string write_snbt(const FloatTag& tag){ std::string snbt; write_snbt(snbt, tag); return snbt; } - inline std::string write_snbt(const DoubleTag& tag){ + std::string write_snbt(const DoubleTag& tag){ std::string snbt; write_snbt(snbt, tag); return snbt; } - inline std::string write_snbt(const ByteArrayTag& tag){ + std::string write_snbt(const ByteArrayTag& tag){ std::string snbt; write_snbt(snbt, tag); return snbt; } - inline std::string write_snbt(const StringTag& tag){ + std::string write_snbt(const StringTag& tag){ std::string snbt; write_snbt(snbt, tag); return snbt; } - inline std::string write_snbt(const ListTag& tag){ + std::string write_snbt(const ListTag& tag){ std::string snbt; write_snbt(snbt, tag); return snbt; } - inline std::string write_snbt(const CompoundTag& tag){ + std::string write_snbt(const CompoundTag& tag){ std::string snbt; write_snbt(snbt, tag); return snbt; } - inline std::string write_snbt(const IntArrayTag& tag){ + std::string write_snbt(const IntArrayTag& tag){ std::string snbt; write_snbt(snbt, tag); return snbt; } - inline std::string write_snbt(const LongArrayTag& tag){ + std::string write_snbt(const LongArrayTag& tag){ std::string snbt; write_snbt(snbt, tag); return snbt; } - inline void write_formatted_snbt(std::string& snbt, const TagNode& tag, const std::string& indent){ + void write_formatted_snbt(std::string& snbt, const TagNode& tag, const std::string& indent){ return write_formatted_snbt(snbt, tag, indent, 0); } - inline void write_formatted_snbt(std::string& snbt, const ByteTag& tag, const std::string& indent){ + void write_formatted_snbt(std::string& snbt, const ByteTag& tag, const std::string& indent){ write_snbt(snbt, tag); } - inline void write_formatted_snbt(std::string& snbt, const ShortTag& tag, const std::string& indent){ + void write_formatted_snbt(std::string& snbt, const ShortTag& tag, const std::string& indent){ write_snbt(snbt, tag); } - inline void write_formatted_snbt(std::string& snbt, const IntTag& tag, const std::string& indent){ + void write_formatted_snbt(std::string& snbt, const IntTag& tag, const std::string& indent){ write_snbt(snbt, tag); } - inline void write_formatted_snbt(std::string& snbt, const LongTag& tag, const std::string& indent){ + void write_formatted_snbt(std::string& snbt, const LongTag& tag, const std::string& indent){ write_snbt(snbt, tag); } - inline void write_formatted_snbt(std::string& snbt, const FloatTag& tag, const std::string& indent){ + void write_formatted_snbt(std::string& snbt, const FloatTag& tag, const std::string& indent){ write_snbt(snbt, tag); } - inline void write_formatted_snbt(std::string& snbt, const DoubleTag& tag, const std::string& indent){ + void write_formatted_snbt(std::string& snbt, const DoubleTag& tag, const std::string& indent){ write_snbt(snbt, tag); } - inline void write_formatted_snbt(std::string& snbt, const ByteArrayTag& tag, const std::string& indent){ + void write_formatted_snbt(std::string& snbt, const ByteArrayTag& tag, const std::string& indent){ write_snbt(snbt, tag); } - inline void write_formatted_snbt(std::string& snbt, const StringTag& tag, const std::string& indent){ + void write_formatted_snbt(std::string& snbt, const StringTag& tag, const std::string& indent){ write_snbt(snbt, tag); } - inline void write_formatted_snbt(std::string& snbt, const ListTag& tag, const std::string& indent){ + void write_formatted_snbt(std::string& snbt, const ListTag& tag, const std::string& indent){ return write_formatted_snbt(snbt, tag, indent, 0); } - inline void write_formatted_snbt(std::string& snbt, const CompoundTag& tag, const std::string& indent){ + void write_formatted_snbt(std::string& snbt, const CompoundTag& tag, const std::string& indent){ return write_formatted_snbt(snbt, tag, indent, 0); } - inline void write_formatted_snbt(std::string& snbt, const IntArrayTag& tag, const std::string& indent){ + void write_formatted_snbt(std::string& snbt, const IntArrayTag& tag, const std::string& indent){ write_snbt(snbt, tag); } - inline void write_formatted_snbt(std::string& snbt, const LongArrayTag& tag, const std::string& indent){ + void write_formatted_snbt(std::string& snbt, const LongArrayTag& tag, const std::string& indent){ write_snbt(snbt, tag); } - inline std::string write_formatted_snbt(const TagNode& tag, const std::string& indent){ + std::string write_formatted_snbt(const TagNode& tag, const std::string& indent){ std::string snbt; write_formatted_snbt(snbt, tag, indent); return snbt; } - inline std::string write_formatted_snbt(const ByteTag& tag, const std::string& indent){ + std::string write_formatted_snbt(const ByteTag& tag, const std::string& indent){ return write_snbt(tag); } - inline std::string write_formatted_snbt(const ShortTag& tag, const std::string& indent){ + std::string write_formatted_snbt(const ShortTag& tag, const std::string& indent){ return write_snbt(tag); } - inline std::string write_formatted_snbt(const IntTag& tag, const std::string& indent){ + std::string write_formatted_snbt(const IntTag& tag, const std::string& indent){ return write_snbt(tag); } - inline std::string write_formatted_snbt(const LongTag& tag, const std::string& indent){ + std::string write_formatted_snbt(const LongTag& tag, const std::string& indent){ return write_snbt(tag); } - inline std::string write_formatted_snbt(const FloatTag& tag, const std::string& indent){ + std::string write_formatted_snbt(const FloatTag& tag, const std::string& indent){ return write_snbt(tag); } - inline std::string write_formatted_snbt(const DoubleTag& tag, const std::string& indent){ + std::string write_formatted_snbt(const DoubleTag& tag, const std::string& indent){ return write_snbt(tag); } - inline std::string write_formatted_snbt(const ByteArrayTag& tag, const std::string& indent){ + std::string write_formatted_snbt(const ByteArrayTag& tag, const std::string& indent){ return write_snbt(tag); } - inline std::string write_formatted_snbt(const StringTag& tag, const std::string& indent){ + std::string write_formatted_snbt(const StringTag& tag, const std::string& indent){ return write_snbt(tag); } - inline std::string write_formatted_snbt(const ListTag& tag, const std::string& indent){ + std::string write_formatted_snbt(const ListTag& tag, const std::string& indent){ std::string snbt; write_formatted_snbt(snbt, tag, indent); return snbt; } - inline std::string write_formatted_snbt(const CompoundTag& tag, const std::string& indent){ + std::string write_formatted_snbt(const CompoundTag& tag, const std::string& indent){ std::string snbt; write_formatted_snbt(snbt, tag, indent); return snbt; } - inline std::string write_formatted_snbt(const IntArrayTag& tag, const std::string& indent){ + std::string write_formatted_snbt(const IntArrayTag& tag, const std::string& indent){ return write_snbt(tag); } - inline std::string write_formatted_snbt(const LongArrayTag& tag, const std::string& indent){ + std::string write_formatted_snbt(const LongArrayTag& tag, const std::string& indent){ return write_snbt(tag); } } diff --git a/src/amulet_nbt/cpp/tag/eq.cpp b/src/amulet_nbt/cpp/tag/eq.cpp index 7919a979..7a62e4b0 100644 --- a/src/amulet_nbt/cpp/tag/eq.cpp +++ b/src/amulet_nbt/cpp/tag/eq.cpp @@ -21,13 +21,13 @@ namespace AmuletNBT{ bool NBTTag_eq(const AmuletNBT::FloatTag& a, const AmuletNBT::FloatTag& b){return a == b;}; bool NBTTag_eq(const AmuletNBT::DoubleTag& a, const AmuletNBT::DoubleTag& b){return a == b;}; bool NBTTag_eq(const AmuletNBT::StringTag& a, const AmuletNBT::StringTag& b){return a == b;}; - bool NBTTag_eq(const AmuletNBT::ByteArrayTagPtr a, const AmuletNBT::ByteArrayTagPtr b){return *a == *b;}; - bool NBTTag_eq(const AmuletNBT::IntArrayTagPtr a, const AmuletNBT::IntArrayTagPtr b){return *a == *b;}; - bool NBTTag_eq(const AmuletNBT::LongArrayTagPtr a, const AmuletNBT::LongArrayTagPtr b){return *a == *b;}; + bool NBTTag_eq(const AmuletNBT::ByteArrayTag& a, const AmuletNBT::ByteArrayTag& b){return a == b;}; + bool NBTTag_eq(const AmuletNBT::IntArrayTag& a, const AmuletNBT::IntArrayTag& b){return a == b;}; + bool NBTTag_eq(const AmuletNBT::LongArrayTag& a, const AmuletNBT::LongArrayTag& b){return a == b;}; template inline bool ListTag_eq(const std::vector& a_vec, const AmuletNBT::ListTag& b){ - if (b.index() != variant_index>()){ + if (!std::holds_alternative>(b)){ return a_vec.size() == 0 && ListTag_size(b) == 0; } const std::vector& b_vec = std::get>(b); @@ -48,7 +48,7 @@ namespace AmuletNBT{ return a_vec == b_vec; } } - bool NBTTag_eq(const AmuletNBT::ListTag& a, const AmuletNBT::ListTag b){ + bool NBTTag_eq(const AmuletNBT::ListTag& a, const AmuletNBT::ListTag& b){ return std::visit([&b](auto&& list) -> bool { using T = std::decay_t; if constexpr (std::is_same_v) { @@ -80,7 +80,15 @@ namespace AmuletNBT{ bool NBTTag_eq(const AmuletNBT::TagNode& a, const AmuletNBT::TagNode& b){ return std::visit([&b](auto&& tag) -> bool { using T = std::decay_t; - return b.index() == variant_index() && NBTTag_eq(tag, std::get(b)); + if (!std::holds_alternative(b)) { + return false; + } + if constexpr (is_shared_ptr::value) { + return NBTTag_eq(*tag, *std::get(b)); + } + else { + return NBTTag_eq(tag, std::get(b)); + } }, a); }; } diff --git a/src/amulet_nbt/include/amulet_nbt/pybind/serialisation.hpp b/src/amulet_nbt/include/amulet_nbt/pybind/serialisation.hpp new file mode 100644 index 00000000..12421365 --- /dev/null +++ b/src/amulet_nbt/include/amulet_nbt/pybind/serialisation.hpp @@ -0,0 +1,144 @@ +#define SerialiseTag(CLSNAME)\ + auto to_nbt_##CLSNAME = [compress](\ + const AmuletNBT::CLSNAME& self,\ + std::string name,\ + bool compressed,\ + std::endian endianness,\ + AmuletNBT::StringEncode string_encoder\ + ) -> py::bytes {\ + py::bytes data = AmuletNBT::write_nbt(name, self, endianness, string_encoder);\ + if (compressed){\ + return compress(data);\ + }\ + return data;\ + };\ + CLSNAME.def(\ + "to_nbt",\ + [to_nbt_##CLSNAME](\ + const AmuletNBT::CLSNAME& self,\ + AmuletNBT::EncodingPreset preset,\ + std::string name\ + ){\ + return to_nbt_##CLSNAME(\ + self,\ + name,\ + preset.compressed,\ + preset.endianness,\ + preset.string_encoding.encode\ + );\ + },\ + py::kw_only(),\ + py::arg("preset") = java_encoding,\ + py::arg("name") = ""\ + );\ + CLSNAME.def(\ + "to_nbt",\ + [to_nbt_##CLSNAME](\ + const AmuletNBT::CLSNAME& self,\ + bool compressed,\ + bool little_endian,\ + AmuletNBT::StringEncoding string_encoding,\ + std::string name\ + ){\ + return to_nbt_##CLSNAME(\ + self,\ + name,\ + compressed,\ + little_endian ? std::endian::little : std::endian::big,\ + string_encoding.encode\ + );\ + },\ + py::kw_only(),\ + py::arg("compressed") = true,\ + py::arg("little_endian") = false,\ + py::arg("string_encoding") = mutf8_encoding,\ + py::arg("name") = ""\ + );\ + auto save_to_##CLSNAME = [to_nbt_##CLSNAME](\ + const AmuletNBT::CLSNAME& self,\ + py::object filepath_or_writable,\ + std::string name,\ + bool compressed,\ + std::endian endianness,\ + AmuletNBT::StringEncode string_encoder\ + ){\ + py::bytes py_data = to_nbt_##CLSNAME(self, name, compressed, endianness, string_encoder);\ + if (!filepath_or_writable.is(py::none())){\ + if (py::isinstance(filepath_or_writable)){\ + std::string data = py_data.cast();\ + std::ofstream file(filepath_or_writable.cast(), std::ios::out | std::ios::binary | std::ios::trunc);\ + file.write(data.c_str(), data.size());\ + } else {\ + filepath_or_writable.attr("write")(py_data);\ + }\ + }\ + return py_data;\ + };\ + CLSNAME.def(\ + "save_to",\ + [save_to_##CLSNAME](\ + const AmuletNBT::CLSNAME& self,\ + py::object filepath_or_writable,\ + AmuletNBT::EncodingPreset preset,\ + std::string name\ + ){\ + return save_to_##CLSNAME(\ + self,\ + filepath_or_writable,\ + name,\ + preset.compressed,\ + preset.endianness,\ + preset.string_encoding.encode\ + );\ + },\ + py::arg("filepath_or_writable") = py::none(),\ + py::pos_only(),\ + py::kw_only(),\ + py::arg("preset") = java_encoding,\ + py::arg("name") = ""\ + );\ + CLSNAME.def(\ + "save_to",\ + [save_to_##CLSNAME](\ + const AmuletNBT::CLSNAME& self,\ + py::object filepath_or_writable,\ + bool compressed,\ + bool little_endian,\ + AmuletNBT::StringEncoding string_encoding,\ + std::string name\ + ){\ + return save_to_##CLSNAME(\ + self,\ + filepath_or_writable,\ + name,\ + compressed,\ + little_endian ? std::endian::little : std::endian::big,\ + string_encoding.encode\ + );\ + },\ + py::arg("filepath_or_writable") = py::none(),\ + py::pos_only(),\ + py::kw_only(),\ + py::arg("compressed") = true,\ + py::arg("little_endian") = false,\ + py::arg("string_encoding") = mutf8_encoding,\ + py::arg("name") = ""\ + );\ + CLSNAME.def(\ + "to_snbt",\ + [](\ + const AmuletNBT::CLSNAME& self,\ + py::object indent\ + ){\ + if (indent.is(py::none())){\ + return AmuletNBT::write_snbt(self);\ + } else if (py::isinstance(indent)){\ + return AmuletNBT::write_formatted_snbt(self, std::string(indent.cast(), ' '));\ + } else if (py::isinstance(indent)){\ + return AmuletNBT::write_formatted_snbt(self, indent.cast());\ + } else {\ + throw std::invalid_argument("indent must be None, int or str");\ + }\ + },\ + py::arg("indent") = py::none()\ + ); diff --git a/src/amulet_nbt/include/amulet_nbt/tag/abc.hpp b/src/amulet_nbt/include/amulet_nbt/tag/abc.hpp index de6d08df..cf6e6c08 100644 --- a/src/amulet_nbt/include/amulet_nbt/tag/abc.hpp +++ b/src/amulet_nbt/include/amulet_nbt/tag/abc.hpp @@ -31,4 +31,22 @@ namespace AmuletNBT { public: virtual ~AbstractBaseArrayTag(){}; }; + + #define FOR_EACH_LIST_TAG(MACRO)\ + MACRO(1, "byte", ByteTag, AmuletNBT::ByteTag, AmuletNBT::ByteListTag)\ + MACRO(2, "short", ShortTag, AmuletNBT::ShortTag, AmuletNBT::ShortListTag)\ + MACRO(3, "int", IntTag, AmuletNBT::IntTag, AmuletNBT::IntListTag)\ + MACRO(4, "long", LongTag, AmuletNBT::LongTag, AmuletNBT::LongListTag)\ + MACRO(5, "float", FloatTag, AmuletNBT::FloatTag, AmuletNBT::FloatListTag)\ + MACRO(6, "double", DoubleTag, AmuletNBT::DoubleTag, AmuletNBT::DoubleListTag)\ + MACRO(7, "byte_array", ByteArrayTag, AmuletNBT::ByteArrayTagPtr, AmuletNBT::ByteArrayListTag)\ + MACRO(8, "string", StringTag, AmuletNBT::StringTag, AmuletNBT::StringListTag)\ + MACRO(9, "list", ListTag, AmuletNBT::ListTagPtr, AmuletNBT::ListListTag)\ + MACRO(10, "compound", CompoundTag, AmuletNBT::CompoundTagPtr, AmuletNBT::CompoundListTag)\ + MACRO(11, "int_array", IntArrayTag, AmuletNBT::IntArrayTagPtr, AmuletNBT::IntArrayListTag)\ + MACRO(12, "long_array", LongArrayTag, AmuletNBT::LongArrayTagPtr, AmuletNBT::LongArrayListTag) + + #define FOR_EACH_LIST_TAG2(MACRO)\ + MACRO(0, "end", std::monostate, std::monostate, std::monostate)\ + FOR_EACH_LIST_TAG(MACRO) } diff --git a/src/amulet_nbt/include/amulet_nbt/tag/compound.hpp b/src/amulet_nbt/include/amulet_nbt/tag/compound.hpp index f2d063b2..bb81730e 100644 --- a/src/amulet_nbt/include/amulet_nbt/tag/compound.hpp +++ b/src/amulet_nbt/include/amulet_nbt/tag/compound.hpp @@ -10,7 +10,6 @@ #include #include #include -#include #include namespace AmuletNBT { @@ -34,7 +33,9 @@ namespace AmuletNBT { LongArrayTagPtr > TagNode; - class CompoundTag: public std::unordered_map, public AbstractBaseMutableTag{ + typedef std::unordered_map CompoundTagNative; + + class CompoundTag: public CompoundTagNative, public AbstractBaseMutableTag{ using unordered_map::unordered_map; }; @@ -43,32 +44,6 @@ namespace AmuletNBT { template<> struct tag_id { static constexpr std::uint8_t value = 10; }; template<> struct tag_id { static constexpr std::uint8_t value = 10; }; - - class CompoundTagIterator { - private: - AmuletNBT::CompoundTagPtr tag; - const AmuletNBT::CompoundTag::iterator begin; - const AmuletNBT::CompoundTag::iterator end; - AmuletNBT::CompoundTag::iterator pos; - size_t size; - public: - CompoundTagIterator( - AmuletNBT::CompoundTagPtr tag - ) : tag(tag), begin(tag->begin()), end(tag->end()), pos(tag->begin()), size(tag->size()) {}; - std::string next() { - if (!is_valid()) { - throw std::runtime_error("CompoundTag changed size during iteration."); - } - return (pos++)->first; - }; - bool has_next() { - return pos != end; - }; - bool is_valid() { - // This is not fool proof. - // There are cases where this is true but the iterator is invalid. - // The programmer should write good code and this will catch some of the bad cases. - return size == tag->size() && begin == tag->begin() && end == tag->end(); - }; - }; } + +#include diff --git a/src/amulet_nbt/include/amulet_nbt/tag/float.hpp b/src/amulet_nbt/include/amulet_nbt/tag/float.hpp index 06a259e6..fcd1bc17 100644 --- a/src/amulet_nbt/include/amulet_nbt/tag/float.hpp +++ b/src/amulet_nbt/include/amulet_nbt/tag/float.hpp @@ -14,13 +14,11 @@ namespace AmuletNBT { "T must be float or double" ); private: - const T value; + T value; public: typedef T native_type; FloatTagTemplate() : value(0.0) {}; FloatTagTemplate(const T& value) : value(value) {}; - FloatTagTemplate(const FloatTagTemplate& other) : value(other.value) {}; - FloatTagTemplate operator=(const FloatTagTemplate& other) { return other.value; }; operator const T&() const { return value; }; diff --git a/src/amulet_nbt/include/amulet_nbt/tag/int.hpp b/src/amulet_nbt/include/amulet_nbt/tag/int.hpp index 41eed8e1..bb81f3ec 100644 --- a/src/amulet_nbt/include/amulet_nbt/tag/int.hpp +++ b/src/amulet_nbt/include/amulet_nbt/tag/int.hpp @@ -17,13 +17,11 @@ namespace AmuletNBT { "T must be int 8, 16, 32 or 64" ); private: - const T value; + T value; public: typedef T native_type; IntTagTemplate() : value(0) {}; IntTagTemplate(const T& value) : value(value) {}; - IntTagTemplate(const IntTagTemplate& other) : value(other.value) {}; - IntTagTemplate operator=(const IntTagTemplate& other) { return other.value; }; operator const T&() const { return value; }; diff --git a/src/amulet_nbt/include/amulet_nbt/tag/list.hpp b/src/amulet_nbt/include/amulet_nbt/tag/list.hpp index d2225aff..c6c3d2b6 100644 --- a/src/amulet_nbt/include/amulet_nbt/tag/list.hpp +++ b/src/amulet_nbt/include/amulet_nbt/tag/list.hpp @@ -86,7 +86,7 @@ namespace AmuletNBT { > = true > inline void ListTag_append(ListTag& self, const tagT& tag) { - if (self.index() == variant_index>()) { + if (std::holds_alternative>(self)) { std::get>(self).push_back(tag); } else if (ListTag_size(self) == 0) { self.emplace>().push_back(tag); @@ -184,7 +184,7 @@ namespace AmuletNBT { void ListTag_set(ListTag& self, indexT index, tagT tag){ // Get the unsigned index. Also do bounds checking. size_t abs_index = ListTag_bounds_check(ListTag_size(self), index); - if (self.index() == variant_index>()){ + if (std::holds_alternative>(self)){ // If the list type is the same as the tag auto& list_tag = std::get>(self); list_tag[abs_index] = tag; @@ -211,7 +211,7 @@ namespace AmuletNBT { template inline TagNode ListTag_pop(ListTag& self, const indexT& index){ - return std::visit([&index](auto&& list) { + return std::visit([&index](auto&& list) -> TagNode { using T = std::decay_t; if constexpr (std::is_same_v) { throw std::out_of_range("ListTag index is out of range."); @@ -226,7 +226,7 @@ namespace AmuletNBT { template void ListTag_insert(ListTag& self, indexT index, const tagT& tag){ - if (self.index() != variant_index>()){ + if (!std::holds_alternative>(self)){ if (ListTag_size(self) == 0) { self.emplace>(); } else { @@ -252,8 +252,8 @@ namespace AmuletNBT { } template - size_t ListTag_index(ListTag& self, tagT tag, indexT start=0, indexT stop=std::numeric_limits::max()){ - if (self.index() != variant_index>()){ + size_t ListTag_index(const ListTag& self, tagT tag, indexT start=0, indexT stop=std::numeric_limits::max()){ + if (!std::holds_alternative>(self)){ throw std::invalid_argument("item is not in the ListTag"); } auto& list_tag = std::get>(self); @@ -269,8 +269,8 @@ namespace AmuletNBT { } template - size_t ListTag_count(ListTag& self, tagT tag){ - if (self.index() != variant_index>()){ + size_t ListTag_count(const ListTag& self, tagT tag){ + if (!std::holds_alternative>(self)){ return 0; } auto& list_tag = std::get>(self); @@ -285,24 +285,6 @@ namespace AmuletNBT { template<> struct tag_id { static constexpr std::uint8_t value = 9; }; template<> struct tag_id { static constexpr std::uint8_t value = 9; }; - - // A class to emulate python's iteration mechanic - class ListTagIterator { - private: - ListTagPtr tag; - size_t index; - std::ptrdiff_t step; - public: - ListTagIterator(ListTagPtr tag, size_t start, std::ptrdiff_t step) : tag(tag), index(start), step(step) {}; - TagNode next() { - auto node = ListTag_get_node(*tag, index); - index += step; - return node; - } - bool has_next() { - return index >= 0 && index < ListTag_size(*tag); - } - }; } namespace std { diff --git a/src/amulet_nbt/include/amulet_nbt/tag/nbt.hpp b/src/amulet_nbt/include/amulet_nbt/tag/nbt.hpp deleted file mode 100644 index adbcc4d8..00000000 --- a/src/amulet_nbt/include/amulet_nbt/tag/nbt.hpp +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include "array.hpp" - -namespace AmuletNBT { - - #define FOR_EACH_LIST_TAG(MACRO)\ - MACRO(1, "byte", ByteTag, AmuletNBT::ByteTag, AmuletNBT::ByteListTag)\ - MACRO(2, "short", ShortTag, AmuletNBT::ShortTag, AmuletNBT::ShortListTag)\ - MACRO(3, "int", IntTag, AmuletNBT::IntTag, AmuletNBT::IntListTag)\ - MACRO(4, "long", LongTag, AmuletNBT::LongTag, AmuletNBT::LongListTag)\ - MACRO(5, "float", FloatTag, AmuletNBT::FloatTag, AmuletNBT::FloatListTag)\ - MACRO(6, "double", DoubleTag, AmuletNBT::DoubleTag, AmuletNBT::DoubleListTag)\ - MACRO(7, "byte_array", ByteArrayTag, AmuletNBT::ByteArrayTagPtr, AmuletNBT::ByteArrayListTag)\ - MACRO(8, "string", StringTag, AmuletNBT::StringTag, AmuletNBT::StringListTag)\ - MACRO(9, "list", ListTag, AmuletNBT::ListTagPtr, AmuletNBT::ListListTag)\ - MACRO(10, "compound", CompoundTag, AmuletNBT::CompoundTagPtr, AmuletNBT::CompoundListTag)\ - MACRO(11, "int_array", IntArrayTag, AmuletNBT::IntArrayTagPtr, AmuletNBT::IntArrayListTag)\ - MACRO(12, "long_array", LongArrayTag, AmuletNBT::LongArrayTagPtr, AmuletNBT::LongArrayListTag) - - #define FOR_EACH_LIST_TAG2(MACRO)\ - MACRO(0, "end", std::monostate, std::monostate, std::monostate)\ - FOR_EACH_LIST_TAG(MACRO) -} diff --git a/src/amulet_nbt/pybind/bnbt.cpp b/src/amulet_nbt/pybind/bnbt.cpp index 9b3ddaa1..0c219b58 100644 --- a/src/amulet_nbt/pybind/bnbt.cpp +++ b/src/amulet_nbt/pybind/bnbt.cpp @@ -8,7 +8,6 @@ #include #include -#include #include #include diff --git a/src/amulet_nbt/pybind/encoding.cpp b/src/amulet_nbt/pybind/encoding.cpp index 15b5b1ed..631f4640 100644 --- a/src/amulet_nbt/pybind/encoding.cpp +++ b/src/amulet_nbt/pybind/encoding.cpp @@ -5,7 +5,6 @@ #include #include -#include #include #include diff --git a/src/amulet_nbt/pybind/snbt.cpp b/src/amulet_nbt/pybind/snbt.cpp index 506cf32e..a8f79250 100644 --- a/src/amulet_nbt/pybind/snbt.cpp +++ b/src/amulet_nbt/pybind/snbt.cpp @@ -4,7 +4,6 @@ #include #include -#include #include namespace py = pybind11; @@ -13,7 +12,7 @@ void init_snbt(py::module& m) { m.def( "read_snbt", [](std::string snbt){ - return AmuletNBT::wrap_node(AmuletNBT::read_snbt(snbt)); + return AmuletNBT::read_snbt(snbt); }, py::arg("snbt"), py::doc( diff --git a/src/amulet_nbt/pybind/tag/py_abc_tag.cpp b/src/amulet_nbt/pybind/tag/py_abc_tag.cpp index e0adb252..070f512c 100644 --- a/src/amulet_nbt/pybind/tag/py_abc_tag.cpp +++ b/src/amulet_nbt/pybind/tag/py_abc_tag.cpp @@ -8,7 +8,7 @@ #include #include -#include +#include #include namespace py = pybind11; @@ -23,7 +23,6 @@ void abstract_method(T self, py::args, const py::kwargs&){ void init_abc(py::module& m) { py::object mutf8_encoding = m.attr("mutf8_encoding"); py::object java_encoding = m.attr("java_encoding"); - py::object compress = py::module::import("gzip").attr("compress"); py::class_ AbstractBaseTag(m, "AbstractBaseTag", "Abstract Base Class for all tag classes" @@ -40,33 +39,15 @@ void init_abc(py::module& m) { "You would be better off using the py_{type} or np_array properties if you require a fixed type.\n"\ "This is here for convenience to get a python representation under the same property name."\ ); - auto to_nbt = [compress]( - const AmuletNBT::AbstractBaseTag& self, - std::string name, - bool compressed, - std::endian endianness, - AmuletNBT::StringEncode string_encoder - ) -> py::bytes { - py::bytes data = self.to_nbt(name, endianness, string_encoder); - if (compressed){ - return compress(data); - } - return data; - }; AbstractBaseTag.def( "to_nbt", - [to_nbt]( + []( const AmuletNBT::AbstractBaseTag& self, AmuletNBT::EncodingPreset preset, std::string name ){ - return to_nbt( - self, - name, - preset.compressed, - preset.endianness, - preset.string_encoding.encode - ); + PyErr_SetString(PyExc_NotImplementedError, ""); + throw py::error_already_set(); }, py::kw_only(), py::arg("preset") = java_encoding, @@ -74,20 +55,15 @@ void init_abc(py::module& m) { ); AbstractBaseTag.def( "to_nbt", - [to_nbt]( + []( const AmuletNBT::AbstractBaseTag& self, bool compressed, bool little_endian, AmuletNBT::StringEncoding string_encoding, std::string name ){ - return to_nbt( - self, - name, - compressed, - little_endian ? std::endian::little : std::endian::big, - string_encoding.encode - ); + PyErr_SetString(PyExc_NotImplementedError, ""); + throw py::error_already_set(); }, py::kw_only(), py::arg("compressed") = true, @@ -95,42 +71,16 @@ void init_abc(py::module& m) { py::arg("string_encoding") = mutf8_encoding, py::arg("name") = "" ); - auto save_to = [to_nbt]( - const AmuletNBT::AbstractBaseTag& self, - py::object filepath_or_writable, - std::string name, - bool compressed, - std::endian endianness, - AmuletNBT::StringEncode string_encoder - ){ - py::bytes py_data = to_nbt(self, name, compressed, endianness, string_encoder); - if (!filepath_or_writable.is(py::none())){ - if (py::isinstance(filepath_or_writable)){ - std::string data = py_data.cast(); - std::ofstream file(filepath_or_writable.cast(), std::ios::out | std::ios::binary | std::ios::trunc); - file.write(data.c_str(), data.size()); - } else { - filepath_or_writable.attr("write")(py_data); - } - } - return py_data; - }; AbstractBaseTag.def( "save_to", - [save_to]( + []( const AmuletNBT::AbstractBaseTag& self, py::object filepath_or_writable, AmuletNBT::EncodingPreset preset, std::string name ){ - return save_to( - self, - filepath_or_writable, - name, - preset.compressed, - preset.endianness, - preset.string_encoding.encode - ); + PyErr_SetString(PyExc_NotImplementedError, ""); + throw py::error_already_set(); }, py::arg("filepath_or_writable") = py::none(), py::pos_only(), @@ -140,7 +90,7 @@ void init_abc(py::module& m) { ); AbstractBaseTag.def( "save_to", - [save_to]( + []( const AmuletNBT::AbstractBaseTag& self, py::object filepath_or_writable, bool compressed, @@ -148,14 +98,8 @@ void init_abc(py::module& m) { AmuletNBT::StringEncoding string_encoding, std::string name ){ - return save_to( - self, - filepath_or_writable, - name, - compressed, - little_endian ? std::endian::little : std::endian::big, - string_encoding.encode - ); + PyErr_SetString(PyExc_NotImplementedError, ""); + throw py::error_already_set(); }, py::arg("filepath_or_writable") = py::none(), py::pos_only(), @@ -171,15 +115,8 @@ void init_abc(py::module& m) { const AmuletNBT::AbstractBaseTag& self, py::object indent ){ - if (indent.is(py::none())){ - return self.to_snbt(); - } else if (py::isinstance(indent)){ - return self.to_snbt(std::string(indent.cast(), ' ')); - } else if (py::isinstance(indent)){ - return self.to_snbt(indent.cast()); - } else { - throw std::invalid_argument("indent must be None, int or str"); - } + PyErr_SetString(PyExc_NotImplementedError, ""); + throw py::error_already_set(); }, py::arg("indent") = py::none() ); diff --git a/src/amulet_nbt/pybind/tag/py_array_tag.cpp b/src/amulet_nbt/pybind/tag/py_array_tag.cpp index b609829b..7edd0cb7 100644 --- a/src/amulet_nbt/pybind/tag/py_array_tag.cpp +++ b/src/amulet_nbt/pybind/tag/py_array_tag.cpp @@ -4,20 +4,27 @@ #include #include #include +#include +#include #include #include #include #include -#include +#include +#include #include +#include +#include +#include +#include namespace py = pybind11; #define PyArray(CLSNAME, ELEMENTCLS, BITCOUNT, TAGID)\ - py::class_ CLSNAME(m, #CLSNAME, py::buffer_protocol(),\ + py::class_> CLSNAME(m, #CLSNAME, AbstractBaseArrayTag, py::buffer_protocol(),\ "This class stores a fixed size signed "#BITCOUNT" bit vector."\ );\ CLSNAME.def_property_readonly_static("tag_id", [](py::object) {return TAGID;});\ @@ -25,28 +32,27 @@ namespace py = pybind11; py::init([asarray, dtype](py::object value) {\ /* Is there a better way to do this? */\ py::array arr = asarray(value, dtype("int"#BITCOUNT)).attr("ravel")().cast();\ - std::vector v = arr.cast> ();\ - std::shared_ptr tag_ptr = std::make_shared(v.begin(), v.end());\ - return AmuletNBT::CLSNAME##Wrapper(tag_ptr);\ + std::vector v = arr.cast> ();\ + return std::make_shared(v.begin(), v.end());\ }),\ py::arg("value") = py::tuple(),\ py::doc("__init__(self: amulet_nbt."#CLSNAME", value: collections.abc.Iterable[typing.SupportsInt] = ()) -> None")\ );\ CLSNAME.def_buffer(\ - [](AmuletNBT::CLSNAME##Wrapper& self) -> py::buffer_info {\ + [](AmuletNBT::CLSNAME& self) -> py::buffer_info {\ return py::buffer_info(\ - self.tag->data(),\ - sizeof(AmuletNBT::ELEMENTCLS),\ - py::format_descriptor::format(),\ + self.data(),\ + sizeof(ELEMENTCLS),\ + py::format_descriptor::format(),\ 1,\ - {self.tag->size()},\ - {sizeof(AmuletNBT::ELEMENTCLS)}\ + {self.size()},\ + {sizeof(ELEMENTCLS)}\ );\ }\ );\ CLSNAME.def_property_readonly(\ "np_array",\ - [asarray](const AmuletNBT::CLSNAME##Wrapper& self){\ + [asarray](const AmuletNBT::CLSNAME& self){\ return asarray(self);\ },\ py::doc(\ @@ -57,7 +63,7 @@ namespace py = pybind11; );\ CLSNAME.def_property_readonly(\ "py_data",\ - [asarray](const AmuletNBT::CLSNAME##Wrapper& self){\ + [asarray](const AmuletNBT::CLSNAME& self){\ return asarray(self);\ },\ py::doc(\ @@ -67,15 +73,16 @@ namespace py = pybind11; "This is here for convenience to get a python representation under the same property name.\n"\ )\ );\ + SerialiseTag(CLSNAME)\ CLSNAME.def(\ "__repr__",\ - [](const AmuletNBT::CLSNAME##Wrapper& self){\ + [](const AmuletNBT::CLSNAME& self){\ std::string out = #CLSNAME "([";\ - for (size_t i = 0; i < self.tag->size(); i++){\ + for (size_t i = 0; i < self.size(); i++){\ if (i){\ out += ", ";\ };\ - out += std::to_string((*self.tag)[i]);\ + out += std::to_string(self[i]);\ };\ out += "])";\ return out;\ @@ -83,13 +90,13 @@ namespace py = pybind11; );\ CLSNAME.def(\ "__str__",\ - [](const AmuletNBT::CLSNAME##Wrapper& self){\ + [](const AmuletNBT::CLSNAME& self){\ std::string out = "[";\ - for (size_t i = 0; i < self.tag->size(); i++){\ + for (size_t i = 0; i < self.size(); i++){\ if (i){\ out += ", ";\ };\ - out += std::to_string((*self.tag)[i]);\ + out += std::to_string(self[i]);\ };\ out += "]";\ return out;\ @@ -97,67 +104,65 @@ namespace py = pybind11; );\ CLSNAME.def(\ py::pickle(\ - [](const AmuletNBT::CLSNAME##Wrapper& self){\ - return py::bytes(AmuletNBT::write_nbt("", self.tag, std::endian::big, AmuletNBT::utf8_to_mutf8));\ + [](const AmuletNBT::CLSNAME& self){\ + return py::bytes(AmuletNBT::write_nbt("", self, std::endian::big, AmuletNBT::utf8_to_mutf8));\ },\ [](py::bytes state){\ - return AmuletNBT::CLSNAME##Wrapper(\ - std::get(\ - AmuletNBT::read_nbt(state, std::endian::big, AmuletNBT::mutf8_to_utf8).tag_node\ - )\ + return std::get(\ + AmuletNBT::read_nbt(state, std::endian::big, AmuletNBT::mutf8_to_utf8).tag_node\ );\ }\ )\ );\ CLSNAME.def(\ "__copy__",\ - [](const AmuletNBT::CLSNAME##Wrapper& self){\ - return AmuletNBT::CLSNAME##Wrapper(NBTTag_copy(*self.tag));\ + [](const AmuletNBT::CLSNAME& self){\ + return NBTTag_copy(self);\ }\ );\ CLSNAME.def(\ "__deepcopy__",\ - [](const AmuletNBT::CLSNAME##Wrapper& self, py::dict){\ - return AmuletNBT::CLSNAME##Wrapper(AmuletNBT::NBTTag_copy(*self.tag));\ + [](const AmuletNBT::CLSNAME& self, py::dict){\ + return AmuletNBT::NBTTag_copy(self);\ },\ py::arg("memo")\ );\ CLSNAME.def(\ "__eq__",\ - [](const AmuletNBT::CLSNAME##Wrapper& self, const AmuletNBT::CLSNAME##Wrapper& other){\ - return *self.tag == *other.tag;\ + [](const AmuletNBT::CLSNAME& self, const AmuletNBT::CLSNAME& other){\ + return self == other;\ },\ py::is_operator()\ );\ CLSNAME.def(\ "__len__",\ - [](const AmuletNBT::CLSNAME##Wrapper& self){\ - return self.tag->size();\ + [](const AmuletNBT::CLSNAME& self){\ + return self.size();\ }\ );\ CLSNAME.def(\ "__iter__",\ - [](const AmuletNBT::CLSNAME##Wrapper& self) {return py::make_iterator(self.tag->begin(), self.tag->end());},\ + [](const AmuletNBT::CLSNAME& self) {return py::make_iterator(self.begin(), self.end());},\ py::keep_alive<0, 1>() /* Essential: keep object alive while iterator exists */);\ CLSNAME.def(\ "__reversed__",\ - [](const AmuletNBT::CLSNAME##Wrapper& self) {return py::make_iterator(self.tag->rbegin(), self.tag->rend());},\ + [](const AmuletNBT::CLSNAME& self) {return py::make_iterator(self.rbegin(), self.rend());},\ py::keep_alive<0, 1>() /* Essential: keep object alive while iterator exists */);\ CLSNAME.def(\ "__getitem__",\ - [asarray](const AmuletNBT::CLSNAME##Wrapper& self, py::object item){\ + [asarray](const AmuletNBT::CLSNAME& self, py::object item){\ return asarray(self).attr("__getitem__")(item);\ }\ );\ CLSNAME.def(\ "__setitem__",\ - [asarray](const AmuletNBT::CLSNAME##Wrapper& self, py::object item, py::object value){\ + [asarray](const AmuletNBT::CLSNAME& self, py::object item, py::object value){\ asarray(self)[item] = value;\ }\ );\ CLSNAME.def(\ "__contains__",\ - [asarray](const AmuletNBT::CLSNAME##Wrapper& self, py::object value){\ + [asarray](const AmuletNBT::CLSNAME& self, py::object value){\ asarray(self).contains(value);\ }\ ); @@ -166,7 +171,11 @@ namespace py = pybind11; void init_array(py::module& m) { py::object asarray = py::module::import("numpy").attr("asarray"); py::object dtype = py::module::import("numpy").attr("dtype"); - PyArray(ByteArrayTag, ByteTag, 8, 7) - PyArray(IntArrayTag, IntTag, 32, 11) - PyArray(LongArrayTag, LongTag, 64, 12) + py::object mutf8_encoding = m.attr("mutf8_encoding"); + py::object java_encoding = m.attr("java_encoding"); + py::object compress = py::module::import("gzip").attr("compress"); + py::object AbstractBaseArrayTag = m.attr("AbstractBaseArrayTag"); + PyArray(ByteArrayTag, std::int8_t, 8, 7) + PyArray(IntArrayTag, std::int32_t, 32, 11) + PyArray(LongArrayTag, std::int64_t, 64, 12) }; diff --git a/src/amulet_nbt/pybind/tag/py_compound_tag.cpp b/src/amulet_nbt/pybind/tag/py_compound_tag.cpp index d132eb81..a4f4396b 100644 --- a/src/amulet_nbt/pybind/tag/py_compound_tag.cpp +++ b/src/amulet_nbt/pybind/tag/py_compound_tag.cpp @@ -5,27 +5,59 @@ #include #include #include +#include #include #include #include #include -#include +#include #include #include #include +#include +#include +#include +#include namespace py = pybind11; +namespace AmuletNBT { + class CompoundTagIterator { + private: + CompoundTagPtr tag; + const CompoundTag::iterator begin; + const CompoundTag::iterator end; + CompoundTag::iterator pos; + size_t size; + public: + CompoundTagIterator( + CompoundTagPtr tag + ) : tag(tag), begin(tag->begin()), end(tag->end()), pos(tag->begin()), size(tag->size()) {}; + std::string next() { + if (!is_valid()) { + throw std::runtime_error("CompoundTag changed size during iteration."); + } + return (pos++)->first; + }; + bool has_next() { + return pos != end; + }; + bool is_valid() { + // This is not fool proof. + // There are cases where this is true but the iterator is invalid. + // The programmer should write good code and this will catch some of the bad cases. + return size == tag->size() && begin == tag->begin() && end == tag->end(); + }; + }; +} + void CompoundTag_update(AmuletNBT::CompoundTag& self, py::dict other){ - auto map = other.cast>(); - for (auto it = map.begin(); it != map.end(); it++){ - if (it->second.index() == 0){ - throw py::type_error("Value cannot be None"); - } - self[it->first] = unwrap_node(it->second); + auto map = other.cast(); + for (const auto& it: map){ + self[it.first] = it.second; } } @@ -70,9 +102,14 @@ void init_compound(py::module& m) { ); py::object AbstractBaseTag = m.attr("AbstractBaseTag"); + py::object AbstractBaseMutableTag = m.attr("AbstractBaseMutableTag"); py::object isinstance = py::module::import("builtins").attr("isinstance"); + py::object mutf8_encoding = m.attr("mutf8_encoding"); + py::object java_encoding = m.attr("java_encoding"); + py::object compress = py::module::import("gzip").attr("compress"); - py::class_ CompoundTag(m, "CompoundTag", + //py::class_> CompoundTag(m, "CompoundTag", + py::class_> CompoundTag(m, "CompoundTag", AbstractBaseMutableTag, "A Python wrapper around a C++ unordered map.\n" "\n" "Note that this class is not thread safe and inherits all the limitations of a C++ unordered_map." @@ -83,19 +120,19 @@ void init_compound(py::module& m) { AmuletNBT::CompoundTagPtr tag = std::make_shared(); CompoundTag_update(*tag, py::dict(value)); CompoundTag_update(*tag, kwargs); - return AmuletNBT::CompoundTagWrapper(tag); + return tag; }), py::arg("value") = py::tuple() ); - auto py_getter = [](const AmuletNBT::CompoundTagWrapper& self){ + auto py_getter = [](const AmuletNBT::CompoundTag& self){ py::dict out; - for (auto it = self.tag->begin(); it != self.tag->end(); it++){ - py::object value = py::cast(AmuletNBT::wrap_node(it->second)); + for (const auto& it: self){ + py::object value = py::cast(it.second); try { - py::str key = py::str(it->first); + py::str key = py::str(it.first); out[key] = value; } catch (py::error_already_set&){ - py::bytes key = py::bytes(it->first); + py::bytes key = py::bytes(it.first); out[key] = value; } } @@ -116,20 +153,21 @@ void init_compound(py::module& m) { "This is here for convenience to get a python representation under the same property name.\n" ) ); + SerialiseTag(CompoundTag) CompoundTag.def( "__repr__", - [](const AmuletNBT::CompoundTagWrapper& self){ + [](const AmuletNBT::CompoundTag& self){ std::string out; out += "CompoundTag({"; - for (auto it = self.tag->begin(); it != self.tag->end(); it++){ - if (it != self.tag->begin()){out += ", ";} + for (auto it = self.begin(); it != self.end(); it++){ + if (it != self.begin()){out += ", ";} try { out += py::repr(py::str(it->first)); } catch (py::error_already_set&){ out += py::repr(py::bytes(it->first)); } out += ": "; - out += py::repr(py::cast(AmuletNBT::wrap_node(it->second))); + out += py::repr(py::cast(it->second)); } out += "})"; return out; @@ -137,80 +175,78 @@ void init_compound(py::module& m) { ); CompoundTag.def( py::pickle( - [](const AmuletNBT::CompoundTagWrapper& self){ - return py::bytes(AmuletNBT::write_nbt("", self.tag, std::endian::big, AmuletNBT::utf8_to_mutf8)); + [](const AmuletNBT::CompoundTag& self){ + return py::bytes(AmuletNBT::write_nbt("", self, std::endian::big, AmuletNBT::utf8_to_mutf8)); }, [](py::bytes state){ - return AmuletNBT::CompoundTagWrapper( - std::get( - AmuletNBT::read_nbt(state, std::endian::big, AmuletNBT::mutf8_to_utf8).tag_node - ) + return std::get( + AmuletNBT::read_nbt(state, std::endian::big, AmuletNBT::mutf8_to_utf8).tag_node ); } ) ); CompoundTag.def( "__copy__", - [](const AmuletNBT::CompoundTagWrapper& self){ - return AmuletNBT::CompoundTagWrapper(NBTTag_copy(*self.tag)); + [](const AmuletNBT::CompoundTag& self){ + return NBTTag_copy(self); } ); CompoundTag.def( "__deepcopy__", - [](const AmuletNBT::CompoundTagWrapper& self, py::dict){ - return AmuletNBT::CompoundTagWrapper(AmuletNBT::NBTTag_deep_copy_compound(*self.tag)); + [](const AmuletNBT::CompoundTag& self, py::dict){ + return AmuletNBT::NBTTag_deep_copy_compound(self); }, py::arg("memo") ); CompoundTag.def( "__str__", - [](const AmuletNBT::CompoundTagWrapper& self){ + [](const AmuletNBT::CompoundTag& self){ return py::str(py::dict(py::cast(self))); } ); CompoundTag.def( "__eq__", - [](const AmuletNBT::CompoundTagWrapper& self, const AmuletNBT::CompoundTagWrapper& other){ - return AmuletNBT::NBTTag_eq(self.tag, other.tag); + [](const AmuletNBT::CompoundTag& self, const AmuletNBT::CompoundTag& other){ + return AmuletNBT::NBTTag_eq(self, other); }, py::is_operator() ); CompoundTag.def( "__len__", - [](const AmuletNBT::CompoundTagWrapper& self){ - return self.tag->size(); + [](const AmuletNBT::CompoundTag& self){ + return self.size(); } ); CompoundTag.def( "__bool__", - [](const AmuletNBT::CompoundTagWrapper& self){ - return !self.tag->empty(); + [](const AmuletNBT::CompoundTag& self){ + return !self.empty(); } ); CompoundTag.def( "__iter__", - [](const AmuletNBT::CompoundTagWrapper& self){ - return AmuletNBT::CompoundTagIterator(self.tag); + [](const AmuletNBT::CompoundTagPtr self){ + return AmuletNBT::CompoundTagIterator(self); } ); CompoundTag.def( "__getitem__", - [](const AmuletNBT::CompoundTagWrapper& self, std::string key){ - auto it = self.tag->find(key); - if (it == self.tag->end()){ + [](const AmuletNBT::CompoundTag& self, std::string key){ + auto it = self.find(key); + if (it == self.end()){ throw py::key_error(key); } - return AmuletNBT::wrap_node(it->second); + return it->second; } ); CompoundTag.def( "get", - [isinstance](const AmuletNBT::CompoundTagWrapper& self, std::string key, py::object default_, py::object cls) -> py::object { - auto it = self.tag->find(key); - if (it == self.tag->end()){ + [isinstance](const AmuletNBT::CompoundTag& self, std::string key, py::object default_, py::object cls) -> py::object { + auto it = self.find(key); + if (it == self.end()){ return default_; } - py::object tag = py::cast(AmuletNBT::wrap_node(it->second)); + py::object tag = py::cast(it->second); if (isinstance(tag, cls)){ return tag; } else { @@ -231,79 +267,76 @@ void init_compound(py::module& m) { ); CompoundTag.def( "__contains__", - [](const AmuletNBT::CompoundTagWrapper& self, std::string key){ - auto it = self.tag->find(key); - return it != self.tag->end(); + [](const AmuletNBT::CompoundTag& self, std::string key){ + auto it = self.find(key); + return it != self.end(); } ); py::object KeysView = py::module::import("collections.abc").attr("KeysView"); CompoundTag.def( "keys", - [KeysView](const AmuletNBT::CompoundTagWrapper& self){ + [KeysView](const AmuletNBT::CompoundTag& self){ return KeysView(py::cast(self)); } ); py::object ItemsView = py::module::import("collections.abc").attr("ItemsView"); CompoundTag.def( "items", - [ItemsView](const AmuletNBT::CompoundTagWrapper& self){ + [ItemsView](const AmuletNBT::CompoundTag& self){ return ItemsView(py::cast(self)); } ); py::object ValuesView = py::module::import("collections.abc").attr("ValuesView"); CompoundTag.def( "values", - [ValuesView](const AmuletNBT::CompoundTagWrapper& self){ + [ValuesView](const AmuletNBT::CompoundTag& self){ return ValuesView(py::cast(self)); } ); CompoundTag.def( "__setitem__", - [](const AmuletNBT::CompoundTagWrapper& self, std::string key, AmuletNBT::WrapperNode value){ - if (value.index() == 0){ - throw py::type_error("Value cannot be None"); - } - (*self.tag)[key] = AmuletNBT::unwrap_node(value); + [](AmuletNBT::CompoundTag& self, std::string key, AmuletNBT::TagNode value){ + self[key] = value; } ); CompoundTag.def( "__delitem__", - [](const AmuletNBT::CompoundTagWrapper& self, std::string key){ - auto it = self.tag->find(key); - if (it == self.tag->end()){ + [](AmuletNBT::CompoundTag& self, std::string key){ + auto it = self.find(key); + if (it == self.end()){ throw py::key_error(key); } - self.tag->erase(it); + self.erase(it); } ); py::object marker = py::module::import("builtins").attr("object")(); CompoundTag.def( "pop", - [marker](const AmuletNBT::CompoundTagWrapper& self, std::string key, py::object default_) -> py::object { - auto it = self.tag->find(key); - if (it == self.tag->end()){ + [marker](AmuletNBT::CompoundTag& self, std::string key, py::object default_) -> py::object { + auto it = self.find(key); + if (it == self.end()){ if (default_.is(marker)){ throw py::key_error(key); } else { return default_; } } - AmuletNBT::WrapperNode tag = AmuletNBT::wrap_node(it->second); - self.tag->erase(it); + AmuletNBT::TagNode tag = it->second; + self.erase(it); return py::cast(tag); }, py::arg("key"), py::arg("default") = marker ); CompoundTag.def( "popitem", - [](const AmuletNBT::CompoundTagWrapper& self) -> std::pair, AmuletNBT::WrapperNode>{ - auto it = self.tag->begin(); - if (it == self.tag->end()){ + [](AmuletNBT::CompoundTag& self) -> std::pair, AmuletNBT::TagNode>{ + auto it = self.begin(); + if (it == self.end()){ throw py::key_error("CompoundTag is empty."); } std::string key = it->first; - AmuletNBT::WrapperNode value = AmuletNBT::wrap_node(it->second); - self.tag->erase(it); + AmuletNBT::TagNode value = it->second; + self.erase(it); try { py::str py_key = py::str(key); return std::make_pair(py_key, value); @@ -315,33 +348,38 @@ void init_compound(py::module& m) { ); CompoundTag.def( "clear", - [](const AmuletNBT::CompoundTagWrapper& self){ - self.tag->clear(); + [](AmuletNBT::CompoundTag& self){ + self.clear(); } ); CompoundTag.def( "update", - [](const AmuletNBT::CompoundTagWrapper& self, py::object other, const py::kwargs& kwargs){ - CompoundTag_update(*self.tag, py::dict(other)); - CompoundTag_update(*self.tag, kwargs); + [](AmuletNBT::CompoundTag& self, py::object other, const py::kwargs& kwargs){ + CompoundTag_update(self, py::dict(other)); + CompoundTag_update(self, kwargs); }, py::arg("other") = py::tuple(), py::pos_only() ); CompoundTag.def( "setdefault", - [isinstance](const AmuletNBT::CompoundTagWrapper& self, std::string key, AmuletNBT::WrapperNode tag, py::object cls) -> py::object { - auto set_value = [self, key, tag](){ - if (tag.index() == 0){ - throw py::type_error("Cannot setdefault a value of None."); - } - (*self.tag)[key] = AmuletNBT::unwrap_node(tag); - return py::cast(tag); + [isinstance](AmuletNBT::CompoundTag& self, std::string key, std::variant tag, py::object cls) -> py::object { + auto set_value = [&self, &key, &tag]() { + return std::visit([&self, &key](auto&& value) -> py::object { + using T = std::decay_t; + if constexpr (std::is_same_v) { + throw py::type_error("Cannot setdefault a value of None."); + } + else { + self[key] = value; + return py::cast(value); + } + }, tag); }; - auto it = self.tag->find(key); - if (it == self.tag->end()){ + auto it = self.find(key); + if (it == self.end()){ return set_value(); } - py::object existing_tag = py::cast(AmuletNBT::wrap_node(it->second)); + py::object existing_tag = py::cast(it->second); if (!isinstance(existing_tag, cls)){ // if the key exists but has the wrong type then set it return set_value(); @@ -352,16 +390,12 @@ void init_compound(py::module& m) { ); CompoundTag.def_static( "fromkeys", - [](py::object keys, AmuletNBT::WrapperNode value){ - if (value.index() == 0){ - throw py::type_error("Value cannot be None"); - } - AmuletNBT::TagNode node = AmuletNBT::unwrap_node(value); + [](py::object keys, AmuletNBT::TagNode value){ AmuletNBT::CompoundTagPtr tag = std::make_shared(); for (std::string& key: keys.cast>()){ - (*tag)[key] = node; + (*tag)[key] = value; } - return AmuletNBT::CompoundTagWrapper(tag); + return tag; } ); @@ -369,22 +403,22 @@ void init_compound(py::module& m) { CompoundTag.def(\ "get_" TAG_NAME,\ [](\ - const AmuletNBT::CompoundTagWrapper& self,\ + const AmuletNBT::CompoundTag& self,\ std::string key,\ - std::variant> default_,\ + std::variant default_,\ bool raise_errors\ - ) -> std::variant> {\ - auto it = self.tag->find(key);\ - if (it == self.tag->end()){\ + ) -> std::variant {\ + auto it = self.find(key);\ + if (it == self.end()){\ if (raise_errors){\ throw pybind11::key_error(key);\ } else {\ return default_;\ }\ }\ - py::object tag = py::cast(AmuletNBT::wrap_node(it->second));\ - if (py::isinstance>(tag)){\ - return tag.cast>();\ + py::object tag = py::cast(it->second);\ + if (py::isinstance(tag)){\ + return tag.cast();\ } else if (raise_errors){\ throw pybind11::type_error(key);\ } else {\ @@ -406,29 +440,32 @@ void init_compound(py::module& m) { CompoundTag.def(\ "setdefault_" TAG_NAME,\ [isinstance](\ - const AmuletNBT::CompoundTagWrapper& self,\ + AmuletNBT::CompoundTag& self,\ std::string key,\ - std::variant> default_\ - ) -> std::variant> {\ - auto set_and_return = [self, key](TAG_STORAGE tag){\ - AmuletNBT::TagNode node(tag);\ - (*self.tag)[key] = node;\ - return AmuletNBT::TagWrapper(tag);\ + std::variant default_\ + ) -> std::variant {\ + auto set_and_return = [&self, &key](TAG_STORAGE tag){\ + self[key] = tag;\ + return tag;\ };\ - auto create_set_return = [set_and_return, default_](){\ - if (default_.index() == 0){\ - return set_and_return(new_tag());\ - } else {\ - return set_and_return(std::get>(default_).tag);\ - }\ + auto create_set_return = [set_and_return, &default_](){\ + return std::visit([set_and_return](auto&& tag) {\ + using T = std::decay_t;\ + if constexpr (std::is_same_v) {\ + return set_and_return(new_tag());\ + }\ + else {\ + return set_and_return(tag);\ + }\ + }, default_);\ };\ - auto it = self.tag->find(key);\ - if (it == self.tag->end()){\ + auto it = self.find(key);\ + if (it == self.end()){\ return create_set_return();\ }\ - py::object existing_tag = py::cast(AmuletNBT::wrap_node(it->second));\ - if (py::isinstance>(existing_tag)){\ - return existing_tag.cast>();\ + py::object existing_tag = py::cast(it->second);\ + if (py::isinstance(existing_tag)){\ + return existing_tag.cast();\ } else {\ /* if the key exists but has the wrong type then set it */\ return create_set_return();\ @@ -448,23 +485,23 @@ void init_compound(py::module& m) { CompoundTag.def(\ "pop_" TAG_NAME,\ [marker](\ - const AmuletNBT::CompoundTagWrapper& self,\ + AmuletNBT::CompoundTag& self,\ std::string key,\ - std::variant> default_,\ + std::variant default_,\ bool raise_errors\ - ) -> std::variant> {\ - auto it = self.tag->find(key);\ - if (it == self.tag->end()){\ + ) -> std::variant {\ + auto it = self.find(key);\ + if (it == self.end()){\ if (raise_errors){\ throw py::key_error(key);\ } else {\ return default_;\ }\ }\ - py::object existing_tag = py::cast(AmuletNBT::wrap_node(it->second));\ - if (py::isinstance>(existing_tag)){\ - self.tag->erase(it);\ - return existing_tag.cast>();\ + py::object existing_tag = py::cast(it->second);\ + if (py::isinstance(existing_tag)){\ + self.erase(it);\ + return existing_tag.cast();\ } else if (raise_errors){\ throw pybind11::type_error(key);\ } else {\ diff --git a/src/amulet_nbt/pybind/tag/py_float_tag.cpp b/src/amulet_nbt/pybind/tag/py_float_tag.cpp index 02f9ccac..7254edf6 100644 --- a/src/amulet_nbt/pybind/tag/py_float_tag.cpp +++ b/src/amulet_nbt/pybind/tag/py_float_tag.cpp @@ -1,23 +1,29 @@ #include +#include #include #include #include -#include +#include +#include +#include +#include +#include +#include namespace py = pybind11; -#define PyFloat(CLSNAME, PRECISION, TAGID)\ - py::class_ CLSNAME(m, #CLSNAME,\ +#define PyFloat(NATIVE, CLSNAME, PRECISION, TAGID)\ + py::class_ CLSNAME(m, #CLSNAME,\ "A "#PRECISION" precision float class."\ );\ CLSNAME.def_property_readonly_static("tag_id", [](py::object) {return TAGID;});\ CLSNAME.def(\ py::init([](py::object value) {\ try {\ - return AmuletNBT::CLSNAME##Wrapper(value.cast());\ + return AmuletNBT::CLSNAME(value.cast());\ } catch (const py::cast_error&){\ throw py::type_error("value must be float or float-like");\ }\ @@ -25,18 +31,22 @@ namespace py = pybind11; py::arg("value") = 0.0,\ py::doc("__init__(self: amulet_nbt."#CLSNAME", value: typing.SupportsFloat) -> None")\ );\ - CLSNAME.def_readonly(\ + CLSNAME.def_property_readonly(\ "py_float",\ - &AmuletNBT::CLSNAME##Wrapper::tag,\ + [](const AmuletNBT::CLSNAME& self) -> NATIVE {\ + return self;\ + },\ py::doc(\ "A python float representation of the class.\n"\ "\n"\ "The returned data is immutable so changes will not mirror the instance."\ )\ );\ - CLSNAME.def_readonly(\ + CLSNAME.def_property_readonly(\ "py_data",\ - &AmuletNBT::CLSNAME##Wrapper::tag,\ + [](const AmuletNBT::CLSNAME& self) -> NATIVE {\ + return self;\ + },\ py::doc(\ "A python representation of the class. Note that the return type is undefined and may change in the future.\n"\ "\n"\ @@ -44,103 +54,107 @@ namespace py = pybind11; "This is here for convenience to get a python representation under the same property name.\n"\ )\ );\ + SerialiseTag(CLSNAME)\ CLSNAME.def(\ "__repr__",\ - [](const AmuletNBT::CLSNAME##Wrapper& self){\ - return #CLSNAME "(" + py::repr(py::cast(self.tag)).cast() + ")";\ + [](const AmuletNBT::CLSNAME& self){\ + return #CLSNAME "(" + py::repr(py::cast(static_cast(self))).cast() + ")";\ }\ );\ CLSNAME.def(\ "__str__",\ - [](const AmuletNBT::CLSNAME##Wrapper& self){\ - return py::repr(py::cast(self.tag));\ + [](const AmuletNBT::CLSNAME& self){\ + return py::repr(py::cast(static_cast(self)));\ }\ );\ CLSNAME.def(\ py::pickle(\ - [](const AmuletNBT::CLSNAME##Wrapper& self){\ - return self.tag;\ + [](const AmuletNBT::CLSNAME& self) -> NATIVE {\ + return self;\ },\ - [](AmuletNBT::CLSNAME state){\ - return AmuletNBT::CLSNAME##Wrapper(state);\ + [](NATIVE state){\ + return AmuletNBT::CLSNAME(state);\ }\ )\ );\ CLSNAME.def(\ "__copy__",\ - [](const AmuletNBT::CLSNAME##Wrapper& self){\ + [](const AmuletNBT::CLSNAME& self){\ return self;\ }\ );\ CLSNAME.def(\ "__deepcopy__",\ - [](const AmuletNBT::CLSNAME##Wrapper& self, py::dict){\ + [](const AmuletNBT::CLSNAME& self, py::dict){\ return self;\ },\ py::arg("memo")\ );\ CLSNAME.def(\ "__hash__",\ - [](const AmuletNBT::CLSNAME##Wrapper& self){\ - return py::hash(py::make_tuple(TAGID, self.tag));\ + [](const AmuletNBT::CLSNAME& self){\ + return py::hash(py::make_tuple(TAGID, static_cast(self)));\ }\ );\ CLSNAME.def(\ "__int__",\ - [](const AmuletNBT::CLSNAME##Wrapper& self) -> py::int_ {\ - return py::cast(self.tag);\ + [](const AmuletNBT::CLSNAME& self) -> py::int_ {\ + return py::cast(static_cast(self));\ }\ );\ CLSNAME.def(\ "__float__",\ - [](const AmuletNBT::CLSNAME##Wrapper& self) {\ - return self.tag;\ + [](const AmuletNBT::CLSNAME& self) -> NATIVE {\ + return self;\ }\ );\ CLSNAME.def(\ "__bool__",\ - [](const AmuletNBT::CLSNAME##Wrapper& self){\ - return self.tag != 0.0;\ + [](const AmuletNBT::CLSNAME& self){\ + return self != 0.0;\ }\ );\ CLSNAME.def(\ "__eq__",\ - [](const AmuletNBT::CLSNAME##Wrapper& self, const AmuletNBT::CLSNAME##Wrapper& other){\ - return self.tag == other.tag;\ + [](const AmuletNBT::CLSNAME& self, const AmuletNBT::CLSNAME& other){\ + return self == other;\ },\ py::is_operator()\ );\ CLSNAME.def(\ "__ge__",\ - [](const AmuletNBT::CLSNAME##Wrapper& self, const AmuletNBT::CLSNAME##Wrapper& other){\ - return self.tag >= other.tag;\ + [](const AmuletNBT::CLSNAME& self, const AmuletNBT::CLSNAME& other){\ + return self >= other;\ },\ py::is_operator()\ );\ CLSNAME.def(\ "__gt__",\ - [](const AmuletNBT::CLSNAME##Wrapper& self, const AmuletNBT::CLSNAME##Wrapper& other){\ - return self.tag > other.tag;\ + [](const AmuletNBT::CLSNAME& self, const AmuletNBT::CLSNAME& other){\ + return self > other;\ },\ py::is_operator()\ );\ CLSNAME.def(\ "__le__",\ - [](const AmuletNBT::CLSNAME##Wrapper& self, const AmuletNBT::CLSNAME##Wrapper& other){\ - return self.tag <= other.tag;\ + [](const AmuletNBT::CLSNAME& self, const AmuletNBT::CLSNAME& other){\ + return self <= other;\ },\ py::is_operator()\ );\ CLSNAME.def(\ "__lt__",\ - [](const AmuletNBT::CLSNAME##Wrapper& self, const AmuletNBT::CLSNAME##Wrapper& other){\ - return self.tag < other.tag;\ + [](const AmuletNBT::CLSNAME& self, const AmuletNBT::CLSNAME& other){\ + return self < other;\ },\ py::is_operator()\ ); void init_float(py::module& m) { - PyFloat(FloatTag, single, 5) - PyFloat(DoubleTag, double, 6) + py::object mutf8_encoding = m.attr("mutf8_encoding"); + py::object java_encoding = m.attr("java_encoding"); + py::object compress = py::module::import("gzip").attr("compress"); + PyFloat(float, FloatTag, single, 5) + PyFloat(double, DoubleTag, double, 6) } diff --git a/src/amulet_nbt/pybind/tag/py_int_tag.cpp b/src/amulet_nbt/pybind/tag/py_int_tag.cpp index ad0dbb0e..a48b3064 100644 --- a/src/amulet_nbt/pybind/tag/py_int_tag.cpp +++ b/src/amulet_nbt/pybind/tag/py_int_tag.cpp @@ -1,16 +1,22 @@ #include +#include #include #include #include -#include +#include +#include +#include +#include +#include +#include namespace py = pybind11; -#define PyInt(CLSNAME, BYTEWIDTH, BITPOW, SIGNBIT, MAGBITS, TAGID)\ - py::class_ CLSNAME(m, #CLSNAME,\ +#define PyInt(NATIVE, CLSNAME, BYTEWIDTH, BITPOW, SIGNBIT, MAGBITS, TAGID)\ + py::class_ CLSNAME(m, #CLSNAME,\ "A "#BYTEWIDTH" byte integer class.\n"\ "\n"\ "Can Store numbers between -(2^"#BITPOW") and (2^"#BITPOW" - 1)"\ @@ -21,26 +27,30 @@ namespace py = pybind11; /* cast to a python int */\ py::object py_int = PyIntCls(py_value);\ /* get the magnitude bits */\ - AmuletNBT::CLSNAME value = py_int.attr("__and__")(py::cast(MAGBITS)).cast();\ + NATIVE value = py_int.attr("__and__")(py::cast(MAGBITS)).cast();\ /* get the sign bits */\ if (py_int.attr("__and__")(py::cast(SIGNBIT)).cast()){value -= SIGNBIT;}\ - return AmuletNBT::CLSNAME##Wrapper(value);\ + return AmuletNBT::CLSNAME(value);\ }),\ py::arg("value") = 0,\ py::doc("__init__(self: amulet_nbt."#CLSNAME", value: typing.SupportsInt) -> None")\ );\ - CLSNAME.def_readonly(\ + CLSNAME.def_property_readonly(\ "py_int",\ - &AmuletNBT::CLSNAME##Wrapper::tag,\ + [](const AmuletNBT::CLSNAME& self) -> NATIVE {\ + return self;\ + },\ py::doc(\ "A python int representation of the class.\n"\ "\n"\ "The returned data is immutable so changes will not mirror the instance."\ )\ );\ - CLSNAME.def_readonly(\ + CLSNAME.def_property_readonly(\ "py_data",\ - &AmuletNBT::CLSNAME##Wrapper::tag,\ + [](const AmuletNBT::CLSNAME& self) -> NATIVE {\ + return self;\ + },\ py::doc(\ "A python representation of the class. Note that the return type is undefined and may change in the future.\n"\ "\n"\ @@ -48,97 +58,98 @@ namespace py = pybind11; "This is here for convenience to get a python representation under the same property name.\n"\ )\ );\ + SerialiseTag(CLSNAME)\ CLSNAME.def(\ "__repr__",\ - [](const AmuletNBT::CLSNAME##Wrapper& self){\ - return #CLSNAME "(" + std::to_string(self.tag) + ")";\ + [](const AmuletNBT::CLSNAME& self){\ + return #CLSNAME "(" + std::to_string(static_cast(self)) + ")";\ }\ );\ CLSNAME.def(\ "__str__",\ - [](const AmuletNBT::CLSNAME##Wrapper& self){\ - return std::to_string(self.tag);\ + [](const AmuletNBT::CLSNAME& self){\ + return std::to_string(static_cast(self));\ }\ );\ CLSNAME.def(\ py::pickle(\ - [](const AmuletNBT::CLSNAME##Wrapper& self){\ - return self.tag;\ + [](const AmuletNBT::CLSNAME& self) -> NATIVE{\ + return self;\ },\ - [](AmuletNBT::CLSNAME state){\ - return AmuletNBT::CLSNAME##Wrapper(state);\ + [](NATIVE state){\ + return AmuletNBT::CLSNAME(state);\ }\ )\ );\ CLSNAME.def(\ "__copy__",\ - [](const AmuletNBT::CLSNAME##Wrapper& self){\ + [](const AmuletNBT::CLSNAME& self){\ return self;\ }\ );\ CLSNAME.def(\ "__deepcopy__",\ - [](const AmuletNBT::CLSNAME##Wrapper& self, py::dict){\ + [](const AmuletNBT::CLSNAME& self, py::dict){\ return self;\ },\ py::arg("memo")\ );\ CLSNAME.def(\ "__hash__",\ - [](const AmuletNBT::CLSNAME##Wrapper& self){\ - return py::hash(py::make_tuple(TAGID, self.tag));\ + [](const AmuletNBT::CLSNAME& self){\ + return py::hash(py::make_tuple(TAGID, static_cast(self)));\ }\ );\ CLSNAME.def(\ "__int__",\ - [](const AmuletNBT::CLSNAME##Wrapper& self){\ - return self.tag;\ + [](const AmuletNBT::CLSNAME& self) -> NATIVE {\ + return self;\ }\ );\ CLSNAME.def(\ "__float__",\ - [](const AmuletNBT::CLSNAME##Wrapper& self) -> py::float_ {\ - return py::cast(self.tag);\ + [](const AmuletNBT::CLSNAME& self) -> py::float_ {\ + return py::cast(static_cast(self));\ }\ );\ CLSNAME.def(\ "__bool__",\ - [](const AmuletNBT::CLSNAME##Wrapper& self){\ - return self.tag != 0;\ + [](const AmuletNBT::CLSNAME& self){\ + return self != 0;\ }\ );\ CLSNAME.def(\ "__eq__",\ - [](const AmuletNBT::CLSNAME##Wrapper& self, const AmuletNBT::CLSNAME##Wrapper& other){\ - return self.tag == other.tag;\ + [](const AmuletNBT::CLSNAME& self, const AmuletNBT::CLSNAME& other){\ + return self == other;\ },\ py::is_operator()\ );\ CLSNAME.def(\ "__ge__",\ - [](const AmuletNBT::CLSNAME##Wrapper& self, const AmuletNBT::CLSNAME##Wrapper& other){\ - return self.tag >= other.tag;\ + [](const AmuletNBT::CLSNAME& self, const AmuletNBT::CLSNAME& other){\ + return self >= other;\ },\ py::is_operator()\ );\ CLSNAME.def(\ "__gt__",\ - [](const AmuletNBT::CLSNAME##Wrapper& self, const AmuletNBT::CLSNAME##Wrapper& other){\ - return self.tag > other.tag;\ + [](const AmuletNBT::CLSNAME& self, const AmuletNBT::CLSNAME& other){\ + return self > other;\ },\ py::is_operator()\ );\ CLSNAME.def(\ "__le__",\ - [](const AmuletNBT::CLSNAME##Wrapper& self, const AmuletNBT::CLSNAME##Wrapper& other){\ - return self.tag <= other.tag;\ + [](const AmuletNBT::CLSNAME& self, const AmuletNBT::CLSNAME& other){\ + return self <= other;\ },\ py::is_operator()\ );\ CLSNAME.def(\ "__lt__",\ - [](const AmuletNBT::CLSNAME##Wrapper& self, const AmuletNBT::CLSNAME##Wrapper& other){\ - return self.tag < other.tag;\ + [](const AmuletNBT::CLSNAME& self, const AmuletNBT::CLSNAME& other){\ + return self < other;\ },\ py::is_operator()\ ); @@ -146,8 +157,11 @@ namespace py = pybind11; void init_int(py::module& m) { py::object PyIntCls = py::module::import("builtins").attr("int"); - PyInt(ByteTag, 1, 7, 0x80, 0x7F, 1) - PyInt(ShortTag, 2, 15, 0x8000, 0x7FFF, 2) - PyInt(IntTag, 4, 31, 0x80000000, 0x7FFFFFFF, 3) - PyInt(LongTag, 8, 63, 0x8000000000000000, 0x7FFFFFFFFFFFFFFF, 4) + py::object mutf8_encoding = m.attr("mutf8_encoding"); + py::object java_encoding = m.attr("java_encoding"); + py::object compress = py::module::import("gzip").attr("compress"); + PyInt(std::int8_t, ByteTag, 1, 7, 0x80, 0x7F, 1) + PyInt(std::int16_t, ShortTag, 2, 15, 0x8000, 0x7FFF, 2) + PyInt(std::int32_t, IntTag, 4, 31, 0x80000000, 0x7FFFFFFF, 3) + PyInt(std::int64_t, LongTag, 8, 63, 0x8000000000000000, 0x7FFFFFFFFFFFFFFF, 4) }; diff --git a/src/amulet_nbt/pybind/tag/py_list_tag.cpp b/src/amulet_nbt/pybind/tag/py_list_tag.cpp index 59277b83..6a319859 100644 --- a/src/amulet_nbt/pybind/tag/py_list_tag.cpp +++ b/src/amulet_nbt/pybind/tag/py_list_tag.cpp @@ -8,44 +8,62 @@ #include #include #include +#include #include #include #include #include -#include +#include #include #include #include +#include +#include +#include +#include namespace py = pybind11; -void ListTag_extend(AmuletNBT::ListTagPtr tag, py::object value){ +namespace AmuletNBT { + // A class to emulate python's iteration mechanic + class ListTagIterator { + private: + ListTagPtr tag; + size_t index; + std::ptrdiff_t step; + public: + ListTagIterator(ListTagPtr tag, size_t start, std::ptrdiff_t step) : tag(tag), index(start), step(step) {}; + TagNode next() { + auto node = ListTag_get_node(*tag, index); + index += step; + return node; + } + bool has_next() { + return index >= 0 && index < ListTag_size(*tag); + } + }; +} + +void ListTag_extend(AmuletNBT::ListTag& tag, py::object value){ // The caller must ensure value is not tag auto it = py::iter(value); while (it != py::iterator::sentinel()){ - AmuletNBT::WrapperNode node = py::cast(*it); - - switch(node.index()){ - #define CASE(ID, TAG_NAME, TAG, TAG_STORAGE, LIST_TAG)\ - case ID:\ - AmuletNBT::ListTag_append(*tag, std::get>(node).tag);\ - break; - case 0: - throw py::type_error("Cannot append null TagNode"); - FOR_EACH_LIST_TAG(CASE) - #undef CASE - } + AmuletNBT::TagNode node = py::cast(*it); + std::visit([&tag](auto&& node_tag) { + using T = std::decay_t; + AmuletNBT::ListTag_append(tag, node_tag); + }, node); ++it; } } template -void ListTag_set_slice(AmuletNBT::ListTagPtr self, const py::slice &slice, std::vector& vec){ - if (self->index() == variant_index>()){ +void ListTag_set_slice(AmuletNBT::ListTag& self, const py::slice &slice, std::vector& vec){ + if (std::holds_alternative>(self)){ // Tag type matches - std::vector& list_tag = std::get>(*self); + std::vector& list_tag = std::get>(self); Py_ssize_t start = 0, stop = 0, step = 0, slice_length = 0; if (!slice.compute(list_tag.size(), &start, &stop, &step, &slice_length)) { throw py::error_already_set(); @@ -77,7 +95,7 @@ void ListTag_set_slice(AmuletNBT::ListTagPtr self, const py::slice &slice, std:: } } else { // Tag type does not match - size_t size = ListTag_size(*self); + size_t size = ListTag_size(self); Py_ssize_t start = 0, stop = 0, step = 0, slice_length = 0; if (!slice.compute(size, &start, &stop, &step, &slice_length)) { throw py::error_already_set(); @@ -92,7 +110,7 @@ void ListTag_set_slice(AmuletNBT::ListTagPtr self, const py::slice &slice, std:: "When overwriting values in a ListTag the types must match or all tags must be overwritten." ); } - self->emplace>(vec); + self.emplace>(vec); } else { throw py::type_error("NBT ListTag item mismatch."); } @@ -131,7 +149,7 @@ void init_list(py::module& m) { "__next__", [](AmuletNBT::ListTagIterator& self){ if (self.has_next()){ - return AmuletNBT::wrap_node(self.next()); + return self.next(); } throw py::stop_iteration(""); } @@ -143,7 +161,14 @@ void init_list(py::module& m) { } ); - py::class_ ListTag(m, "ListTag", + py::object mutf8_encoding = m.attr("mutf8_encoding"); + py::object java_encoding = m.attr("java_encoding"); + py::object compress = py::module::import("gzip").attr("compress"); + py::object AbstractBaseMutableTag = m.attr("AbstractBaseMutableTag"); + + //py::class_> ListTag(m, "ListTag", + py::class_> ListTag(m, "ListTag", AbstractBaseMutableTag, + //py::class_> ListTag(m, "ListTag", "A Python wrapper around a C++ vector.\n" "\n" "All contained data must be of the same NBT data type." @@ -159,8 +184,8 @@ void init_list(py::module& m) { throw std::invalid_argument("element_tag_id must be in the range 0-12"); #undef CASE } - ListTag_extend(tag, value); - return AmuletNBT::ListTagWrapper(tag); + ListTag_extend(*tag, value); + return tag; }), py::arg("value") = py::tuple(), py::arg("element_tag_id") = 1, py::doc("__init__(self: amulet_nbt.ListTag, value: typing.Iterable[amulet_nbt.ByteTag] | typing.Iterable[amulet_nbt.ShortTag] | typing.Iterable[amulet_nbt.IntTag] | typing.Iterable[amulet_nbt.LongTag] | typing.Iterable[amulet_nbt.FloatTag] | typing.Iterable[amulet_nbt.DoubleTag] | typing.Iterable[amulet_nbt.ByteArrayTag] | typing.Iterable[amulet_nbt.StringTag] | typing.Iterable[amulet_nbt.ListTag] | typing.Iterable[amulet_nbt.CompoundTag] | typing.Iterable[amulet_nbt.IntArrayTag] | typing.Iterable[amulet_nbt.LongArrayTag] = (), element_tag_id = 1) -> None") @@ -168,23 +193,19 @@ void init_list(py::module& m) { ListTag.attr("__class_getitem__") = PyClassMethod_New( py::cpp_function([](const py::type &cls, const py::args &args){return cls;}).ptr() ); - auto py_getter = [](const AmuletNBT::ListTagWrapper& self){ + auto py_getter = [](const AmuletNBT::ListTag& self){ py::list list; - switch(self.tag->index()){ - #define CASE(ID, TAG_NAME, TAG, TAG_STORAGE, LIST_TAG)\ - case ID:\ - {\ - LIST_TAG& tag = std::get(*self.tag);\ - for (size_t i = 0; i < tag.size(); i++){\ - list.append(\ - AmuletNBT::TagWrapper(tag[i])\ - );\ - };\ - break;\ - } - FOR_EACH_LIST_TAG(CASE) - #undef CASE - } + std::visit([&list](auto&& vec) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + // do nothing + } + else { + for (const auto& tag : vec) { + list.append(tag); + } + } + }, self); return list; }; ListTag.def_property_readonly( @@ -207,91 +228,86 @@ void init_list(py::module& m) { "This is here for convenience to get a python representation under the same property name.\n" ) ); + SerialiseTag(ListTag)\ ListTag.def( "__repr__", - [](const AmuletNBT::ListTagWrapper& self){ + [](const AmuletNBT::ListTag& self){ std::string out; out += "ListTag(["; - switch(self.tag->index()){ - case 0: - break; - #define CASE(ID, TAG_NAME, TAG, TAG_STORAGE, LIST_TAG)\ - case ID:\ - {\ - LIST_TAG& list_tag = std::get(*self.tag);\ - for (size_t i = 0; i < list_tag.size(); i++){\ - if (i != 0){out += ", ";}\ - out += py::repr(py::cast(AmuletNBT::TagWrapper(list_tag[i])));\ - }\ - };\ - break; - FOR_EACH_LIST_TAG(CASE) - #undef CASE - } + std::visit([&out](auto&& vec) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + // do nothing + } + else { + for (size_t i = 0; i < vec.size(); i++){ + if (i != 0){out += ", ";} + out += py::repr(py::cast(vec[i])); + } + } + }, self); out += "], "; - out += std::to_string(self.tag->index()); + out += std::to_string(self.index()); out += ")"; return out; } ); ListTag.def( "__str__", - [](const AmuletNBT::ListTagWrapper& self){ + [](const AmuletNBT::ListTag& self){ return py::str(py::list(py::cast(self))); } ); ListTag.def( py::pickle( - [](const AmuletNBT::ListTagWrapper& self){ - return py::bytes(AmuletNBT::write_nbt("", self.tag, std::endian::big, AmuletNBT::utf8_to_mutf8)); + [](const AmuletNBT::ListTag& self){ + return py::bytes(AmuletNBT::write_nbt("", self, std::endian::big, AmuletNBT::utf8_to_mutf8)); }, [](py::bytes state){ - return AmuletNBT::ListTagWrapper( - std::get( - AmuletNBT::read_nbt(state, std::endian::big, AmuletNBT::mutf8_to_utf8).tag_node - ) + return std::get( + AmuletNBT::read_nbt(state, std::endian::big, AmuletNBT::mutf8_to_utf8).tag_node ); } ) ); ListTag.def( "__copy__", - [](const AmuletNBT::ListTagWrapper& self){ - return AmuletNBT::ListTagWrapper(NBTTag_copy(*self.tag)); + [](const AmuletNBT::ListTag& self){ + return NBTTag_copy(self); } ); ListTag.def( "__deepcopy__", - [](const AmuletNBT::ListTagWrapper& self, py::dict){ - return AmuletNBT::ListTagWrapper(AmuletNBT::NBTTag_deep_copy_list(*self.tag)); + [](const AmuletNBT::ListTag& self, py::dict){ + return AmuletNBT::NBTTag_deep_copy_list(self); }, py::arg("memo") ); ListTag.def( "__eq__", - [](const AmuletNBT::ListTagWrapper& self, const AmuletNBT::ListTagWrapper& other){ - return AmuletNBT::NBTTag_eq(self.tag, other.tag); + [](const AmuletNBT::ListTag& self, const AmuletNBT::ListTag& other){ + return AmuletNBT::NBTTag_eq(self, other); }, py::is_operator() ); ListTag.def( "__len__", - [](const AmuletNBT::ListTagWrapper& self){ - return AmuletNBT::ListTag_size(*self.tag); + [](const AmuletNBT::ListTag& self){ + return AmuletNBT::ListTag_size(self); } ); ListTag.def( "__bool__", - [](const AmuletNBT::ListTagWrapper& self){ - return AmuletNBT::ListTag_size(*self.tag) != 0; + [](const AmuletNBT::ListTag& self){ + return AmuletNBT::ListTag_size(self) != 0; } ); ListTag.def_property_readonly( "element_tag_id", - [](const AmuletNBT::ListTagWrapper& self){ - return self.tag->index(); + [](const AmuletNBT::ListTag& self){ + return self.index(); } ); const std::array NBTClasses = { @@ -311,283 +327,233 @@ void init_list(py::module& m) { }; ListTag.def_property_readonly( "element_class", - [NBTClasses](const AmuletNBT::ListTagWrapper& self){ - return NBTClasses[self.tag->index()]; + [&NBTClasses](const AmuletNBT::ListTag& self){ + return NBTClasses[self.index()]; } ); ListTag.def( "__getitem__", - [](const AmuletNBT::ListTagWrapper& self, Py_ssize_t item){ - return AmuletNBT::wrap_node(AmuletNBT::ListTag_get_node(*self.tag, item)); + [](const AmuletNBT::ListTag& self, Py_ssize_t item){ + return AmuletNBT::ListTag_get_node(self, item); } ); ListTag.def( "__getitem__", - [](const AmuletNBT::ListTagWrapper& self, const py::slice& slice) { + [](const AmuletNBT::ListTag& self, const py::slice& slice) { py::list out; Py_ssize_t start = 0, stop = 0, step = 0, slice_length = 0; - if (!slice.compute(ListTag_size(*self.tag), &start, &stop, &step, &slice_length)) { + if (!slice.compute(ListTag_size(self), &start, &stop, &step, &slice_length)) { throw py::error_already_set(); } for (Py_ssize_t i = 0; i < slice_length; ++i) { - out.append(AmuletNBT::wrap_node(AmuletNBT::ListTag_get_node(*self.tag, start))); + out.append(AmuletNBT::ListTag_get_node(self, start)); start += step; } return out; }); ListTag.def( "__iter__", - [](const AmuletNBT::ListTagWrapper& self) { - return AmuletNBT::ListTagIterator(self.tag, 0, 1); + [](const AmuletNBT::ListTagPtr& self) { + return AmuletNBT::ListTagIterator(self, 0, 1); } ); ListTag.def( "__reversed__", - [](const AmuletNBT::ListTagWrapper& self) { - return AmuletNBT::ListTagIterator(self.tag, ListTag_size(*self.tag) - 1, -1); + [](const AmuletNBT::ListTagPtr& self) { + return AmuletNBT::ListTagIterator(self, ListTag_size(*self) - 1, -1); } ); ListTag.def( "__contains__", - [](const AmuletNBT::ListTagWrapper& self, AmuletNBT::WrapperNode item){ - if (item.index() == 0) { - throw py::type_error("item cannot be None."); - } - if (item.index() != self.tag->index()){ + [](const AmuletNBT::ListTag& self, AmuletNBT::TagNode item){ + return std::visit([&self](auto&& tag) { + using T = std::decay_t; + if (std::holds_alternative>(self)) { + const std::vector& vec = std::get>(self); + for (const T& tag2: vec) { + if (AmuletNBT::NBTTag_eq(tag, tag2)) { + return true; + } + } + } return false; - } - switch(item.index()){ - case 0: - throw py::type_error("item cannot be None."); - #define CASE(ID, TAG_NAME, TAG, TAG_STORAGE, LIST_TAG)\ - case ID:\ - {\ - TAG_STORAGE item_tag = std::get>(item).tag;\ - LIST_TAG& list_tag = std::get(*self.tag);\ - for (TAG_STORAGE tag: list_tag){\ - if (AmuletNBT::NBTTag_eq(tag, item_tag)){\ - return true;\ - }\ - }\ - return false;\ - }\ - break; - FOR_EACH_LIST_TAG(CASE) - #undef CASE - default: - return false; - } + }, item); } ); ListTag.def( "index", - [](const AmuletNBT::ListTagWrapper& self, AmuletNBT::WrapperNode tag, Py_ssize_t start, Py_ssize_t stop) -> size_t { - switch(tag.index()){ - #define CASE(ID, TAG_NAME, TAG, TAG_STORAGE, LIST_TAG)\ - case ID:\ - return AmuletNBT::ListTag_index(*self.tag, std::get>(tag).tag, start, stop); - FOR_EACH_LIST_TAG(CASE) - #undef CASE - default: - throw py::type_error("tag cannot be None"); - } + [](const AmuletNBT::ListTag& self, AmuletNBT::TagNode node, Py_ssize_t start, Py_ssize_t stop) -> size_t { + return std::visit([&self, &start, &stop](auto&& tag) { + using T = std::decay_t; + return AmuletNBT::ListTag_index(self, tag, start, stop); + }, node); }, py::arg("tag"), py::arg("start") = 0, py::arg("stop") = std::numeric_limits::max() ); ListTag.def( "count", - [](const AmuletNBT::ListTagWrapper& self, AmuletNBT::WrapperNode tag) -> size_t { - switch(tag.index()){ - #define CASE(ID, TAG_NAME, TAG, TAG_STORAGE, LIST_TAG)\ - case ID:\ - return AmuletNBT::ListTag_count(*self.tag, std::get>(tag).tag); - FOR_EACH_LIST_TAG(CASE) - #undef CASE - default: - throw py::type_error("Null TagNode is invalid."); - } + [](const AmuletNBT::ListTag& self, AmuletNBT::TagNode node) -> size_t { + return std::visit([&self](auto&& tag) { + using T = std::decay_t; + return AmuletNBT::ListTag_count(self, tag); + }, node); } ); ListTag.def( "__setitem__", - [](const AmuletNBT::ListTagWrapper& self, Py_ssize_t index, AmuletNBT::WrapperNode tag){ - switch(tag.index()){ - #define CASE(ID, TAG_NAME, TAG, TAG_STORAGE, LIST_TAG)\ - case ID:\ - AmuletNBT::ListTag_set(*self.tag, index, std::get>(tag).tag);\ - break; - FOR_EACH_LIST_TAG(CASE) - #undef CASE - default: - throw py::type_error("Invalid tag to set."); - } + [](AmuletNBT::ListTag& self, Py_ssize_t index, AmuletNBT::TagNode node){ + std::visit([&self, &index](auto&& tag) { + using T = std::decay_t; + AmuletNBT::ListTag_set(self, index, tag); + }, node); } ); ListTag.def( "__setitem__", - [](const AmuletNBT::ListTagWrapper& self, const py::slice &slice, py::object values){ + [](AmuletNBT::ListTag& self, const py::slice &slice, py::object values){ // Cast values to a list to get a consistent format auto list = py::list(values); if (list){ // If the value has items in it // Switch based on the type of the first element - AmuletNBT::WrapperNode first = list[0].cast(); - switch(first.index()){ - #define CASE(ID, TAG_NAME, TAG, TAG_STORAGE, LIST_TAG)\ - case ID:{\ - /* Cast to C++ objects. Also validate that they are all the same type. */\ - std::vector vec;\ - vec.push_back(std::get>(first).tag);\ - for (size_t i = 1; i < list.size(); i++){\ - AmuletNBT::WrapperNode tag = list[i].cast();\ - vec.push_back(std::get>(tag).tag);\ - }\ - ListTag_set_slice(self.tag, slice, vec);\ - break;\ + AmuletNBT::TagNode first = list[0].cast(); + std::visit([&self, &list, &slice](auto&& tag) { + using T = std::decay_t; + // Cast to C++ objects. Also validate that they are all the same type. + std::vector vec; + vec.push_back(tag); + for (size_t i = 1; i < list.size(); i++){ + vec.push_back(list[i].cast()); } - FOR_EACH_LIST_TAG(CASE) - #undef CASE - default: - throw py::type_error("Cannot set a null tag."); - } + ListTag_set_slice(self, slice, vec); + }, first); } else { // The value is empty // empty the slice - switch(self.tag->index()){ - #define CASE(ID, TAG_NAME, TAG, TAG_STORAGE, LIST_TAG)\ - case ID:{\ - auto vec = std::vector();\ - ListTag_set_slice(self.tag, slice, vec);\ - break;\ + std::visit([&self, &slice](auto&& tag) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + // Do nothing } - FOR_EACH_LIST_TAG(CASE) - #undef CASE - } + else { + auto vec = std::vector(); + ListTag_set_slice(self, slice, vec); + } + }, self); } } ); ListTag.def( "__delitem__", - [](const AmuletNBT::ListTagWrapper& self, Py_ssize_t item){ - AmuletNBT::ListTag_del(*self.tag, item); + [](AmuletNBT::ListTag& self, Py_ssize_t item){ + AmuletNBT::ListTag_del(self, item); } ); ListTag.def( "__delitem__", - [](const AmuletNBT::ListTagWrapper& self, const py::slice &slice){ - switch(self.tag->index()){ - #define CASE(ID, TAG_NAME, TAG, TAG_STORAGE, LIST_TAG)\ - case ID:{\ - ListTag_del_slice(std::get>(*self.tag), slice);\ - break;\ + [](AmuletNBT::ListTag& self, const py::slice &slice){ + std::visit([&slice](auto&& tag) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + // Do nothing } - FOR_EACH_LIST_TAG(CASE) - #undef CASE - } + else { + ListTag_del_slice(tag, slice); + } + }, self); } ); ListTag.def( "insert", - [](const AmuletNBT::ListTagWrapper& self, Py_ssize_t index, AmuletNBT::WrapperNode tag){ - switch(tag.index()){ - #define CASE(ID, TAG_NAME, TAG, TAG_STORAGE, LIST_TAG)\ - case ID:\ - AmuletNBT::ListTag_insert(*self.tag, index, std::get>(tag).tag);\ - break; - case 0: - throw py::type_error("Cannot insert null TagNode"); - FOR_EACH_LIST_TAG(CASE) - #undef CASE - } + [](AmuletNBT::ListTag& self, Py_ssize_t index, AmuletNBT::TagNode node){ + std::visit([&self, &index](auto&& tag) { + using T = std::decay_t; + AmuletNBT::ListTag_insert(self, index, tag); + }, node); } ); ListTag.def( "append", - [](const AmuletNBT::ListTagWrapper& self, AmuletNBT::WrapperNode tag){ - switch(tag.index()){ - #define CASE(ID, TAG_NAME, TAG, TAG_STORAGE, LIST_TAG) case ID: AmuletNBT::ListTag_append(*self.tag, std::get>(tag).tag); break; - case 0: - throw py::type_error("Cannot append null TagNode"); - FOR_EACH_LIST_TAG(CASE) - #undef CASE - } + [](AmuletNBT::ListTag& self, AmuletNBT::TagNode node){ + std::visit([&self](auto&& tag) { + using T = std::decay_t; + AmuletNBT::ListTag_append(self, tag); + }, node); } ); ListTag.def( "clear", - [](const AmuletNBT::ListTagWrapper& self){ - switch(self.tag->index()){ - #define CASE(ID, TAG_NAME, TAG, TAG_STORAGE, LIST_TAG) case ID: std::get(*self.tag).clear(); break; - FOR_EACH_LIST_TAG(CASE) - #undef CASE - } + [](AmuletNBT::ListTag& self){ + std::visit([](auto&& list_tag) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + // Do nothing + } + else { + list_tag.clear(); + } + }, self); } ); ListTag.def( "reverse", - [](const AmuletNBT::ListTagWrapper& self){ - switch(self.tag->index()){ - #define CASE(ID, TAG_NAME, TAG, TAG_STORAGE, LIST_TAG) case ID: {LIST_TAG& tag = std::get(*self.tag); std::reverse(tag.begin(), tag.end());}; break; - FOR_EACH_LIST_TAG(CASE) - #undef CASE - } + [](AmuletNBT::ListTag& self){ + std::visit([&self](auto&& list_tag) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + // Do nothing + } + else { + std::reverse(list_tag.begin(), list_tag.end()); + } + }, self); } ); ListTag.def( "extend", - [](const AmuletNBT::ListTagWrapper& self, py::object value){ - ListTag_extend(self.tag, py::list(value)); + [](AmuletNBT::ListTag& self, py::object value){ + ListTag_extend(self, py::list(value)); } ); ListTag.def( "pop", - [](const AmuletNBT::ListTagWrapper& self, Py_ssize_t item){ - return AmuletNBT::wrap_node(ListTag_pop(*self.tag, item)); + [](AmuletNBT::ListTag& self, Py_ssize_t item){ + return ListTag_pop(self, item); }, py::arg("item") = -1 ); ListTag.def( "remove", - [](const AmuletNBT::ListTagWrapper& self, AmuletNBT::WrapperNode tag){ - switch(tag.index()){ - #define CASE(ID, TAG_NAME, TAG, TAG_STORAGE, LIST_TAG)\ - case ID:\ - {\ - size_t index = AmuletNBT::ListTag_index(*self.tag, std::get>(tag).tag);\ - std::vector& list_tag = std::get>(*self.tag);\ - list_tag.erase(list_tag.begin() + index);\ - break;\ - } - FOR_EACH_LIST_TAG(CASE) - #undef CASE - default: - throw py::type_error("tag cannot be None"); - } + [](AmuletNBT::ListTag& self, AmuletNBT::TagNode node){ + std::visit([&self](auto&& tag) { + using T = std::decay_t; + size_t index = AmuletNBT::ListTag_index(self, tag); + std::vector& list_tag = std::get>(self); + list_tag.erase(list_tag.begin() + index); + }, node); } ); ListTag.def( "__iadd__", - [](const AmuletNBT::ListTagWrapper& self, py::object value){ - ListTag_extend(self.tag, py::list(value)); + [](AmuletNBT::ListTagPtr self, py::object value){ + ListTag_extend(*self, py::list(value)); return self; } ); ListTag.def( "copy", - [](const AmuletNBT::ListTagWrapper& self){ - AmuletNBT::ListTagPtr tag = std::make_shared(); - - return AmuletNBT::ListTagWrapper(tag); + [](const AmuletNBT::ListTag& self){ + return std::make_shared(self); } ); #define CASE(ID, TAG_NAME, TAG, TAG_STORAGE, LIST_TAG)\ ListTag.def(\ "get_" TAG_NAME,\ - [](const AmuletNBT::ListTagWrapper& self, Py_ssize_t index){\ - if (self.tag->index() != variant_index>()){\ + [](const AmuletNBT::ListTag& self, Py_ssize_t index){\ + if (!std::holds_alternative>(self)){\ throw pybind11::type_error("ListTag elements are not "#TAG);\ }\ - return AmuletNBT::wrap_node(AmuletNBT::ListTag_get(*self.tag, index));\ + return AmuletNBT::ListTag_get(self, index);\ },\ py::doc(\ "Get the tag at index if it is a "#TAG".\n"\ diff --git a/src/amulet_nbt/pybind/tag/py_named_tag.cpp b/src/amulet_nbt/pybind/tag/py_named_tag.cpp index 3878817e..d1e7158b 100644 --- a/src/amulet_nbt/pybind/tag/py_named_tag.cpp +++ b/src/amulet_nbt/pybind/tag/py_named_tag.cpp @@ -10,8 +10,8 @@ #include #include -#include -#include +#include +#include #include #include #include @@ -63,12 +63,16 @@ void init_named_tag(py::module& m) { py::class_ NamedTag(m, "NamedTag"); NamedTag.def( - py::init([](AmuletNBT::WrapperNode tag, std::string name) { - if (tag.index() == 0){ - return AmuletNBT::NamedTag(name, std::make_shared()); - } else { - return AmuletNBT::NamedTag(name, AmuletNBT::unwrap_node(tag)); - } + py::init([](std::variant value, std::string name) { + return std::visit([&name](auto&& tag) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + return AmuletNBT::NamedTag(name, std::make_shared()); + } + else { + return AmuletNBT::NamedTag(name, tag); + } + }, value); }), py::arg("tag") = py::none(), py::arg("name") = "" ); @@ -88,13 +92,10 @@ void init_named_tag(py::module& m) { NamedTag.def_property( "tag", [](const AmuletNBT::NamedTag& self){ - return AmuletNBT::wrap_node(self.tag_node); + return self.tag_node; }, - [](AmuletNBT::NamedTag& self, AmuletNBT::WrapperNode tag){ - if (tag.index() == 0){ - throw std::invalid_argument("tag cannot be None"); - } - self.tag_node = AmuletNBT::unwrap_node(tag); + [](AmuletNBT::NamedTag& self, AmuletNBT::TagNode tag){ + self.tag_node = tag; } ); auto to_nbt = [compress]( @@ -231,7 +232,7 @@ void init_named_tag(py::module& m) { [](const AmuletNBT::NamedTag& self){ std::string out; out += "NamedTag("; - out += py::repr(py::cast(AmuletNBT::wrap_node(self.tag_node))); + out += py::repr(py::cast(self.tag_node)); out += ", "; try { out += py::repr(py::str(self.name)); @@ -299,10 +300,10 @@ void init_named_tag(py::module& m) { NamedTag.def_property_readonly(\ TAG_NAME,\ [](const AmuletNBT::NamedTag& self){\ - if (self.tag_node.index() != ID){\ + if (!std::holds_alternative(self.tag_node)){\ throw pybind11::type_error("tag_node is not a "#TAG);\ }\ - return AmuletNBT::TagWrapper(std::get(self.tag_node));\ + return std::get(self.tag_node);\ },\ py::doc(\ "Get the tag if it is a "#TAG".\n"\ diff --git a/src/amulet_nbt/pybind/tag/py_string_tag.cpp b/src/amulet_nbt/pybind/tag/py_string_tag.cpp index 69c7aba0..441b6eca 100644 --- a/src/amulet_nbt/pybind/tag/py_string_tag.cpp +++ b/src/amulet_nbt/pybind/tag/py_string_tag.cpp @@ -1,34 +1,48 @@ #include +#include +#include #include #include #include -#include +#include +#include +#include +#include +#include +#include +#include namespace py = pybind11; void init_string(py::module& m) { - py::class_ StringTag(m, "StringTag", + py::object mutf8_encoding = m.attr("mutf8_encoding"); + py::object java_encoding = m.attr("java_encoding"); + py::object compress = py::module::import("gzip").attr("compress"); + + py::class_ StringTag(m, "StringTag", "A class that behaves like a string." ); StringTag.def_property_readonly_static("tag_id", [](py::object) {return 8;}); StringTag.def( py::init([](py::object value) { - if (py::isinstance(value)){ - return value.cast(); + if (py::isinstance(value)){ + return value.cast(); } else if (py::isinstance(value) || py::isinstance(value)){ - return AmuletNBT::StringTagWrapper(value.cast()); + return AmuletNBT::StringTag(value.cast()); } else { - return AmuletNBT::StringTagWrapper(py::str(value).cast()); + return AmuletNBT::StringTag(py::str(value).cast()); } }), py::arg("value") = "", py::doc("__init__(self: amulet_nbt.StringTag, value: str | bytes) -> None") ); - StringTag.def_readonly( + StringTag.def_property_readonly( "py_str", - &AmuletNBT::StringTagWrapper::tag, + [](const AmuletNBT::StringTag& self) -> std::string { + return self; + }, py::doc( "The data stored in the class as a python string.\n" "\n" @@ -37,8 +51,8 @@ void init_string(py::module& m) { ); StringTag.def_property_readonly( "py_bytes", - [](const AmuletNBT::StringTagWrapper& self){ - return py::bytes(self.tag); + [](const AmuletNBT::StringTag& self){ + return py::bytes(self); }, py::doc( "The bytes stored in the class." @@ -46,8 +60,8 @@ void init_string(py::module& m) { ); StringTag.def_property_readonly( "py_data", - [](const AmuletNBT::StringTagWrapper& self){ - return py::bytes(self.tag); + [](const AmuletNBT::StringTag& self){ + return py::bytes(self); }, py::doc( "A python representation of the class. Note that the return type is undefined and may change in the future.\n" @@ -56,95 +70,96 @@ void init_string(py::module& m) { "This is here for convenience to get a python representation under the same property name.\n" ) ); + SerialiseTag(StringTag)\ StringTag.def( "__repr__", - [](const AmuletNBT::StringTagWrapper& self){ + [](const AmuletNBT::StringTag& self){ try { - return "StringTag(" + py::repr(py::str(self.tag)).cast() + ")"; + return "StringTag(" + py::repr(py::str(self)).cast() + ")"; } catch (py::error_already_set&){ - return "StringTag(" + py::repr(py::bytes(self.tag)).cast() + ")"; + return "StringTag(" + py::repr(py::bytes(self)).cast() + ")"; } } ); StringTag.def( "__str__", - [](const AmuletNBT::StringTagWrapper& self){ - return self.tag; + [](const AmuletNBT::StringTag& self) -> std::string { + return self; } ); StringTag.def( "__bytes__", - [](const AmuletNBT::StringTagWrapper& self){ - return py::bytes(self.tag); + [](const AmuletNBT::StringTag& self){ + return py::bytes(self); } ); StringTag.def( py::pickle( - [](const AmuletNBT::StringTagWrapper& self){ - return py::bytes(self.tag); + [](const AmuletNBT::StringTag& self){ + return py::bytes(self); }, [](py::bytes state){ - return AmuletNBT::StringTagWrapper(state); + return AmuletNBT::StringTag(state); } ) ); StringTag.def( "__copy__", - [](const AmuletNBT::StringTagWrapper& self){ + [](const AmuletNBT::StringTag& self){ return self; } ); StringTag.def( "__deepcopy__", - [](const AmuletNBT::StringTagWrapper& self, py::dict){ + [](const AmuletNBT::StringTag& self, py::dict){ return self; }, py::arg("memo") ); StringTag.def( "__hash__", - [](const AmuletNBT::StringTagWrapper& self){ - return py::hash(py::make_tuple(8, py::bytes(self.tag))); + [](const AmuletNBT::StringTag& self){ + return py::hash(py::make_tuple(8, py::bytes(self))); } ); StringTag.def( "__bool__", - [](const AmuletNBT::StringTagWrapper& self){ - return !self.tag.empty(); + [](const AmuletNBT::StringTag& self){ + return !self.empty(); } ); StringTag.def( "__eq__", - [](const AmuletNBT::StringTagWrapper& self, const AmuletNBT::StringTagWrapper& other){ - return self.tag == other.tag; + [](const AmuletNBT::StringTag& self, const AmuletNBT::StringTag& other){ + return self == other; }, py::is_operator() ); StringTag.def( "__ge__", - [](const AmuletNBT::StringTagWrapper& self, const AmuletNBT::StringTagWrapper& other){ - return self.tag >= other.tag; + [](const AmuletNBT::StringTag& self, const AmuletNBT::StringTag& other){ + return self >= other; }, py::is_operator() ); StringTag.def( "__gt__", - [](const AmuletNBT::StringTagWrapper& self, const AmuletNBT::StringTagWrapper& other){ - return self.tag > other.tag; + [](const AmuletNBT::StringTag& self, const AmuletNBT::StringTag& other){ + return self > other; }, py::is_operator() ); StringTag.def( "__le__", - [](const AmuletNBT::StringTagWrapper& self, const AmuletNBT::StringTagWrapper& other){ - return self.tag <= other.tag; + [](const AmuletNBT::StringTag& self, const AmuletNBT::StringTag& other){ + return self <= other; }, py::is_operator() ); StringTag.def( "__lt__", - [](const AmuletNBT::StringTagWrapper& self, const AmuletNBT::StringTagWrapper& other){ - return self.tag < other.tag; + [](const AmuletNBT::StringTag& self, const AmuletNBT::StringTag& other){ + return self < other; }, py::is_operator() ); diff --git a/tests/test_amulet_nbt/test_tag/test_list.py b/tests/test_amulet_nbt/test_tag/test_list.py index 93ee9358..58f398a4 100644 --- a/tests/test_amulet_nbt/test_tag/test_list.py +++ b/tests/test_amulet_nbt/test_tag/test_list.py @@ -728,14 +728,13 @@ def test_remove(self) -> None: def test_iadd(self) -> None: tag_ = tag = ListTag() tag += [StringTag("val1")] - self.assertEqual(tag_, tag) self.assertIsInstance(tag, ListTag) self.assertEqual( ListTag([StringTag("val1")]), tag, ) - tag += ListTag([StringTag("val2"), StringTag("val3")]) self.assertEqual(tag_, tag) + tag += ListTag([StringTag("val2"), StringTag("val3")]) self.assertIsInstance(tag, ListTag) self.assertEqual( ListTag( @@ -747,6 +746,7 @@ def test_iadd(self) -> None: ), tag, ) + self.assertEqual(tag_, tag) for cls1, cls2 in itertools.product(self.nbt_types, repeat=2): with self.subTest(cls1=cls1, cls2=cls2): From c81533ae0507901a42a7d5cb4144db2c8cc7e3fa Mon Sep 17 00:00:00 2001 From: gentlegiantJGC Date: Fri, 26 Jul 2024 11:03:56 +0100 Subject: [PATCH 4/6] Added missing typename --- src/amulet_nbt/cpp/nbt_encoding/binary/write_binary.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/amulet_nbt/cpp/nbt_encoding/binary/write_binary.cpp b/src/amulet_nbt/cpp/nbt_encoding/binary/write_binary.cpp index 90907359..826486bf 100644 --- a/src/amulet_nbt/cpp/nbt_encoding/binary/write_binary.cpp +++ b/src/amulet_nbt/cpp/nbt_encoding/binary/write_binary.cpp @@ -69,7 +69,7 @@ inline void write_payload(AmuletNBT::BinaryWriter& writer, const T& value){ } std::int32_t length = static_cast(value.size()); writer.writeNumeric(length); - for (const T::value_type& element: value){ + for (const typename T::value_type& element: value){ writer.writeNumeric(element); } } From 72b9e0daf34f6053638c82734bac9d66ed39d67c Mon Sep 17 00:00:00 2001 From: gentlegiantJGC Date: Fri, 26 Jul 2024 11:06:36 +0100 Subject: [PATCH 5/6] Fix duplicate template parameter --- src/amulet_nbt/cpp/nbt_encoding/binary/write_binary.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/amulet_nbt/cpp/nbt_encoding/binary/write_binary.cpp b/src/amulet_nbt/cpp/nbt_encoding/binary/write_binary.cpp index 826486bf..806f9d2a 100644 --- a/src/amulet_nbt/cpp/nbt_encoding/binary/write_binary.cpp +++ b/src/amulet_nbt/cpp/nbt_encoding/binary/write_binary.cpp @@ -195,8 +195,8 @@ template < > inline void write_name_and_tag(AmuletNBT::BinaryWriter& writer, const std::string& name, const AmuletNBT::TagNode& node){ std::visit([&writer, &name](auto&& tag) { - using T = std::decay_t; - write_name_and_tag(writer, name, tag); + using tagT = std::decay_t; + write_name_and_tag(writer, name, tag); }, node); } From 55f007c157357193faafa6e596b4a920ed76228b Mon Sep 17 00:00:00 2001 From: gentlegiantJGC Date: Fri, 26 Jul 2024 13:15:39 +0100 Subject: [PATCH 6/6] Refactor numerical --- .../cpp/nbt_encoding/string/write_string.cpp | 18 ++++++++++-------- .../include/amulet_nbt/tag/float.hpp | 15 +++++++++------ src/amulet_nbt/include/amulet_nbt/tag/int.hpp | 15 +++++++++------ 3 files changed, 28 insertions(+), 20 deletions(-) diff --git a/src/amulet_nbt/cpp/nbt_encoding/string/write_string.cpp b/src/amulet_nbt/cpp/nbt_encoding/string/write_string.cpp index d9045269..cc758399 100644 --- a/src/amulet_nbt/cpp/nbt_encoding/string/write_string.cpp +++ b/src/amulet_nbt/cpp/nbt_encoding/string/write_string.cpp @@ -92,12 +92,13 @@ namespace AmuletNBT { } inline void write_snbt(std::string& snbt, const FloatTag& tag){ - if (std::isfinite(tag)){ - snbt.append(encode_float(tag)); + FloatTagNative native_tag = static_cast(tag); + if (std::isfinite(native_tag)){ + snbt.append(encode_float(native_tag)); snbt.push_back('f'); - } else if (tag == std::numeric_limits::infinity()){ + } else if (native_tag == std::numeric_limits::infinity()){ snbt.append("Infinityf"); - } else if (tag == -std::numeric_limits::infinity()){ + } else if (native_tag == -std::numeric_limits::infinity()){ snbt.append("-Infinityf"); } else { snbt.append("NaNf"); @@ -105,12 +106,13 @@ namespace AmuletNBT { } inline void write_snbt(std::string& snbt, const DoubleTag& tag){ - if (std::isfinite(tag)){ - snbt.append(encode_float(tag)); + DoubleTagNative native_tag = static_cast(tag); + if (std::isfinite(native_tag)){ + snbt.append(encode_float(native_tag)); snbt.push_back('d'); - } else if (tag == std::numeric_limits::infinity()){ + } else if (native_tag == std::numeric_limits::infinity()){ snbt.append("Infinityd"); - } else if (tag == -std::numeric_limits::infinity()){ + } else if (native_tag == -std::numeric_limits::infinity()){ snbt.append("-Infinityd"); } else { snbt.append("NaNd"); diff --git a/src/amulet_nbt/include/amulet_nbt/tag/float.hpp b/src/amulet_nbt/include/amulet_nbt/tag/float.hpp index fcd1bc17..5b6e4a5c 100644 --- a/src/amulet_nbt/include/amulet_nbt/tag/float.hpp +++ b/src/amulet_nbt/include/amulet_nbt/tag/float.hpp @@ -13,15 +13,18 @@ namespace AmuletNBT { std::is_same_v, "T must be float or double" ); - private: - T value; public: + T value; typedef T native_type; - FloatTagTemplate() : value(0.0) {}; + FloatTagTemplate() : value() {}; FloatTagTemplate(const T& value) : value(value) {}; - operator const T&() const { - return value; - }; + FloatTagTemplate(const FloatTagTemplate& other) : value(other.value) {}; + FloatTagTemplate& operator=(const FloatTagTemplate& rhs) { value = rhs.value; return *this; }; + FloatTagTemplate& operator=(const T& rhs) { value = rhs; return *this; }; + operator const T&() const { return value; }; + operator T& () { return value; }; + bool operator==(const FloatTagTemplate& rhs) { return value == rhs.value; } + bool operator<(const FloatTagTemplate& rhs) { return value < rhs.value; } }; typedef float FloatTagNative; diff --git a/src/amulet_nbt/include/amulet_nbt/tag/int.hpp b/src/amulet_nbt/include/amulet_nbt/tag/int.hpp index bb81f3ec..95769f52 100644 --- a/src/amulet_nbt/include/amulet_nbt/tag/int.hpp +++ b/src/amulet_nbt/include/amulet_nbt/tag/int.hpp @@ -16,15 +16,18 @@ namespace AmuletNBT { std::is_same_v, "T must be int 8, 16, 32 or 64" ); - private: - T value; public: + T value; typedef T native_type; - IntTagTemplate() : value(0) {}; + IntTagTemplate() : value() {}; IntTagTemplate(const T& value) : value(value) {}; - operator const T&() const { - return value; - }; + IntTagTemplate(const IntTagTemplate& other) : value(other.value) {}; + IntTagTemplate& operator=(const IntTagTemplate& rhs) { value = rhs.value; return *this; }; + IntTagTemplate& operator=(const T& rhs) { value = rhs; return *this; }; + operator const T&() const { return value; }; + operator T& () { return value; }; + bool operator==(const IntTagTemplate& rhs) { return value == rhs.value; } + bool operator<(const IntTagTemplate& rhs) { return value < rhs.value; } }; typedef std::int8_t ByteTagNative;