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