Coverage Report

Created: 2018-09-25 14:53

/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