<div dir="ltr">hey, sorry I didn't spot this earlier, but looking at the RPCTypeName traits, would it be possible to implement this without mutable globals & maybe avoid user provided mutexes?<br><br>...<br>Â static const char* getName() {<br>Â Â static const std::string Name = []() {<br>Â Â Â raw_string_ostream(Name) << ... ;<br>Â Â }();<br>Â Â return Name;<br>Â }Â <br><br>This avoids any problems with order of initialization of global statics (eg: if RPC was used from a global initializer - getName could be invoked before the Name std::string had been constructed (before it would be valid to even call 'empty()')).<br><br>(Google's C++ style guide also has issues with global /dtors/ too:Â <a href="https://google.github.io/styleguide/cppguide.html#Static_and_Global_Variables">https://google.github.io/styleguide/cppguide.html#Static_and_Global_Variables</a>Â - but not sure LLVM worries about that particular issue)</div><br><div class="gmail_quote"><div dir="ltr">On Mon, Jul 30, 2018 at 2:08 PM Lang Hames via llvm-commits <<a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: lhames<br>
Date: Mon Jul 30 14:08:06 2018<br>
New Revision: 338305<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=338305&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=338305&view=rev</a><br>
Log:<br>
[ORC] Add SerializationTraits for std::set and std::map.<br>
<br>
Also, make SerializationTraits for pairs forward the actual pair<br>
template type arguments to the underlying serializer. This allows, for example,<br>
std::pair<StringRef, bool> to be passed as an argument to an RPC call expecting<br>
a std::pair<std::string, bool>, since there is an underlying serializer from<br>
StringRef to std::string that can be used.<br>
<br>
Modified:<br>
  llvm/trunk/include/llvm/ExecutionEngine/Orc/RPCSerialization.h<br>
  llvm/trunk/unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp<br>
<br>
Modified: llvm/trunk/include/llvm/ExecutionEngine/Orc/RPCSerialization.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/Orc/RPCSerialization.h?rev=338305&r1=338304&r2=338305&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/Orc/RPCSerialization.h?rev=338305&r1=338304&r2=338305&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/ExecutionEngine/Orc/RPCSerialization.h (original)<br>
+++ llvm/trunk/include/llvm/ExecutionEngine/Orc/RPCSerialization.h Mon Jul 30 14:08:06 2018<br>
@@ -14,7 +14,10 @@<br>
 #include "llvm/Support/thread.h"<br>
 #include <map><br>
 #include <mutex><br>
+#include <set><br>
 #include <sstream><br>
