Skip to content

Commit

Permalink
Removed templates from write_nbt.hpp
Browse files Browse the repository at this point in the history
Hopefully this will solve the template issues here
  • Loading branch information
gentlegiantJGC committed Feb 17, 2024
1 parent 3c47478 commit d42c729
Showing 1 changed file with 117 additions and 118 deletions.
235 changes: 117 additions & 118 deletions src/amulet_nbt/_nbt_encoding/_binary/_cpp/write_nbt.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,24 @@
#include "../../../_tag/_cpp/nbt.hpp"
#include "../../../_tag/_cpp/array.hpp"

// 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


void write_byte_payload(BinaryWriter& writer, const CByteTag& value);
void write_short_payload(BinaryWriter& writer, const CShortTag& value);
void write_int_payload(BinaryWriter& writer, const CIntTag& value);
void write_long_payload(BinaryWriter& writer, const CLongTag& value);
void write_float_payload(BinaryWriter& writer, const CFloatTag& value);
void write_double_payload(BinaryWriter& writer, const CDoubleTag& value);
void write_byte_array_payload(BinaryWriter& writer, const CByteArrayTagPtr& value);
void write_string_payload(BinaryWriter& writer, const CStringTag& value);
void write_list_payload(BinaryWriter& writer, const CListTagPtr& value);
void write_compound_payload(BinaryWriter& writer, const CCompoundTagPtr& value);
void write_int_array_payload(BinaryWriter& writer, const CIntArrayTagPtr& value);
void write_long_array_payload(BinaryWriter& writer, const CLongArrayTagPtr& value);


// Forward declarations
template <
typename T,
std::enable_if_t<
Expand All @@ -28,9 +44,47 @@ template <
std::is_same_v<T, CIntArrayTagPtr> ||
std::is_same_v<T, CLongArrayTagPtr>,
bool
>
> = true
>
void write_tag_payload(BinaryWriter& writer, const T& value);
void write_named_tag(BinaryWriter& writer, const std::string& name, const T& tag){
writer.writeNumeric<std::uint8_t>(variant_index<TagNode, T>());
write_string_payload(writer, name);
if constexpr (std::is_same_v<T, CByteTag>){write_byte_payload(writer, tag);} else
if constexpr (std::is_same_v<T, CShortTag>){write_short_payload(writer, tag);} else
if constexpr (std::is_same_v<T, CIntTag>){write_int_payload(writer, tag);} else
if constexpr (std::is_same_v<T, CLongTag>){write_long_payload(writer, tag);} else
if constexpr (std::is_same_v<T, CFloatTag>){write_float_payload(writer, tag);} else
if constexpr (std::is_same_v<T, CDoubleTag>){write_double_payload(writer, tag);} else
if constexpr (std::is_same_v<T, CByteArrayTagPtr>){write_byte_array_payload(writer, tag);} else
if constexpr (std::is_same_v<T, CStringTag>){write_string_payload(writer, tag);} else
if constexpr (std::is_same_v<T, CListTagPtr>){write_list_payload(writer, tag);} else
if constexpr (std::is_same_v<T, CCompoundTagPtr>){write_compound_payload(writer, tag);} else
if constexpr (std::is_same_v<T, CIntArrayTagPtr>){write_int_array_payload(writer, tag);} else
if constexpr (std::is_same_v<T, CLongArrayTagPtr>){write_long_array_payload(writer, tag);}
}


