1 /* 2 ============================================================================== 3 4 This file is part of the JUCE library. 5 Copyright (c) 2020 - Raw Material Software Limited 6 7 JUCE is an open source library subject to commercial or open-source 8 licensing. 9 10 The code included in this file is provided under the terms of the ISC license 11 http://www.isc.org/downloads/software-support-policy/isc-license. Permission 12 To use, copy, modify, and/or distribute this software for any purpose with or 13 without fee is hereby granted provided that the above copyright notice and 14 this permission notice appear in all copies. 15 16 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER 17 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE 18 DISCLAIMED. 19 20 ============================================================================== 21 */ 22 23 namespace juce 24 { 25 26 //============================================================================== 27 /** 28 Wraps a pointer to a null-terminated UTF-32 character string, and provides 29 various methods to operate on the data. 30 @see CharPointer_UTF8, CharPointer_UTF16 31 32 @tags{Core} 33 */ 34 class CharPointer_UTF32 final 35 { 36 public: 37 using CharType = juce_wchar; 38 CharPointer_UTF32(const CharType * rawPointer)39 inline explicit CharPointer_UTF32 (const CharType* rawPointer) noexcept 40 : data (const_cast<CharType*> (rawPointer)) 41 { 42 } 43 44 inline CharPointer_UTF32 (const CharPointer_UTF32& other) = default; 45 46 inline CharPointer_UTF32 operator= (CharPointer_UTF32 other) noexcept 47 { 48 data = other.data; 49 return *this; 50 } 51 52 inline CharPointer_UTF32 operator= (const CharType* text) noexcept 53 { 54 data = const_cast<CharType*> (text); 55 return *this; 56 } 57 58 /** This is a pointer comparison, it doesn't compare the actual text. */ 59 inline bool operator== (CharPointer_UTF32 other) const noexcept { return data == other.data; } 60 inline bool operator!= (CharPointer_UTF32 other) const noexcept { return data != other.data; } 61 inline bool operator<= (CharPointer_UTF32 other) const noexcept { return data <= other.data; } 62 inline bool operator< (CharPointer_UTF32 other) const noexcept { return data < other.data; } 63 inline bool operator>= (CharPointer_UTF32 other) const noexcept { return data >= other.data; } 64 inline bool operator> (CharPointer_UTF32 other) const noexcept { return data > other.data; } 65 66 /** Returns the address that this pointer is pointing to. */ getAddress()67 inline CharType* getAddress() const noexcept { return data; } 68 69 /** Returns the address that this pointer is pointing to. */ 70 inline operator const CharType*() const noexcept { return data; } 71 72 /** Returns true if this pointer is pointing to a null character. */ isEmpty()73 inline bool isEmpty() const noexcept { return *data == 0; } 74 75 /** Returns true if this pointer is not pointing to a null character. */ isNotEmpty()76 inline bool isNotEmpty() const noexcept { return *data != 0; } 77 78 /** Returns the unicode character that this pointer is pointing to. */ 79 inline juce_wchar operator*() const noexcept { return *data; } 80 81 /** Moves this pointer along to the next character in the string. */ 82 inline CharPointer_UTF32 operator++() noexcept 83 { 84 ++data; 85 return *this; 86 } 87 88 /** Moves this pointer to the previous character in the string. */ 89 inline CharPointer_UTF32 operator--() noexcept 90 { 91 --data; 92 return *this; 93 } 94 95 /** Returns the character that this pointer is currently pointing to, and then 96 advances the pointer to point to the next character. */ getAndAdvance()97 inline juce_wchar getAndAdvance() noexcept { return *data++; } 98 99 /** Moves this pointer along to the next character in the string. */ 100 CharPointer_UTF32 operator++ (int) noexcept 101 { 102 auto temp (*this); 103 ++data; 104 return temp; 105 } 106 107 /** Moves this pointer forwards by the specified number of characters. */ 108 inline void operator+= (int numToSkip) noexcept 109 { 110 data += numToSkip; 111 } 112 113 inline void operator-= (int numToSkip) noexcept 114 { 115 data -= numToSkip; 116 } 117 118 /** Returns the character at a given character index from the start of the string. */ 119 inline juce_wchar& operator[] (int characterIndex) const noexcept 120 { 121 return data [characterIndex]; 122 } 123 124 /** Returns a pointer which is moved forwards from this one by the specified number of characters. */ 125 CharPointer_UTF32 operator+ (int numToSkip) const noexcept 126 { 127 return CharPointer_UTF32 (data + numToSkip); 128 } 129 130 /** Returns a pointer which is moved backwards from this one by the specified number of characters. */ 131 CharPointer_UTF32 operator- (int numToSkip) const noexcept 132 { 133 return CharPointer_UTF32 (data - numToSkip); 134 } 135 136 /** Writes a unicode character to this string, and advances this pointer to point to the next position. */ write(juce_wchar charToWrite)137 inline void write (juce_wchar charToWrite) noexcept 138 { 139 *data++ = charToWrite; 140 } 141 replaceChar(juce_wchar newChar)142 inline void replaceChar (juce_wchar newChar) noexcept 143 { 144 *data = newChar; 145 } 146 147 /** Writes a null character to this string (leaving the pointer's position unchanged). */ writeNull()148 inline void writeNull() const noexcept 149 { 150 *data = 0; 151 } 152 153 /** Returns the number of characters in this string. */ length()154 size_t length() const noexcept 155 { 156 #if JUCE_NATIVE_WCHAR_IS_UTF32 && ! JUCE_ANDROID 157 return wcslen (data); 158 #else 159 size_t n = 0; 160 while (data[n] != 0) 161 ++n; 162 return n; 163 #endif 164 } 165 166 /** Returns the number of characters in this string, or the given value, whichever is lower. */ lengthUpTo(size_t maxCharsToCount)167 size_t lengthUpTo (size_t maxCharsToCount) const noexcept 168 { 169 return CharacterFunctions::lengthUpTo (*this, maxCharsToCount); 170 } 171 172 /** Returns the number of characters in this string, or up to the given end pointer, whichever is lower. */ lengthUpTo(CharPointer_UTF32 end)173 size_t lengthUpTo (CharPointer_UTF32 end) const noexcept 174 { 175 return CharacterFunctions::lengthUpTo (*this, end); 176 } 177 178 /** Returns the number of bytes that are used to represent this string. 179 This includes the terminating null character. 180 */ sizeInBytes()181 size_t sizeInBytes() const noexcept 182 { 183 return sizeof (CharType) * (length() + 1); 184 } 185 186 /** Returns the number of bytes that would be needed to represent the given 187 unicode character in this encoding format. 188 */ getBytesRequiredFor(juce_wchar)189 static size_t getBytesRequiredFor (juce_wchar) noexcept 190 { 191 return sizeof (CharType); 192 } 193 194 /** Returns the number of bytes that would be needed to represent the given 195 string in this encoding format. 196 The value returned does NOT include the terminating null character. 197 */ 198 template <class CharPointer> getBytesRequiredFor(CharPointer text)199 static size_t getBytesRequiredFor (CharPointer text) noexcept 200 { 201 return sizeof (CharType) * text.length(); 202 } 203 204 /** Returns a pointer to the null character that terminates this string. */ findTerminatingNull()205 CharPointer_UTF32 findTerminatingNull() const noexcept 206 { 207 return CharPointer_UTF32 (data + length()); 208 } 209 210 /** Copies a source string to this pointer, advancing this pointer as it goes. */ 211 template <typename CharPointer> writeAll(CharPointer src)212 void writeAll (CharPointer src) noexcept 213 { 214 CharacterFunctions::copyAll (*this, src); 215 } 216 217 /** Copies a source string to this pointer, advancing this pointer as it goes. */ writeAll(CharPointer_UTF32 src)218 void writeAll (CharPointer_UTF32 src) noexcept 219 { 220 auto* s = src.data; 221 222 while ((*data = *s) != 0) 223 { 224 ++data; 225 ++s; 226 } 227 } 228 229 /** Copies a source string to this pointer, advancing this pointer as it goes. 230 The maxDestBytes parameter specifies the maximum number of bytes that can be written 231 to the destination buffer before stopping. 232 */ 233 template <typename CharPointer> writeWithDestByteLimit(CharPointer src,size_t maxDestBytes)234 size_t writeWithDestByteLimit (CharPointer src, size_t maxDestBytes) noexcept 235 { 236 return CharacterFunctions::copyWithDestByteLimit (*this, src, maxDestBytes); 237 } 238 239 /** Copies a source string to this pointer, advancing this pointer as it goes. 240 The maxChars parameter specifies the maximum number of characters that can be 241 written to the destination buffer before stopping (including the terminating null). 242 */ 243 template <typename CharPointer> writeWithCharLimit(CharPointer src,int maxChars)244 void writeWithCharLimit (CharPointer src, int maxChars) noexcept 245 { 246 CharacterFunctions::copyWithCharLimit (*this, src, maxChars); 247 } 248 249 /** Compares this string with another one. */ 250 template <typename CharPointer> compare(CharPointer other)251 int compare (CharPointer other) const noexcept 252 { 253 return CharacterFunctions::compare (*this, other); 254 } 255 256 #if JUCE_NATIVE_WCHAR_IS_UTF32 && ! JUCE_ANDROID 257 /** Compares this string with another one. */ compare(CharPointer_UTF32 other)258 int compare (CharPointer_UTF32 other) const noexcept 259 { 260 return wcscmp (data, other.data); 261 } 262 #endif 263 264 /** Compares this string with another one, up to a specified number of characters. */ 265 template <typename CharPointer> compareUpTo(CharPointer other,int maxChars)266 int compareUpTo (CharPointer other, int maxChars) const noexcept 267 { 268 return CharacterFunctions::compareUpTo (*this, other, maxChars); 269 } 270 271 /** Compares this string with another one. */ 272 template <typename CharPointer> compareIgnoreCase(CharPointer other)273 int compareIgnoreCase (CharPointer other) const 274 { 275 return CharacterFunctions::compareIgnoreCase (*this, other); 276 } 277 278 /** Compares this string with another one, up to a specified number of characters. */ 279 template <typename CharPointer> compareIgnoreCaseUpTo(CharPointer other,int maxChars)280 int compareIgnoreCaseUpTo (CharPointer other, int maxChars) const noexcept 281 { 282 return CharacterFunctions::compareIgnoreCaseUpTo (*this, other, maxChars); 283 } 284 285 /** Returns the character index of a substring, or -1 if it isn't found. */ 286 template <typename CharPointer> indexOf(CharPointer stringToFind)287 int indexOf (CharPointer stringToFind) const noexcept 288 { 289 return CharacterFunctions::indexOf (*this, stringToFind); 290 } 291 292 /** Returns the character index of a unicode character, or -1 if it isn't found. */ indexOf(juce_wchar charToFind)293 int indexOf (juce_wchar charToFind) const noexcept 294 { 295 int i = 0; 296 297 while (data[i] != 0) 298 { 299 if (data[i] == charToFind) 300 return i; 301 302 ++i; 303 } 304 305 return -1; 306 } 307 308 /** Returns the character index of a unicode character, or -1 if it isn't found. */ indexOf(juce_wchar charToFind,bool ignoreCase)309 int indexOf (juce_wchar charToFind, bool ignoreCase) const noexcept 310 { 311 return ignoreCase ? CharacterFunctions::indexOfCharIgnoreCase (*this, charToFind) 312 : CharacterFunctions::indexOfChar (*this, charToFind); 313 } 314 315 /** Returns true if the first character of this string is whitespace. */ isWhitespace()316 bool isWhitespace() const { return CharacterFunctions::isWhitespace (*data) != 0; } 317 /** Returns true if the first character of this string is a digit. */ isDigit()318 bool isDigit() const { return CharacterFunctions::isDigit (*data) != 0; } 319 /** Returns true if the first character of this string is a letter. */ isLetter()320 bool isLetter() const { return CharacterFunctions::isLetter (*data) != 0; } 321 /** Returns true if the first character of this string is a letter or digit. */ isLetterOrDigit()322 bool isLetterOrDigit() const { return CharacterFunctions::isLetterOrDigit (*data) != 0; } 323 /** Returns true if the first character of this string is upper-case. */ isUpperCase()324 bool isUpperCase() const { return CharacterFunctions::isUpperCase (*data) != 0; } 325 /** Returns true if the first character of this string is lower-case. */ isLowerCase()326 bool isLowerCase() const { return CharacterFunctions::isLowerCase (*data) != 0; } 327 328 /** Returns an upper-case version of the first character of this string. */ toUpperCase()329 juce_wchar toUpperCase() const noexcept { return CharacterFunctions::toUpperCase (*data); } 330 /** Returns a lower-case version of the first character of this string. */ toLowerCase()331 juce_wchar toLowerCase() const noexcept { return CharacterFunctions::toLowerCase (*data); } 332 333 /** Parses this string as a 32-bit integer. */ getIntValue32()334 int getIntValue32() const noexcept { return CharacterFunctions::getIntValue <int, CharPointer_UTF32> (*this); } 335 /** Parses this string as a 64-bit integer. */ getIntValue64()336 int64 getIntValue64() const noexcept { return CharacterFunctions::getIntValue <int64, CharPointer_UTF32> (*this); } 337 338 /** Parses this string as a floating point double. */ getDoubleValue()339 double getDoubleValue() const noexcept { return CharacterFunctions::getDoubleValue (*this); } 340 341 /** Returns the first non-whitespace character in the string. */ findEndOfWhitespace()342 CharPointer_UTF32 findEndOfWhitespace() const noexcept { return CharacterFunctions::findEndOfWhitespace (*this); } 343 344 /** Move this pointer to the first non-whitespace character in the string. */ incrementToEndOfWhitespace()345 void incrementToEndOfWhitespace() noexcept { CharacterFunctions::incrementToEndOfWhitespace (*this); } 346 347 /** Returns true if the given unicode character can be represented in this encoding. */ canRepresent(juce_wchar character)348 static bool canRepresent (juce_wchar character) noexcept 349 { 350 return ((uint32) character) < (uint32) 0x10ffff; 351 } 352 353 /** Returns true if this data contains a valid string in this encoding. */ isValidString(const CharType * dataToTest,int maxBytesToRead)354 static bool isValidString (const CharType* dataToTest, int maxBytesToRead) 355 { 356 maxBytesToRead /= (int) sizeof (CharType); 357 358 while (--maxBytesToRead >= 0 && *dataToTest != 0) 359 if (! canRepresent (*dataToTest++)) 360 return false; 361 362 return true; 363 } 364 365 /** Atomically swaps this pointer for a new value, returning the previous value. */ atomicSwap(CharPointer_UTF32 newValue)366 CharPointer_UTF32 atomicSwap (CharPointer_UTF32 newValue) 367 { 368 return CharPointer_UTF32 (reinterpret_cast<Atomic<CharType*>&> (data).exchange (newValue.data)); 369 } 370 371 private: 372 CharType* data; 373 }; 374 375 } // namespace juce 376