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