Bug 1696969 [wpt PR 27896] - Allow fuzzy matching for replaced-element-003, a=testonly
[gecko.git] / xpcom / string / nsTStringRepr.h
blobf0a775c70d66ff9e100bbd7072712e3095344954
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/. */
7 #ifndef nsTStringRepr_h
8 #define nsTStringRepr_h
10 #include <type_traits> // std::enable_if
12 #include "mozilla/Char16.h"
13 #include "mozilla/fallible.h"
14 #include "nsStringFlags.h"
15 #include "nsStringIterator.h"
16 #include "nsCharTraits.h"
18 template <typename T>
19 class nsTSubstringTuple;
21 namespace mozilla {
23 // This is mainly intended to be used in the context of nsTStrings where
24 // we want to enable a specific function only for a given character class. In
25 // order for this technique to work the member function needs to be templated
26 // on something other than `T`. We keep this in the `mozilla` namespace rather
27 // than `nsTStringRepr` as it's intentionally not dependent on `T`.
29 // The 'T' at the end of `Char[16]OnlyT` is refering to the `::type` portion
30 // which will only be defined if the character class is correct. This is similar
31 // to `std::enable_if_t` which is available in C++14, but not C++11.
33 // `CharType` is generally going to be a shadowed type of `T`.
35 // Example usage of a function that will only be defined if `T` == `char`:
37 // template <typename T>
38 // class nsTSubstring : public nsTStringRepr<T> {
39 // template <typename Q = T, typename EnableForChar = typename CharOnlyT<Q>>
40 // int Foo() { return 42; }
41 // };
43 // Please note that we had to use a separate type `Q` for this to work. You
44 // will get a semi-decent compiler error if you use `T` directly.
46 template <typename CharType>
47 using CharOnlyT =
48 typename std::enable_if<std::is_same<char, CharType>::value>::type;
50 template <typename CharType>
51 using Char16OnlyT =
52 typename std::enable_if<std::is_same<char16_t, CharType>::value>::type;
54 namespace detail {
56 // nsTStringRepr defines a string's memory layout and some accessor methods.
57 // This class exists so that nsTLiteralString can avoid inheriting
58 // nsTSubstring's destructor. All methods on this class must be const because
59 // literal strings are not writable.
61 // This class is an implementation detail and should not be instantiated
62 // directly, nor used in any way outside of the string code itself. It is
63 // buried in a namespace to discourage its use in function parameters.
64 // If you need to take a parameter, use [const] ns[C]Substring&.
65 // If you need to instantiate a string, use ns[C]String or descendents.
67 // NAMES:
68 // nsStringRepr for wide characters
69 // nsCStringRepr for narrow characters
70 template <typename T>
71 class nsTStringRepr {
72 public:
73 typedef mozilla::fallible_t fallible_t;
75 typedef T char_type;
77 typedef nsCharTraits<char_type> char_traits;
78 typedef typename char_traits::incompatible_char_type incompatible_char_type;
80 typedef nsTStringRepr<T> self_type;
81 typedef self_type base_string_type;
83 typedef nsTSubstring<T> substring_type;
84 typedef nsTSubstringTuple<T> substring_tuple_type;
86 typedef nsReadingIterator<char_type> const_iterator;
87 typedef char_type* iterator;
89 typedef nsTStringComparator<char_type> comparator_type;
91 typedef const char_type* const_char_iterator;
93 typedef uint32_t index_type;
94 typedef uint32_t size_type;
96 // These are only for internal use within the string classes:
97 typedef StringDataFlags DataFlags;
98 typedef StringClassFlags ClassFlags;
100 // Reading iterators.
101 constexpr const_char_iterator BeginReading() const { return mData; }
102 constexpr const_char_iterator EndReading() const { return mData + mLength; }
104 // Deprecated reading iterators.
105 const_iterator& BeginReading(const_iterator& aIter) const {
106 aIter.mStart = mData;
107 aIter.mEnd = mData + mLength;
108 aIter.mPosition = aIter.mStart;
109 return aIter;
112 const_iterator& EndReading(const_iterator& aIter) const {
113 aIter.mStart = mData;
114 aIter.mEnd = mData + mLength;
115 aIter.mPosition = aIter.mEnd;
116 return aIter;
119 const_char_iterator& BeginReading(const_char_iterator& aIter) const {
120 return aIter = mData;
123 const_char_iterator& EndReading(const_char_iterator& aIter) const {
124 return aIter = mData + mLength;
127 // Accessors.
128 template <typename U, typename Dummy>
129 struct raw_type {
130 typedef const U* type;
132 #if defined(MOZ_USE_CHAR16_WRAPPER)
133 template <typename Dummy>
134 struct raw_type<char16_t, Dummy> {
135 typedef char16ptr_t type;
137 #endif
139 // Returns pointer to string data (not necessarily null-terminated)
140 constexpr const typename raw_type<T, int>::type Data() const { return mData; }
142 constexpr size_type Length() const { return mLength; }
144 constexpr DataFlags GetDataFlags() const { return mDataFlags; }
146 constexpr bool IsEmpty() const { return mLength == 0; }
148 constexpr bool IsLiteral() const {
149 return !!(mDataFlags & DataFlags::LITERAL);
152 constexpr bool IsVoid() const { return !!(mDataFlags & DataFlags::VOIDED); }
154 constexpr bool IsTerminated() const {
155 return !!(mDataFlags & DataFlags::TERMINATED);
158 constexpr char_type CharAt(index_type aIndex) const {
159 NS_ASSERTION(aIndex < mLength, "index exceeds allowable range");
160 return mData[aIndex];
163 constexpr char_type operator[](index_type aIndex) const {
164 return CharAt(aIndex);
167 char_type First() const;
169 char_type Last() const;
171 size_type NS_FASTCALL CountChar(char_type) const;
172 int32_t NS_FASTCALL FindChar(char_type, index_type aOffset = 0) const;
174 bool Contains(char_type aChar) const;
176 // Equality.
177 bool NS_FASTCALL Equals(const self_type&) const;
178 bool NS_FASTCALL Equals(const self_type&, comparator_type) const;
180 bool NS_FASTCALL Equals(const substring_tuple_type& aTuple) const;
181 bool NS_FASTCALL Equals(const substring_tuple_type& aTuple,
182 comparator_type) const;
184 bool NS_FASTCALL Equals(const char_type* aData) const;
185 bool NS_FASTCALL Equals(const char_type* aData, comparator_type) const;
188 * Compares a given string to this string.
190 * @param aString is the string to be compared
191 * @param aIgnoreCase tells us how to treat case
192 * @param aCount tells us how many chars to compare
193 * @return -1,0,1
195 template <typename Q = T, typename EnableIfChar = mozilla::CharOnlyT<Q>>
196 int32_t Compare(const char_type* aString, bool aIgnoreCase = false,
197 int32_t aCount = -1) const;
200 * Equality check between given string and this string.
202 * @param aString is the string to check
203 * @param aIgnoreCase tells us how to treat case
204 * @param aCount tells us how many chars to compare
205 * @return boolean
207 template <typename Q = T, typename EnableIfChar = mozilla::CharOnlyT<Q>>
208 bool EqualsIgnoreCase(const char_type* aString, int32_t aCount = -1) const {
209 return Compare(aString, true, aCount) == 0;
212 template <typename Q = T, typename EnableIfChar16 = mozilla::Char16OnlyT<Q>>
213 bool EqualsIgnoreCase(const incompatible_char_type* aString,
214 int32_t aCount = -1) const;
216 #if defined(MOZ_USE_CHAR16_WRAPPER)
217 template <typename Q = T, typename EnableIfChar16 = Char16OnlyT<Q>>
218 bool NS_FASTCALL Equals(char16ptr_t aData) const {
219 return Equals(static_cast<const char16_t*>(aData));
221 template <typename Q = T, typename EnableIfChar16 = Char16OnlyT<Q>>
222 bool NS_FASTCALL Equals(char16ptr_t aData, comparator_type aComp) const {
223 return Equals(static_cast<const char16_t*>(aData), aComp);
225 #endif
227 // An efficient comparison with ASCII that can be used even
228 // for wide strings. Call this version when you know the
229 // length of 'data'.
230 bool NS_FASTCALL EqualsASCII(const char* aData, size_type aLen) const;
231 // An efficient comparison with ASCII that can be used even
232 // for wide strings. Call this version when 'data' is
233 // null-terminated.
234 bool NS_FASTCALL EqualsASCII(const char* aData) const;
236 // An efficient comparison with Latin1 characters that can be used even for
237 // wide strings.
238 bool EqualsLatin1(const char* aData, size_type aLength) const;
240 // EqualsLiteral must ONLY be called with an actual literal string, or
241 // a char array *constant* declared without an explicit size and with an
242 // initializer that is a string literal or is otherwise null-terminated.
243 // Use EqualsASCII for other char array variables.
244 // (Although this method may happen to produce expected results for other
245 // char arrays that have bound one greater than the sequence of interest,
246 // such use is discouraged for reasons of readability and maintainability.)
247 // The template trick to acquire the array bound at compile time without
248 // using a macro is due to Corey Kosak, with much thanks.
249 template <int N>
250 inline bool EqualsLiteral(const char (&aStr)[N]) const {
251 return EqualsASCII(aStr, N - 1);
254 // EqualsLiteral must ONLY be called with an actual literal string, or
255 // a char array *constant* declared without an explicit size and with an
256 // initializer that is a string literal or is otherwise null-terminated.
257 // Use EqualsASCII for other char array variables.
258 // (Although this method may happen to produce expected results for other
259 // char arrays that have bound one greater than the sequence of interest,
260 // such use is discouraged for reasons of readability and maintainability.)
261 // The template trick to acquire the array bound at compile time without
262 // using a macro is due to Corey Kosak, with much thanks.
263 template <size_t N, typename = std::enable_if_t<!std::is_same_v<
264 const char (&)[N], const char_type (&)[N]>>>
265 inline bool EqualsLiteral(const char_type (&aStr)[N]) const {
266 return *this == nsTLiteralString<char_type>(aStr);
269 // The LowerCaseEquals methods compare the ASCII-lowercase version of
270 // this string (lowercasing only ASCII uppercase characters) to some
271 // ASCII/Literal string. The ASCII string is *not* lowercased for
272 // you. If you compare to an ASCII or literal string that contains an
273 // uppercase character, it is guaranteed to return false. We will
274 // throw assertions too.
275 bool NS_FASTCALL LowerCaseEqualsASCII(const char* aData,
276 size_type aLen) const;
277 bool NS_FASTCALL LowerCaseEqualsASCII(const char* aData) const;
279 // LowerCaseEqualsLiteral must ONLY be called with an actual literal string,
280 // or a char array *constant* declared without an explicit size and with an
281 // initializer that is a string literal or is otherwise null-terminated.
282 // Use LowerCaseEqualsASCII for other char array variables.
283 // (Although this method may happen to produce expected results for other
284 // char arrays that have bound one greater than the sequence of interest,
285 // such use is discouraged for reasons of readability and maintainability.)
286 template <int N>
287 bool LowerCaseEqualsLiteral(const char (&aStr)[N]) const {
288 return LowerCaseEqualsASCII(aStr, N - 1);
291 // Returns true if this string overlaps with the given string fragment.
292 bool IsDependentOn(const char_type* aStart, const char_type* aEnd) const {
293 // If it _isn't_ the case that one fragment starts after the other ends,
294 // or ends before the other starts, then, they conflict:
296 // !(f2.begin >= f1.aEnd || f2.aEnd <= f1.begin)
298 // Simplified, that gives us (To avoid relying on Undefined Behavior
299 // from comparing pointers from different allocations (which in
300 // principle gives the optimizer the permission to assume elsewhere
301 // that the pointers are from the same allocation), the comparisons
302 // are done on integers, which merely relies on implementation-defined
303 // behavior of converting pointers to integers. std::less and
304 // std::greater implementations don't actually provide the guarantees
305 // that they should.):
306 return (reinterpret_cast<uintptr_t>(aStart) <
307 reinterpret_cast<uintptr_t>(mData + mLength) &&
308 reinterpret_cast<uintptr_t>(aEnd) >
309 reinterpret_cast<uintptr_t>(mData));
312 protected:
313 nsTStringRepr() = delete; // Never instantiate directly
315 constexpr nsTStringRepr(char_type* aData, size_type aLength,
316 DataFlags aDataFlags, ClassFlags aClassFlags)
317 : mData(aData),
318 mLength(aLength),
319 mDataFlags(aDataFlags),
320 mClassFlags(aClassFlags) {}
322 char_type* mData;
323 size_type mLength;
324 DataFlags mDataFlags;
325 ClassFlags const mClassFlags;
328 extern template class nsTStringRepr<char>;
329 extern template class nsTStringRepr<char16_t>;
331 } // namespace detail
332 } // namespace mozilla
334 template <typename T>
335 int NS_FASTCALL Compare(const mozilla::detail::nsTStringRepr<T>& aLhs,
336 const mozilla::detail::nsTStringRepr<T>& aRhs,
337 nsTStringComparator<T> = nsTDefaultStringComparator<T>);
339 extern template int NS_FASTCALL Compare<char>(
340 const mozilla::detail::nsTStringRepr<char>&,
341 const mozilla::detail::nsTStringRepr<char>&, nsTStringComparator<char>);
343 extern template int NS_FASTCALL
344 Compare<char16_t>(const mozilla::detail::nsTStringRepr<char16_t>&,
345 const mozilla::detail::nsTStringRepr<char16_t>&,
346 nsTStringComparator<char16_t>);
348 template <typename T>
349 inline constexpr bool operator!=(
350 const mozilla::detail::nsTStringRepr<T>& aLhs,
351 const mozilla::detail::nsTStringRepr<T>& aRhs) {
352 return !aLhs.Equals(aRhs);
355 template <typename T>
356 inline constexpr bool operator!=(const mozilla::detail::nsTStringRepr<T>& aLhs,
357 const T* aRhs) {
358 return !aLhs.Equals(aRhs);
361 template <typename T>
362 inline bool operator<(const mozilla::detail::nsTStringRepr<T>& aLhs,
363 const mozilla::detail::nsTStringRepr<T>& aRhs) {
364 return Compare(aLhs, aRhs) < 0;
367 template <typename T>
368 inline bool operator<=(const mozilla::detail::nsTStringRepr<T>& aLhs,
369 const mozilla::detail::nsTStringRepr<T>& aRhs) {
370 return Compare(aLhs, aRhs) <= 0;
373 template <typename T>
374 inline bool operator==(const mozilla::detail::nsTStringRepr<T>& aLhs,
375 const mozilla::detail::nsTStringRepr<T>& aRhs) {
376 return aLhs.Equals(aRhs);
379 template <typename T>
380 inline bool operator==(const mozilla::detail::nsTStringRepr<T>& aLhs,
381 const T* aRhs) {
382 return aLhs.Equals(aRhs);
385 template <typename T>
386 inline bool operator>=(const mozilla::detail::nsTStringRepr<T>& aLhs,
387 const mozilla::detail::nsTStringRepr<T>& aRhs) {
388 return Compare(aLhs, aRhs) >= 0;
391 template <typename T>
392 inline bool operator>(const mozilla::detail::nsTStringRepr<T>& aLhs,
393 const mozilla::detail::nsTStringRepr<T>& aRhs) {
394 return Compare(aLhs, aRhs) > 0;
397 #endif