1 2 /** 3 * Copyright (C) 2018-present MongoDB, Inc. 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the Server Side Public License, version 1, 7 * as published by MongoDB, Inc. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * Server Side Public License for more details. 13 * 14 * You should have received a copy of the Server Side Public License 15 * along with this program. If not, see 16 * <http://www.mongodb.com/licensing/server-side-public-license>. 17 * 18 * As a special exception, the copyright holders give permission to link the 19 * code of portions of this program with the OpenSSL library under certain 20 * conditions as described in each individual source file and distribute 21 * linked combinations including the program with the OpenSSL library. You 22 * must comply with the Server Side Public License in all respects for 23 * all of the code used other than as permitted herein. If you modify file(s) 24 * with this exception, you may extend this exception to your version of the 25 * file(s), but you are not obligated to do so. If you do not wish to do so, 26 * delete this exception statement from your version. If you delete this 27 * exception statement from all source files in the program, then also delete 28 * it in the license file. 29 */ 30 31 #pragma once 32 33 #include <boost/container/flat_set.hpp> 34 #include <initializer_list> 35 #include <map> 36 #include <set> 37 #include <vector> 38 39 #include "mongo/base/disallow_copying.h" 40 #include "mongo/base/string_data_comparator_interface.h" 41 #include "mongo/stdx/unordered_map.h" 42 #include "mongo/stdx/unordered_set.h" 43 #include "mongo/util/assert_util.h" 44 45 namespace mongo { 46 47 class BSONElement; 48 class BSONObj; 49 50 /** 51 * Base class for the BSONObj and BSONElement comparator interfaces. 52 */ 53 template <typename T> 54 class BSONComparatorInterfaceBase { 55 MONGO_DISALLOW_COPYING(BSONComparatorInterfaceBase); 56 57 public: 58 BSONComparatorInterfaceBase(BSONComparatorInterfaceBase&& other) = default; 59 BSONComparatorInterfaceBase& operator=(BSONComparatorInterfaceBase&& other) = default; 60 61 /** 62 * Set of rules used in the comparison of BSON Objects and Elements. 63 */ 64 enum ComparisonRules { 65 // Set this bit to consider the field name in element comparisons. 66 // if (kConsiderFieldName = 0) --> 'a: 1' == 'b: 1' 67 // if (kConsiderFieldName = 1) --> 'a: 1' != 'b: 1' 68 kConsiderFieldName = 1 << 0, 69 70 // Set this bit to ignore the element order in BSON Object comparisons. This field will 71 // remain set/unset for nested objects. 72 // 73 // e.g. if kIgnoreFieldOrder == 1, then the following objects are considered equal: 74 // 75 // obj1: { 76 // a: { 77 // b: 1, 78 // c: 1 79 // }, 80 // d: 1 81 // } 82 // 83 // obj2: { 84 // d: 1, 85 // a: { 86 // c: 1, 87 // b: 1, 88 // }, 89 // } 90 kIgnoreFieldOrder = 1 << 1, 91 }; 92 using ComparisonRulesSet = uint32_t; 93 94 /** 95 * A deferred comparison between two objects of type T, which can be converted into a boolean 96 * via the evaluate() method. 97 */ 98 struct DeferredComparison { 99 enum class Type { 100 kLT, 101 kLTE, 102 kEQ, 103 kGT, 104 kGTE, 105 kNE, 106 }; 107 DeferredComparisonDeferredComparison108 DeferredComparison(Type type, const T& lhs, const T& rhs) 109 : type(type), lhs(lhs), rhs(rhs) {} 110 111 Type type; 112 const T& lhs; 113 const T& rhs; 114 }; 115 116 /** 117 * Functor compatible for use with ordered STL containers. 118 */ 119 class LessThan { 120 public: LessThan(const BSONComparatorInterfaceBase * comparator)121 explicit LessThan(const BSONComparatorInterfaceBase* comparator) 122 : _comparator(comparator) {} 123 operator()124 bool operator()(const T& lhs, const T& rhs) const { 125 return _comparator->compare(lhs, rhs) < 0; 126 } 127 128 private: 129 const BSONComparatorInterfaceBase* _comparator; 130 }; 131 132 /** 133 * Functor compatible for use with unordered STL containers. 134 */ 135 class EqualTo { 136 public: EqualTo(const BSONComparatorInterfaceBase * comparator)137 explicit EqualTo(const BSONComparatorInterfaceBase* comparator) : _comparator(comparator) {} 138 operator()139 bool operator()(const T& lhs, const T& rhs) const { 140 return _comparator->compare(lhs, rhs) == 0; 141 } 142 143 private: 144 const BSONComparatorInterfaceBase* _comparator; 145 }; 146 147 /** 148 * Function object for hashing with respect to this comparator. Compatible with the hash concept 149 * from std::hash. 150 */ 151 class Hasher { 152 public: Hasher(const BSONComparatorInterfaceBase * comparator)153 explicit Hasher(const BSONComparatorInterfaceBase* comparator) : _comparator(comparator) {} 154 operator()155 size_t operator()(const T& toHash) const { 156 return _comparator->hash(toHash); 157 } 158 159 private: 160 const BSONComparatorInterfaceBase* _comparator; 161 }; 162 163 using Set = std::set<T, LessThan>; 164 165 using FlatSet = boost::container::flat_set<T, LessThan>; 166 167 using UnorderedSet = stdx::unordered_set<T, Hasher, EqualTo>; 168 169 template <typename ValueType> 170 using Map = std::map<T, ValueType, LessThan>; 171 172 template <typename ValueType> 173 using UnorderedMap = stdx::unordered_map<T, ValueType, Hasher, EqualTo>; 174 175 virtual ~BSONComparatorInterfaceBase() = default; 176 177 /** 178 * Compares two BSONObj/BSONElement objects. Returns <0, 0, >0 if 'lhs' < 'rhs', 'lhs' == 'rhs', 179 * or 'lhs' > 'rhs' respectively. 180 */ 181 virtual int compare(const T& lhs, const T& rhs) const = 0; 182 183 /** 184 * Produces a hash for a BSONObj or BSONElement in such a way that respects this comparator. 185 * 186 * The hash function is subject to change. Do not use in cases where hashes need to be 187 * consistent across versions. 188 */ hash(const T & toHash)189 size_t hash(const T& toHash) const { 190 size_t seed = 0; 191 hash_combine(seed, toHash); 192 return seed; 193 } 194 195 /** 196 * Produces a hash for a BSONObj or BSONElement in such a way that respects this comparator. The 197 * resulting hash is combined with 'seed', allowing the caller to create a composite hash out of 198 * several BSONObj/BSONElement objects. 199 * 200 * The hash function is subject to change. Do not use in cases where hashes need to be 201 * consistent across versions. 202 */ 203 virtual void hash_combine(size_t& seed, const T& toHash) const = 0; 204 205 /** 206 * Evaluates a deferred comparison object generated by invocation of one of the BSONObj operator 207 * overloads for relops. 208 */ evaluate(DeferredComparison deferredComparison)209 bool evaluate(DeferredComparison deferredComparison) const { 210 int cmp = compare(deferredComparison.lhs, deferredComparison.rhs); 211 switch (deferredComparison.type) { 212 case DeferredComparison::Type::kLT: 213 return cmp < 0; 214 case DeferredComparison::Type::kLTE: 215 return cmp <= 0; 216 case DeferredComparison::Type::kEQ: 217 return cmp == 0; 218 case DeferredComparison::Type::kGT: 219 return cmp > 0; 220 case DeferredComparison::Type::kGTE: 221 return cmp >= 0; 222 case DeferredComparison::Type::kNE: 223 return cmp != 0; 224 } 225 226 MONGO_UNREACHABLE; 227 } 228 229 /** 230 * Returns a function object which computes whether one BSONObj is less than another under this 231 * comparator. This comparator must outlive the returned function object. 232 */ makeLessThan()233 LessThan makeLessThan() const { 234 return LessThan(this); 235 } 236 237 /** 238 * Returns a function object which computes whether one BSONObj is equal to another under this 239 * comparator. This comparator must outlive the returned function object. 240 */ makeEqualTo()241 EqualTo makeEqualTo() const { 242 return EqualTo(this); 243 } 244 245 protected: 246 constexpr BSONComparatorInterfaceBase() = default; 247 248 Set makeSet(std::initializer_list<T> init = {}) const { 249 return Set(init, LessThan(this)); 250 } 251 makeFlatSet(const std::vector<T> & elements)252 FlatSet makeFlatSet(const std::vector<T>& elements) const { 253 return FlatSet(elements.begin(), elements.end(), LessThan(this)); 254 } 255 256 UnorderedSet makeUnorderedSet(std::initializer_list<T> init = {}) const { 257 return UnorderedSet(init, 0, Hasher(this), EqualTo(this)); 258 } 259 260 template <typename ValueType> 261 Map<ValueType> makeMap(std::initializer_list<std::pair<const T, ValueType>> init = {}) const { 262 return Map<ValueType>(init, LessThan(this)); 263 } 264 265 template <typename ValueType> 266 UnorderedMap<ValueType> makeUnorderedMap( 267 std::initializer_list<std::pair<const T, ValueType>> init = {}) const { 268 return UnorderedMap<ValueType>(init, 0, Hasher(this), EqualTo(this)); 269 } 270 271 /** 272 * Hashes 'objToHash', respecting the equivalence classes given by 'stringComparator'. 273 * 274 * Helper intended for use by subclasses. 275 */ 276 static void hashCombineBSONObj(size_t& seed, 277 const BSONObj& objToHash, 278 ComparisonRulesSet rules, 279 const StringData::ComparatorInterface* stringComparator); 280 281 /** 282 * Hashes 'elemToHash', respecting the equivalence classes given by 'stringComparator'. 283 * 284 * Helper intended for use by subclasses. 285 */ 286 static void hashCombineBSONElement(size_t& seed, 287 BSONElement elemToHash, 288 ComparisonRulesSet rules, 289 const StringData::ComparatorInterface* stringComparator); 290 }; 291 292 } // namespace mongo 293