template <
typename T,
std::enable_if_t<std::is_same_v<T, TagNode>, bool> = true
>
void write_named_tag(BinaryWriter& writer, const std::string& name, const TagNode& node){
switch (node.index()){
case 1: write_named_tag<CByteTag>(writer, name, std::get<CByteTag>(node)); break;
case 2: write_named_tag<CShortTag>(writer, name, std::get<CShortTag>(node)); break;
case 3: write_named_tag<CIntTag>(writer, name, std::get<CIntTag>(node)); break;
case 4: write_named_tag<CLongTag>(writer, name, std::get<CLongTag>(node)); break;
case 5: write_named_tag<CFloatTag>(writer, name, std::get<CFloatTag>(node)); break;
case 6: write_named_tag<CDoubleTag>(writer, name, std::get<CDoubleTag>(node)); break;
case 7: write_named_tag<CByteArrayTagPtr>(writer, name, std::get<CByteArrayTagPtr>(node)); break;
case 8: write_named_tag<CStringTag>(writer, name, std::get<CStringTag>(node)); break;
case 9: write_named_tag<CListTagPtr>(writer, name, std::get<CListTagPtr>(node)); break;
case 10: write_named_tag<CCompoundTagPtr>(writer, name, std::get<CCompoundTagPtr>(node)); break;
case 11: write_named_tag<CIntArrayTagPtr>(writer, name, std::get<CIntArrayTagPtr>(node)); break;
case 12: write_named_tag<CLongArrayTagPtr>(writer, name, std::get<CLongArrayTagPtr>(node)); break;
default: throw std::runtime_error("TagNode cannot be in null state when writing.");
}
}


template <
Expand All @@ -50,9 +104,13 @@ template <
std::is_same_v<T, CIntArrayTagPtr> ||
std::is_same_v<T, CLongArrayTagPtr>,
bool
>
> = true
>
void write_named_tag(BinaryWriter& writer, const std::string& name, const T& tag);
std::string write_named_tag(const std::string& name, const T& tag, std::endian endianness, StringEncode stringEncode){
BinaryWriter writer(endianness, stringEncode);
write_named_tag<T>(writer, name, tag);
return writer.getBuffer();
}


template<typename V, typename T, size_t I = 0>
Expand All @@ -66,32 +124,31 @@ constexpr size_t variant_index() {
}


template<class... Ts>
struct overloaded : Ts... { using Ts::operator()...; };
void write_byte_payload(BinaryWriter& writer, const CByteTag& value){
writer.writeNumeric<CByteTag>(value);
}

void write_short_payload(BinaryWriter& writer, const CShortTag& value){
writer.writeNumeric<CShortTag>(value);
}

