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> 18 class nsTSubstringTuple; 19 template <typename T> 20 class nsTLiteralString; 21 22 // The base for string comparators 23 template <typename T> 24 class nsTStringComparator { 25 public: 26 typedef T char_type; 27 nsTStringComparator()28 nsTStringComparator() {} 29 30 virtual int operator()(const char_type*, const char_type*, uint32_t, 31 uint32_t) const = 0; 32 }; 33 34 // The default string comparator (case-sensitive comparision) 35 template <typename T> 36 class nsTDefaultStringComparator : public nsTStringComparator<T> { 37 public: 38 typedef T char_type; 39 nsTDefaultStringComparator()40 nsTDefaultStringComparator() {} 41 42 virtual int operator()(const char_type*, const char_type*, uint32_t, 43 uint32_t) const override; 44 }; 45 46 extern template class nsTDefaultStringComparator<char>; 47 extern template class nsTDefaultStringComparator<char16_t>; 48 49 namespace mozilla { 50 51 // This is mainly intended to be used in the context of nsTStrings where 52 // we want to enable a specific function only for a given character class. In 53 // order for this technique to work the member function needs to be templated 54 // on something other than `T`. We keep this in the `mozilla` namespace rather 55 // than `nsTStringRepr` as it's intentionally not dependent on `T`. 56 // 57 // The 'T' at the end of `Char[16]OnlyT` is refering to the `::type` portion 58 // which will only be defined if the character class is correct. This is similar 59 // to `std::enable_if_t` which is available in C++14, but not C++11. 60 // 61 // `CharType` is generally going to be a shadowed type of `T`. 62 // 63 // Example usage of a function that will only be defined if `T` == `char`: 64 // 65 // template <typename T> 66 // class nsTSubstring : public nsTStringRepr<T> { 67 // template <typename Q = T, typename EnableForChar = typename CharOnlyT<Q>> 68 // int Foo() { return 42; } 69 // }; 70 // 71 // Please note that we had to use a separate type `Q` for this to work. You 72 // will get a semi-decent compiler error if you use `T` directly. 73 74 template <typename CharType> 75 using CharOnlyT = 76 typename std::enable_if<std::is_same<char, CharType>::value>::type; 77 78 template <typename CharType> 79 using Char16OnlyT = 80 typename std::enable_if<std::is_same<char16_t, CharType>::value>::type; 81 82 namespace detail { 83 84 // nsTStringRepr defines a string's memory layout and some accessor methods. 85 // This class exists so that nsTLiteralString can avoid inheriting 86 // nsTSubstring's destructor. All methods on this class must be const because 87 // literal strings are not writable. 88 // 89 // This class is an implementation detail and should not be instantiated 90 // directly, nor used in any way outside of the string code itself. It is 91 // buried in a namespace to discourage its use in function parameters. 92 // If you need to take a parameter, use [const] ns[C]Substring&. 93 // If you need to instantiate a string, use ns[C]String or descendents. 94 // 95 // NAMES: 96 // nsStringRepr for wide characters 97 // nsCStringRepr for narrow characters 98 template <typename T> 99 class nsTStringRepr { 100 public: 101 typedef mozilla::fallible_t fallible_t; 102 103 typedef T char_type; 104 105 typedef nsCharTraits<char_type> char_traits; 106 typedef typename char_traits::incompatible_char_type incompatible_char_type; 107 108 typedef nsTStringRepr<T> self_type; 109 typedef self_type base_string_type; 110 111 typedef nsTSubstring<T> substring_type; 112 typedef nsTSubstringTuple<T> substring_tuple_type; 113 typedef nsTLiteralString<T> literalstring_type; 114 115 typedef nsReadingIterator<char_type> const_iterator; 116 typedef nsWritingIterator<char_type> iterator; 117 118 typedef nsTStringComparator<char_type> comparator_type; 119 120 typedef char_type* char_iterator; 121 typedef const char_type* const_char_iterator; 122 123 typedef uint32_t index_type; 124 typedef uint32_t size_type; 125 126 // These are only for internal use within the string classes: 127 typedef StringDataFlags DataFlags; 128 typedef StringClassFlags ClassFlags; 129 130 // Reading iterators. BeginReading()131 const_char_iterator BeginReading() const { return mData; } EndReading()132 const_char_iterator EndReading() const { return mData + mLength; } 133 134 // Deprecated reading iterators. BeginReading(const_iterator & aIter)135 const_iterator& BeginReading(const_iterator& aIter) const { 136 aIter.mStart = mData; 137 aIter.mEnd = mData + mLength; 138 aIter.mPosition = aIter.mStart; 139 return aIter; 140 } 141 EndReading(const_iterator & aIter)142 const_iterator& EndReading(const_iterator& aIter) const { 143 aIter.mStart = mData; 144 aIter.mEnd = mData + mLength; 145 aIter.mPosition = aIter.mEnd; 146 return aIter; 147 } 148 BeginReading(const_char_iterator & aIter)149 const_char_iterator& BeginReading(const_char_iterator& aIter) const { 150 return aIter = mData; 151 } 152 EndReading(const_char_iterator & aIter)153 const_char_iterator& EndReading(const_char_iterator& aIter) const { 154 return aIter = mData + mLength; 155 } 156 157 // Accessors. 158 template <typename U, typename Dummy> 159 struct raw_type { 160 typedef const U* type; 161 }; 162 #if defined(MOZ_USE_CHAR16_WRAPPER) 163 template <typename Dummy> 164 struct raw_type<char16_t, Dummy> { 165 typedef char16ptr_t type; 166 }; 167 #endif 168 169 // Returns pointer to string data (not necessarily null-terminated) 170 const typename raw_type<T, int>::type Data() const { return mData; } 171 172 size_type Length() const { return mLength; } 173 174 DataFlags GetDataFlags() const { return mDataFlags; } 175 176 bool IsEmpty() const { return mLength == 0; } 177 178 bool IsLiteral() const { return !!(mDataFlags & DataFlags::LITERAL); } 179 180 bool IsVoid() const { return !!(mDataFlags & DataFlags::VOIDED); } 181 182 bool IsTerminated() const { return !!(mDataFlags & DataFlags::TERMINATED); } 183 184 char_type CharAt(index_type aIndex) const { 185 NS_ASSERTION(aIndex < mLength, "index exceeds allowable range"); 186 return mData[aIndex]; 187 } 188 189 char_type operator[](index_type aIndex) const { return CharAt(aIndex); } 190 191 char_type First() const; 192 193 char_type Last() const; 194 195 size_type NS_FASTCALL CountChar(char_type) const; 196 int32_t NS_FASTCALL FindChar(char_type, index_type aOffset = 0) const; 197 198 inline bool Contains(char_type aChar) const { 199 return FindChar(aChar) != kNotFound; 200 } 201 202 // Equality. 203 bool NS_FASTCALL Equals(const self_type&) const; 204 bool NS_FASTCALL Equals(const self_type&, const comparator_type&) const; 205 206 bool NS_FASTCALL Equals(const substring_tuple_type& aTuple) const; 207 bool NS_FASTCALL Equals(const substring_tuple_type& aTuple, 208 const comparator_type& aComp) const; 209 210 bool NS_FASTCALL Equals(const char_type* aData) const; 211 bool NS_FASTCALL Equals(const char_type* aData, 212 const comparator_type& aComp) const; 213 214 #if defined(MOZ_USE_CHAR16_WRAPPER) 215 template <typename Q = T, typename EnableIfChar16 = Char16OnlyT<Q>> 216 bool NS_FASTCALL Equals(char16ptr_t aData) const { 217 return Equals(static_cast<const char16_t*>(aData)); 218 } 219 template <typename Q = T, typename EnableIfChar16 = Char16OnlyT<Q>> 220 bool NS_FASTCALL Equals(char16ptr_t aData, 221 const comparator_type& aComp) const { 222 return Equals(static_cast<const char16_t*>(aData), aComp); 223 } 224 #endif 225 226 // An efficient comparison with ASCII that can be used even 227 // for wide strings. Call this version when you know the 228 // length of 'data'. 229 bool NS_FASTCALL EqualsASCII(const char* aData, size_type aLen) const; 230 // An efficient comparison with ASCII that can be used even 231 // for wide strings. Call this version when 'data' is 232 // null-terminated. 233 bool NS_FASTCALL EqualsASCII(const char* aData) const; 234 235 // EqualsLiteral must ONLY be applied to an actual literal string, or 236 // a char array *constant* declared without an explicit size. 237 // Do not attempt to use it with a regular char* pointer, or with a 238 // non-constant char array variable. Use EqualsASCII for them. 239 // The template trick to acquire the array length at compile time without 240 // using a macro is due to Corey Kosak, with much thanks. 241 template <int N> 242 inline bool EqualsLiteral(const char (&aStr)[N]) const { 243 return EqualsASCII(aStr, N - 1); 244 } 245 246 // The LowerCaseEquals methods compare the ASCII-lowercase version of 247 // this string (lowercasing only ASCII uppercase characters) to some 248 // ASCII/Literal string. The ASCII string is *not* lowercased for 249 // you. If you compare to an ASCII or literal string that contains an 250 // uppercase character, it is guaranteed to return false. We will 251 // throw assertions too. 252 bool NS_FASTCALL LowerCaseEqualsASCII(const char* aData, 253 size_type aLen) const; 254 bool NS_FASTCALL LowerCaseEqualsASCII(const char* aData) const; 255 256 // LowerCaseEqualsLiteral must ONLY be applied to an actual 257 // literal string, or a char array *constant* declared without an 258 // explicit size. Do not attempt to use it with a regular char* 259 // pointer, or with a non-constant char array variable. Use 260 // LowerCaseEqualsASCII for them. 261 template <int N> 262 bool LowerCaseEqualsLiteral(const char (&aStr)[N]) const { 263 return LowerCaseEqualsASCII(aStr, N - 1); 264 } 265 266 // Returns true if this string overlaps with the given string fragment. 267 bool IsDependentOn(const char_type* aStart, const char_type* aEnd) const { 268 // If it _isn't_ the case that one fragment starts after the other ends, 269 // or ends before the other starts, then, they conflict: 270 // 271 // !(f2.begin >= f1.aEnd || f2.aEnd <= f1.begin) 272 // 273 // Simplified, that gives us: 274 return (aStart < (mData + mLength) && aEnd > mData); 275 } 276 277 protected: 278 nsTStringRepr() = delete; // Never instantiate directly 279 280 constexpr nsTStringRepr(char_type* aData, size_type aLength, 281 DataFlags aDataFlags, ClassFlags aClassFlags) 282 : mData(aData), 283 mLength(aLength), 284 mDataFlags(aDataFlags), 285 mClassFlags(aClassFlags) {} 286 287 char_type* mData; 288 size_type mLength; 289 DataFlags mDataFlags; 290 ClassFlags const mClassFlags; 291 }; 292 293 extern template class nsTStringRepr<char>; 294 extern template class nsTStringRepr<char16_t>; 295 296 } // namespace detail 297 } // namespace mozilla 298 299 template <typename T> 300 int NS_FASTCALL 301 Compare(const mozilla::detail::nsTStringRepr<T>& aLhs, 302 const mozilla::detail::nsTStringRepr<T>& aRhs, 303 const nsTStringComparator<T>& = nsTDefaultStringComparator<T>()); 304 305 template <typename T> 306 inline bool operator!=(const mozilla::detail::nsTStringRepr<T>& aLhs, 307 const mozilla::detail::nsTStringRepr<T>& aRhs) { 308 return !aLhs.Equals(aRhs); 309 } 310 311 template <typename T> 312 inline bool operator!=(const mozilla::detail::nsTStringRepr<T>& aLhs, 313 const T* aRhs) { 314 return !aLhs.Equals(aRhs); 315 } 316 317 template <typename T> 318 inline bool operator<(const mozilla::detail::nsTStringRepr<T>& aLhs, 319 const mozilla::detail::nsTStringRepr<T>& aRhs) { 320 return Compare(aLhs, aRhs) < 0; 321 } 322 323 template <typename T> 324 inline bool operator<=(const mozilla::detail::nsTStringRepr<T>& aLhs, 325 const mozilla::detail::nsTStringRepr<T>& aRhs) { 326 return Compare(aLhs, aRhs) <= 0; 327 } 328 329 template <typename T> 330 inline bool operator==(const mozilla::detail::nsTStringRepr<T>& aLhs, 331 const mozilla::detail::nsTStringRepr<T>& aRhs) { 332 return aLhs.Equals(aRhs); 333 } 334 335 template <typename T> 336 inline bool operator==(const mozilla::detail::nsTStringRepr<T>& aLhs, 337 const T* aRhs) { 338 return aLhs.Equals(aRhs); 339 } 340 341 template <typename T> 342 inline bool operator>=(const mozilla::detail::nsTStringRepr<T>& aLhs, 343 const mozilla::detail::nsTStringRepr<T>& aRhs) { 344 return Compare(aLhs, aRhs) >= 0; 345 } 346 347 template <typename T> 348 inline bool operator>(const mozilla::detail::nsTStringRepr<T>& aLhs, 349 const mozilla::detail::nsTStringRepr<T>& aRhs) { 350 return Compare(aLhs, aRhs) > 0; 351 } 352 353 #endif 354