fishy commented on code in PR #3788:
URL: https://github.com/apache/thrift/pull/3788#discussion_r3941040189


##########
compiler/cpp/src/thrift/generate/t_go_generator.cc:
##########
@@ -4027,28 +4027,71 @@ void 
t_go_generator::generate_serialize_container(ostream& out,
       if (pointer_field) {
         wrapped_prefix = "(" + prefix + ")";
       }
-      string keyType = type_to_go_type(tmap->get_key_type());
-      out << indent() << "for i := 0; i < len(" << prefix << "); i++ {" << 
'\n';
-      indent_up();
-      out << indent() << "for j := i + 1; j < len(" << prefix << "); j++ {" << 
'\n';
-      indent_up();
-      out << indent() << "if func(tgt, src " << keyType << ") bool {" << '\n';
-      indent_up();
-      generate_go_equals(out, tmap->get_key_type(), "tgt", "src");
-      out << indent() << "return true" << '\n';
-      indent_down();
-      out << indent() << "}(" << wrapped_prefix << "[i].Key, " << 
wrapped_prefix << "[j].Key) {"
-          << '\n';
-      indent_up();
-      out << indent() << "return 
thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, "
-          << "fmt.Errorf(\"%T error writing map field %q: keys are not 
unique\", "
-          << wrapped_prefix << ", \"" << escape_string(prefix) << "\"))" << 
'\n';
-      indent_down();
-      out << indent() << "}" << '\n';
-      indent_down();
-      out << indent() << "}" << '\n';
-      indent_down();
-      out << indent() << "}" << '\n';
+      string not_unique
+          = "return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, "
+            "fmt.Errorf(\"%T error writing map field %q: keys are not 
unique\", "
+            + wrapped_prefix + ", \"" + escape_string(prefix) + "\"))";
+      if (is_comparable_struct_key(tmap->get_key_type())) {
+        // Every field of the key struct is a non-pointer scalar, so the struct
+        // value is a valid Go map key and "==" agrees with Equals. Collecting
+        // the keys in a set costs linear time, where comparing every pair
+        // costs quadratic time.
+        string seen = tmp("seen");
+        string sawNil = tmp("sawNil");
+        string entry = tmp("e");
+        string keyValueType = 
publicize(type_name(tmap->get_key_type()->get_true_type()));
+        out << indent() << "if len(" << wrapped_prefix << ") > 1 {" << '\n';
+        indent_up();
+        out << indent() << seen << " := make(map[" << keyValueType << 
"]struct{}, len("
+            << wrapped_prefix << "))" << '\n';
+        out << indent() << sawNil << " := false" << '\n';
+        out << indent() << "for _, " << entry << " := range " << 
wrapped_prefix << " {" << '\n';
+        indent_up();
+        // A nil key writes as an empty struct, and Equals treats two of them 
as
+        // equal, so track nil separately rather than dereferencing it.
+        out << indent() << "if " << entry << ".Key == nil {" << '\n';
+        indent_up();
+        out << indent() << "if " << sawNil << " {" << '\n';
+        indent_up();
+        out << indent() << not_unique << '\n';
+        indent_down();
+        out << indent() << "}" << '\n';
+        out << indent() << sawNil << " = true" << '\n';
+        out << indent() << "continue" << '\n';
+        indent_down();
+        out << indent() << "}" << '\n';
+        out << indent() << "if _, ok := " << seen << "[*" << entry << ".Key]; 
ok {" << '\n';
+        indent_up();
+        out << indent() << not_unique << '\n';
+        indent_down();
+        out << indent() << "}" << '\n';
+        out << indent() << seen << "[*" << entry << ".Key] = struct{}{}" << 
'\n';
+        indent_down();
+        out << indent() << "}" << '\n';
+        indent_down();
+        out << indent() << "}" << '\n';
+      } else {

Review Comment:
   I would suggest to add a test case for this into `StructKeyTest.thrift`.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to