template <
typename T,
std::enable_if_t<
std::is_same_v<T, CByteTag> ||
std::is_same_v<T, CShortTag> ||
std::is_same_v<T, CIntTag> ||
std::is_same_v<T, CLongTag> ||
std::is_same_v<T, CFloatTag> ||
std::is_same_v<T, CDoubleTag>,
bool
> = true
>
void write_tag_payload(BinaryWriter& writer, const T& value){
writer.writeNumeric<T>(value);
void write_int_payload(BinaryWriter& writer, const CIntTag& value){
writer.writeNumeric<CIntTag>(value);
}

void write_long_payload(BinaryWriter& writer, const CLongTag& value){
writer.writeNumeric<CLongTag>(value);
}

template <
typename T,
std::enable_if_t<std::is_same_v<T, CStringTag>, bool> = true
>
void write_tag_payload(BinaryWriter& writer, const CStringTag& value){
void write_float_payload(BinaryWriter& writer, const CFloatTag& value){
writer.writeNumeric<CFloatTag>(value);
}

void write_double_payload(BinaryWriter& writer, const CDoubleTag& value){
writer.writeNumeric<CDoubleTag>(value);
}

void write_string_payload(BinaryWriter& writer, const CStringTag& value){
std::string encoded_string = writer.encodeString(value);
if (encoded_string.size() > static_cast<size_t>(std::numeric_limits<std::uint16_t>::max())){
throw std::overflow_error(std::format("String of length {} is too long.", encoded_string.size()));
Expand Down Expand Up @@ -129,16 +186,23 @@ void write_list_tag_payload(BinaryWriter& writer, const CListTagPtr& value){
std::int32_t length = static_cast<std::int32_t>(list.size());
writer.writeNumeric<std::int32_t>(length);
for (const T& element: list){
write_tag_payload<T>(writer, element);
if constexpr (std::is_same_v<T, CByteTag>){write_byte_payload(writer, element);} else
if constexpr (std::is_same_v<T, CShortTag>){write_short_payload(writer, element);} else
if constexpr (std::is_same_v<T, CIntTag>){write_int_payload(writer, element);} else
if constexpr (std::is_same_v<T, CLongTag>){write_long_payload(writer, element);} else
if constexpr (std::is_same_v<T, CFloatTag>){write_float_payload(writer, element);} else
if constexpr (std::is_same_v<T, CDoubleTag>){write_double_payload(writer, element);} else
if constexpr (std::is_same_v<T, CByteArrayTagPtr>){write_byte_array_payload(writer, element);} else
if constexpr (std::is_same_v<T, CStringTag>){write_string_payload(writer, element);} else
if constexpr (std::is_same_v<T, CListTagPtr>){write_list_payload(writer, element);} else
if constexpr (std::is_same_v<T, CCompoundTagPtr>){write_compound_payload(writer, element);} else
if constexpr (std::is_same_v<T, CIntArrayTagPtr>){write_int_array_payload(writer, element);} else
if constexpr (std::is_same_v<T, CLongArrayTagPtr>){write_long_array_payload(writer, element);}
}
}


template <
typename T,
std::enable_if_t<std::is_same_v<T, CListTagPtr>, bool> = true
>
void write_tag_payload(BinaryWriter& writer, const CListTagPtr& value){
void write_list_payload(BinaryWriter& writer, const CListTagPtr& value){
switch (value->index()){
case 0:
writer.writeNumeric<std::uint8_t>(0);
Expand All @@ -160,108 +224,43 @@ void write_tag_payload(BinaryWriter& writer, const CListTagPtr& value){
}


template <
typename T,
std::enable_if_t<std::is_same_v<T, CCompoundTagPtr>, bool> = true
>
void write_tag_payload(BinaryWriter& writer, const CCompoundTagPtr& value){
void write_compound_payload(BinaryWriter& writer, const CCompoundTagPtr& value){
for (auto it = value->begin(); it != value->end(); it++){
write_named_tag<TagNode>(writer, it->first, it->second);
}
writer.writeNumeric<std::uint8_t>(0);
};


template <
typename T,
std::enable_if_t<
std::is_same_v<T, CByteArrayTagPtr> ||
std::is_same_v<T, CIntArrayTagPtr> ||
std::is_same_v<T, CLongArrayTagPtr>,
bool
> = true
>
void write_tag_payload(BinaryWriter& writer, const T& value){
void write_byte_array_payload(BinaryWriter& writer, const CByteArrayTagPtr& value){
if (value->size() > static_cast<size_t>(std::numeric_limits<std::int32_t>::max())){
throw std::overflow_error(std::format("Array of length {} is too long.", value->size()));
}
std::int32_t length = static_cast<std::int32_t>(value->size());
writer.writeNumeric<std::int32_t>(length);
for (const typename T::element_type::value_type& element: *value){
writer.writeNumeric<typename T::element_type::value_type>(element);
for (const CByteTag& element: *value){
writer.writeNumeric<CByteTag>(element);
}
}


template <
typename T,
std::enable_if_t<
std::is_same_v<T, CByteTag> ||
std::is_same_v<T, CShortTag> ||
std::is_same_v<T, CIntTag> ||
std::is_same_v<T, CLongTag> ||
std::is_same_v<T, CFloatTag> ||
std::is_same_v<T, CDoubleTag> ||
std::is_same_v<T, CByteArrayTagPtr> ||
std::is_same_v<T, CStringTag> ||
std::is_same_v<T, CListTagPtr> ||
std::is_same_v<T, CCompoundTagPtr> ||
std::is_same_v<T, CIntArrayTagPtr> ||
std::is_same_v<T, CLongArrayTagPtr>,
bool
> = true
>
void write_named_tag(BinaryWriter& writer, const std::string& name, const T& tag){
writer.writeNumeric<std::uint8_t>(variant_index<TagNode, T>());
write_tag_payload<CStringTag>(writer, name);
write_tag_payload<T>(writer, tag);
}


template <
typename T,
std::enable_if_t<std::is_same_v<T, TagNode>, bool> = true
>
void write_named_tag(BinaryWriter& writer, const std::string& name, const TagNode& node){
switch (node.index()){
case 1: write_named_tag<CByteTag>(writer, name, std::get<CByteTag>(node)); break;
case 2: write_named_tag<CShortTag>(writer, name, std::get<CShortTag>(node)); break;
case 3: write_named_tag<CIntTag>(writer, name, std::get<CIntTag>(node)); break;
case 4: write_named_tag<CLongTag>(writer, name, std::get<CLongTag>(node)); break;
case 5: write_named_tag<CFloatTag>(writer, name, std::get<CFloatTag>(node)); break;
case 6: write_named_tag<CDoubleTag>(writer, name, std::get<CDoubleTag>(node)); break;
case 7: write_named_tag<CByteArrayTagPtr>(writer, name, std::get<CByteArrayTagPtr>(node)); break;
case 8: write_named_tag<CStringTag>(writer, name, std::get<CStringTag>(node)); break;
case 9: write_named_tag<CListTagPtr>(writer, name, std::get<CListTagPtr>(node)); break;
case 10: write_named_tag<CCompoundTagPtr>(writer, name, std::get<CCompoundTagPtr>(node)); break;
case 11: write_named_tag<CIntArrayTagPtr>(writer, name, std::get<CIntArrayTagPtr>(node)); break;
case 12: write_named_tag<CLongArrayTagPtr>(writer, name, std::get<CLongArrayTagPtr>(node)); break;
default: throw std::runtime_error("TagNode cannot be in null state when writing.");
void write_int_array_payload(BinaryWriter& writer, const CIntArrayTagPtr& value){
if (value->size() > static_cast<size_t>(std::numeric_limits<std::int32_t>::max())){
throw std::overflow_error(std::format("Array of length {} is too long.", value->size()));
}
std::int32_t length = static_cast<std::int32_t>(value->size());
writer.writeNumeric<std::int32_t>(length);
for (const CIntTag& element: *value){
writer.writeNumeric<CIntTag>(element);
}
}


template <
typename T,
std::enable_if_t<
std::is_same_v<T, TagNode> ||
std::is_same_v<T, CByteTag> ||
std::is_same_v<T, CShortTag> ||
std::is_same_v<T, CIntTag> ||
std::is_same_v<T, CLongTag> ||
std::is_same_v<T, CFloatTag> ||
std::is_same_v<T, CDoubleTag> ||
std::is_same_v<T, CByteArrayTagPtr> ||
std::is_same_v<T, CStringTag> ||
std::is_same_v<T, CListTagPtr> ||
std::is_same_v<T, CCompoundTagPtr> ||
std::is_same_v<T, CIntArrayTagPtr> ||
std::is_same_v<T, CLongArrayTagPtr>,
bool
> = true
>
std::string write_named_tag(const std::string& name, const T& tag, std::endian endianness, StringEncode stringEncode){
BinaryWriter writer(endianness, stringEncode);
write_named_tag<T>(writer, name, tag);
return writer.getBuffer();
void write_long_array_payload(BinaryWriter& writer, const CLongArrayTagPtr& value){
if (value->size() > static_cast<size_t>(std::numeric_limits<std::int32_t>::max())){
throw std::overflow_error(std::format("Array of length {} is too long.", value->size()));
}
std::int32_t length = static_cast<std::int32_t>(value->size());
writer.writeNumeric<std::int32_t>(length);
for (const CLongTag& element: *value){
writer.writeNumeric<CLongTag>(element);
}
}

0 comments on commit d42c729

Please sign in to comment.