Index: third_party/protobuf/src/google/protobuf/util/field_comparator.cc |
diff --git a/third_party/protobuf/src/google/protobuf/util/field_comparator.cc b/third_party/protobuf/src/google/protobuf/util/field_comparator.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..9f613265e8554f5a89a1effcd486641dd6318d78 |
--- /dev/null |
+++ b/third_party/protobuf/src/google/protobuf/util/field_comparator.cc |
@@ -0,0 +1,188 @@ |
+// Protocol Buffers - Google's data interchange format |
+// Copyright 2008 Google Inc. All rights reserved. |
+// https://developers.google.com/protocol-buffers/ |
+// |
+// Redistribution and use in source and binary forms, with or without |
+// modification, are permitted provided that the following conditions are |
+// met: |
+// |
+// * Redistributions of source code must retain the above copyright |
+// notice, this list of conditions and the following disclaimer. |
+// * Redistributions in binary form must reproduce the above |
+// copyright notice, this list of conditions and the following disclaimer |
+// in the documentation and/or other materials provided with the |
+// distribution. |
+// * Neither the name of Google Inc. nor the names of its |
+// contributors may be used to endorse or promote products derived from |
+// this software without specific prior written permission. |
+// |
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
+ |
+// Author: ksroka@google.com (Krzysztof Sroka) |
+ |
+#include <google/protobuf/util/field_comparator.h> |
+ |
+#include <string> |
+ |
+#include <google/protobuf/descriptor.h> |
+#include <google/protobuf/message.h> |
+#include <google/protobuf/stubs/map_util.h> |
+#include <google/protobuf/stubs/mathlimits.h> |
+#include <google/protobuf/stubs/mathutil.h> |
+ |
+namespace google { |
+namespace protobuf { |
+namespace util { |
+ |
+FieldComparator::FieldComparator() {} |
+FieldComparator::~FieldComparator() {} |
+ |
+DefaultFieldComparator::DefaultFieldComparator() |
+ : float_comparison_(EXACT), |
+ treat_nan_as_equal_(false), |
+ has_default_tolerance_(false) { |
+} |
+ |
+DefaultFieldComparator::~DefaultFieldComparator() {} |
+ |
+FieldComparator::ComparisonResult DefaultFieldComparator::Compare( |
+ const google::protobuf::Message& message_1, |
+ const google::protobuf::Message& message_2, |
+ const google::protobuf::FieldDescriptor* field, |
+ int index_1, int index_2, |
+ const google::protobuf::util::FieldContext* field_context) { |
+ const Reflection* reflection_1 = message_1.GetReflection(); |
+ const Reflection* reflection_2 = message_2.GetReflection(); |
+ |
+ switch (field->cpp_type()) { |
+#define COMPARE_FIELD(METHOD) \ |
+ if (field->is_repeated()) { \ |
+ return ResultFromBoolean(Compare##METHOD( \ |
+ *field, \ |
+ reflection_1->GetRepeated##METHOD(message_1, field, index_1), \ |
+ reflection_2->GetRepeated##METHOD(message_2, field, index_2))); \ |
+ } else { \ |
+ return ResultFromBoolean(Compare##METHOD( \ |
+ *field, \ |
+ reflection_1->Get##METHOD(message_1, field), \ |
+ reflection_2->Get##METHOD(message_2, field))); \ |
+ } \ |
+ break; // Make sure no fall-through is introduced. |
+ |
+ case FieldDescriptor::CPPTYPE_BOOL: |
+ COMPARE_FIELD(Bool); |
+ case FieldDescriptor::CPPTYPE_DOUBLE: |
+ COMPARE_FIELD(Double); |
+ case FieldDescriptor::CPPTYPE_ENUM: |
+ COMPARE_FIELD(Enum); |
+ case FieldDescriptor::CPPTYPE_FLOAT: |
+ COMPARE_FIELD(Float); |
+ case FieldDescriptor::CPPTYPE_INT32: |
+ COMPARE_FIELD(Int32); |
+ case FieldDescriptor::CPPTYPE_INT64: |
+ COMPARE_FIELD(Int64); |
+ case FieldDescriptor::CPPTYPE_STRING: |
+ COMPARE_FIELD(String); |
+ case FieldDescriptor::CPPTYPE_UINT32: |
+ COMPARE_FIELD(UInt32); |
+ case FieldDescriptor::CPPTYPE_UINT64: |
+ COMPARE_FIELD(UInt64); |
+ |
+#undef COMPARE_FIELD |
+ |
+ case FieldDescriptor::CPPTYPE_MESSAGE: |
+ return RECURSE; |
+ |
+ default: |
+ GOOGLE_LOG(FATAL) << "No comparison code for field " << field->full_name() |
+ << " of CppType = " << field->cpp_type(); |
+ return DIFFERENT; |
+ } |
+} |
+ |
+void DefaultFieldComparator::SetDefaultFractionAndMargin(double fraction, |
+ double margin) { |
+ default_tolerance_ = Tolerance(fraction, margin); |
+ has_default_tolerance_ = true; |
+} |
+ |
+void DefaultFieldComparator::SetFractionAndMargin(const FieldDescriptor* field, |
+ double fraction, |
+ double margin) { |
+ GOOGLE_CHECK(FieldDescriptor::CPPTYPE_FLOAT == field->cpp_type() || |
+ FieldDescriptor::CPPTYPE_DOUBLE == field->cpp_type()) |
+ << "Field has to be float or double type. Field name is: " |
+ << field->full_name(); |
+ map_tolerance_[field] = Tolerance(fraction, margin); |
+} |
+ |
+bool DefaultFieldComparator::CompareDouble(const FieldDescriptor& field, |
+ double value_1, double value_2) { |
+ return CompareDoubleOrFloat(field, value_1, value_2); |
+} |
+ |
+bool DefaultFieldComparator::CompareEnum(const FieldDescriptor& field, |
+ const EnumValueDescriptor* value_1, |
+ const EnumValueDescriptor* value_2) { |
+ return value_1->number() == value_2->number(); |
+} |
+ |
+bool DefaultFieldComparator::CompareFloat(const FieldDescriptor& field, |
+ float value_1, float value_2) { |
+ return CompareDoubleOrFloat(field, value_1, value_2); |
+} |
+ |
+template<typename T> |
+bool DefaultFieldComparator::CompareDoubleOrFloat(const FieldDescriptor& field, |
+ T value_1, T value_2) { |
+ if (value_1 == value_2) { |
+ // Covers +inf and -inf (which are not within margin or fraction of |
+ // themselves), and is a shortcut for finite values. |
+ return true; |
+ } else if (float_comparison_ == EXACT) { |
+ if (treat_nan_as_equal_ && |
+ MathLimits<T>::IsNaN(value_1) && MathLimits<T>::IsNaN(value_2)) { |
+ return true; |
+ } |
+ return false; |
+ } else { |
+ if (treat_nan_as_equal_ && |
+ MathLimits<T>::IsNaN(value_1) && MathLimits<T>::IsNaN(value_2)) { |
+ return true; |
+ } |
+ // float_comparison_ == APPROXIMATE covers two use cases. |
+ Tolerance* tolerance = FindOrNull(map_tolerance_, &field); |
+ if (tolerance == NULL && has_default_tolerance_) { |
+ tolerance = &default_tolerance_; |
+ } |
+ if (tolerance == NULL) { |
+ return MathUtil::AlmostEquals(value_1, value_2); |
+ } else { |
+ // Use user-provided fraction and margin. Since they are stored as |
+ // doubles, we explicitely cast them to types of values provided. This |
+ // is very likely to fail if provided values are not numeric. |
+ return MathUtil::WithinFractionOrMargin( |
+ value_1, value_2, static_cast<T>(tolerance->fraction), |
+ static_cast<T>(tolerance->margin)); |
+ } |
+ } |
+} |
+ |
+FieldComparator::ComparisonResult DefaultFieldComparator::ResultFromBoolean( |
+ bool boolean_result) const { |
+ return boolean_result ? FieldComparator::SAME : FieldComparator::DIFFERENT; |
+} |
+ |
+} // namespace util |
+} // namespace protobuf |
+} // namespace google |