/src/mozilla-central/xpcom/string/nsTStringRepr.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #ifndef nsTStringRepr_h |
8 | | #define nsTStringRepr_h |
9 | | |
10 | | #include <type_traits> // std::enable_if |
11 | | |
12 | | #include "mozilla/Char16.h" |
13 | | #include "mozilla/fallible.h" |
14 | | #include "nsStringFlags.h" |
15 | | #include "nsCharTraits.h" |
16 | | |
17 | | template <typename T> class nsTSubstringTuple; |
18 | | |
19 | | // The base for string comparators |
20 | | template <typename T> class nsTStringComparator |
21 | | { |
22 | | public: |
23 | | typedef T char_type; |
24 | | |
25 | 204k | nsTStringComparator() {} |
26 | | |
27 | | virtual int operator()(const char_type*, const char_type*, |
28 | | uint32_t, uint32_t) const = 0; |
29 | | }; |
30 | | |
31 | | // The default string comparator (case-sensitive comparision) |
32 | | template <typename T> class nsTDefaultStringComparator |
33 | | : public nsTStringComparator<T> |
34 | | { |
35 | | public: |
36 | | typedef T char_type; |
37 | | |
38 | 0 | nsTDefaultStringComparator() {} |
39 | | |
40 | | virtual int operator()(const char_type*, const char_type*, |
41 | | uint32_t, uint32_t) const override; |
42 | | }; |
43 | | |
44 | | extern template class nsTDefaultStringComparator<char>; |
45 | | extern template class nsTDefaultStringComparator<char16_t>; |
46 | | |
47 | | namespace mozilla { |
48 | | |
49 | | // This is mainly intended to be used in the context of nsTStrings where |
50 | | // we want to enable a specific function only for a given character class. In |
51 | | // order for this technique to work the member function needs to be templated |
52 | | // on something other than `T`. We keep this in the `mozilla` namespace rather |
53 | | // than `nsTStringRepr` as it's intentionally not dependent on `T`. |
54 | | // |
55 | | // The 'T' at the end of `Char[16]OnlyT` is refering to the `::type` portion |
56 | | // which will only be defined if the character class is correct. This is similar |
57 | | // to `std::enable_if_t` which is available in C++14, but not C++11. |
58 | | // |
59 | | // `CharType` is generally going to be a shadowed type of `T`. |
60 | | // |
61 | | // Example usage of a function that will only be defined if `T` == `char`: |
62 | | // |
63 | | // template <typename T> |
64 | | // class nsTSubstring : public nsTStringRepr<T> { |
65 | | // template <typename Q = T, typename EnableForChar = typename CharOnlyT<Q>> |
66 | | // int Foo() { return 42; } |
67 | | // }; |
68 | | // |
69 | | // Please note that we had to use a separate type `Q` for this to work. You |
70 | | // will get a semi-decent compiler error if you use `T` directly. |
71 | | |
72 | | template <typename CharType> using CharOnlyT = |
73 | | typename std::enable_if<std::is_same<char, CharType>::value>::type; |
74 | | |
75 | | template <typename CharType> using Char16OnlyT = |
76 | | typename std::enable_if<std::is_same<char16_t, CharType>::value>::type; |
77 | | |
78 | | namespace detail { |
79 | | |
80 | | // nsTStringRepr defines a string's memory layout and some accessor methods. |
81 | | // This class exists so that nsTLiteralString can avoid inheriting |
82 | | // nsTSubstring's destructor. All methods on this class must be const because |
83 | | // literal strings are not writable. |
84 | | // |
85 | | // This class is an implementation detail and should not be instantiated |
86 | | // directly, nor used in any way outside of the string code itself. It is |
87 | | // buried in a namespace to discourage its use in function parameters. |
88 | | // If you need to take a parameter, use [const] ns[C]Substring&. |
89 | | // If you need to instantiate a string, use ns[C]String or descendents. |
90 | | // |
91 | | // NAMES: |
92 | | // nsStringRepr for wide characters |
93 | | // nsCStringRepr for narrow characters |
94 | | template <typename T> class nsTStringRepr |
95 | | { |
96 | | public: |
97 | | typedef mozilla::fallible_t fallible_t; |
98 | | |
99 | | typedef T char_type; |
100 | | |
101 | | typedef nsCharTraits<char_type> char_traits; |
102 | | typedef typename char_traits::incompatible_char_type incompatible_char_type; |
103 | | |
104 | | typedef nsTStringRepr<T> self_type; |
105 | | typedef self_type base_string_type; |
106 | | |
107 | | typedef nsTSubstring<T> substring_type; |
108 | | typedef nsTSubstringTuple<T> substring_tuple_type; |
109 | | |
110 | | typedef nsReadingIterator<char_type> const_iterator; |
111 | | typedef char_type* iterator; |
112 | | |
113 | | typedef nsTStringComparator<char_type> comparator_type; |
114 | | |
115 | | typedef const char_type* const_char_iterator; |
116 | | |
117 | | typedef uint32_t index_type; |
118 | | typedef uint32_t size_type; |
119 | | |
120 | | // These are only for internal use within the string classes: |
121 | | typedef StringDataFlags DataFlags; |
122 | | typedef StringClassFlags ClassFlags; |
123 | | |
124 | | // Reading iterators. |
125 | | const_char_iterator BeginReading() const |
126 | | { |
127 | | return mData; |
128 | | } |
129 | | const_char_iterator EndReading() const |
130 | 6.23M | { |
131 | 6.23M | return mData + mLength; |
132 | 6.23M | } mozilla::detail::nsTStringRepr<char>::EndReading() const Line | Count | Source | 130 | 5.81M | { | 131 | 5.81M | return mData + mLength; | 132 | 5.81M | } |
mozilla::detail::nsTStringRepr<char16_t>::EndReading() const Line | Count | Source | 130 | 416k | { | 131 | 416k | return mData + mLength; | 132 | 416k | } |
|
133 | | |
134 | | // Deprecated reading iterators. |
135 | | const_iterator& BeginReading(const_iterator& aIter) const |
136 | 158k | { |
137 | 158k | aIter.mStart = mData; |
138 | 158k | aIter.mEnd = mData + mLength; |
139 | 158k | aIter.mPosition = aIter.mStart; |
140 | 158k | return aIter; |
141 | 158k | } |
142 | | |
143 | | const_iterator& EndReading(const_iterator& aIter) const |
144 | 158k | { |
145 | 158k | aIter.mStart = mData; |
146 | 158k | aIter.mEnd = mData + mLength; |
147 | 158k | aIter.mPosition = aIter.mEnd; |
148 | 158k | return aIter; |
149 | 158k | } |
150 | | |
151 | | const_char_iterator& BeginReading(const_char_iterator& aIter) const |
152 | 6.12M | { |
153 | 6.12M | return aIter = mData; |
154 | 6.12M | } mozilla::detail::nsTStringRepr<char>::BeginReading(char const*&) const Line | Count | Source | 152 | 6.10M | { | 153 | 6.10M | return aIter = mData; | 154 | 6.10M | } |
mozilla::detail::nsTStringRepr<char16_t>::BeginReading(char16_t const*&) const Line | Count | Source | 152 | 11.7k | { | 153 | 11.7k | return aIter = mData; | 154 | 11.7k | } |
|
155 | | |
156 | | const_char_iterator& EndReading(const_char_iterator& aIter) const |
157 | 6.12M | { |
158 | 6.12M | return aIter = mData + mLength; |
159 | 6.12M | } mozilla::detail::nsTStringRepr<char>::EndReading(char const*&) const Line | Count | Source | 157 | 6.10M | { | 158 | 6.10M | return aIter = mData + mLength; | 159 | 6.10M | } |
mozilla::detail::nsTStringRepr<char16_t>::EndReading(char16_t const*&) const Line | Count | Source | 157 | 11.7k | { | 158 | 11.7k | return aIter = mData + mLength; | 159 | 11.7k | } |
|
160 | | |
161 | | // Accessors. |
162 | | template <typename U, typename Dummy> struct raw_type { typedef const U* type; }; |
163 | | #if defined(MOZ_USE_CHAR16_WRAPPER) |
164 | | template <typename Dummy> struct raw_type<char16_t, Dummy> { typedef char16ptr_t type; }; |
165 | | #endif |
166 | | |
167 | | // Returns pointer to string data (not necessarily null-terminated) |
168 | | const typename raw_type<T, int>::type Data() const |
169 | 44.6M | { |
170 | 44.6M | return mData; |
171 | 44.6M | } mozilla::detail::nsTStringRepr<char16_t>::Data() const Line | Count | Source | 169 | 318k | { | 170 | 318k | return mData; | 171 | 318k | } |
mozilla::detail::nsTStringRepr<char>::Data() const Line | Count | Source | 169 | 44.2M | { | 170 | 44.2M | return mData; | 171 | 44.2M | } |
|
172 | | |
173 | | size_type Length() const |
174 | | { |
175 | | return mLength; |
176 | | } |
177 | | |
178 | | DataFlags GetDataFlags() const |
179 | 3.90M | { |
180 | 3.90M | return mDataFlags; |
181 | 3.90M | } mozilla::detail::nsTStringRepr<char>::GetDataFlags() const Line | Count | Source | 179 | 3.87M | { | 180 | 3.87M | return mDataFlags; | 181 | 3.87M | } |
mozilla::detail::nsTStringRepr<char16_t>::GetDataFlags() const Line | Count | Source | 179 | 27.6k | { | 180 | 27.6k | return mDataFlags; | 181 | 27.6k | } |
|
182 | | |
183 | | bool IsEmpty() const |
184 | 232k | { |
185 | 232k | return mLength == 0; |
186 | 232k | } |
187 | | |
188 | | bool IsLiteral() const |
189 | 834 | { |
190 | 834 | return !!(mDataFlags & DataFlags::LITERAL); |
191 | 834 | } mozilla::detail::nsTStringRepr<char16_t>::IsLiteral() const Line | Count | Source | 189 | 6 | { | 190 | 6 | return !!(mDataFlags & DataFlags::LITERAL); | 191 | 6 | } |
mozilla::detail::nsTStringRepr<char>::IsLiteral() const Line | Count | Source | 189 | 828 | { | 190 | 828 | return !!(mDataFlags & DataFlags::LITERAL); | 191 | 828 | } |
|
192 | | |
193 | | bool IsVoid() const |
194 | | { |
195 | | return !!(mDataFlags & DataFlags::VOIDED); |
196 | | } |
197 | | |
198 | | bool IsTerminated() const |
199 | 4.00M | { |
200 | 4.00M | return !!(mDataFlags & DataFlags::TERMINATED); |
201 | 4.00M | } mozilla::detail::nsTStringRepr<char>::IsTerminated() const Line | Count | Source | 199 | 3.87M | { | 200 | 3.87M | return !!(mDataFlags & DataFlags::TERMINATED); | 201 | 3.87M | } |
mozilla::detail::nsTStringRepr<char16_t>::IsTerminated() const Line | Count | Source | 199 | 130k | { | 200 | 130k | return !!(mDataFlags & DataFlags::TERMINATED); | 201 | 130k | } |
|
202 | | |
203 | | char_type CharAt(index_type aIndex) const |
204 | 2.20M | { |
205 | 2.20M | NS_ASSERTION(aIndex < mLength, "index exceeds allowable range"); |
206 | 2.20M | return mData[aIndex]; |
207 | 2.20M | } mozilla::detail::nsTStringRepr<char16_t>::CharAt(unsigned int) const Line | Count | Source | 204 | 123 | { | 205 | 123 | NS_ASSERTION(aIndex < mLength, "index exceeds allowable range"); | 206 | 123 | return mData[aIndex]; | 207 | 123 | } |
mozilla::detail::nsTStringRepr<char>::CharAt(unsigned int) const Line | Count | Source | 204 | 2.20M | { | 205 | 2.20M | NS_ASSERTION(aIndex < mLength, "index exceeds allowable range"); | 206 | 2.20M | return mData[aIndex]; | 207 | 2.20M | } |
|
208 | | |
209 | | char_type operator[](index_type aIndex) const |
210 | 2.20M | { |
211 | 2.20M | return CharAt(aIndex); |
212 | 2.20M | } mozilla::detail::nsTStringRepr<char16_t>::operator[](unsigned int) const Line | Count | Source | 210 | 87 | { | 211 | 87 | return CharAt(aIndex); | 212 | 87 | } |
mozilla::detail::nsTStringRepr<char>::operator[](unsigned int) const Line | Count | Source | 210 | 2.20M | { | 211 | 2.20M | return CharAt(aIndex); | 212 | 2.20M | } |
|
213 | | |
214 | | char_type First() const; |
215 | | |
216 | | char_type Last() const; |
217 | | |
218 | | size_type NS_FASTCALL CountChar(char_type) const; |
219 | | int32_t NS_FASTCALL FindChar(char_type, index_type aOffset = 0) const; |
220 | | |
221 | | inline bool Contains(char_type aChar) const |
222 | 2.17M | { |
223 | 2.17M | return FindChar(aChar) != kNotFound; |
224 | 2.17M | } mozilla::detail::nsTStringRepr<char>::Contains(char) const Line | Count | Source | 222 | 2.17M | { | 223 | 2.17M | return FindChar(aChar) != kNotFound; | 224 | 2.17M | } |
Unexecuted instantiation: mozilla::detail::nsTStringRepr<char16_t>::Contains(char16_t) const |
225 | | |
226 | | // Equality. |
227 | | bool NS_FASTCALL Equals(const self_type&) const; |
228 | | bool NS_FASTCALL Equals(const self_type&, const comparator_type&) const; |
229 | | |
230 | | bool NS_FASTCALL Equals(const substring_tuple_type& aTuple) const; |
231 | | bool NS_FASTCALL Equals(const substring_tuple_type& aTuple, |
232 | | const comparator_type& aComp) const; |
233 | | |
234 | | bool NS_FASTCALL Equals(const char_type* aData) const; |
235 | | bool NS_FASTCALL Equals(const char_type* aData, |
236 | | const comparator_type& aComp) const; |
237 | | |
238 | | #if defined(MOZ_USE_CHAR16_WRAPPER) |
239 | | template <typename Q = T, typename EnableIfChar16 = Char16OnlyT<Q>> |
240 | | bool NS_FASTCALL Equals(char16ptr_t aData) const |
241 | | { |
242 | | return Equals(static_cast<const char16_t*>(aData)); |
243 | | } |
244 | | template <typename Q = T, typename EnableIfChar16 = Char16OnlyT<Q>> |
245 | | bool NS_FASTCALL Equals(char16ptr_t aData, const comparator_type& aComp) const |
246 | | { |
247 | | return Equals(static_cast<const char16_t*>(aData), aComp); |
248 | | } |
249 | | #endif |
250 | | |
251 | | // An efficient comparison with ASCII that can be used even |
252 | | // for wide strings. Call this version when you know the |
253 | | // length of 'data'. |
254 | | bool NS_FASTCALL EqualsASCII(const char* aData, size_type aLen) const; |
255 | | // An efficient comparison with ASCII that can be used even |
256 | | // for wide strings. Call this version when 'data' is |
257 | | // null-terminated. |
258 | | bool NS_FASTCALL EqualsASCII(const char* aData) const; |
259 | | |
260 | | // EqualsLiteral must ONLY be applied to an actual literal string, or |
261 | | // a char array *constant* declared without an explicit size. |
262 | | // Do not attempt to use it with a regular char* pointer, or with a |
263 | | // non-constant char array variable. Use EqualsASCII for them. |
264 | | // The template trick to acquire the array length at compile time without |
265 | | // using a macro is due to Corey Kosak, with much thanks. |
266 | | template<int N> |
267 | | inline bool EqualsLiteral(const char (&aStr)[N]) const |
268 | | { |
269 | | return EqualsASCII(aStr, N - 1); |
270 | | } |
271 | | |
272 | | // The LowerCaseEquals methods compare the ASCII-lowercase version of |
273 | | // this string (lowercasing only ASCII uppercase characters) to some |
274 | | // ASCII/Literal string. The ASCII string is *not* lowercased for |
275 | | // you. If you compare to an ASCII or literal string that contains an |
276 | | // uppercase character, it is guaranteed to return false. We will |
277 | | // throw assertions too. |
278 | | bool NS_FASTCALL LowerCaseEqualsASCII(const char* aData, |
279 | | size_type aLen) const; |
280 | | bool NS_FASTCALL LowerCaseEqualsASCII(const char* aData) const; |
281 | | |
282 | | // LowerCaseEqualsLiteral must ONLY be applied to an actual |
283 | | // literal string, or a char array *constant* declared without an |
284 | | // explicit size. Do not attempt to use it with a regular char* |
285 | | // pointer, or with a non-constant char array variable. Use |
286 | | // LowerCaseEqualsASCII for them. |
287 | | template<int N> |
288 | | bool LowerCaseEqualsLiteral(const char (&aStr)[N]) const |
289 | | { |
290 | | return LowerCaseEqualsASCII(aStr, N - 1); |
291 | | } |
292 | | |
293 | | // Returns true if this string overlaps with the given string fragment. |
294 | | bool IsDependentOn(const char_type* aStart, const char_type* aEnd) const |
295 | 36.4M | { |
296 | 36.4M | // If it _isn't_ the case that one fragment starts after the other ends, |
297 | 36.4M | // or ends before the other starts, then, they conflict: |
298 | 36.4M | // |
299 | 36.4M | // !(f2.begin >= f1.aEnd || f2.aEnd <= f1.begin) |
300 | 36.4M | // |
301 | 36.4M | // Simplified, that gives us (To avoid relying on Undefined Behavior |
302 | 36.4M | // from comparing pointers from different allocations (which in |
303 | 36.4M | // principle gives the optimizer the permission to assume elsewhere |
304 | 36.4M | // that the pointers are from the same allocation), the comparisons |
305 | 36.4M | // are done on integers, which merely relies on implementation-defined |
306 | 36.4M | // behavior of converting pointers to integers. std::less and |
307 | 36.4M | // std::greater implementations don't actually provide the guarantees |
308 | 36.4M | // that they should.): |
309 | 36.4M | return (reinterpret_cast<uintptr_t>(aStart) < |
310 | 36.4M | reinterpret_cast<uintptr_t>(mData + mLength) && |
311 | 36.4M | reinterpret_cast<uintptr_t>(aEnd) > |
312 | 19.7M | reinterpret_cast<uintptr_t>(mData)); |
313 | 36.4M | } mozilla::detail::nsTStringRepr<char>::IsDependentOn(char const*, char const*) const Line | Count | Source | 295 | 35.0M | { | 296 | 35.0M | // If it _isn't_ the case that one fragment starts after the other ends, | 297 | 35.0M | // or ends before the other starts, then, they conflict: | 298 | 35.0M | // | 299 | 35.0M | // !(f2.begin >= f1.aEnd || f2.aEnd <= f1.begin) | 300 | 35.0M | // | 301 | 35.0M | // Simplified, that gives us (To avoid relying on Undefined Behavior | 302 | 35.0M | // from comparing pointers from different allocations (which in | 303 | 35.0M | // principle gives the optimizer the permission to assume elsewhere | 304 | 35.0M | // that the pointers are from the same allocation), the comparisons | 305 | 35.0M | // are done on integers, which merely relies on implementation-defined | 306 | 35.0M | // behavior of converting pointers to integers. std::less and | 307 | 35.0M | // std::greater implementations don't actually provide the guarantees | 308 | 35.0M | // that they should.): | 309 | 35.0M | return (reinterpret_cast<uintptr_t>(aStart) < | 310 | 35.0M | reinterpret_cast<uintptr_t>(mData + mLength) && | 311 | 35.0M | reinterpret_cast<uintptr_t>(aEnd) > | 312 | 18.5M | reinterpret_cast<uintptr_t>(mData)); | 313 | 35.0M | } |
mozilla::detail::nsTStringRepr<char16_t>::IsDependentOn(char16_t const*, char16_t const*) const Line | Count | Source | 295 | 1.33M | { | 296 | 1.33M | // If it _isn't_ the case that one fragment starts after the other ends, | 297 | 1.33M | // or ends before the other starts, then, they conflict: | 298 | 1.33M | // | 299 | 1.33M | // !(f2.begin >= f1.aEnd || f2.aEnd <= f1.begin) | 300 | 1.33M | // | 301 | 1.33M | // Simplified, that gives us (To avoid relying on Undefined Behavior | 302 | 1.33M | // from comparing pointers from different allocations (which in | 303 | 1.33M | // principle gives the optimizer the permission to assume elsewhere | 304 | 1.33M | // that the pointers are from the same allocation), the comparisons | 305 | 1.33M | // are done on integers, which merely relies on implementation-defined | 306 | 1.33M | // behavior of converting pointers to integers. std::less and | 307 | 1.33M | // std::greater implementations don't actually provide the guarantees | 308 | 1.33M | // that they should.): | 309 | 1.33M | return (reinterpret_cast<uintptr_t>(aStart) < | 310 | 1.33M | reinterpret_cast<uintptr_t>(mData + mLength) && | 311 | 1.33M | reinterpret_cast<uintptr_t>(aEnd) > | 312 | 1.20M | reinterpret_cast<uintptr_t>(mData)); | 313 | 1.33M | } |
|
314 | | |
315 | | protected: |
316 | | nsTStringRepr() = delete; // Never instantiate directly |
317 | | |
318 | | constexpr |
319 | | nsTStringRepr(char_type* aData, size_type aLength, |
320 | | DataFlags aDataFlags, ClassFlags aClassFlags) |
321 | | : mData(aData) |
322 | | , mLength(aLength) |
323 | | , mDataFlags(aDataFlags) |
324 | | , mClassFlags(aClassFlags) |
325 | | { |
326 | | } |
327 | | |
328 | | char_type* mData; |
329 | | size_type mLength; |
330 | | DataFlags mDataFlags; |
331 | | ClassFlags const mClassFlags; |
332 | | }; |
333 | | |
334 | | extern template class nsTStringRepr<char>; |
335 | | extern template class nsTStringRepr<char16_t>; |
336 | | |
337 | | } // namespace detail |
338 | | } // namespace mozilla |
339 | | |
340 | | template <typename T> |
341 | | int NS_FASTCALL |
342 | | Compare(const mozilla::detail::nsTStringRepr<T>& aLhs, |
343 | | const mozilla::detail::nsTStringRepr<T>& aRhs, |
344 | | const nsTStringComparator<T>& = nsTDefaultStringComparator<T>()); |
345 | | |
346 | | template <typename T> |
347 | | inline bool |
348 | | operator!=(const mozilla::detail::nsTStringRepr<T>& aLhs, |
349 | | const mozilla::detail::nsTStringRepr<T>& aRhs) |
350 | | { |
351 | | return !aLhs.Equals(aRhs); |
352 | | } |
353 | | |
354 | | template <typename T> |
355 | | inline bool |
356 | | operator!=(const mozilla::detail::nsTStringRepr<T>& aLhs, |
357 | | const T* aRhs) |
358 | | { |
359 | | return !aLhs.Equals(aRhs); |
360 | | } |
361 | | |
362 | | template <typename T> |
363 | | inline bool |
364 | | operator<(const mozilla::detail::nsTStringRepr<T>& aLhs, |
365 | | const mozilla::detail::nsTStringRepr<T>& aRhs) |
366 | | { |
367 | | return Compare(aLhs, aRhs) < 0; |
368 | | } |
369 | | |
370 | | template <typename T> |
371 | | inline bool |
372 | | operator<=(const mozilla::detail::nsTStringRepr<T>& aLhs, |
373 | | const mozilla::detail::nsTStringRepr<T>& aRhs) |
374 | | { |
375 | | return Compare(aLhs, aRhs) <= 0; |
376 | | } |
377 | | |
378 | | template <typename T> |
379 | | inline bool |
380 | | operator==(const mozilla::detail::nsTStringRepr<T>& aLhs, |
381 | | const mozilla::detail::nsTStringRepr<T>& aRhs) |
382 | | { |
383 | | return aLhs.Equals(aRhs); |
384 | | } |
385 | | |
386 | | template <typename T> |
387 | | inline bool |
388 | | operator==(const mozilla::detail::nsTStringRepr<T>& aLhs, |
389 | | const T* aRhs) |
390 | | { |
391 | | return aLhs.Equals(aRhs); |
392 | | } |
393 | | |
394 | | template <typename T> |
395 | | inline bool |
396 | | operator>=(const mozilla::detail::nsTStringRepr<T>& aLhs, |
397 | | const mozilla::detail::nsTStringRepr<T>& aRhs) |
398 | | { |
399 | | return Compare(aLhs, aRhs) >= 0; |
400 | | } |
401 | | |
402 | | template <typename T> |
403 | | inline bool |
404 | | operator>(const mozilla::detail::nsTStringRepr<T>& aLhs, |
405 | | const mozilla::detail::nsTStringRepr<T>& aRhs) |
406 | | { |
407 | | return Compare(aLhs, aRhs) > 0; |
408 | | } |
409 | | |
410 | | #endif |