+#include <string><br>
+#include <vector><br>
<br>
 namespace llvm {<br>
 namespace orc {<br>
@@ -205,6 +208,42 @@ std::mutex RPCTypeName<std::vector<T>>::<br>
 template <typename T><br>
 std::string RPCTypeName<std::vector<T>>::Name;<br>
<br>
+template <typename T> class RPCTypeName<std::set<T>> {<br>
+public:<br>
+Â static const char *getName() {<br>
+Â Â std::lock_guard<std::mutex> Lock(NameMutex);<br>
+Â Â if (Name.empty())<br>
+Â Â Â raw_string_ostream(Name)<br>
+Â Â Â Â Â << "std::set<" << RPCTypeName<T>::getName() << ">";<br>
+Â Â return Name.data();<br>
+Â }<br>
+<br>
+private:<br>
+Â static std::mutex NameMutex;<br>
+Â static std::string Name;<br>
+};<br>
+<br>
+template <typename T> std::mutex RPCTypeName<std::set<T>>::NameMutex;<br>
+template <typename T> std::string RPCTypeName<std::set<T>>::Name;<br>
+<br>
+template <typename K, typename V> class RPCTypeName<std::map<K, V>> {<br>
+public:<br>
+Â static const char *getName() {<br>
+Â Â std::lock_guard<std::mutex> Lock(NameMutex);<br>
+Â Â if (Name.empty())<br>
+Â Â Â raw_string_ostream(Name)<br>
+Â Â Â Â Â << "std::map<" << RPCTypeNameSequence<K, V>() << ">";<br>
+Â Â return Name.data();<br>
+Â }<br>
+<br>
+private:<br>
+Â static std::mutex NameMutex;<br>
+Â static std::string Name;<br>
+};<br>
+<br>
+template <typename K, typename V><br>
+std::mutex RPCTypeName<std::map<K, V>>::NameMutex;<br>
+template <typename K, typename V> std::string RPCTypeName<std::map<K, V>>::Name;<br>
<br>
 /// The SerializationTraits<ChannelT, T> class describes how to serialize and<br>
 /// deserialize an instance of type T to/from an abstract channel of type<br>
@@ -527,15 +566,20 @@ public:<br>
 };<br>
<br>
 /// SerializationTraits default specialization for std::pair.<br>
-template <typename ChannelT, typename T1, typename T2><br>
-class SerializationTraits<ChannelT, std::pair<T1, T2>> {<br>
+template <typename ChannelT, typename T1, typename T2, typename T3, typename T4><br>
+class SerializationTraits<ChannelT, std::pair<T1, T2>, std::pair<T3, T4>> {<br>
 public:<br>
-Â static Error serialize(ChannelT &C, const std::pair<T1, T2> &V) {<br>
-Â Â return serializeSeq(C, V.first, V.second);<br>
+Â static Error serialize(ChannelT &C, const std::pair<T3, T4> &V) {<br>
+Â Â if (auto Err = SerializationTraits<ChannelT, T1, T3>::serialize(C, V.first))<br>
+Â Â Â return Err;<br>
+Â Â return SerializationTraits<ChannelT, T2, T4>::serialize(C, V.second);<br>
  }<br>
<br>
-Â static Error deserialize(ChannelT &C, std::pair<T1, T2> &V) {<br>
-Â Â return deserializeSeq(C, V.first, V.second);<br>
+Â static Error deserialize(ChannelT &C, std::pair<T3, T4> &V) {<br>
+Â Â if (auto Err =<br>
+Â Â Â Â Â Â SerializationTraits<ChannelT, T1, T3>::deserialize(C, V.first))<br>
+Â Â Â return Err;<br>
+Â Â return SerializationTraits<ChannelT, T2, T4>::deserialize(C, V.second);<br>
  }<br>
 };<br>
<br>
@@ -589,6 +633,9 @@ public:<br>
<br>
  /// Deserialize a std::vector<T> to a std::vector<T>.<br>
  static Error deserialize(ChannelT &C, std::vector<T> &V) {<br>
+Â Â assert(V.empty() &&<br>
+Â Â Â Â Â Â "Expected default-constructed vector to deserialize into");<br>
+<br>
   uint64_t Count = 0;<br>
   if (auto Err = deserializeSeq(C, Count))<br>
    return Err;<br>
@@ -600,6 +647,92 @@ public:<br>
<br>
   return Error::success();<br>
  }<br>
+};<br>
+<br>
+template <typename ChannelT, typename T, typename T2><br>
+class SerializationTraits<ChannelT, std::set<T>, std::set<T2>> {<br>
+public:<br>
+Â /// Serialize a std::set<T> from std::set<T2>.<br>
+Â static Error serialize(ChannelT &C, const std::set<T2> &S) {<br>
+Â Â if (auto Err = serializeSeq(C, static_cast<uint64_t>(S.size())))<br>
+Â Â Â return Err;<br>
+<br>
+Â Â for (const auto &E : S)<br>
+Â Â Â if (auto Err = SerializationTraits<ChannelT, T, T2>::serialize(C, E))<br>
+Â Â Â Â return Err;<br>
+<br>
+Â Â return Error::success();<br>
+Â }<br>
+<br>
+Â /// Deserialize a std::set<T> to a std::set<T>.<br>
+Â static Error deserialize(ChannelT &C, std::set<T2> &S) {<br>
+Â Â assert(S.empty() && "Expected default-constructed set to deserialize into");<br>
+<br>
+Â Â uint64_t Count = 0;<br>
+Â Â if (auto Err = deserializeSeq(C, Count))<br>
+Â Â Â return Err;<br>
+<br>
+Â Â while (Count-- != 0) {<br>
+Â Â Â T2 Val;<br>
+Â Â Â if (auto Err = SerializationTraits<ChannelT, T, T2>::deserialize(C, Val))<br>
+Â Â Â Â return Err;<br>
+<br>
+Â Â Â auto Added = S.insert(Val).second;<br>
+Â Â Â if (!Added)<br>
+Â Â Â Â return make_error<StringError>("Duplicate element in deserialized set",<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â orcError(OrcErrorCode::UnknownORCError));<br>
+Â Â }<br>
+<br>
+Â Â return Error::success();<br>
+Â }<br>
+};<br>
+<br>
+template <typename ChannelT, typename K, typename V, typename K2, typename V2><br>
+class SerializationTraits<ChannelT, std::map<K, V>, std::map<K2, V2>> {<br>
+public:<br>
+Â /// Serialize a std::map<K, V> from std::map<K2, V2>.<br>
+Â static Error serialize(ChannelT &C, const std::map<K2, V2> &M) {<br>
+Â Â if (auto Err = serializeSeq(C, static_cast<uint64_t>(M.size())))<br>
+Â Â Â return Err;<br>
+<br>
+Â Â for (const auto &E : M) {<br>
+Â Â Â if (auto Err =<br>
+Â Â Â Â Â Â Â SerializationTraits<ChannelT, K, K2>::serialize(C, E.first))<br>
+Â Â Â Â return Err;<br>
+Â Â Â if (auto Err =<br>
+Â Â Â Â Â Â Â SerializationTraits<ChannelT, V, V2>::serialize(C, E.second))<br>
+Â Â Â Â return Err;<br>
+Â Â }<br>
+<br>
+Â Â return Error::success();<br>
+Â }<br>
+<br>
+Â /// Deserialize a std::map<K, V> to a std::map<K, V>.<br>
+Â static Error deserialize(ChannelT &C, std::map<K2, V2> &M) {<br>
+Â Â assert(M.empty() && "Expected default-constructed map to deserialize into");<br>
+<br>
+Â Â uint64_t Count = 0;<br>
+Â Â if (auto Err = deserializeSeq(C, Count))<br>
+Â Â Â return Err;<br>
+<br>
+Â Â while (Count-- != 0) {<br>
+Â Â Â std::pair<K2, V2> Val;<br>
+Â Â Â if (auto Err =<br>
+Â Â Â Â Â Â Â SerializationTraits<ChannelT, K, K2>::deserialize(C, Val.first))<br>
+Â Â Â Â return Err;<br>
+<br>
+Â Â Â if (auto Err =<br>
+Â Â Â Â Â Â Â SerializationTraits<ChannelT, V, V2>::deserialize(C, Val.second))<br>
+Â Â Â Â return Err;<br>
+<br>
+Â Â Â auto Added = M.insert(Val).second;<br>
+Â Â Â if (!Added)<br>
+Â Â Â Â return make_error<StringError>("Duplicate element in deserialized map",<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â orcError(OrcErrorCode::UnknownORCError));<br>
+Â Â }<br>
+<br>
+Â Â return Error::success();<br>
+Â }<br>
 };<br>
<br>
 } // end namespace rpc<br>
<br>
Modified: llvm/trunk/unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp?rev=338305&r1=338304&r2=338305&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp?rev=338305&r1=338304&r2=338305&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp (original)<br>
+++ llvm/trunk/unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp Mon Jul 30 14:08:06 2018<br>
@@ -133,10 +133,10 @@ namespace DummyRPCAPI {<br>
  };<br>
<br>
  class AllTheTypes<br>
-Â Â : public Function<AllTheTypes,<br>
-Â Â Â Â Â Â Â Â Â Â Â void(int8_t, uint8_t, int16_t, uint16_t, int32_t,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â uint32_t, int64_t, uint64_t, bool, std::string,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â std::vector<int>)> {<br>
+Â Â Â : public Function<AllTheTypes, void(int8_t, uint8_t, int16_t, uint16_t,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â int32_t, uint32_t, int64_t, uint64_t,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â bool, std::string, std::vector<int>,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â std::set<int>, std::map<int, bool>)> {<br>
  public:<br>
   static const char* getName() { return "AllTheTypes"; }<br>
  };<br>
@@ -451,43 +451,50 @@ TEST(DummyRPC, TestSerialization) {<br>
  DummyRPCEndpoint Server(*Channels.second);<br>
<br>
  std::thread ServerThread([&]() {<br>
-Â Â Â Server.addHandler<DummyRPCAPI::AllTheTypes>(<br>
-Â Â Â Â Â [&](int8_t S8, uint8_t U8, int16_t S16, uint16_t U16,<br>
-Â Â Â Â Â Â Â int32_t S32, uint32_t U32, int64_t S64, uint64_t U64,<br>
-Â Â Â Â Â Â Â bool B, std::string S, std::vector<int> V) {<br>
-<br>
-Â Â Â Â Â Â EXPECT_EQ(S8, -101) << "int8_t serialization broken";<br>
-Â Â Â Â Â Â EXPECT_EQ(U8, 250) << "uint8_t serialization broken";<br>
-Â Â Â Â Â Â EXPECT_EQ(S16, -10000) << "int16_t serialization broken";<br>
-Â Â Â Â Â Â EXPECT_EQ(U16, 10000) << "uint16_t serialization broken";<br>
-Â Â Â Â Â Â EXPECT_EQ(S32, -1000000000) << "int32_t serialization broken";<br>
-Â Â Â Â Â Â EXPECT_EQ(U32, 1000000000ULL) << "uint32_t serialization broken";<br>
-Â Â Â Â Â Â EXPECT_EQ(S64, -10000000000) << "int64_t serialization broken";<br>
-Â Â Â Â Â Â EXPECT_EQ(U64, 10000000000ULL) << "uint64_t serialization broken";<br>
-Â Â Â Â Â Â EXPECT_EQ(B, true) << "bool serialization broken";<br>
-Â Â Â Â Â Â EXPECT_EQ(S, "foo") << "std::string serialization broken";<br>
-Â Â Â Â Â Â EXPECT_EQ(V, std::vector<int>({42, 7}))<br>
-Â Â Â Â Â Â Â << "std::vector serialization broken";<br>
-Â Â Â Â Â Â return Error::success();<br>
-Â Â Â Â Â });<br>
-<br>
-Â Â Â {<br>
-Â Â Â Â // Poke the server to handle the negotiate call.<br>
-Â Â Â Â auto Err = Server.handleOne();<br>
-Â Â Â Â EXPECT_FALSE(!!Err) << "Server failed to handle call to negotiate";<br>
-Â Â Â }<br>
-<br>
-Â Â Â {<br>
-Â Â Â Â // Poke the server to handle the AllTheTypes call.<br>
-Â Â Â Â auto Err = Server.handleOne();<br>
-Â Â Â Â EXPECT_FALSE(!!Err) << "Server failed to handle call to void(bool)";<br>
-Â Â Â }<br>
+Â Â Server.addHandler<DummyRPCAPI::AllTheTypes>([&](int8_t S8, uint8_t U8,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â int16_t S16, uint16_t U16,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â int32_t S32, uint32_t U32,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â int64_t S64, uint64_t U64,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â bool B, std::string S,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â std::vector<int> V,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â std::set<int> S2,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â std::map<int, bool> M) {<br>
+Â Â Â EXPECT_EQ(S8, -101) << "int8_t serialization broken";<br>
+Â Â Â EXPECT_EQ(U8, 250) << "uint8_t serialization broken";<br>
+Â Â Â EXPECT_EQ(S16, -10000) << "int16_t serialization broken";<br>
+Â Â Â EXPECT_EQ(U16, 10000) << "uint16_t serialization broken";<br>
+Â Â Â EXPECT_EQ(S32, -1000000000) << "int32_t serialization broken";<br>
+Â Â Â EXPECT_EQ(U32, 1000000000ULL) << "uint32_t serialization broken";<br>
+Â Â Â EXPECT_EQ(S64, -10000000000) << "int64_t serialization broken";<br>
+Â Â Â EXPECT_EQ(U64, 10000000000ULL) << "uint64_t serialization broken";<br>
+Â Â Â EXPECT_EQ(B, true) << "bool serialization broken";<br>
+Â Â Â EXPECT_EQ(S, "foo") << "std::string serialization broken";<br>
+Â Â Â EXPECT_EQ(V, std::vector<int>({42, 7}))<br>
+Â Â Â Â Â << "std::vector serialization broken";<br>
+Â Â Â EXPECT_EQ(S2, std::set<int>({7, 42})) << "std::set serialization broken";<br>
+Â Â Â EXPECT_EQ(M, (std::map<int, bool>({{7, false}, {42, true}})))<br>
+Â Â Â Â Â << "std::map serialization broken";<br>
+Â Â Â return Error::success();<br>
   });<br>
<br>
+Â Â {<br>
+Â Â Â // Poke the server to handle the negotiate call.<br>
+Â Â Â auto Err = Server.handleOne();<br>
+Â Â Â EXPECT_FALSE(!!Err) << "Server failed to handle call to negotiate";<br>
+Â Â }<br>
+<br>
+Â Â {<br>
+Â Â Â // Poke the server to handle the AllTheTypes call.<br>
+Â Â Â auto Err = Server.handleOne();<br>
+Â Â Â EXPECT_FALSE(!!Err) << "Server failed to handle call to void(bool)";<br>
+Â Â }<br>
+Â });<br>
<br>
  {<br>
   // Make an async call.<br>
-Â Â std::vector<int> v({42, 7});<br>
+Â Â std::vector<int> V({42, 7});<br>
+Â Â std::set<int> S({7, 42});<br>
+Â Â std::map<int, bool> M({{7, false}, {42, true}});<br>
   auto Err = Client.callAsync<DummyRPCAPI::AllTheTypes>(<br>
     [](Error Err) {<br>
      EXPECT_FALSE(!!Err) << "Async AllTheTypes response handler failed";<br>
@@ -497,7 +504,7 @@ TEST(DummyRPC, TestSerialization) {<br>
     static_cast<int16_t>(-10000), static_cast<uint16_t>(10000),<br>
     static_cast<int32_t>(-1000000000), static_cast<uint32_t>(1000000000),<br>
     static_cast<int64_t>(-10000000000), static_cast<uint64_t>(10000000000),<br>
-Â Â Â Â true, std::string("foo"), v);<br>
+Â Â Â Â true, std::string("foo"), V, S, M);<br>
   EXPECT_FALSE(!!Err) << "Client.callAsync failed for AllTheTypes";<br>
  }<br>
<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits</a><br>
</blockquote></div>