Mercurial > projects > dwt2
view com.ibm.icu/src/com/ibm/icu/mangoicu/UString.d @ 120:536e43f63c81
Comprehensive update for Win32/Linux32 dmd-2.053/dmd-1.068+Tango-r5661
===D2===
* added [Try]Immutable/Const/Shared templates to work with differenses in D1/D2 instead of version statements
used these templates to work with strict type storage rules of dmd-2.053
* com.ibm.icu now also compilable with D2, but not tested yet
* small fixes
Snippet288 - shared data is in TLS
===Phobos===
* fixed critical bugs in Phobos implemention
completely incorrect segfault prone fromStringz (Linux's port ruthless killer)
terrible, incorrect StringBuffer realization (StyledText killer)
* fixed small bugs as well
Snippet72 - misprint in the snippet
* implemented missed functionality for Phobos
ByteArrayOutputStream implemented (image loading available)
formatting correctly works for all DWT's cases
As a result, folowing snippets now works with Phobos (Snippet### - what is fixed):
Snippet24, 42, 111, 115, 130, 235, 276 - bad string formatting
Snippet48, 282 - crash on image loading
Snippet163, 189, 211, 213, 217, 218, 222 - crash on copy/cut in StyledText
Snippet244 - hang-up
===Tango===
* few changes for the latest Tango trunc-r5661
* few small performance improvments
===General===
* implMissing-s for only one version changed to implMissingInTango/InPhobos
* incorrect calls to Format in toString-s fixed
* fixed loading \uXXXX characters in ResourceBundle
* added good UTF-8 support for StyledText, TextLayout (Win32) and friends
UTF functions revised and tested. It is now in java.nonstandard.*Utf modules
StyledText and TextLayout (Win32) modules revised for UTF-8 support
* removed small diferences in most identical files in *.swt.* folders
*.swt.internal.image, *.swt.events and *.swt.custom are identical in Win32/Linux32
now 179 of 576 (~31%) files in *.swt.* folders are fully identical
* Win32: snippets now have right subsystem, pretty icons and native system style controls
* small fixes in snippets
Snippet44 - it's not Snippet44
Snippet212 - functions work with different images and offsets arrays
Win32: Snippet282 - crash on close if the button has an image
Snippet293 - setGrayed is commented
and others
Win32: As a result, folowing snippets now works
Snippet68 - color doesn't change
Snippet163, 189, 211, 213, 217, 218, 222 - UTF-8 issues (see above)
Snippet193 - no tabel headers
author | Denis Shelomovskij <verylonglogin.reg@gmail.com> |
---|---|
date | Sat, 09 Jul 2011 15:50:20 +0300 |
parents | ebefa5c2eab4 |
children |
line wrap: on
line source
/******************************************************************************* @file UString.d Copyright (c) 2004 Kris Bell This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for damages of any kind arising from the use of this software. Permission is hereby granted to anyone to use this software for any purpose, including commercial applications, and to alter it and/or redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment within documentation of said product would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any distribution of the source. 4. Derivative works are permitted, but they must carry this notice in full and credit the original source. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @version Initial version, October 2004 @author Kris Note that this package and documentation is built around the ICU project (http://oss.software.ibm.com/icu/). Below is the license statement as specified by that software: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ICU License - ICU 1.8.1 and later COPYRIGHT AND PERMISSION NOTICE Copyright (c) 1995-2003 International Business Machines Corporation and others. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, provided that the above copyright notice(s) and this permission notice appear in all copies of the Software and that both the above copyright notice(s) and this permission notice appear in supporting documentation. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. Except as contained in this notice, the name of a copyright holder shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization of the copyright holder. ---------------------------------------------------------------------- All trademarks and registered trademarks mentioned herein are the property of their respective owners. *******************************************************************************/ module com.ibm.icu.mangoicu.UString; private import com.ibm.icu.mangoicu.ICU, com.ibm.icu.mangoicu.UChar, com.ibm.icu.mangoicu.ULocale; import java.lang.util; /******************************************************************************* *******************************************************************************/ private extern (C) void memmove (void* dst, void* src, uint bytes); /******************************************************************************* Bind to the IReadable and IWritable interfaces if we're building along with the mango.io package *******************************************************************************/ version=Isolated; version (Isolated) { private interface ITextOther {} private interface IStringOther {} } else { private import com.ibm.icu.mangoicu.UMango; private import mango.io.model.IReader, mango.io.model.IWriter; private interface ITextOther : IWritable {} private interface IStringOther : IReadable {} } /******************************************************************************* UString is a string class that stores Unicode characters directly and provides similar functionality as the Java String class. In ICU, a Unicode string consists of 16-bit Unicode code units. A Unicode character may be stored with either one code unit — which is the most common case — or with a matched pair of special code units ("surrogates"). The data type for code units is UChar. For single-character handling, a Unicode character code point is a value in the range 0..0x10ffff. ICU uses the UChar32 type for code points. Indexes and offsets into and lengths of strings always count code units, not code points. This is the same as with multi-byte char* strings in traditional string handling. Operations on partial strings typically do not test for code point boundaries. If necessary, the user needs to take care of such boundaries by testing for the code unit values or by using functions like getChar32Start() and getChar32Limit() UString methods are more lenient with regard to input parameter values than other ICU APIs. In particular: - If indexes are out of bounds for a UString object (< 0 or > length) then they are "pinned" to the nearest boundary. - If primitive string pointer values (e.g., const wchar* or char*) for input strings are null, then those input string parameters are treated as if they pointed to an empty string. However, this is not the case for char* parameters for charset names or other IDs. *******************************************************************************/ class UString : UStringView, IStringOther { alias opCat append; alias opIndexAssign setCharAt; /*********************************************************************** Create an empty UString with the specified available space ***********************************************************************/ this (uint space = 0) { content.length = space; mutable = true; } /*********************************************************************** Create a UString upon the provided content. If said content is immutable (read-only) then you might consider setting the 'mutable' parameter to false. Doing so will avoid allocating heap-space for the content until it is modified. ***********************************************************************/ this (in wchar[] content, bool mutable = true) { setTo (content, mutable); } /*********************************************************************** Create a UString via the content of a UStringView. Note that the default is to assume the content is immutable (read-only). ***********************************************************************/ this (UStringView other, bool mutable = false) { this (other.get, mutable); } /*********************************************************************** Create a UString via the content of a UString. If said content is immutable (read-only) then you might consider setting the 'mutable' parameter to false. Doing so will avoid allocating heap-space for the content until it is modified via UString methods. ***********************************************************************/ this (UString other, bool mutable = true) { this (other.get, mutable); } /*********************************************************************** Support for reading content via the IO system ***********************************************************************/ version (Isolated){} else { /*************************************************************** Internal adapter to handle loading and conversion of UString content. Once constructed, this may be used as the target for an IReader. Alternatively, invoke the load() method with an IBuffer of choice. ***************************************************************/ class UStringDecoder : StringDecoder16 { private UString s; // construct a decoder on the given UString this (UConverter c, uint bytes, UString s) { super (c, bytes); this.s = s; } // IReadable adapter to perform the conversion protected void read (IReader r) { load (r.buffer); } // read from the provided buffer until we // either have all the content, or an eof // condition throws an exception. package void load (IBuffer b) { uint produced = super.read (b, s.content); while (toGo) { s.expand (toGo); produced += super.read (b, s.content[produced..$]); } s.len = produced; } } /*************************************************************** Another constructor for loading known content length into a UString. ***************************************************************/ this (IBuffer buffer, uint contentLength, UConverter cvt) { this (contentLength); UStringDecoder sd = new UStringDecoder (cvt, contentLength, this); sd.load (buffer); } /*************************************************************** Read as many bytes from the input as is necessary to produce the expected number of wchar elements. This uses the default wchar handler, which can be altered by binding a StringDecoder to the IReader in use (see UMango for details). We're mutable, so ensure we don't mess with the IO buffers. Interestingly, changing the length of a D array will account for slice assignments (it checks the pointer to see if it's a starting point in the pool). Unfortunately, that doesn't catch the case where a slice starts at offset 0, which is where IBuffer slices may come from. To be safe, we ask the allocator in use whether the content it provided can be mutated or not. Note that this is not necessary for UStringView, since that is a read-only construct. ***************************************************************/ void read (IReader r) { r.get (content); len = content.length; mutable = r.getAllocator.isMutable (content); } /*************************************************************** Return a streaming decoder that can be used to populate this UString with a specified number of input bytes. This differs from the above read() method in the way content is read: in the above case, exactly the specified number of wchar elements will be converter from the input, whereas in this case a variable number of wchar elements are converted until 'bytes' have been read from the input. This is useful in those cases where the original number of elements has been lost, and only the resultant converted byte-count remains (a la HTTP). The returned StringDecoder is one-shot only. You may reuse it (both the converter and the byte count) via its reset() method. One applies the resultant converter directly with an IReader like so: @code UString s = ...; IReader r = ...; // r >> s.createDecoder(cvt, bytes); r.get (s.createDecoder(cvt, bytes)); @endcode which will read the specified number of bytes from the input and convert them to an appropriate number of wchars within the UString. ***************************************************************/ StringDecoder createDecoder (UConverter c, uint bytes) { return new UStringDecoder (c, bytes, this); } } /*********************************************************************** Append text to this UString ***********************************************************************/ UString opCat (UStringView other) { return opCat (other.get); } /*********************************************************************** Append partial text to this UString ***********************************************************************/ UString opCat (UStringView other, uint start, uint len=uint.max) { other.pinIndices (start, len); return opCat (other.content [start..start+len]); } /*********************************************************************** Append a single character to this UString ***********************************************************************/ UString opCat (wchar chr) { return opCat (&chr, 1); } /*********************************************************************** Append a single UTF32 unit to this UString ***********************************************************************/ UString opCat (dchar chr) { dchar[1] chars = chr; return opCat (chars); } /*********************************************************************** Append text to this UString ***********************************************************************/ UString opCat (wchar[] chars) { return opCat (chars.ptr, chars.length); } /*********************************************************************** Converts a sequence of UTF-8 bytes to UChars (UTF-16) ***********************************************************************/ UString opCat (char[] chars) { uint fmt (wchar* dst, uint len, ref UErrorCode e) { uint x; u_strFromUTF8 (dst, len, &x, chars.ptr, chars.length, e); return x; } expand (chars.length); return format (&fmt, "failed to append UTF char[]"); } /*********************************************************************** Converts a sequence of UTF32 units to UChars (UTF-16) ***********************************************************************/ UString opCat (dchar[] chars) { uint fmt (wchar* dst, uint len, ref UErrorCode e) { uint x; u_strFromUTF32 (dst, len, &x, chars.ptr, chars.length, e); return x; } expand (chars.length); return format (&fmt, "failed to append UTF dchar[]"); } /*********************************************************************** Set a section of this UString to the specified character ***********************************************************************/ UString setTo (wchar chr, uint start=0, uint len=uint.max) { pinIndices (start, len); if (! mutable) realloc (); content [start..start+len] = chr; return this; } /*********************************************************************** Set the content to the provided array. Parameter 'mutable' specifies whether the given array is likely to change. If not, the array is aliased until such time this UString is altered. ***********************************************************************/ UString setTo (in wchar[] chars, bool mutable = true) { len = chars.length; if ((this.mutable = mutable) == true) content = chars.dup; else content = cast(wchar[])chars; return this; } /*********************************************************************** Replace the content of this UString. If the new content is immutable (read-only) then you might consider setting the 'mutable' parameter to false. Doing so will avoid allocating heap-space for the content until it is modified via one of these methods. ***********************************************************************/ UString setTo (UStringView other, bool mutable = true) { return setTo (other.get, mutable); } /*********************************************************************** Replace the content of this UString. If the new content is immutable (read-only) then you might consider setting the 'mutable' parameter to false. Doing so will avoid allocating heap-space for the content until it is modified via one of these methods. ***********************************************************************/ UString setTo (UStringView other, uint start, uint len, bool mutable = true) { other.pinIndices (start, len); return setTo (other.content [start..start+len], mutable); } /*********************************************************************** Replace the character at the specified location. ***********************************************************************/ final UString opIndexAssign (wchar chr, uint index) in { if (index >= len) exception ("index of out bounds"); } body { if (! mutable) realloc (); content [index] = chr; return this; } /*********************************************************************** Remove a piece of this UString. ***********************************************************************/ UString remove (uint start, uint length=uint.max) { pinIndices (start, length); if (length) if (start >= len) truncate (start); else { if (! mutable) realloc (); uint i = start + length; memmove (&content[start], &content[i], (len-i) * wchar.sizeof); len -= length; } return this; } /*********************************************************************** Truncate the length of this UString. ***********************************************************************/ UString truncate (uint length=0) { if (length <= len) len = length; return this; } /*********************************************************************** Insert leading spaces in this UString ***********************************************************************/ UString padLeading (uint count, wchar padChar = 0x0020) { expand (count); memmove (&content[count], content.ptr, len * wchar.sizeof); len += count; return setTo (padChar, 0, count); } /*********************************************************************** Append some trailing spaces to this UString. ***********************************************************************/ UString padTrailing (uint length, wchar padChar = 0x0020) { expand (length); len += length; return setTo (padChar, len-length, length); } /*********************************************************************** Check for available space within the buffer, and expand as necessary. ***********************************************************************/ package final void expand (uint count) { if ((len + count) > content.length) realloc (count); } /*********************************************************************** Allocate memory due to a change in the content. We handle the distinction between mutable and immutable here. ***********************************************************************/ private final void realloc (uint count = 0) { uint size = (content.length + count + 63) & ~63; if (mutable) content.length = size; else { mutable = true; wchar[] x = content; content = new wchar [size]; if (len) content[0..len] = x; } } /*********************************************************************** Internal method to support UString appending ***********************************************************************/ private final UString opCat (wchar* chars, uint count) { expand (count); content[len..len+count] = chars[0..count]; len += count; return this; } /*********************************************************************** Internal method to support formatting into this UString. This is used by many of the ICU wrappers to append content into a UString. ***********************************************************************/ typedef uint delegate (wchar* dst, uint len, ref UErrorCode e) Formatter; package final UString format (Formatter format, String msg) { UErrorCode e; uint length; while (true) { e = e.OK; length = format (&content[len], content.length - len, e); if (e == e.BufferOverflow) expand (length); else break; } if (isError (e)) exception (msg); len += length; return this; } } /******************************************************************************* Immutable (read-only) text -- use UString for mutable strings. *******************************************************************************/ class UStringView : ICU, ITextOther { alias opIndex charAt; // the core of the UStringView and UString attributes. The name 'len' // is used rather than the more obvious 'length' since there is // a collision with the silly array[length] syntactic sugar ... package uint len; package wchar[] content; // this should probably be in UString only, but there seems to // be a compiler bug where it doesn't get initialised correctly, // and it's perhaps useful to have here for when a UString is // passed as a UStringView argument. private bool mutable; // toFolded() argument public enum CaseOption { Default = 0, SpecialI = 1 } /*********************************************************************** Hidden constructor ***********************************************************************/ private this () { } /*********************************************************************** Construct read-only wrapper around the given content ***********************************************************************/ this (wchar[] content) { this.content = content; this.len = content.length; } /*********************************************************************** Support for writing via the Mango IO subsystem ***********************************************************************/ version (Isolated){} else { void write (IWriter w) { w.put (get); } } /*********************************************************************** Return the valid content from this UStringView ***********************************************************************/ final package wchar[] get () { return content [0..len]; } /*********************************************************************** Is this UStringView equal to another? ***********************************************************************/ final override equals_t opEquals (Object o) { UStringView other = cast(UStringView) o; if (other) return (other is this || compare (other) == 0); return 0; } /*********************************************************************** Compare this UStringView to another. ***********************************************************************/ final override int opCmp (Object o) { UStringView other = cast(UStringView) o; if (other is this) return 0; else if (other) return compare (other); return 1; } /*********************************************************************** Hash this UStringView ***********************************************************************/ final override uint toHash () { return typeid(wchar[]).getHash (&content[0..len]); } /*********************************************************************** Clone this UStringView into a UString ***********************************************************************/ final UString copy () { return new UString (content); } /*********************************************************************** Clone a section of this UStringView into a UString ***********************************************************************/ final UString extract (uint start, uint len=uint.max) { pinIndices (start, len); return new UString (content[start..start+len]); } /*********************************************************************** Count unicode code points in the length UChar code units of the string. A code point may occupy either one or two UChar code units. Counting code points involves reading all code units. ***********************************************************************/ final uint codePoints (uint start=0, uint length=uint.max) { pinIndices (start, length); return u_countChar32 (&content[start], length); } /*********************************************************************** Return an indication whether or not there are surrogate pairs within the string. ***********************************************************************/ final bool hasSurrogates (uint start=0, uint length=uint.max) { pinIndices (start, length); return codePoints (start, length) != length; } /*********************************************************************** Return the character at the specified position. ***********************************************************************/ final wchar opIndex (uint index) in { if (index >= len) exception ("index of out bounds"); } body { return content [index]; } /*********************************************************************** Return the length of the valid content ***********************************************************************/ final uint length () { return len; } /*********************************************************************** The comparison can be done in code unit order or in code point order. They differ only in UTF-16 when comparing supplementary code points (U+10000..U+10ffff) to BMP code points near the end of the BMP (i.e., U+e000..U+ffff). In code unit order, high BMP code points sort after supplementary code points because they are stored as pairs of surrogates which are at U+d800..U+dfff. ***********************************************************************/ final int compare (UStringView other, bool codePointOrder=false) { return compare (other.get, codePointOrder); } /*********************************************************************** The comparison can be done in code unit order or in code point order. They differ only in UTF-16 when comparing supplementary code points (U+10000..U+10ffff) to BMP code points near the end of the BMP (i.e., U+e000..U+ffff). In code unit order, high BMP code points sort after supplementary code points because they are stored as pairs of surrogates which are at U+d800..U+dfff. ***********************************************************************/ final int compare (wchar[] other, bool codePointOrder=false) { return u_strCompare (content.ptr, len, other.ptr, other.length, codePointOrder); } /*********************************************************************** The comparison can be done in UTF-16 code unit order or in code point order. They differ only when comparing supplementary code points (U+10000..U+10ffff) to BMP code points near the end of the BMP (i.e., U+e000..U+ffff). In code unit order, high BMP code points sort after supplementary code points because they are stored as pairs of surrogates which are at U+d800..U+dfff. ***********************************************************************/ final int compareFolded (UStringView other, CaseOption option = CaseOption.Default) { return compareFolded (other.content, option); } /*********************************************************************** The comparison can be done in UTF-16 code unit order or in code point order. They differ only when comparing supplementary code points (U+10000..U+10ffff) to BMP code points near the end of the BMP (i.e., U+e000..U+ffff). In code unit order, high BMP code points sort after supplementary code points because they are stored as pairs of surrogates which are at U+d800..U+dfff. ***********************************************************************/ final int compareFolded (wchar[] other, CaseOption option = CaseOption.Default) { return compareFolded (get, other, option); } /*********************************************************************** Does this UStringView start with specified string? ***********************************************************************/ final bool startsWith (UStringView other) { return startsWith (other.get); } /*********************************************************************** Does this UStringView start with specified string? ***********************************************************************/ final bool startsWith (wchar[] chars) { if (len >= chars.length) return compareFolded (content[0..chars.length], chars) == 0; return false; } /*********************************************************************** Does this UStringView end with specified string? ***********************************************************************/ final bool endsWith (UStringView other) { return endsWith (other.get); } /*********************************************************************** Does this UStringView end with specified string? ***********************************************************************/ final bool endsWith (wchar[] chars) { if (len >= chars.length) return compareFolded (content[len-chars.length..len], chars) == 0; return false; } /*********************************************************************** Find the first occurrence of a BMP code point in a string. A surrogate code point is found only if its match in the text is not part of a surrogate pair. ***********************************************************************/ final uint indexOf (wchar c, uint start=0) { pinIndex (start); wchar* s = u_memchr (&content[start], c, len-start); if (s) return s - content.ptr; return uint.max; } /*********************************************************************** Find the first occurrence of a substring in a string. The substring is found at code point boundaries. That means that if the substring begins with a trail surrogate or ends with a lead surrogate, then it is found only if these surrogates stand alone in the text. Otherwise, the substring edge units would be matched against halves of surrogate pairs. ***********************************************************************/ final uint indexOf (UStringView other, uint start=0) { return indexOf (other.get, start); } /*********************************************************************** Find the first occurrence of a substring in a string. The substring is found at code point boundaries. That means that if the substring begins with a trail surrogate or ends with a lead surrogate, then it is found only if these surrogates stand alone in the text. Otherwise, the substring edge units would be matched against halves of surrogate pairs. ***********************************************************************/ final uint indexOf (wchar[] chars, uint start=0) { pinIndex (start); wchar* s = u_strFindFirst (&content[start], len-start, chars.ptr, chars.length); if (s) return s - content.ptr; return uint.max; } /*********************************************************************** Find the last occurrence of a BMP code point in a string. A surrogate code point is found only if its match in the text is not part of a surrogate pair. ***********************************************************************/ final uint lastIndexOf (wchar c, uint start=uint.max) { pinIndex (start); wchar* s = u_memrchr (content.ptr, c, start); if (s) return s - content.ptr; return uint.max; } /*********************************************************************** Find the last occurrence of a BMP code point in a string. A surrogate code point is found only if its match in the text is not part of a surrogate pair. ***********************************************************************/ final uint lastIndexOf (UStringView other, uint start=uint.max) { return lastIndexOf (other.get, start); } /*********************************************************************** Find the last occurrence of a substring in a string. The substring is found at code point boundaries. That means that if the substring begins with a trail surrogate or ends with a lead surrogate, then it is found only if these surrogates stand alone in the text. Otherwise, the substring edge units would be matched against halves of surrogate pairs. ***********************************************************************/ final uint lastIndexOf (wchar[] chars, uint start=uint.max) { pinIndex (start); wchar* s = u_strFindLast (content.ptr, start, chars.ptr, chars.length); if (s) return s - content.ptr; return uint.max; } /*********************************************************************** Lowercase the characters into a seperate UString. Casing is locale-dependent and context-sensitive. The result may be longer or shorter than the original. Note that the return value refers to the provided destination UString. ***********************************************************************/ final UString toLower (UString dst) { return toLower (dst, ULocale.Default); } /*********************************************************************** Lowercase the characters into a seperate UString. Casing is locale-dependent and context-sensitive. The result may be longer or shorter than the original. Note that the return value refers to the provided destination UString. ***********************************************************************/ final UString toLower (UString dst, ref ULocale locale) { uint lower (wchar* dst, uint length, ref UErrorCode e) { return u_strToLower (dst, length, content.ptr, len, ICU.toString(locale.name), e); } dst.expand (len + 32); return dst.format (&lower, "toLower() failed"); } /*********************************************************************** Uppercase the characters into a seperate UString. Casing is locale-dependent and context-sensitive. The result may be longer or shorter than the original. Note that the return value refers to the provided destination UString. ***********************************************************************/ final UString toUpper (UString dst) { return toUpper (dst, ULocale.Default); } /*********************************************************************** Uppercase the characters into a seperate UString. Casing is locale-dependent and context-sensitive. The result may be longer or shorter than the original. Note that the return value refers to the provided destination UString. ***********************************************************************/ final UString toUpper (UString dst, ref ULocale locale) { uint upper (wchar* dst, uint length, ref UErrorCode e) { return u_strToUpper (dst, length, content.ptr, len, ICU.toString(locale.name), e); } dst.expand (len + 32); return dst.format (&upper, "toUpper() failed"); } /*********************************************************************** Case-fold the characters into a seperate UString. Case-folding is locale-independent and not context-sensitive, but there is an option for whether to include or exclude mappings for dotted I and dotless i that are marked with 'I' in CaseFolding.txt. The result may be longer or shorter than the original. Note that the return value refers to the provided destination UString. ***********************************************************************/ final UString toFolded (UString dst, CaseOption option = CaseOption.Default) { uint fold (wchar* dst, uint length, ref UErrorCode e) { return u_strFoldCase (dst, length, content.ptr, len, option, e); } dst.expand (len + 32); return dst.format (&fold, "toFolded() failed"); } /*********************************************************************** Converts a sequence of wchar (UTF-16) to UTF-8 bytes. If the output array is not provided, an array of appropriate size will be allocated and returned. Where the output is provided, it must be large enough to hold potentially four bytes per character for surrogate-pairs or three bytes per character for BMP only. Consider using UConverter where streaming conversions are required. Returns an array slice representing the valid UTF8 content. ***********************************************************************/ final char[] toUtf8 (char[] dst = null) { uint x; UErrorCode e; if (! cast(char*) dst) dst = new char[len * 4]; u_strToUTF8 (dst.ptr, dst.length, &x, content.ptr, len, e); testError (e, "failed to convert to UTF8"); return dst [0..x]; } /*********************************************************************** Remove leading and trailing whitespace from this UStringView. Note that we slice the content to remove leading space. ***********************************************************************/ UStringView trim () { wchar c; uint i = len; // cut off trailing white space while (i && ((c = charAt(i-1)) == 0x20 || UChar.isWhiteSpace (c))) --i; len = i; // now remove leading whitespace for (i=0; i < len && ((c = charAt(i)) == 0x20 || UChar.isWhiteSpace (c)); ++i) {} if (i) { len -= i; content = content[i..$-i]; } return this; } /*********************************************************************** Unescape a string of characters and write the resulting Unicode characters to the destination buffer. The following escape sequences are recognized: uhhhh 4 hex digits; h in [0-9A-Fa-f] Uhhhhhhhh 8 hex digits xhh 1-2 hex digits x{h...} 1-8 hex digits ooo 1-3 octal digits; o in [0-7] cX control-X; X is masked with 0x1F as well as the standard ANSI C escapes: a => U+0007, \\b => U+0008, \\t => U+0009, \\n => U+000A, v => U+000B, \\f => U+000C, \\r => U+000D, \\e => U+001B, \\" =U+0022, \\' => U+0027, \\? => U+003F, \\\\ => U+005C Anything else following a backslash is generically escaped. For example, "[a\\-z]" returns "[a-z]". If an escape sequence is ill-formed, this method returns an empty string. An example of an ill-formed sequence is "\\u" followed by fewer than 4 hex digits. ***********************************************************************/ final UString unEscape () { UString result = new UString (len); for (uint i=0; i < len;) { dchar c = charAt(i++); if (c == 0x005C) { // bump index ... c = u_unescapeAt (&_charAt, &i, len, cast(void*) this); // error? if (c == 0xFFFFFFFF) { result.truncate (); // return empty string break; // invalid escape sequence } } result.append (c); } return result; } /*********************************************************************** Is this code point a surrogate (U+d800..U+dfff)? ***********************************************************************/ final static bool isSurrogate (wchar c) { return (c & 0xfffff800) == 0xd800; } /*********************************************************************** Is this code unit a lead surrogate (U+d800..U+dbff)? ***********************************************************************/ final static bool isLeading (wchar c) { return (c & 0xfffffc00) == 0xd800; } /*********************************************************************** Is this code unit a trail surrogate (U+dc00..U+dfff)? ***********************************************************************/ final static bool isTrailing (wchar c) { return (c & 0xfffffc00) == 0xdc00; } /*********************************************************************** Adjust a random-access offset to a code point boundary at the start of a code point. If the offset points to the trail surrogate of a surrogate pair, then the offset is decremented. Otherwise, it is not modified. ***********************************************************************/ final uint getCharStart (uint i) in { if (i >= len) exception ("index of out bounds"); } body { if (isTrailing (content[i]) && i && isLeading (content[i-1])) --i; return i; } /*********************************************************************** Adjust a random-access offset to a code point boundary after a code point. If the offset is behind the lead surrogate of a surrogate pair, then the offset is incremented. Otherwise, it is not modified. ***********************************************************************/ final uint getCharLimit (uint i) in { if (i >= len) exception ("index of out bounds"); } body { if (i && isLeading(content[i-1]) && isTrailing (content[i])) ++i; return i; } /*********************************************************************** Callback for C unescapeAt() function ***********************************************************************/ extern (C) { typedef wchar function (uint offset, void* context) CharAt; private static wchar _charAt (uint offset, void* context) { return (cast(UString) context).charAt (offset); } } /*********************************************************************** Pin the given index to a valid position. ***********************************************************************/ final private void pinIndex (ref uint x) { if (x > len) x = len; } /*********************************************************************** Pin the given index and length to a valid position. ***********************************************************************/ final private void pinIndices (ref uint start, ref uint length) { if (start > len) start = len; if (length > (len - start)) length = len - start; } /*********************************************************************** Helper for comparison methods ***********************************************************************/ final private int compareFolded (wchar[] s1, wchar[] s2, CaseOption option = CaseOption.Default) { UErrorCode e; int x = u_strCaseCompare (s1.ptr, s1.length, s2.ptr, s2.length, option, e); testError (e, "compareFolded failed"); return x; } /*********************************************************************** Bind the ICU functions from a shared library. This is complicated by the issues regarding D and DLLs on the Windows platform ***********************************************************************/ mixin(genICUNative!("uc" ,"wchar* function (wchar*, uint, wchar*, uint)", "u_strFindFirst" ,"wchar* function (wchar*, uint, wchar*, uint)", "u_strFindLast" ,"wchar* function (wchar*, wchar, uint)", "u_memchr" ,"wchar* function (wchar*, wchar, uint)", "u_memrchr" ,"int function (wchar*, uint, wchar*, uint, bool)", "u_strCompare" ,"int function (wchar*, uint, wchar*, uint, uint, ref UErrorCode)", "u_strCaseCompare" ,"dchar function (CharAt, uint*, uint, void*)", "u_unescapeAt" ,"uint function (wchar*, uint)", "u_countChar32" ,"uint function (wchar*, uint, wchar*, uint, char*, ref UErrorCode)", "u_strToUpper" ,"uint function (wchar*, uint, wchar*, uint, char*, ref UErrorCode)", "u_strToLower" ,"uint function (wchar*, uint, wchar*, uint, uint, ref UErrorCode)", "u_strFoldCase" ,"wchar* function (wchar*, uint, uint*, char*, uint, ref UErrorCode)", "u_strFromUTF8" ,"wchar* function (wchar*, uint, uint*, dchar*, uint, ref UErrorCode)", "u_strFromUTF32" ,"char* function (char*, uint, uint*, wchar*, uint, ref UErrorCode)", "u_strToUTF8" )); /*********************************************************************** ***********************************************************************/ //private static void test() //{ // UString s = new UString (r"aaaqw \uabcd eaaa"); // const String16 x = "dssfsdff"; // s ~ x ~ x; // wchar c = s[3]; // s[3] = 'Q'; // int y = s.indexOf ("qwe"); // s.unEscape (); // s.toUpper (new UString); // s.padLeading(2).padTrailing(2).trim(); //} }