Skip to content

Commit

Permalink
THRIFT-5772: UUID support for c++ #2952
Browse files Browse the repository at this point in the history
Client: cpp
Patch: CJCombrink

This closes #2952
  • Loading branch information
CJCombrink authored and Jens-G committed Apr 7, 2024
1 parent 381d86e commit 1d886ca
Show file tree
Hide file tree
Showing 26 changed files with 329 additions and 38 deletions.
51 changes: 33 additions & 18 deletions compiler/cpp/src/thrift/generate/t_cpp_generator.cc
Expand Up @@ -296,7 +296,7 @@ class t_cpp_generator : public t_oop_generator {
(ttype->annotations_.find("cpp.customostream") != ttype->annotations_.end());
}

/**
/**
* Determine if all fields of t_struct's storage do not throw
* Move/Copy Constructors and Assignments applicable for 'noexcept'
* Move defaults to 'noexcept'
Expand All @@ -318,7 +318,7 @@ class t_cpp_generator : public t_oop_generator {

/**
* Returns the legal program name to use for a file generated by program, if the
* program name contains dots then replace it with underscores, otherwise return the
* program name contains dots then replace it with underscores, otherwise return the
* original program name.
*/
std::string get_legal_program_name(std::string program_name);
Expand Down Expand Up @@ -981,7 +981,7 @@ bool t_cpp_generator::has_field_with_default_value(t_struct* tstruct)

