1// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc. All rights reserved.
3// https://developers.google.com/protocol-buffers/
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
8//
9// * Redistributions of source code must retain the above copyright
10// notice, this list of conditions and the following disclaimer.
11// * Redistributions in binary form must reproduce the above
12// copyright notice, this list of conditions and the following disclaimer
13// in the documentation and/or other materials provided with the
14// distribution.
15// * Neither the name of Google Inc. nor the names of its
16// contributors may be used to endorse or promote products derived from
17// this software without specific prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31// Defines classes for field comparison.
32
33#ifndef GOOGLE_PROTOBUF_UTIL_FIELD_COMPARATOR_H__
34#define GOOGLE_PROTOBUF_UTIL_FIELD_COMPARATOR_H__
35
36
37#include <cstdint>
38#include <map>
39#include <string>
40#include <vector>
41
42#include <google/protobuf/stubs/common.h>
43
44// Must be included last.
45#include <google/protobuf/port_def.inc>
46
47namespace google {
48namespace protobuf {
49
50class Message;
51class EnumValueDescriptor;
52class FieldDescriptor;
53
54namespace util {
55
56class FieldContext;
57class MessageDifferencer;
58
59// Base class specifying the interface for comparing protocol buffer fields.
60// Regular users should consider using or subclassing DefaultFieldComparator
61// rather than this interface.
62// Currently, this does not support comparing unknown fields.
63class PROTOBUF_EXPORT FieldComparator {
64 public:
65 FieldComparator();
66 virtual ~FieldComparator();
67
68 enum ComparisonResult {
69 SAME, // Compared fields are equal. In case of comparing submessages,
70 // user should not recursively compare their contents.
71 DIFFERENT, // Compared fields are different. In case of comparing
72 // submessages, user should not recursively compare their
73 // contents.
74 RECURSE, // Compared submessages need to be compared recursively.
75 // FieldComparator does not specify the semantics of recursive
76 // comparison. This value should not be returned for simple
77 // values.
78 };
79
80 // Compares the values of a field in two protocol buffer messages.
81 // Returns SAME or DIFFERENT for simple values, and SAME, DIFFERENT or RECURSE
82 // for submessages. Returning RECURSE for fields not being submessages is
83 // illegal.
84 // In case the given FieldDescriptor points to a repeated field, the indices
85 // need to be valid. Otherwise they should be ignored.
86 //
87 // FieldContext contains information about the specific instances of the
88 // fields being compared, versus FieldDescriptor which only contains general
89 // type information about the fields.
90 virtual ComparisonResult Compare(const Message& message_1,
91 const Message& message_2,
92 const FieldDescriptor* field, int index_1,
93 int index_2,
94 const util::FieldContext* field_context) = 0;
95
96 private:
97 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldComparator);
98};
99
100// Basic implementation of FieldComparator. Supports three modes of floating
101// point value comparison: exact, approximate using MathUtil::AlmostEqual
102// method, and arbitrarily precise using MathUtil::WithinFractionOrMargin.
103class PROTOBUF_EXPORT SimpleFieldComparator : public FieldComparator {
104 public:
105 enum FloatComparison {
106 EXACT, // Floats and doubles are compared exactly.
107 APPROXIMATE, // Floats and doubles are compared using the
108 // MathUtil::AlmostEqual method or
109 // MathUtil::WithinFractionOrMargin method.
110 // TODO(ksroka): Introduce third value to differentiate uses of AlmostEqual
111 // and WithinFractionOrMargin.
112 };
113
114 // Creates new comparator with float comparison set to EXACT.
115 SimpleFieldComparator();
116
117 ~SimpleFieldComparator() override;
118
119 void set_float_comparison(FloatComparison float_comparison) {
120 float_comparison_ = float_comparison;
121 }
122
123 FloatComparison float_comparison() const { return float_comparison_; }
124
125 // Set whether the FieldComparator shall treat floats or doubles that are both
126 // NaN as equal (treat_nan_as_equal = true) or as different
127 // (treat_nan_as_equal = false). Default is treating NaNs always as different.
128 void set_treat_nan_as_equal(bool treat_nan_as_equal) {
129 treat_nan_as_equal_ = treat_nan_as_equal;
130 }
131
132 bool treat_nan_as_equal() const { return treat_nan_as_equal_; }
133
134 // Sets the fraction and margin for the float comparison of a given field.
135 // Uses MathUtil::WithinFractionOrMargin to compare the values.
136 //
137 // REQUIRES: field->cpp_type == FieldDescriptor::CPPTYPE_DOUBLE or
138 // field->cpp_type == FieldDescriptor::CPPTYPE_FLOAT
139 // REQUIRES: float_comparison_ == APPROXIMATE
140 void SetFractionAndMargin(const FieldDescriptor* field, double fraction,
141 double margin);
142
143 // Sets the fraction and margin for the float comparison of all float and
144 // double fields, unless a field has been given a specific setting via
145 // SetFractionAndMargin() above.
146 // Uses MathUtil::WithinFractionOrMargin to compare the values.
147 //
148 // REQUIRES: float_comparison_ == APPROXIMATE
149 void SetDefaultFractionAndMargin(double fraction, double margin);
150
151 protected:
152 // Returns the comparison result for the given field in two messages.
153 //
154 // This function is called directly by DefaultFieldComparator::Compare.
155 // Subclasses can call this function to compare fields they do not need to
156 // handle specially.
157 ComparisonResult SimpleCompare(const Message& message_1,
158 const Message& message_2,
159 const FieldDescriptor* field, int index_1,
160 int index_2,
161 const util::FieldContext* field_context);
162
163 // Compare using the provided message_differencer. For example, a subclass can
164 // use this method to compare some field in a certain way using the same
165 // message_differencer instance and the field context.
166 bool CompareWithDifferencer(MessageDifferencer* differencer,
167 const Message& message1, const Message& message2,
168 const util::FieldContext* field_context);
169
170 // Returns FieldComparator::SAME if boolean_result is true and
171 // FieldComparator::DIFFERENT otherwise.
172 ComparisonResult ResultFromBoolean(bool boolean_result) const;
173
174 private:
175 // Defines the tolerance for floating point comparison (fraction and margin).
176 struct Tolerance {
177 double fraction;
178 double margin;
179 Tolerance() : fraction(0.0), margin(0.0) {}
180 Tolerance(double f, double m) : fraction(f), margin(m) {}
181 };
182
183 // Defines the map to store the tolerances for floating point comparison.
184 typedef std::map<const FieldDescriptor*, Tolerance> ToleranceMap;
185
186 friend class MessageDifferencer;
187 // The following methods get executed when CompareFields is called for the
188 // basic types (instead of submessages). They return true on success. One
189 // can use ResultFromBoolean() to convert that boolean to a ComparisonResult
190 // value.
191 bool CompareBool(const FieldDescriptor& /* unused */, bool value_1,
192 bool value_2) {
193 return value_1 == value_2;
194 }
195
196 // Uses CompareDoubleOrFloat, a helper function used by both CompareDouble and
197 // CompareFloat.
198 bool CompareDouble(const FieldDescriptor& field, double value_1,
199 double value_2);
200
201 bool CompareEnum(const FieldDescriptor& field,
202 const EnumValueDescriptor* value_1,
203 const EnumValueDescriptor* value_2);
204
205 // Uses CompareDoubleOrFloat, a helper function used by both CompareDouble and
206 // CompareFloat.
207 bool CompareFloat(const FieldDescriptor& field, float value_1, float value_2);
208
209 bool CompareInt32(const FieldDescriptor& /* unused */, int32_t value_1,
210 int32_t value_2) {
211 return value_1 == value_2;
212 }
213
214 bool CompareInt64(const FieldDescriptor& /* unused */, int64_t value_1,
215 int64_t value_2) {
216 return value_1 == value_2;
217 }
218
219 bool CompareString(const FieldDescriptor& /* unused */,
220 const std::string& value_1, const std::string& value_2) {
221 return value_1 == value_2;
222 }
223
224 bool CompareUInt32(const FieldDescriptor& /* unused */, uint32_t value_1,
225 uint32_t value_2) {
226 return value_1 == value_2;
227 }
228
229 bool CompareUInt64(const FieldDescriptor& /* unused */, uint64_t value_1,
230 uint64_t value_2) {
231 return value_1 == value_2;
232 }
233
234 // This function is used by CompareDouble and CompareFloat to avoid code
235 // duplication. There are no checks done against types of the values passed,
236 // but it's likely to fail if passed non-numeric arguments.
237 template <typename T>
238 bool CompareDoubleOrFloat(const FieldDescriptor& field, T value_1, T value_2);
239
240 FloatComparison float_comparison_;
241
242 // If true, floats and doubles that are both NaN are considered to be
243 // equal. Otherwise, two floats or doubles that are NaN are considered to be
244 // different.
245 bool treat_nan_as_equal_;
246
247 // True iff default_tolerance_ has been explicitly set.
248 //
249 // If false, then the default tolerance for floats and doubles is that which
250 // is used by MathUtil::AlmostEquals().
251 bool has_default_tolerance_;
252
253 // Default float/double tolerance. Only meaningful if
254 // has_default_tolerance_ == true.
255 Tolerance default_tolerance_;
256
257 // Field-specific float/double tolerances, which override any default for
258 // those particular fields.
259 ToleranceMap map_tolerance_;
260
261 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SimpleFieldComparator);
262};
263
264// Default field comparison: use the basic implementation of FieldComparator.
265#ifdef PROTOBUF_FUTURE_BREAKING_CHANGES
266class PROTOBUF_EXPORT DefaultFieldComparator final
267 : public SimpleFieldComparator
268#else // PROTOBUF_FUTURE_BREAKING_CHANGES
269class PROTOBUF_EXPORT DefaultFieldComparator : public SimpleFieldComparator
270#endif // PROTOBUF_FUTURE_BREAKING_CHANGES
271{
272 public:
273 ComparisonResult Compare(const Message& message_1, const Message& message_2,
274 const FieldDescriptor* field, int index_1,
275 int index_2,
276 const util::FieldContext* field_context) override {
277 return SimpleCompare(message_1, message_2, field, index_1, index_2,
278 field_context);
279 }
280};
281
282} // namespace util
283} // namespace protobuf
284} // namespace google
285
286#include <google/protobuf/port_undef.inc>
287
288#endif // GOOGLE_PROTOBUF_UTIL_FIELD_COMPARATOR_H__
289