Home | History | Annotate | Download | only in util
      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 (at) 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 
    120   void set_float_comparison(FloatComparison float_comparison) {
    121     float_comparison_ = float_comparison;
    122   }
    123 
    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.
    131   void set_treat_nan_as_equal(bool treat_nan_as_equal) {
    132     treat_nan_as_equal_ = treat_nan_as_equal;
    133   }
    134 
    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;
    161     Tolerance()
    162         : fraction(0.0),
    163           margin(0.0) {}
    164     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.
    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 
    195   bool CompareInt32(const google::protobuf::FieldDescriptor& field,
    196                     int32 value_1, int32 value_2) {
    197     return value_1 == value_2;
    198   }
    199 
    200   bool CompareInt64(const google::protobuf::FieldDescriptor& field,
    201                     int64 value_1, int64 value_2) {
    202     return value_1 == value_2;
    203   }
    204 
    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 
    210   bool CompareUInt32(const google::protobuf::FieldDescriptor& field,
    211                      uint32 value_1, uint32 value_2) {
    212     return value_1 == value_2;
    213   }
    214 
    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