00001 /******************************************************************************* 00002 00003 @file String.d 00004 00005 Copyright (c) 2004 Kris Bell 00006 00007 This software is provided 'as-is', without any express or implied 00008 warranty. In no event will the authors be held liable for damages 00009 of any kind arising from the use of this software. 00010 00011 Permission is hereby granted to anyone to use this software for any 00012 purpose, including commercial applications, and to alter it and/or 00013 redistribute it freely, subject to the following restrictions: 00014 00015 1. The origin of this software must not be misrepresented; you must 00016 not claim that you wrote the original software. If you use this 00017 software in a product, an acknowledgment within documentation of 00018 said product would be appreciated but is not required. 00019 00020 2. Altered source versions must be plainly marked as such, and must 00021 not be misrepresented as being the original software. 00022 00023 3. This notice may not be removed or altered from any distribution 00024 of the source. 00025 00026 4. Derivative works are permitted, but they must carry this notice 00027 in full and credit the original source. 00028 00029 00030 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 00031 00032 00033 class MutableString(T) : String!(T) 00034 { 00035 // reset the content 00036 MutableString set (T[] chars, bool mutable=true); 00037 MutableString set (String other, bool mutable=true); 00038 00039 // get the index and length of the current selection 00040 uint selection (inout int length); 00041 00042 // make a selection 00043 MutableString select (int start=0, int length=int.max); 00044 00045 // move the selection around 00046 bool select (T c); 00047 bool select (T[] chars); 00048 bool select (String other); 00049 bool rselect (T c); 00050 bool rselect (T[] chars); 00051 bool rselect (String other); 00052 00053 // append behind current selection 00054 MutableString append (String other); 00055 MutableString append (char[] other); 00056 MutableString append (wchar[] other); 00057 MutableString append (dchar[] other); 00058 MutableString append (T chr, int count=1); 00059 MutableString append (int value, T[] format=null); 00060 MutableString append (long value, T[] format=null); 00061 MutableString append (double value, T[] format=null); 00062 00063 // format and layout behind current selection 00064 MutableString format (T[] format, ...); 00065 MutableString layout (T[] layout ...); 00066 00067 // insert before current selection 00068 MutableString prepend (T[] other); 00069 MutableString prepend (String other); 00070 MutableString prepend (T chr, int count=1); 00071 00072 // replace current selection 00073 MutableString replace (T chr); 00074 MutableString replace (T[] other); 00075 MutableString replace (String other); 00076 00077 // remove current selection 00078 MutableString remove (); 00079 00080 // truncate at point, or current selection 00081 MutableString truncate (int point = int.max); 00082 00083 // trim content 00084 MutableString trim (); 00085 00086 // return content 00087 T[] aliasOf (); 00088 } 00089 00090 class String(T) : UniString 00091 { 00092 // iterate across content 00093 opApply (int delegate(inout T) dg); 00094 00095 // hash content 00096 uint toHash (); 00097 00098 // return length of content 00099 uint length (); 00100 00101 // compare content 00102 bool equals (T[] other); 00103 bool equals (String other); 00104 bool ends (T[] other); 00105 bool ends (String other); 00106 bool starts (T[] other); 00107 bool starts (String other); 00108 int compare (T[] other); 00109 int compare (String other); 00110 int opEquals (Object other); 00111 int opCmp (Object other); 00112 00113 // copy content 00114 T[] copy (T[] dst); 00115 T[] copy (); 00116 } 00117 00118 abstract class UniString 00119 { 00120 // convert content 00121 abstract char[] utf8 (char[] dst = null); 00122 abstract wchar[] utf16 (wchar[] dst = null); 00123 abstract dchar[] utf32 (dchar[] dst = null); 00124 } 00125 00126 00127 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 00128 00129 00130 @version Initial version, December 2005 00131 00132 @author Kris 00133 00134 *******************************************************************************/ 00135 00136 module mango.text.String; 00137 00138 private import mango.text.Text; 00139 00140 private import mango.convert.Type, 00141 mango.convert.Format, 00142 mango.convert.Unicode; 00143 00144 private import mango.text.model.UniString; 00145 00146 /******************************************************************************* 00147 00148 *******************************************************************************/ 00149 00150 private extern (C) void memmove (void* dst, void* src, uint bytes); 00151 00152 00153 /******************************************************************************* 00154 00155 MutableString is a string class that stores Unicode characters. 00156 00157 Indexes and lengths of strings always count code units, not code 00158 points. This is similar to traditional multi-byte string handling. 00159 Operations on strings do not test for code point boundaries since 00160 the approach taken here is based upon pattern-matching rather than 00161 direct indexing. 00162 00163 MutableString maintains a current "selection", controlled via the 00164 select() and rselect() methods. Append(), prepend(), replace() and 00165 remove() each operate with respect to the selection. The select() 00166 methods themselves operate with respect to the current selection 00167 also, providing a means of iterating across matched patterns. To 00168 reset the selection to the entire string, use the select() method 00169 with no arguments. 00170 00171 *******************************************************************************/ 00172 00173 class MutableStringTemplate(T) : StringTemplate!(T) 00174 { 00175 public alias append opCat; 00176 00177 private alias MutableStringTemplate MutableString; 00178 private alias FormatStructTemplate!(T) Format; 00179 private alias Unicode.Into!(T) Into; 00180 00181 public Into into; // unicode converter 00182 private T[] scratch; // formatting scratchpad 00183 private T[] converts; // unicode buffer 00184 private Format formatter; // printf formatter 00185 00186 00187 /*********************************************************************** 00188 00189 Create an empty MutableString with the specified available 00190 space 00191 00192 ***********************************************************************/ 00193 00194 this (uint space = 0) 00195 { 00196 content.length = space; 00197 mutable = true; 00198 setup (); 00199 } 00200 00201 /*********************************************************************** 00202 00203 Create a MutableString upon the provided content. If said 00204 content is immutable (read-only) then you might consider 00205 setting the 'mutable' parameter to false. Doing so will 00206 avoid allocating heap-space for the content until it is 00207 modified. 00208 00209 ***********************************************************************/ 00210 00211 this (T[] content, bool mutable = true) 00212 { 00213 set (content, mutable); 00214 setup (); 00215 } 00216 00217 /*********************************************************************** 00218 00219 Create a MutableString via the content of a MutableString. 00220 If said content is immutable (read-only) then you might 00221 consider setting the 'mutable' parameter to false. Doing 00222 so will avoid allocating heap-space for the content until 00223 it is modified via MutableString methods. 00224 00225 ***********************************************************************/ 00226 00227 this (MutableString other, bool mutable = true) 00228 { 00229 this (other.get, mutable); 00230 } 00231 00232 /*********************************************************************** 00233 00234 Create a MutableString via the content of a String. Note 00235 that the default is to assume the content is immutable 00236 00237 ***********************************************************************/ 00238 00239 this (String other, bool mutable = false) 00240 { 00241 this (other.get, mutable); 00242 } 00243 00244 /*********************************************************************** 00245 00246 Set the content to the provided array. Parameter 'mutable' 00247 specifies whether the given array is likely to change. If 00248 not, the array is aliased until such time it is altered. 00249 00250 ***********************************************************************/ 00251 00252 MutableString set (T[] chars, bool mutable = true) 00253 { 00254 contentLength = chars.length; 00255 select (0, contentLength); 00256 00257 if ((this.mutable = mutable) == true) 00258 content = chars.dup; 00259 else 00260 content = chars; 00261 return this; 00262 } 00263 00264 /*********************************************************************** 00265 00266 Replace the content of this MutableString. If the new content 00267 is immutable (read-only) then you might consider setting the 00268 'mutable' parameter to false. Doing so will avoid allocating 00269 heap-space for the content until it is modified via one of 00270 these methods. 00271 00272 ***********************************************************************/ 00273 00274 MutableString set (String other, bool mutable = true) 00275 { 00276 return set (other.get, mutable); 00277 } 00278 00279 /*********************************************************************** 00280 00281 Return the index and length of the current selection 00282 00283 ***********************************************************************/ 00284 00285 uint selection (inout int length) 00286 { 00287 length = selectLength; 00288 return selectPoint; 00289 } 00290 00291 /*********************************************************************** 00292 00293 Explicitly set the current selection 00294 00295 ***********************************************************************/ 00296 00297 MutableString select (int start=0, int length=int.max) 00298 { 00299 pinIndices (start, length); 00300 selectPoint = start; 00301 selectLength = length; 00302 return this; 00303 } 00304 00305 /*********************************************************************** 00306 00307 Find the first occurrence of a BMP code point in a string. 00308 A surrogate code point is found only if its match in the 00309 text is not part of a surrogate pair. 00310 00311 ***********************************************************************/ 00312 00313 bool select (T c) 00314 { 00315 int x = utils.indexOf (get(), c, selectPoint); 00316 if (x >= 0) 00317 { 00318 select (x, 1); 00319 return true; 00320 } 00321 return false; 00322 } 00323 00324 /*********************************************************************** 00325 00326 Find the first occurrence of a substring in a string. 00327 00328 The substring is found at code point boundaries. That means 00329 that if the substring begins with a trail surrogate or ends 00330 with a lead surrogate, then it is found only if these 00331 surrogates stand alone in the text. Otherwise, the substring 00332 edge units would be matched against halves of surrogate pairs. 00333 00334 ***********************************************************************/ 00335 00336 bool select (String other) 00337 { 00338 return select (other.get); 00339 } 00340 00341 /*********************************************************************** 00342 00343 Find the first occurrence of a substring in a string. 00344 00345 The substring is found at code point boundaries. That means 00346 that if the substring begins with a trail surrogate or ends 00347 with a lead surrogate, then it is found only if these 00348 surrogates stand alone in the text. Otherwise, the substring 00349 edge units would be matched against halves of surrogate pairs. 00350 00351 ***********************************************************************/ 00352 00353 bool select (T[] chars) 00354 { 00355 int x = utils.indexOf (get(), chars, selectPoint); 00356 if (x >= 0) 00357 { 00358 select (x, chars.length); 00359 return true; 00360 } 00361 return false; 00362 } 00363 00364 /*********************************************************************** 00365 00366 Find the last occurrence of a BMP code point in a string. 00367 A surrogate code point is found only if its match in the 00368 text is not part of a surrogate pair. 00369 00370 ***********************************************************************/ 00371 00372 bool rselect (T c) 00373 { 00374 int x = utils.rIndexOf (get(), c, selectPoint+selectLength); 00375 if (x >= 0) 00376 { 00377 select (x, 1); 00378 return true; 00379 } 00380 return false; 00381 } 00382 00383 /*********************************************************************** 00384 00385 Find the last occurrence of a BMP code point in a string. 00386 A surrogate code point is found only if its match in the 00387 text is not part of a surrogate pair. 00388 00389 ***********************************************************************/ 00390 00391 bool rselect (String other) 00392 { 00393 return rselect (other.get); 00394 } 00395 00396 /*********************************************************************** 00397 00398 Find the last occurrence of a substring in a string. 00399 00400 The substring is found at code point boundaries. That means 00401 that if the substring begins with a trail surrogate or ends 00402 with a lead surrogate, then it is found only if these 00403 surrogates stand alone in the text. Otherwise, the substring 00404 edge units would be matched against halves of surrogate pairs. 00405 00406 ***********************************************************************/ 00407 00408 bool rselect (T[] chars) 00409 { 00410 int x = utils.rIndexOf (get(), chars, selectPoint+selectLength); 00411 if (x >= 0) 00412 { 00413 select (x, chars.length); 00414 return true; 00415 } 00416 return false; 00417 } 00418 00419 /*********************************************************************** 00420 00421 Append partial text to this MutableString 00422 00423 ***********************************************************************/ 00424 00425 MutableString append (String other) 00426 { 00427 return append (other.get); 00428 } 00429 00430 /*********************************************************************** 00431 00432 Append text to this MutableString 00433 00434 ***********************************************************************/ 00435 00436 MutableString append (char[] chars) 00437 { 00438 convert (chars, Type.Utf8); 00439 return this; 00440 } 00441 00442 /*********************************************************************** 00443 00444 Append text to this MutableString 00445 00446 ***********************************************************************/ 00447 00448 MutableString append (wchar[] chars) 00449 { 00450 convert (chars, Type.Utf16); 00451 return this; 00452 } 00453 00454 /*********************************************************************** 00455 00456 Append text to this MutableString 00457 00458 ***********************************************************************/ 00459 00460 MutableString append (dchar[] chars) 00461 { 00462 convert (chars, Type.Utf32); 00463 return this; 00464 } 00465 00466 /*********************************************************************** 00467 00468 Append a count of characters to this MutableString 00469 00470 ***********************************************************************/ 00471 00472 MutableString append (T chr, int count=1) 00473 { 00474 uint point = selectPoint + selectLength; 00475 expand (point, count); 00476 return set (chr, point, count); 00477 } 00478 00479 /*********************************************************************** 00480 00481 Append an integer to this MutableString, using standard 00482 printf() notation 00483 00484 ***********************************************************************/ 00485 00486 MutableString append (int v, T[] format=null) 00487 { 00488 formatter (format, &v, v.sizeof, Type.Int); 00489 return this; 00490 } 00491 00492 /*********************************************************************** 00493 00494 Append a long to this MutableString, using standard 00495 printf() notation 00496 00497 ***********************************************************************/ 00498 00499 MutableString append (long v, T[] format=null) 00500 { 00501 formatter (format, &v, v.sizeof, Type.Long); 00502 return this; 00503 } 00504 00505 /*********************************************************************** 00506 00507 Append a double to this MutableString, using standard 00508 printf() notation 00509 00510 ***********************************************************************/ 00511 00512 MutableString append (double v, T[] format=null) 00513 { 00514 formatter (format, &v, v.sizeof, Type.Double); 00515 return this; 00516 } 00517 00518 /********************************************************************** 00519 00520 Format a set of arguments using the standard printf() 00521 formatting notation 00522 00523 **********************************************************************/ 00524 00525 MutableString format (T[] fmt, ...) 00526 { 00527 formatter (fmt, _arguments, _argptr); 00528 return this; 00529 } 00530 00531 /*********************************************************************** 00532 00533 Insert characters into this MutableString 00534 00535 ***********************************************************************/ 00536 00537 MutableString prepend (T chr, uint count=1) 00538 { 00539 expand (selectPoint, count); 00540 return set (chr, selectPoint, count); 00541 } 00542 00543 /*********************************************************************** 00544 00545 Insert text into this MutableString 00546 00547 ***********************************************************************/ 00548 00549 MutableString prepend (T[] other) 00550 { 00551 expand (selectPoint, other.length); 00552 content[selectPoint..selectPoint+other.length] = other; 00553 return this; 00554 } 00555 00556 /*********************************************************************** 00557 00558 Insert another String into this MutableString 00559 00560 ***********************************************************************/ 00561 00562 MutableString prepend (String other) 00563 { 00564 return prepend (other.get); 00565 } 00566 00567 /*********************************************************************** 00568 00569 Replace a section of this MutableString with the specified 00570 character 00571 00572 ***********************************************************************/ 00573 00574 MutableString replace (T chr) 00575 { 00576 return set (chr, selectPoint, selectLength); 00577 } 00578 00579 /*********************************************************************** 00580 00581 Replace a section of this MutableString with the specified 00582 array 00583 00584 ***********************************************************************/ 00585 00586 MutableString replace (T[] chars) 00587 { 00588 int chunk = chars.length - selectLength; 00589 if (chunk >= 0) 00590 expand (selectPoint, chunk); 00591 else 00592 remove (-chunk); 00593 00594 content [selectPoint .. selectPoint+chars.length] = chars; 00595 select (selectPoint, chars.length); 00596 return this; 00597 } 00598 00599 /*********************************************************************** 00600 00601 Replace a section of this MutableString with the specified 00602 String 00603 00604 ***********************************************************************/ 00605 00606 MutableString replace (String other) 00607 { 00608 return replace (other.get); 00609 } 00610 00611 /*********************************************************************** 00612 00613 Remove the selection from this MutableString and reset the 00614 selection to zero length 00615 00616 ***********************************************************************/ 00617 00618 MutableString remove () 00619 { 00620 remove (selectLength); 00621 select (selectPoint, 0); 00622 return this; 00623 } 00624 00625 /*********************************************************************** 00626 00627 Remove the selection from this MutableString and reset the 00628 selection to zero length 00629 00630 ***********************************************************************/ 00631 00632 private int remove (int count) 00633 { 00634 int start = selectPoint; 00635 pinIndices (start, count); 00636 if (count > 0) 00637 { 00638 if (! mutable) 00639 realloc (); 00640 00641 uint i = start + count; 00642 memmove (content.ptr+start, content.ptr+i, (contentLength-i) * T.sizeof); 00643 contentLength -= count; 00644 } 00645 return count; 00646 } 00647 00648 /*********************************************************************** 00649 00650 Truncate this string. Default behaviour is to truncate at 00651 the current append point 00652 00653 ***********************************************************************/ 00654 00655 MutableString truncate (int index = int.max) 00656 { 00657 if (index is int.max) 00658 index = selectPoint + selectLength; 00659 00660 pinIndex (index); 00661 contentLength = index; 00662 } 00663 00664 /********************************************************************** 00665 00666 Arranges text strings in order, using indices to specify 00667 where each particular argument should be positioned within 00668 the text. This is handy for collating I18N components. 00669 00670 @code 00671 auto string = new MutableString; 00672 00673 string.layout ("%2 %1", "one", "two"); 00674 @endcode 00675 00676 The index numbers range from one through nine 00677 00678 **********************************************************************/ 00679 00680 MutableString layout (T[][] layout ...) 00681 { 00682 int args; 00683 bool state; 00684 00685 args = layout.length - 1; 00686 foreach (T c; layout[0]) 00687 { 00688 if (state) 00689 { 00690 state = false; 00691 if (c >= '1' || c <= '9') 00692 { 00693 uint index = c - '0'; 00694 if (index <= args) 00695 { 00696 append (layout[index]); 00697 continue; 00698 } 00699 else 00700 formatter.error ("TextLayout : invalid argument"); 00701 } 00702 } 00703 else 00704 if (c == '%') 00705 { 00706 state = true; 00707 continue; 00708 } 00709 append (c); 00710 } 00711 return this; 00712 } 00713 00714 /*********************************************************************** 00715 00716 Remove leading and trailing whitespace from this String, 00717 and reset the selection to the trimmed content 00718 00719 ***********************************************************************/ 00720 00721 MutableString trim () 00722 { 00723 content = utils.trim (get()); 00724 select (0, contentLength = content.length); 00725 return this; 00726 } 00727 00728 /*********************************************************************** 00729 00730 Return an alias to the content of this MutableString 00731 00732 ***********************************************************************/ 00733 00734 T[] aliasOf () 00735 { 00736 return get (); 00737 } 00738 00739 00740 /* ================================================================== */ 00741 00742 00743 /*********************************************************************** 00744 00745 make room available to insert or append something 00746 00747 ***********************************************************************/ 00748 00749 private final void expand (uint index, uint count) 00750 { 00751 if (!mutable || (contentLength + count) > content.length) 00752 realloc (count); 00753 00754 memmove (content.ptr+index+count, content.ptr+index, (contentLength - index) * T.sizeof); 00755 selectLength += count; 00756 contentLength += count; 00757 } 00758 00759 /*********************************************************************** 00760 00761 Replace a section of this MutableString with the specified 00762 character 00763 00764 ***********************************************************************/ 00765 00766 private final MutableString set (T chr, uint start, uint count) 00767 { 00768 content [start..start+count] = chr; 00769 return this; 00770 } 00771 00772 /*********************************************************************** 00773 00774 Allocate memory due to a change in the content. We handle 00775 the distinction between mutable and immutable here. 00776 00777 ***********************************************************************/ 00778 00779 private final void realloc (uint count = 0) 00780 { 00781 uint size = (content.length + count + 127) & ~127; 00782 00783 if (mutable) 00784 content.length = size; 00785 else 00786 { 00787 mutable = true; 00788 T[] x = content; 00789 content = new T[size]; 00790 if (contentLength) 00791 content[0..contentLength] = x; 00792 } 00793 } 00794 00795 /*********************************************************************** 00796 00797 Internal method to support MutableString appending 00798 00799 ***********************************************************************/ 00800 00801 private final MutableString append (T* chars, uint count) 00802 { 00803 uint point = selectPoint + selectLength; 00804 expand (point, count); 00805 content[point .. point+count] = chars[0 .. count]; 00806 return this; 00807 } 00808 00809 /*********************************************************************** 00810 00811 Initialize this MutableString. Allocate conversion buffers 00812 and prime the formatter 00813 00814 ***********************************************************************/ 00815 00816 private void setup (Format.DblFormat df = null) 00817 { 00818 00819 scratch = new T[64]; 00820 converts = new T[256]; 00821 formatter.ctor (&convert, null, scratch, df); 00822 } 00823 00824 /********************************************************************** 00825 00826 Support for the formatter, to convert from one encoding 00827 to another 00828 00829 **********************************************************************/ 00830 00831 private uint convert (void[] v, uint type) 00832 { 00833 // convert as required 00834 auto s = cast(T[]) into.convert (v, type, converts); 00835 00836 // hang onto conversion buffer when it grows 00837 if (s.length > converts.length) 00838 converts = s; 00839 00840 // append to string 00841 append (s.ptr, s.length); 00842 return s.length; 00843 } 00844 } 00845 00846 00847 00848 /******************************************************************************* 00849 00850 Immutable string 00851 00852 *******************************************************************************/ 00853 00854 class StringTemplate(T) : UniString 00855 { 00856 public alias int delegate (T[] a, T[] b) Comparator; 00857 public alias get opIndex; 00858 00859 private alias StringTemplate String; 00860 00861 // unicode converter and utility functions 00862 public Unicode.From!(T) from; 00863 public TextTemplate!(T) utils; 00864 00865 // the core of the String and MutableString attributes. The name 00866 // 'contentLength' is used rather than the more obvious 'length' 00867 // since there is a collision with the noxious array[length] sugar 00868 protected T[] content; 00869 protected uint selectPoint, 00870 selectLength, 00871 contentLength; 00872 00873 // this should probably be in MutableString only, but there seems to 00874 // be a compiler bug where it doesn't get initialised correctly, 00875 // and it's perhaps useful to have here for when a MutableString is 00876 // passed as a String argument. 00877 protected bool mutable; 00878 00879 private Comparator comparator; 00880 00881 /*********************************************************************** 00882 00883 Hidden constructor 00884 00885 ***********************************************************************/ 00886 00887 private this () 00888 { 00889 this.comparator = &simpleComparator; 00890 } 00891 00892 /*********************************************************************** 00893 00894 Construct read-only wrapper around the given content 00895 00896 ***********************************************************************/ 00897 00898 this (T[] content) 00899 { 00900 this(); 00901 this.content = content; 00902 this.selectPoint = 0; 00903 this.selectLength = this.contentLength = content.length; 00904 } 00905 00906 /*********************************************************************** 00907 00908 Set the comparator delegate 00909 00910 ***********************************************************************/ 00911 00912 void setComparator (Comparator comparator) 00913 { 00914 this.comparator = comparator; 00915 } 00916 00917 /*********************************************************************** 00918 00919 Hash this String 00920 00921 ***********************************************************************/ 00922 00923 override uint toHash () 00924 { 00925 return hash (content [0 .. contentLength]); 00926 } 00927 00928 /*********************************************************************** 00929 00930 Return the length of the valid content 00931 00932 ***********************************************************************/ 00933 00934 uint length () 00935 { 00936 return contentLength; 00937 } 00938 00939 /*********************************************************************** 00940 00941 Is this String equal to another? 00942 00943 ***********************************************************************/ 00944 00945 bool equals (String other) 00946 { 00947 if (other is this) 00948 return true; 00949 return equals (other.get); 00950 } 00951 00952 /*********************************************************************** 00953 00954 Is this String equal to the the provided text? 00955 00956 ***********************************************************************/ 00957 00958 bool equals (T[] other) 00959 { 00960 if (other.length == contentLength) 00961 return utils.equal (other.ptr, content.ptr, contentLength); 00962 return false; 00963 } 00964 00965 /*********************************************************************** 00966 00967 Does this String end with another? 00968 00969 ***********************************************************************/ 00970 00971 bool ends (String other) 00972 { 00973 return ends (other.get); 00974 } 00975 00976 /*********************************************************************** 00977 00978 Does this String end with the specified string? 00979 00980 ***********************************************************************/ 00981 00982 bool ends (T[] chars) 00983 { 00984 if (chars.length <= contentLength) 00985 return utils.equal (content.ptr+(contentLength-chars.length), chars.ptr, chars.length); 00986 return false; 00987 } 00988 00989 /*********************************************************************** 00990 00991 Does this String start with another? 00992 00993 ***********************************************************************/ 00994 00995 bool starts (String other) 00996 { 00997 return starts (other.get); 00998 } 00999 01000 /*********************************************************************** 01001 01002 Does this String start with the specified string? 01003 01004 ***********************************************************************/ 01005 01006 bool starts (T[] chars) 01007 { 01008 if (chars.length <= contentLength) 01009 return utils.equal (content.ptr, chars.ptr, chars.length); 01010 return false; 01011 } 01012 01013 /*********************************************************************** 01014 01015 Compare this String start with another. Returns 0 if the 01016 content matches, less than zero if this String is "less" 01017 than the other, or greater than zero where this String 01018 is "bigger". 01019 01020 ***********************************************************************/ 01021 01022 int compare (String other) 01023 { 01024 if (other is this) 01025 return 0; 01026 01027 return compare (other.get); 01028 } 01029 01030 /*********************************************************************** 01031 01032 Compare this String start with an array. Returns 0 if the 01033 content matches, less than zero if this String is "less" 01034 than the other, or greater than zero where this String 01035 is "bigger". 01036 01037 ***********************************************************************/ 01038 01039 int compare (T[] chars) 01040 { 01041 return comparator (get(), chars); 01042 } 01043 01044 /*********************************************************************** 01045 01046 Return content from this String 01047 01048 A slice of dst is returned, representing a copy of the 01049 content. The slice is clipped to the minimum of either 01050 the length of the provided array, or the length of the 01051 content minus the stipulated start point 01052 01053 ***********************************************************************/ 01054 01055 T[] copy (T[] dst) 01056 { 01057 uint i = contentLength; 01058 if (i > dst.length) 01059 i = dst.length; 01060 01061 return dst [0 .. i] = content [0 .. i]; 01062 } 01063 01064 /*********************************************************************** 01065 01066 Return dup'd content from this String 01067 01068 ***********************************************************************/ 01069 01070 T[] copy () 01071 { 01072 return content [0 .. contentLength].dup; 01073 } 01074 01075 /*********************************************************************** 01076 01077 Convert to the AbstractString types. The optional argument 01078 dst will be resized as required to house the conversion. 01079 To minimize heap allocation, use the following pattern: 01080 01081 String string; 01082 01083 wchar[] buffer; 01084 wchar[] result = string.toUtf16 (buffer); 01085 01086 if (result.length > buffer.length) 01087 buffer = result; 01088 01089 You can also provide a buffer from the stack, but the output 01090 will be moved to the heap if said buffer is not large enough 01091 01092 ***********************************************************************/ 01093 01094 char[] utf8 (char[] dst = null) 01095 { 01096 return cast(char[]) from.convert (get(), Type.Utf8, dst); 01097 } 01098 01099 wchar[] utf16 (wchar[] dst = null) 01100 { 01101 return cast(wchar[]) from.convert (get(), Type.Utf16, dst); 01102 } 01103 01104 dchar[] utf32 (dchar[] dst = null) 01105 { 01106 return cast(dchar[]) from.convert (get(), Type.Utf32, dst); 01107 } 01108 01109 /********************************************************************** 01110 01111 Iterate over the characters in this string. Note that 01112 this is a read-only freachable ~ the worst a user can 01113 do is alter the temporary 'c' 01114 01115 **********************************************************************/ 01116 01117 int opApply (int delegate(inout T) dg) 01118 { 01119 int result = 0; 01120 01121 foreach (T c; get()) 01122 if ((result = dg (c)) != 0) 01123 break; 01124 return result; 01125 } 01126 01127 /*********************************************************************** 01128 01129 Compare this String to another 01130 01131 ***********************************************************************/ 01132 01133 final override int opCmp (Object o) 01134 { 01135 auto other = cast (String) o; 01136 01137 if (other is null) 01138 return -1; 01139 01140 return compare (other); 01141 } 01142 01143 /*********************************************************************** 01144 01145 Is this String equal to another? 01146 01147 ***********************************************************************/ 01148 01149 final override int opEquals (Object o) 01150 { 01151 auto other = cast (String) o; 01152 01153 if (other is null) 01154 return 0; 01155 01156 return equals (other); 01157 } 01158 01159 /********************************************************************** 01160 01161 hash() -- hash a variable-length key into a 32-bit value 01162 01163 k : the key (the unaligned variable-length array of bytes) 01164 len : the length of the key, counting by bytes 01165 level : can be any 4-byte value 01166 01167 Returns a 32-bit value. Every bit of the key affects every bit of 01168 the return value. Every 1-bit and 2-bit delta achieves avalanche. 01169 01170 About 4.3*len + 80 X86 instructions, with excellent pipelining 01171 01172 The best hash table sizes are powers of 2. There is no need to do 01173 mod a prime (mod is sooo slow!). If you need less than 32 bits, 01174 use a bitmask. For example, if you need only 10 bits, do 01175 01176 h = (h & hashmask(10)); 01177 01178 In which case, the hash table should have hashsize(10) elements. 01179 If you are hashing n strings (ub1 **)k, do it like this: 01180 01181 for (i=0, h=0; i<n; ++i) h = hash( k[i], len[i], h); 01182 01183 By Bob Jenkins, 1996. bob_jenkins@burtleburtle.net. You may use 01184 this code any way you wish, private, educational, or commercial. 01185 It's free. 01186 01187 See http://burlteburtle.net/bob/hash/evahash.html 01188 Use for hash table lookup, or anything where one collision in 2^32 01189 is acceptable. Do NOT use for cryptographic purposes. 01190 01191 **********************************************************************/ 01192 01193 static final uint hash (void[] x, uint c = 0) 01194 { 01195 uint a, 01196 b; 01197 01198 a = b = 0x9e3779b9; 01199 01200 uint len = x.length; 01201 ubyte* k = cast(ubyte *) x.ptr; 01202 01203 // handle most of the key 01204 while (len >= 12) 01205 { 01206 a += *cast(uint *)(k+0); 01207 b += *cast(uint *)(k+4); 01208 c += *cast(uint *)(k+8); 01209 01210 a -= b; a -= c; a ^= (c>>13); 01211 b -= c; b -= a; b ^= (a<<8); 01212 c -= a; c -= b; c ^= (b>>13); 01213 a -= b; a -= c; a ^= (c>>12); 01214 b -= c; b -= a; b ^= (a<<16); 01215 c -= a; c -= b; c ^= (b>>5); 01216 a -= b; a -= c; a ^= (c>>3); 01217 b -= c; b -= a; b ^= (a<<10); 01218 c -= a; c -= b; c ^= (b>>15); 01219 k += 12; len -= 12; 01220 } 01221 01222 // handle the last 11 bytes 01223 c += x.length; 01224 switch (len) 01225 { 01226 case 11: c+=(cast(uint)k[10]<<24); 01227 case 10: c+=(cast(uint)k[9]<<16); 01228 case 9 : c+=(cast(uint)k[8]<<8); 01229 case 8 : b+=(cast(uint)k[7]<<24); 01230 case 7 : b+=(cast(uint)k[6]<<16); 01231 case 6 : b+=(cast(uint)k[5]<<8); 01232 case 5 : b+=k[4]; 01233 case 4 : a+=(cast(uint)k[3]<<24); 01234 case 3 : a+=(cast(uint)k[2]<<16); 01235 case 2 : a+=(cast(uint)k[1]<<8); 01236 case 1 : a+=k[0]; 01237 default: 01238 } 01239 01240 a -= b; a -= c; a ^= (c>>13); 01241 b -= c; b -= a; b ^= (a<<8); 01242 c -= a; c -= b; c ^= (b>>13); 01243 a -= b; a -= c; a ^= (c>>12); 01244 b -= c; b -= a; b ^= (a<<16); 01245 c -= a; c -= b; c ^= (b>>5); 01246 a -= b; a -= c; a ^= (c>>3); 01247 b -= c; b -= a; b ^= (a<<10); 01248 c -= a; c -= b; c ^= (b>>15); 01249 01250 return c; 01251 } 01252 01253 /*********************************************************************** 01254 01255 Throw an exception 01256 01257 ***********************************************************************/ 01258 01259 protected final void error (char[] msg) 01260 { 01261 static class TextException : Exception 01262 { 01263 this (char[] msg) 01264 { 01265 super (msg); 01266 } 01267 } 01268 01269 throw new TextException (msg); 01270 } 01271 01272 /*********************************************************************** 01273 01274 Return the valid content from this String 01275 01276 ***********************************************************************/ 01277 01278 package final T[] get () 01279 { 01280 return content [0 .. contentLength]; 01281 } 01282 01283 /*********************************************************************** 01284 01285 Pin the given index to a valid position. 01286 01287 ***********************************************************************/ 01288 01289 protected final void pinIndex (inout int x) 01290 { 01291 if (x > contentLength) 01292 x = contentLength; 01293 } 01294 01295 /*********************************************************************** 01296 01297 Pin the given index and length to a valid position. 01298 01299 ***********************************************************************/ 01300 01301 protected final void pinIndices (inout int start, inout int length) 01302 { 01303 if (start > contentLength) 01304 start = contentLength; 01305 01306 if (length > (contentLength - start)) 01307 length = contentLength - start; 01308 } 01309 01310 /*********************************************************************** 01311 01312 Simple comparator 01313 01314 Compare two arrays. Returns 0 if the content matches, less 01315 than zero if A is "less" than B, or greater than zero where 01316 A is "bigger". Where the substrings match, the shorter is 01317 considered "less". 01318 01319 ***********************************************************************/ 01320 01321 protected final int simpleComparator (T[] a, T[] b) 01322 { 01323 uint i = a.length; 01324 if (b.length < i) 01325 i = b.length; 01326 01327 for (int j, k; j < i; ++j) 01328 if ((k = a[j] - b[j]) != 0) 01329 return k; 01330 01331 return a.length - b.length; 01332 } 01333 } 01334 01335 01336 // convenience alias 01337 alias StringTemplate!(char) String; 01338 01339 // convenience alias 01340 alias MutableStringTemplate!(char) MutableString; 01341