for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
t_type* t = get_true_type((*m_iter)->get_type());
if (is_reference(*m_iter) || t->is_string()) {
if (is_reference(*m_iter) || t->is_string() || t->is_uuid()) {
t_const_value* cv = (*m_iter)->get_value();
if (cv != nullptr) {
return true;
Expand Down Expand Up @@ -1032,7 +1032,7 @@ void t_cpp_generator::generate_default_constructor(ostream& out,
} else if (t->is_enum()) {
dval += "static_cast<" + type_name(t) + ">(0)";
} else {
dval += (t->is_string() || is_reference(*m_iter)) ? "" : "0";
dval += (t->is_string() || is_reference(*m_iter) || t->is_uuid()) ? "" : "0";
}
if (!init_ctor) {
init_ctor = true;
Expand Down Expand Up @@ -1127,7 +1127,7 @@ void t_cpp_generator::generate_constructor_helper(ostream& out,
has_nonrequired_fields = true;
indent(out) << (*f_iter)->get_name() << " = "
<< maybeMove(
tmp_name + "." + (*f_iter)->get_name(),
tmp_name + "." + (*f_iter)->get_name(),
is_move && is_complex_type((*f_iter)->get_type()))
<< ";" << endl;
}
Expand Down Expand Up @@ -1177,7 +1177,7 @@ void t_cpp_generator::generate_assignment_helper(ostream& out, t_struct* tstruct
has_nonrequired_fields = true;
indent(out) << (*f_iter)->get_name() << " = "
<< maybeMove(
tmp_name + "." + (*f_iter)->get_name(),
tmp_name + "." + (*f_iter)->get_name(),
is_move && is_complex_type((*f_iter)->get_type()))
<< ";" << endl;
}
Expand Down Expand Up @@ -1276,7 +1276,7 @@ void t_cpp_generator::generate_struct_declaration(ostream& out,

// Move constructor
if (gen_moveable_) {
indent(out) << tstruct->get_name() << "(" << tstruct->get_name() << "&&) noexcept;"
indent(out) << tstruct->get_name() << "(" << tstruct->get_name() << "&&) noexcept;"
<< endl;
}

Expand All @@ -1286,12 +1286,12 @@ void t_cpp_generator::generate_struct_declaration(ostream& out,

// Move assignment operator
if (gen_moveable_) {
indent(out) << tstruct->get_name() << "& operator=(" << tstruct->get_name() << "&&) noexcept;"
indent(out) << tstruct->get_name() << "& operator=(" << tstruct->get_name() << "&&) noexcept;"
<< endl;
}

bool has_default_value = has_field_with_default_value(tstruct);

// Default constructor
std::string clsname_ctor = tstruct->get_name() + "()";
indent(out) << clsname_ctor << (has_default_value ? "" : " noexcept") << ";" << endl;
Expand Down Expand Up @@ -1732,7 +1732,7 @@ void t_cpp_generator::generate_struct_result_writer(ostream& out,
void t_cpp_generator::generate_struct_swap(ostream& out, t_struct* tstruct) {
if (tstruct->get_name() == "a" || tstruct->get_name() == "b") {
out << indent() << "void swap(" << tstruct->get_name() << " &a1, " << tstruct->get_name()
<< " &a2) {" << endl;
<< " &a2) {" << endl;
} else {
out << indent() << "void swap(" << tstruct->get_name() << " &a, " << tstruct->get_name()
<< " &b) {" << endl;
Expand Down Expand Up @@ -1763,7 +1763,7 @@ void t_cpp_generator::generate_struct_swap(ostream& out, t_struct* tstruct) {

if (has_nonrequired_fields) {
if (tstruct->get_name() == "a" || tstruct->get_name() == "b") {
out << indent() << "swap(a1.__isset, a2.__isset);" << endl;
out << indent() << "swap(a1.__isset, a2.__isset);" << endl;
} else {
out << indent() << "swap(a.__isset, b.__isset);" << endl;
}
Expand Down Expand Up @@ -1942,7 +1942,7 @@ void t_cpp_generator::generate_service(t_service* tservice) {
<< endl;
if (gen_cob_style_) {
f_header_ << "#include <thrift/transport/TBufferTransports.h>" << endl // TMemoryBuffer
<< "#include <functional>" << endl
<< "#include <functional>" << endl
<< "namespace apache { namespace thrift { namespace async {" << endl
<< "class TAsyncChannel;" << endl << "}}}" << endl;
}
Expand Down Expand Up @@ -2578,7 +2578,7 @@ void t_cpp_generator::generate_service_client(t_service* tservice, string style)
f_header_ << ", std::shared_ptr< ::apache::thrift::async::TConcurrentClientSyncInfo> sync";
}
f_header_ << ") ";

if (extends.empty()) {
if (style == "Concurrent") {
f_header_ << ": sync_(sync)" << endl;
Expand Down Expand Up @@ -2677,7 +2677,7 @@ void t_cpp_generator::generate_service_client(t_service* tservice, string style)
vector<t_function*>::const_iterator f_iter;
for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
generate_java_doc(f_header_, *f_iter);
indent(f_header_) << function_signature(*f_iter, ifstyle)
indent(f_header_) << function_signature(*f_iter, ifstyle)
<< " override;" << endl;
// TODO(dreiss): Use private inheritance to avoid generating thise in cob-style.
if (style == "Concurrent" && !(*f_iter)->is_oneway()) {
Expand Down Expand Up @@ -3227,7 +3227,7 @@ void ProcessorGenerator::generate_class_definition() {
f_header_ << indent() << "virtual " << ret_type_ << "dispatchCall(" << finish_cob_
<< "::apache::thrift::protocol::TProtocol* iprot, "
<< "::apache::thrift::protocol::TProtocol* oprot, "
<< "const std::string& fname, int32_t seqid" << call_context_
<< "const std::string& fname, int32_t seqid" << call_context_
<< ") override;" << endl;
if (generator_->gen_templates_) {
f_header_ << indent() << "virtual " << ret_type_ << "dispatchCallTemplated(" << finish_cob_
Expand Down Expand Up @@ -4046,6 +4046,9 @@ void t_cpp_generator::generate_deserialize_field(ostream& out,
case t_base_type::TYPE_VOID:
throw "compiler error: cannot serialize void field in a struct: " + name;
break;
case t_base_type::TYPE_UUID:
out << "readUUID(" << name << ");";
break;
case t_base_type::TYPE_STRING:
if (type->is_binary()) {
out << "readBinary(" << name << ");";
Expand All @@ -4072,13 +4075,13 @@ void t_cpp_generator::generate_deserialize_field(ostream& out,
out << "readDouble(" << name << ");";
break;
default:
throw "compiler error: no C++ reader for base type " + t_base_type::t_base_name(tbase) + name;
throw "compiler error: no C++ reader for base type " + t_base_type::t_base_name(tbase) + " " + name;
}
out << endl;
} else if (type->is_enum()) {
string t = tmp("ecast");
out << indent() << "int32_t " << t << ";" << endl << indent() << "xfer += iprot->readI32(" << t
<< ");" << endl << indent() << name << " = static_cast<"
<< ");" << endl << indent() << name << " = static_cast<"
<< type_name(type) << ">(" << t << ");" << endl;
} else {
printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
Expand Down Expand Up @@ -4254,6 +4257,9 @@ void t_cpp_generator::generate_serialize_field(ostream& out,
case t_base_type::TYPE_VOID:
throw "compiler error: cannot serialize void field in a struct: " + name;
break;
case t_base_type::TYPE_UUID:
out << "writeUUID(" << name << ");";
break;
case t_base_type::TYPE_STRING:
if (type->is_binary()) {
out << "writeBinary(" << name << ");";
Expand Down Expand Up @@ -4281,7 +4287,7 @@ void t_cpp_generator::generate_serialize_field(ostream& out,
break;
default:
throw "compiler error: no C++ writer for base type " + t_base_type::t_base_name(tbase)
+ name;
+ " " + name;
}
} else if (type->is_enum()) {
out << "writeI32(static_cast<int32_t>(" << name << "));";
Expand Down Expand Up @@ -4568,6 +4574,9 @@ string t_cpp_generator::base_type_name(t_base_type::t_base tbase) {
return "int64_t";
case t_base_type::TYPE_DOUBLE:
return "double";
case t_base_type::TYPE_UUID:
// TODO: discuss possibility of a class TUuid;
return "std::string";
default:
throw "compiler error: no C++ base type name for base type " + t_base_type::t_base_name(tbase);
}
Expand Down Expand Up @@ -4609,6 +4618,9 @@ string t_cpp_generator::declare_field(t_field* tfield,
case t_base_type::TYPE_VOID:
case t_base_type::TYPE_STRING:
break;
case t_base_type::TYPE_UUID:
result += " = std::string(\"00000000-0000-0000-0000-000000000000\")";
break;
case t_base_type::TYPE_BOOL:
result += " = false";
break;
Expand Down Expand Up @@ -4735,6 +4747,8 @@ string t_cpp_generator::type_to_enum(t_type* type) {
return "::apache::thrift::protocol::T_I64";
case t_base_type::TYPE_DOUBLE:
return "::apache::thrift::protocol::T_DOUBLE";
case t_base_type::TYPE_UUID:
return "::apache::thrift::protocol::T_UUID";
default:
break;
}
Expand Down Expand Up @@ -4776,6 +4790,7 @@ bool t_cpp_generator::is_struct_storage_not_throwing(t_struct* tstruct) const {
continue;
case t_base_type::TYPE_VOID:
case t_base_type::TYPE_STRING:
case t_base_type::TYPE_UUID:
default:
return false;
}
Expand Down
1 change: 1 addition & 0 deletions lib/cpp/CMakeLists.txt
Expand Up @@ -43,6 +43,7 @@ set(thriftcpp_SOURCES
src/thrift/protocol/TJSONProtocol.cpp
src/thrift/protocol/TMultiplexedProtocol.cpp
src/thrift/protocol/TProtocol.cpp
src/thrift/protocol/TUuidUtils.cpp
src/thrift/transport/TTransportException.cpp
src/thrift/transport/TFDTransport.cpp
src/thrift/transport/TSimpleFileTransport.cpp
Expand Down
1 change: 1 addition & 0 deletions lib/cpp/Makefile.am
Expand Up @@ -69,6 +69,7 @@ libthrift_la_SOURCES = src/thrift/TApplicationException.cpp \
src/thrift/protocol/TBase64Utils.cpp \
src/thrift/protocol/TMultiplexedProtocol.cpp \
src/thrift/protocol/TProtocol.cpp \
src/thrift/protocol/TUuidUtils.cpp \
src/thrift/transport/TTransportException.cpp \
src/thrift/transport/TFDTransport.cpp \
src/thrift/transport/TFileTransport.cpp \
Expand Down
1 change: 1 addition & 0 deletions lib/cpp/libthrift.vcxproj
Expand Up @@ -49,6 +49,7 @@
<ClCompile Include="src\thrift\protocol\TJSONProtocol.cpp" />
<ClCompile Include="src\thrift\protocol\TMultiplexedProtocol.cpp" />
<ClCompile Include="src\thrift\protocol\TProtocol.cpp" />
<ClCompile Include="src\thrift\protocol\TUuidUtils.cpp" />
<ClCompile Include="src\thrift\server\TConnectedClient.cpp" />
<ClCompile Include="src\thrift\server\TServer.cpp" />
<ClCompile Include="src\thrift\server\TServerFramework.cpp" />
Expand Down
3 changes: 3 additions & 0 deletions lib/cpp/libthrift.vcxproj.filters
Expand Up @@ -30,6 +30,9 @@
<ClCompile Include="src\thrift\protocol\TMultiplexedProtocol.cpp">
<Filter>protocol</Filter>
</ClCompile>
<ClCompile Include="src\thrift\protocol\TUuidUtils.cpp">
<Filter>protocol</Filter>
</ClCompile>
<ClCompile Include="src\thrift\transport\TFDTransport.cpp">
<Filter>transport</Filter>
</ClCompile>
Expand Down
4 changes: 4 additions & 0 deletions lib/cpp/src/thrift/protocol/TBinaryProtocol.h
Expand Up @@ -119,6 +119,8 @@ class TBinaryProtocolT : public TVirtualProtocol<TBinaryProtocolT<Transport_, By

inline uint32_t writeBinary(const std::string& str);

inline uint32_t writeUUID(const std::string& str);

/**
* Reading functions
*/
Expand Down Expand Up @@ -166,6 +168,8 @@ class TBinaryProtocolT : public TVirtualProtocol<TBinaryProtocolT<Transport_, By

inline uint32_t readBinary(std::string& str);

inline uint32_t readUUID(std::string& str);

int getMinSerializedSize(TType type) override;

void checkReadBytesAvailable(TSet& set) override
Expand Down
25 changes: 24 additions & 1 deletion lib/cpp/src/thrift/protocol/TBinaryProtocol.tcc
Expand Up @@ -21,6 +21,7 @@
#define _THRIFT_PROTOCOL_TBINARYPROTOCOL_TCC_ 1

#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/protocol/TUuidUtils.hpp>
#include <thrift/transport/TTransportException.h>

#include <limits>
Expand Down Expand Up @@ -193,6 +194,20 @@ uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeBinary(const std::string
return TBinaryProtocolT<Transport_, ByteOrder_>::writeString(str);
}

template <class Transport_, class ByteOrder_>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeUUID(const std::string& str) {
std::string out;
const bool encoded = uuid_encode(str, out);
if(!encoded)
throw TProtocolException(TProtocolException::INVALID_DATA);
// This should not happen, but check for now
if(out.size() != 16)
throw TProtocolException(TProtocolException::UNKNOWN);
// TODO: Consider endian swapping, see lib/delphi/src/Thrift.Utils.pas:377
this->trans_->write((uint8_t*)out.data(), 16);
return 16;
}

/**
* Reading functions
*/
Expand Down Expand Up @@ -286,7 +301,7 @@ uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readMapBegin(TType& keyType,
throw TProtocolException(TProtocolException::SIZE_LIMIT);
}
size = (uint32_t)sizei;

TMap map(keyType, valType, size);
checkReadBytesAvailable(map);

Expand Down Expand Up @@ -428,6 +443,14 @@ uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readBinary(std::string& str)
return TBinaryProtocolT<Transport_, ByteOrder_>::readString(str);
}

template <class Transport_, class ByteOrder_>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readUUID(std::string& str) {
std::string in;
readStringBody(in, 16);
uuid_decode(in, str);
return 16;
}

template <class Transport_, class ByteOrder_>
template <typename StrType>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readStringBody(StrType& str, int32_t size) {
Expand Down
25 changes: 21 additions & 4 deletions lib/cpp/src/thrift/protocol/TDebugProtocol.cpp
Expand Up @@ -18,6 +18,7 @@
*/

#include <thrift/protocol/TDebugProtocol.h>
#include <thrift/protocol/TUuidUtils.hpp>

#include <thrift/TToString.h>
#include <cassert>
Expand Down Expand Up @@ -70,10 +71,8 @@ string TDebugProtocol::fieldTypeName(TType type) {
return "set";
case T_LIST:
return "list";
case T_UTF8:
return "utf8";
case T_UTF16:
return "utf16";
case T_UUID:
return "uuid";
default:
return "unknown";
}
Expand Down Expand Up @@ -388,6 +387,24 @@ uint32_t TDebugProtocol::writeBinary(const string& str) {
// XXX Hex?
return TDebugProtocol::writeString(str);
}

uint32_t TDebugProtocol::writeUUID(const string& str) {
std::string out_raw;
uuid_encode(str, out_raw);

std::string out_encoded;
uuid_decode(out_raw, out_encoded);

size_t size = writePlain("{\n");
indentUp();
size += writeIndented("[in ] = \"" + str + "\",\n");
size += writeIndented("[raw] = ");
size += writeString(out_raw);
size += writeIndented("[enc] = \"" + out_encoded + "\"\n");
indentDown();
size += writeIndented("}\n");
return size;
}
}
}
} // apache::thrift::protocol
2 changes: 2 additions & 0 deletions lib/cpp/src/thrift/protocol/TDebugProtocol.h
Expand Up @@ -110,6 +110,8 @@ class TDebugProtocol : public TVirtualProtocol<TDebugProtocol> {

uint32_t writeBinary(const std::string& str);

uint32_t writeUUID(const std::string& str);

private:
void indentUp();
void indentDown();
Expand Down
7 changes: 3 additions & 4 deletions lib/cpp/src/thrift/protocol/TEnum.h
Expand Up @@ -18,7 +18,7 @@
*/

#ifndef _THRIFT_ENUM_H_
#define _THRIFT_ENUM_H_
#define _THRIFT_ENUM_H_

namespace apache {
namespace thrift {
Expand Down Expand Up @@ -46,8 +46,7 @@ enum TType {
T_MAP = 13,
T_SET = 14,
T_LIST = 15,
T_UTF8 = 16,
T_UTF16 = 17
T_UUID = 16,
};

/**
Expand All @@ -63,4 +62,4 @@ enum TMessageType {

}}} // apache::thrift::protocol

#endif // #define _THRIFT_ENUM_H_
#endif // #define _THRIFT_ENUM_H_

0 comments on commit 1d886ca

Please sign in to comment.