|
22 | 22 |
|
23 | 23 | #include "google/protobuf/descriptor.pb.h" |
24 | 24 | #include "absl/container/flat_hash_map.h" |
| 25 | +#include "absl/hash/hash.h" |
25 | 26 | #include "absl/log/absl_check.h" |
26 | 27 | #include "absl/log/absl_log.h" |
27 | 28 | #include "absl/strings/escaping.h" |
@@ -1518,6 +1519,44 @@ struct UnknownFieldOrdering { |
1518 | 1519 | } |
1519 | 1520 | }; |
1520 | 1521 |
|
| 1522 | +size_t GetRepeatedElementHash(const Message& message, |
| 1523 | + const FieldDescriptor* field, int index) { |
| 1524 | + const Reflection* reflection = message.GetReflection(); |
| 1525 | + switch (field->cpp_type()) { |
| 1526 | + case FieldDescriptor::CPPTYPE_INT32: |
| 1527 | + return absl::HashOf(reflection->GetRepeatedInt32(message, field, index)); |
| 1528 | + case FieldDescriptor::CPPTYPE_INT64: |
| 1529 | + return absl::HashOf(reflection->GetRepeatedInt64(message, field, index)); |
| 1530 | + case FieldDescriptor::CPPTYPE_UINT32: |
| 1531 | + return absl::HashOf(reflection->GetRepeatedUInt32(message, field, index)); |
| 1532 | + case FieldDescriptor::CPPTYPE_UINT64: |
| 1533 | + return absl::HashOf(reflection->GetRepeatedUInt64(message, field, index)); |
| 1534 | + case FieldDescriptor::CPPTYPE_DOUBLE: |
| 1535 | + return absl::HashOf(reflection->GetRepeatedDouble(message, field, index)); |
| 1536 | + case FieldDescriptor::CPPTYPE_FLOAT: |
| 1537 | + return absl::HashOf(reflection->GetRepeatedFloat(message, field, index)); |
| 1538 | + case FieldDescriptor::CPPTYPE_BOOL: |
| 1539 | + return absl::HashOf(reflection->GetRepeatedBool(message, field, index)); |
| 1540 | + case FieldDescriptor::CPPTYPE_ENUM: |
| 1541 | + return absl::HashOf( |
| 1542 | + reflection->GetRepeatedEnumValue(message, field, index)); |
| 1543 | + case FieldDescriptor::CPPTYPE_STRING: { |
| 1544 | + std::string scratch; |
| 1545 | + const std::string& value = reflection->GetRepeatedStringReference( |
| 1546 | + message, field, index, &scratch); |
| 1547 | + return absl::HashOf(value); |
| 1548 | + } |
| 1549 | + case FieldDescriptor::CPPTYPE_MESSAGE: { |
| 1550 | + const Message& sub_message = |
| 1551 | + reflection->GetRepeatedMessage(message, field, index); |
| 1552 | + std::string serialized; |
| 1553 | + sub_message.SerializePartialToString(&serialized); |
| 1554 | + return absl::HashOf(serialized); |
| 1555 | + } |
| 1556 | + } |
| 1557 | + return 0; |
| 1558 | +} |
| 1559 | + |
1521 | 1560 | } // namespace |
1522 | 1561 |
|
1523 | 1562 | bool MessageDifferencer::UnpackAnyField::UnpackAny( |
@@ -1971,52 +2010,82 @@ bool MessageDifferencer::MatchRepeatedFieldIndices( |
1971 | 2010 | } |
1972 | 2011 | } |
1973 | 2012 | } |
| 2013 | + absl::flat_hash_map<size_t, std::vector<int>> hash_to_indices2; |
| 2014 | + if (IsTreatedAsSet(repeated_field) && !is_treated_as_smart_set) { |
| 2015 | + for (int j = start_offset; j < count2; ++j) { |
| 2016 | + if (match_list2->at(j) == -1) { |
| 2017 | + size_t h2 = GetRepeatedElementHash(message2, repeated_field, j); |
| 2018 | + hash_to_indices2[h2].push_back(j); |
| 2019 | + } |
| 2020 | + } |
| 2021 | + } |
| 2022 | + |
1974 | 2023 | for (int i = start_offset; i < count1; ++i) { |
1975 | 2024 | // Indicates any matched elements for this repeated field. |
1976 | 2025 | bool match = false; |
1977 | 2026 | int matched_j = -1; |
1978 | 2027 |
|
1979 | | - for (int j = start_offset; j < count2; j++) { |
1980 | | - if (match_list2->at(j) != -1) { |
1981 | | - if (!is_treated_as_smart_set || num_diffs_list1[i] == 0 || |
1982 | | - num_diffs_list1[match_list2->at(j)] == 0) { |
1983 | | - continue; |
| 2028 | + // Fast-path for set comparison using hash map lookup. |
| 2029 | + if (IsTreatedAsSet(repeated_field) && !is_treated_as_smart_set) { |
| 2030 | + size_t h1 = GetRepeatedElementHash(message1, repeated_field, i); |
| 2031 | + auto it = hash_to_indices2.find(h1); |
| 2032 | + if (it != hash_to_indices2.end()) { |
| 2033 | + for (int j : it->second) { |
| 2034 | + if (match_list2->at(j) != -1) continue; |
| 2035 | + if (IsMatch(repeated_field, key_comparator, &message1, &message2, |
| 2036 | + unpacked_any, parent_fields, nullptr, i, j)) { |
| 2037 | + matched_j = j; |
| 2038 | + match = true; |
| 2039 | + break; |
| 2040 | + } |
1984 | 2041 | } |
1985 | 2042 | } |
| 2043 | + } |
1986 | 2044 |
|
1987 | | - if (is_treated_as_smart_set) { |
1988 | | - num_diffs_reporter.Reset(); |
1989 | | - match = |
1990 | | - IsMatch(repeated_field, key_comparator, &message1, &message2, |
1991 | | - unpacked_any, parent_fields, &num_diffs_reporter, i, j); |
1992 | | - } else { |
1993 | | - match = IsMatch(repeated_field, key_comparator, &message1, &message2, |
1994 | | - unpacked_any, parent_fields, nullptr, i, j); |
1995 | | - } |
| 2045 | + if (!match) { |
| 2046 | + for (int j = start_offset; j < count2; j++) { |
| 2047 | + if (match_list2->at(j) != -1) { |
| 2048 | + if (!is_treated_as_smart_set || num_diffs_list1[i] == 0 || |
| 2049 | + num_diffs_list1[match_list2->at(j)] == 0) { |
| 2050 | + continue; |
| 2051 | + } |
| 2052 | + } |
1996 | 2053 |
|
1997 | | - if (is_treated_as_smart_set) { |
1998 | | - if (match) { |
1999 | | - num_diffs_list1[i] = 0; |
2000 | | - } else if (repeated_field->cpp_type() == |
2001 | | - FieldDescriptor::CPPTYPE_MESSAGE) { |
2002 | | - // Replace with the one with fewer diffs. |
2003 | | - const int32_t num_diffs = num_diffs_reporter.GetNumDiffs(); |
2004 | | - if (num_diffs < num_diffs_list1[i]) { |
2005 | | - // If j has been already matched to some element, ensure the |
2006 | | - // current num_diffs is smaller. |
2007 | | - if (match_list2->at(j) == -1 || |
2008 | | - num_diffs < num_diffs_list1[match_list2->at(j)]) { |
2009 | | - num_diffs_list1[i] = num_diffs; |
2010 | | - match = true; |
| 2054 | + if (is_treated_as_smart_set) { |
| 2055 | + num_diffs_reporter.Reset(); |
| 2056 | + match = |
| 2057 | + IsMatch(repeated_field, key_comparator, &message1, &message2, |
| 2058 | + unpacked_any, parent_fields, &num_diffs_reporter, i, j); |
| 2059 | + } else { |
| 2060 | + match = |
| 2061 | + IsMatch(repeated_field, key_comparator, &message1, &message2, |
| 2062 | + unpacked_any, parent_fields, nullptr, i, j); |
| 2063 | + } |
| 2064 | + |
| 2065 | + if (is_treated_as_smart_set) { |
| 2066 | + if (match) { |
| 2067 | + num_diffs_list1[i] = 0; |
| 2068 | + } else if (repeated_field->cpp_type() == |
| 2069 | + FieldDescriptor::CPPTYPE_MESSAGE) { |
| 2070 | + // Replace with the one with fewer diffs. |
| 2071 | + const int32_t num_diffs = num_diffs_reporter.GetNumDiffs(); |
| 2072 | + if (num_diffs < num_diffs_list1[i]) { |
| 2073 | + // If j has been already matched to some element, ensure the |
| 2074 | + // current num_diffs is smaller. |
| 2075 | + if (match_list2->at(j) == -1 || |
| 2076 | + num_diffs < num_diffs_list1[match_list2->at(j)]) { |
| 2077 | + num_diffs_list1[i] = num_diffs; |
| 2078 | + match = true; |
| 2079 | + } |
2011 | 2080 | } |
2012 | 2081 | } |
2013 | 2082 | } |
2014 | | - } |
2015 | 2083 |
|
2016 | | - if (match) { |
2017 | | - matched_j = j; |
2018 | | - if (!is_treated_as_smart_set || num_diffs_list1[i] == 0) { |
2019 | | - break; |
| 2084 | + if (match) { |
| 2085 | + matched_j = j; |
| 2086 | + if (!is_treated_as_smart_set || num_diffs_list1[i] == 0) { |
| 2087 | + break; |
| 2088 | + } |
2020 | 2089 | } |
2021 | 2090 | } |
2022 | 2091 | } |
|
0 commit comments