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 <memory> 34 #include <string> 35 36 #include "mongo/base/disallow_copying.h" 37 #include "mongo/base/string_data.h" 38 #include "mongo/base/string_data_comparator_interface.h" 39 #include "mongo/bson/bsonobj_comparator_interface.h" 40 #include "mongo/db/query/collation/collation_spec.h" 41 42 namespace mongo { 43 44 /** 45 * An interface for ordering and matching according to a collation. Instances should be retrieved 46 * from the CollatorFactoryInterface and may not be copied. 47 * 48 * All methods are thread-safe. 49 * 50 * Does not throw exceptions. 51 */ 52 class CollatorInterface : public StringData::ComparatorInterface { 53 MONGO_DISALLOW_COPYING(CollatorInterface); 54 55 public: 56 /** 57 * Every string has a corresponding ComparisonKey with respect to this collator. Two 58 * ComparisonKeys can be lexicographically ordered in order to obtain the collation's sort order 59 * and equivalence classes. 60 * 61 * A ComparisonKey is logically an owned array of bytes. It is cheap to move but potentially 62 * expensive to copy. 63 * 64 * ComparisonKeys may only be obtained via CollatorInterface::getComparisonKey(). 65 * 66 * In general, two strings should be compared with respect to a collation using 67 * CollatorInterface::compare(). ComparisonKey::compare() may be faster if repeatedly comparing 68 * the same string(s). 69 */ 70 class ComparisonKey { 71 public: 72 /** 73 * Returns the underlying byte array represented by this ComparisonKey. 74 * 75 * The returned StringData may not outlive the ComparisonKey used to create it, since the 76 * ComparisonKey owns the underlying byte array. 77 */ getKeyData()78 StringData getKeyData() const { 79 return StringData(_key); 80 } 81 82 private: 83 friend class CollatorInterface; 84 ComparisonKey(std::string key)85 ComparisonKey(std::string key) : _key(std::move(key)) {} 86 87 std::string _key; 88 }; 89 90 /** 91 * Constructs a CollatorInterface capable of computing the collation described by 'spec'. 92 */ CollatorInterface(CollationSpec spec)93 CollatorInterface(CollationSpec spec) : _spec(std::move(spec)) {} 94 ~CollatorInterface()95 virtual ~CollatorInterface() {} 96 97 virtual std::unique_ptr<CollatorInterface> clone() const = 0; 98 99 /** 100 * Returns a number < 0 if 'left' is less than 'right' with respect to the collation, a number > 101 * 0 if 'left' is greater than 'right' w.r.t. the collation, and 0 if 'left' and 'right' are 102 * equal w.r.t. the collation. 103 */ 104 virtual int compare(StringData left, StringData right) const = 0; 105 106 /** 107 * Hashes the string such that strings which are equal under this collation also have equal 108 * hashes. 109 */ 110 void hash_combine(size_t& seed, StringData stringToHash) const final; 111 112 /** 113 * Returns the comparison key for 'stringData', according to this collation. See ComparisonKey's 114 * comments for details. 115 */ 116 virtual ComparisonKey getComparisonKey(StringData stringData) const = 0; 117 118 /** 119 * Returns whether this collation has the same matching and sorting semantics as 'other'. 120 */ 121 bool operator==(const CollatorInterface& other) const { 122 return getSpec() == other.getSpec(); 123 } 124 125 /** 126 * Returns whether this collation *does not* have the same matching and sorting semantics as 127 * 'other'. 128 */ 129 bool operator!=(const CollatorInterface& other) const { 130 return !(*this == other); 131 } 132 133 /** 134 * Returns a reference to the CollationSpec. 135 */ getSpec()136 const CollationSpec& getSpec() const { 137 return _spec; 138 } 139 140 /** 141 * Returns true if lhs and rhs are both nullptr, or if they point to equivalent collators. 142 */ collatorsMatch(const CollatorInterface * lhs,const CollatorInterface * rhs)143 static bool collatorsMatch(const CollatorInterface* lhs, const CollatorInterface* rhs) { 144 if (lhs == nullptr && rhs == nullptr) { 145 return true; 146 } 147 if (lhs == nullptr || rhs == nullptr) { 148 return false; 149 } 150 return (*lhs == *rhs); 151 } 152 153 /** 154 * Returns a clone of 'collator'. If 'collator' is nullptr, returns the null collator. 155 */ cloneCollator(const CollatorInterface * collator)156 static std::unique_ptr<CollatorInterface> cloneCollator(const CollatorInterface* collator) { 157 if (!collator) { 158 return {nullptr}; 159 } 160 return collator->clone(); 161 } 162 163 protected: makeComparisonKey(std::string key)164 static ComparisonKey makeComparisonKey(std::string key) { 165 return ComparisonKey(std::move(key)); 166 } 167 168 private: 169 const CollationSpec _spec; 170 }; 171 172 } // namespace mongo 173