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 // Author: ksroka@google.com (Krzysztof Sroka)
32 
33 #ifndef GOOGLE_PROTOBUF_UTIL_FIELD_COMPARATOR_H__
34 #define GOOGLE_PROTOBUF_UTIL_FIELD_COMPARATOR_H__
35 
36 #include <map>
37 #include <string>
38 
39 #include <google/protobuf/stubs/common.h>
40 
41 namespace google {
42 namespace protobuf {
43 
44 class Message;
45 class EnumValueDescriptor;
46 class FieldDescriptor;
47 
48 namespace util {
49 
50 class FieldContext;
51 
52 // Base class specifying the interface for comparing protocol buffer fields.
53 // Regular users should consider using or subclassing DefaultFieldComparator
54 // rather than this interface.
55 // Currently, this does not support comparing unknown fields.
56 class LIBPROTOBUF_EXPORT FieldComparator {
57  public:
58   FieldComparator();
59   virtual ~FieldComparator();
60 
61   enum ComparisonResult {
62     SAME,       // Compared fields are equal. In case of comparing submessages,
63                 // user should not recursively compare their contents.
64     DIFFERENT,  // Compared fields are different. In case of comparing
65                 // submessages, user should not recursively compare their
66                 // contents.
67     RECURSE,    // Compared submessages need to be compared recursively.
68                 // FieldComparator does not specify the semantics of recursive
69                 // comparison. This value should not be returned for simple
70                 // values.
71   };
72 
73   // Compares the values of a field in two protocol buffer messages.
74   // Returns SAME or DIFFERENT for simple values, and SAME, DIFFERENT or RECURSE
75   // for submessages. Returning RECURSE for fields not being submessages is
76   // illegal.
77   // In case the given FieldDescriptor points to a repeated field, the indices
78   // need to be valid. Otherwise they should be ignored.
79   //
80   // FieldContext contains information about the specific instances of the
81   // fields being compared, versus FieldDescriptor which only contains general
82   // type information about the fields.
83   virtual ComparisonResult Compare(
84       const google::protobuf::Message& message_1,
85       const google::protobuf::Message& message_2,
86       const google::protobuf::FieldDescriptor* field,
87       int index_1, int index_2,
88       const google::protobuf::util::FieldContext* field_context) = 0;
89 
90  private:
91   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldComparator);
92 };
93 
94 // Basic implementation of FieldComparator.  Supports three modes of floating
95 // point value comparison: exact, approximate using MathUtil::AlmostEqual
96 // method, and arbitrarily precise using MathUtil::WithinFractionOrMargin.
97 class LIBPROTOBUF_EXPORT DefaultFieldComparator : public FieldComparator {
98  public:
99   enum FloatComparison {
100      EXACT,               // Floats and doubles are compared exactly.
101      APPROXIMATE,         // Floats and doubles are compared using the
102                           // MathUtil::AlmostEqual method or
103                           // MathUtil::WithinFractionOrMargin method.
104      // TODO(ksroka): Introduce third value to differenciate uses of AlmostEqual
105      //               and WithinFractionOrMargin.
106   };
107 
108   // Creates new comparator with float comparison set to EXACT.
109   DefaultFieldComparator();
110 
111   virtual ~DefaultFieldComparator();
112 
113   virtual ComparisonResult Compare(
114       const google::protobuf::Message& message_1,
115       const google::protobuf::Message& message_2,
116       const google::protobuf::FieldDescriptor* field,
117       int index_1, int index_2,
118       const google::protobuf::util::FieldContext* field_context);
119 
set_float_comparison(FloatComparison float_comparison)120   void set_float_comparison(FloatComparison float_comparison) {
121     float_comparison_ = float_comparison;
122   }
123 
float_comparison()124   FloatComparison float_comparison() const {
125     return float_comparison_;
126   }
127 
128   // Set whether the FieldComparator shall treat floats or doubles that are both
129   // NaN as equal (treat_nan_as_equal = true) or as different
130   // (treat_nan_as_equal = false). Default is treating NaNs always as different.
set_treat_nan_as_equal(bool treat_nan_as_equal)131   void set_treat_nan_as_equal(bool treat_nan_as_equal) {
132     treat_nan_as_equal_ = treat_nan_as_equal;
133   }
134 
treat_nan_as_equal()135   bool treat_nan_as_equal() const {
136     return treat_nan_as_equal_;
137   }
138 
139   // Sets the fraction and margin for the float comparison of a given field.
140   // Uses MathUtil::WithinFractionOrMargin to compare the values.
141   //
142   // REQUIRES: field->cpp_type == FieldDescriptor::CPPTYPE_DOUBLE or
143   //           field->cpp_type == FieldDescriptor::CPPTYPE_FLOAT
144   // REQUIRES: float_comparison_ == APPROXIMATE
145   void SetFractionAndMargin(const FieldDescriptor* field, double fraction,
146                             double margin);
147 
148   // Sets the fraction and margin for the float comparison of all float and
149   // double fields, unless a field has been given a specific setting via
150   // SetFractionAndMargin() above.
151   // Uses MathUtil::WithinFractionOrMargin to compare the values.
152   //
153   // REQUIRES: float_comparison_ == APPROXIMATE
154   void SetDefaultFractionAndMargin(double fraction, double margin);
155 
156  private:
157   // Defines the tolerance for floating point comparison (fraction and margin).
158   struct Tolerance {
159     double fraction;
160     double margin;
ToleranceTolerance161     Tolerance()
162         : fraction(0.0),
163           margin(0.0) {}
ToleranceTolerance164     Tolerance(double f, double m)
165         : fraction(f),
166           margin(m) {}
167   };
168 
169   // Defines the map to store the tolerances for floating point comparison.
170   typedef map<const FieldDescriptor*, Tolerance> ToleranceMap;
171 
172   // The following methods get executed when CompareFields is called for the
173   // basic types (instead of submessages). They return true on success. One
174   // can use ResultFromBoolean() to convert that boolean to a ComparisonResult
175   // value.
CompareBool(const google::protobuf::FieldDescriptor & field,bool value_1,bool value_2)176   bool CompareBool(const google::protobuf::FieldDescriptor& field,
177                    bool value_1, bool value_2) {
178     return value_1 == value_2;
179   }
180 
181   // Uses CompareDoubleOrFloat, a helper function used by both CompareDouble and
182   // CompareFloat.
183   bool CompareDouble(const google::protobuf::FieldDescriptor& field,
184                      double value_1, double value_2);
185 
186   bool CompareEnum(const google::protobuf::FieldDescriptor& field,
187                    const EnumValueDescriptor* value_1,
188                    const EnumValueDescriptor* value_2);
189 
190   // Uses CompareDoubleOrFloat, a helper function used by both CompareDouble and
191   // CompareFloat.
192   bool CompareFloat(const google::protobuf::FieldDescriptor& field,
193                     float value_1, float value_2);
194 
CompareInt32(const google::protobuf::FieldDescriptor & field,int32 value_1,int32 value_2)195   bool CompareInt32(const google::protobuf::FieldDescriptor& field,
196                     int32 value_1, int32 value_2) {
197     return value_1 == value_2;
198   }
199 
CompareInt64(const google::protobuf::FieldDescriptor & field,int64 value_1,int64 value_2)200   bool CompareInt64(const google::protobuf::FieldDescriptor& field,
201                     int64 value_1, int64 value_2) {
202     return value_1 == value_2;
203   }
204 
CompareString(const google::protobuf::FieldDescriptor & field,const string & value_1,const string & value_2)205   bool CompareString(const google::protobuf::FieldDescriptor& field,
206                      const string& value_1, const string& value_2) {
207     return value_1 == value_2;
208   }
209 
CompareUInt32(const google::protobuf::FieldDescriptor & field,uint32 value_1,uint32 value_2)210   bool CompareUInt32(const google::protobuf::FieldDescriptor& field,
211                      uint32 value_1, uint32 value_2) {
212     return value_1 == value_2;
213   }
214 
CompareUInt64(const google::protobuf::FieldDescriptor & field,uint64 value_1,uint64 value_2)215   bool CompareUInt64(const google::protobuf::FieldDescriptor& field,
216                      uint64 value_1, uint64 value_2) {
217     return value_1 == value_2;
218   }
219 
220   // This function is used by CompareDouble and CompareFloat to avoid code
221   // duplication. There are no checks done against types of the values passed,
222   // but it's likely to fail if passed non-numeric arguments.
223   template<typename T>
224   bool CompareDoubleOrFloat(const google::protobuf::FieldDescriptor& field,
225                             T value_1, T value_2);
226 
227   // Returns FieldComparator::SAME if boolean_result is true and
228   // FieldComparator::DIFFERENT otherwise.
229   ComparisonResult ResultFromBoolean(bool boolean_result) const;
230 
231   FloatComparison float_comparison_;
232 
233   // If true, floats and doubles that are both NaN are considered to be
234   // equal. Otherwise, two floats or doubles that are NaN are considered to be
235   // different.
236   bool treat_nan_as_equal_;
237 
238   // True iff default_tolerance_ has been explicitly set.
239   //
240   // If false, then the default tolerance for flaots and doubles is that which
241   // is used by MathUtil::AlmostEquals().
242   bool has_default_tolerance_;
243 
244   // Default float/double tolerance. Only meaningful if
245   // has_default_tolerance_ == true.
246   Tolerance default_tolerance_;
247 
248   // Field-specific float/double tolerances, which override any default for
249   // those particular fields.
250   ToleranceMap map_tolerance_;
251 
252   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DefaultFieldComparator);
253 };
254 
255 }  // namespace util
256 }  // namespace protobuf
257 
258 }  // namespace google
259 #endif  // GOOGLE_PROTOBUF_UTIL_FIELD_COMPARATOR_H__
260