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