root/trunk/src/semitwist/util/ctfe.d

Revision 240, 11.2 kB (checked in by Abscissa, 6 months ago)

Fixed for 64bit

  • Property svn:eol-style set to native
Line 
1 // SemiTwist Library
2 // Written in the D programming language.
3
4 module semitwist.util.ctfe;
5
6 import std.algorithm;
7 import std.array;
8 import std.range;
9 import std.stdio;
10 import std.string;
11 import std.traits;
12 import std.uni;
13
14 import semitwist.util.all;
15
16 T[] ctfe_pad(T)(T[] str, int length, T[] padChar=" ")
17 {
18     return ctfe_pad(str, length, true, padChar);
19 }
20 T[] ctfe_pad(T)(T[] str, int length, bool padLeft, T[] padChar=" ")
21 {
22     if(str.length < length)
23     {
24         auto paddingSize = min(length - str.length, int.max);
25         auto padding = ctfe_repeat!(T)(padChar, paddingSize);
26        
27         if(padLeft)
28             str = padding ~ str;
29         else
30             str = str ~ padding;
31     }
32    
33     return str;
34 }
35
36 /*T[] ctfe_repeat(T)(T chr, int count)
37 {
38     return ctfe_repeat("" ~ chr, count);
39 }*/
40 T[] ctfe_repeat(T)(T[] str, int count)
41 {
42     T[] ret = "";
43    
44     for(int i=0; i < count; i++)
45         ret ~= str;
46        
47     return ret;
48 }
49
50 //size_t ctfe_find(T, TElem)(T collection, TElem elem, size_t start=0) if(isSomeString!T && is(unqual!T:TElem[]))
51 size_t ctfe_find(T)(const(T)[] collection, const(T) elem, size_t start=0)
52 {
53     for(size_t i=start; i<collection.length; i++)
54     {
55         if(collection[i] == elem)
56             return i;
57     }
58     return collection.length;
59 }
60
61 size_t ctfe_find(T)(const(T)[] haystack, const(T)[] needle, size_t start=0) //if(isSomeString!T)
62 {
63     if(haystack.length < needle.length)
64         return haystack.length;
65
66     for(size_t i=start; i <= haystack.length-needle.length; i++)
67     {
68         if(haystack[i..i+needle.length] == needle)
69             return i;
70     }
71     return haystack.length;
72 }
73
74 T ctfe_join(T)(T[] strs, T delim) if(isSomeString!T)
75 {
76     T value = "";
77    
78     foreach(i, str; strs)
79         value ~= (i==0?"":delim) ~ str;
80    
81     return value;
82 }
83
84 T ctfe_substitute(T)(T str, T match, T replace) if(isSomeString!T)
85 {
86     T value = "";
87    
88     if(str.length < match.length)
89         return str;
90    
91     while(str.length >= match.length)
92     {
93         if(str[0..match.length] == match)
94         {
95             value ~= replace;
96             str = str[match.length .. $];
97         }
98         else
99         {
100             // Can't do "value ~= str[0];" because of DMD Issue #5722
101             //TODO: Change back to "value ~= str[0];" when DMD Issue #5722 is fixed
102             value ~= [ str[0] ];
103
104             str = str[1 .. $];
105         }
106     }
107     value ~= str;
108     return value;
109 }
110
111 T[] ctfe_split(T)(T str, T delim) if(isSomeString!T)
112 {
113     T[] arr;
114     auto currStr = str;
115     size_t index;
116     while((index=ctfe_find(currStr, delim)) < currStr.length)
117     {
118         arr ~= currStr[0..index];
119         currStr = currStr[index+delim.length..$];
120     }
121     arr ~= currStr;
122     return arr;
123 }
124
125
126 /// ctfe_subMapJoin("Hi WHO. ", "WHO", ["Joey", "Q", "Sue"])
127 /// --> "Hi Joey. Hi Q. Hi Sue. "
128 T ctfe_subMapJoin(T)(T str, T match, T[] replacements) if(isSomeString!T)
129 {
130     T value = "";
131     foreach(T replace; replacements)
132         value ~= ctfe_substitute(str, match, replace);
133
134     return value;
135 }
136
137 bool ctfe_iswhite(dchar ch)
138 {
139     foreach(i; 0..whitespace.length)
140     if(ch == whitespace[i])
141         return true;
142
143     return false;
144 }
145
146 T ctfe_to(T)(string str) if(is(T==uint))
147 {
148     T val = 0;
149     foreach(i; 0..str.length)
150     {
151         auto newVal = cast(ubyte)str[i];
152         if(newVal < cast(ubyte)'0' || newVal > cast(ubyte)'9')
153             throw new Exception("Invalid character");
154        
155         val *= 10;
156         val += newVal - cast(ubyte)'0';
157     }
158    
159     return val;
160 }
161
162 T ctfe_strip(T)(T str) if(isSomeString!T)
163 {
164     if(!__ctfe)
165         return strip(str);
166    
167     return str.ctfe_stripl().ctfe_stripr();
168 }
169
170 T ctfe_stripl(T)(T str) if(isSomeString!T)
171 {
172     if(!__ctfe)
173         return stripl(str);
174    
175     alias ElementEncodingType!T TChar;
176    
177     size_t startIndex = str.length;
178    
179     foreach(i, TChar ch; str)
180     if(!ctfe_isWhite(cast(dchar)ch))
181     {
182         startIndex = i;
183         break;
184     }
185    
186     return str[startIndex..$];
187 }
188
189 T ctfe_stripr(T)(T str) if(isSomeString!T)
190 {
191     if(!__ctfe)
192         return stripr(str);
193    
194     alias ElementEncodingType!T TChar;
195    
196     size_t endIndex = 0;
197    
198     foreach_reverse(i, TChar ch; str)
199     if(!ctfe_isWhite(cast(dchar)ch))
200     {
201         endIndex = i+1;
202         break;
203     }
204    
205     return str[0..endIndex];
206 }
207
208 bool ctfe_isWhite(dchar ch)
209 {
210     return
211         ch == ' ' || ch == '\r' || ch == '\n' || ch == '\t' ||
212         ch == '\v' || ch == '\f' ||
213         ch == '\u2028' || ch == '\u2029' ||
214         ch == '\u0085' || ch == '\u00A0' || ch == '\u1680' || ch == '\u180E' ||
215         (ch >= '\u2000' && ch <= '\u200A') ||
216         ch == '\u202F' || ch == '\u205F' || ch == '\u3000';
217 }
218
219 mixin(unittestSemiTwistDLib(q{
220
221     // ctfe_find ---------------------------
222     mixin(deferEnsure!(q{ ctfe_find("abcde", 'd' ) }, q{ _==3 }));
223     mixin(deferEnsure!(q{ ctfe_find("abcde", 'X' ) }, q{ _==5 }));
224     mixin(deferEnsure!(q{ ctfe_find("abcde", "d" ) }, q{ _==3 }));
225     mixin(deferEnsure!(q{ ctfe_find("abcde", "cd") }, q{ _==2 }));
226     mixin(deferEnsure!(q{ ctfe_find("abcde", "cX") }, q{ _==5 }));
227
228     mixin(deferEnsure!(q{ ctfe_find("cdbcde", 'd' , 2) }, q{ _==4 }));
229     mixin(deferEnsure!(q{ ctfe_find("cdbcde", "d" , 2) }, q{ _==4 }));
230     mixin(deferEnsure!(q{ ctfe_find("cdbcde", "cd", 1) }, q{ _==3 }));
231     mixin(deferEnsure!(q{ ctfe_find("cXbcde", "cX", 1) }, q{ _==6 }));
232
233     mixin(deferEnsure!(q{ ctfe_find("abc", 'a')     }, q{ _==0 }));
234     mixin(deferEnsure!(q{ ctfe_find("abc", 'c')     }, q{ _==2 }));
235     mixin(deferEnsure!(q{ ctfe_find("abc", "a")     }, q{ _==0 }));
236     mixin(deferEnsure!(q{ ctfe_find("abc", "c")     }, q{ _==2 }));
237     mixin(deferEnsure!(q{ ctfe_find("aabbcc", "aa") }, q{ _==0 }));
238     mixin(deferEnsure!(q{ ctfe_find("aabbcc", "cc") }, q{ _==4 }));
239
240     mixin(deferEnsure!(q{ ctfe_find("abc", "abcde") }, q{ _==3 }));
241
242     // ctfe_split ---------------------------
243     mixin(deferEnsure!(q{ ctfe_split("a--b-b--ccc---d----e--", "--") }, q{ _==["a","b-b","ccc","-d","","e",""] }));
244     mixin(deferEnsure!(q{ ctfe_split("-Xa", "-X") }, q{ _==["","a"] }));
245
246     // ctfe_iswhite ---------------------------
247     mixin(deferEnsure!(q{ ctfe_iswhite(' ')  }, q{ _==true  }));
248     mixin(deferEnsure!(q{ ctfe_iswhite('\t') }, q{ _==true  }));
249     mixin(deferEnsure!(q{ ctfe_iswhite('\r') }, q{ _==true  }));
250     mixin(deferEnsure!(q{ ctfe_iswhite('\n') }, q{ _==true  }));
251     mixin(deferEnsure!(q{ ctfe_iswhite('X')  }, q{ _==false }));
252
253     // ctfe_join ---------------------------
254     mixin(deferEnsure!(q{ ctfe_join([""," ","","A","","BC","","D"," ",""], "\n") }, q{ _=="\n \n\nA\n\nBC\n\nD\n \n" }));
255     //mixin(traceVal!(q{ "\n"~ctfe_join([""," ","","A","","BC","","D"," ",""], "\n").escapeDDQS() }));
256
257     // ctfe_substitute ---------------------------
258     enum ctfe_substitute_test_1 = ctfe_substitute("hello", "X", "R");
259     mixin(deferEnsure!(q{ ctfe_substitute_test_1 }, q{ _=="hello" }));
260    
261     enum ctfe_substitute_test_2 = ctfe_substitute("hello", "e", "e");
262     mixin(deferEnsure!(q{ ctfe_substitute_test_2 }, q{ _=="hello" }));
263
264     enum ctfe_substitute_test_3 = ctfe_substitute("hello", "e", "X");
265     mixin(deferEnsure!(q{ ctfe_substitute_test_3 }, q{ _=="hXllo" }));
266    
267     enum ctfe_substitute_test_4 = ctfe_substitute("日本語", "X", "R");
268     mixin(deferEnsure!(q{ ctfe_substitute_test_4 }, q{ _=="日本語" }));
269    
270     enum ctfe_substitute_test_5 = ctfe_substitute("こんにちわ", "X", "R");
271     mixin(deferEnsure!(q{ ctfe_substitute_test_5 }, q{ _=="こんにちわ" }));
272    
273     enum ctfe_substitute_test_6 = ctfe_substitute("こんにちわ", "にち", "ばん");
274     mixin(deferEnsure!(q{ ctfe_substitute_test_6 }, q{ _=="こんばんわ" }));
275    
276     enum wstring ctfe_substitute_test_7 = ctfe_substitute("こんにちわ"w, "にち"w, "ばん"w);
277     mixin(deferEnsure!(q{ ctfe_substitute_test_7 }, q{ _=="こんばんわ"w }));
278    
279     enum dstring ctfe_substitute_test_8 = ctfe_substitute("こんにちわ"d, "にち"d, "ばん"d);
280     mixin(deferEnsure!(q{ ctfe_substitute_test_8 }, q{ _=="こんばんわ"d }));
281    
282     // ctfe_pad ---------------------------
283     enum ctfe_pad_test_1 = ctfe_pad("Hi", 5);
284     mixin(deferEnsure!(`ctfe_pad_test_1`, `_ == "   Hi"`));
285
286     enum ctfe_pad_test_2 = ctfe_pad("Hi", 5, "-");
287     mixin(deferEnsure!(`ctfe_pad_test_2`, `_ == "---Hi"`));
288
289     enum ctfe_pad_test_3 = ctfe_pad("Hi", 1, "-");
290     mixin(deferEnsure!(`ctfe_pad_test_3`, `_ == "Hi"`));
291
292     enum ctfe_pad_test_4 = ctfe_pad("Hi", 4, false);
293     mixin(deferEnsure!(`ctfe_pad_test_4`, `_ == "Hi  "`));
294
295     enum ctfe_pad_test_5 = ctfe_pad("Hi", 1, false);
296     mixin(deferEnsure!(`ctfe_pad_test_5`, `_ == "Hi"`));
297
298     enum ctfe_pad_test_6 = ctfe_pad("Hi", 5, false, "+");
299     mixin(deferEnsure!(`ctfe_pad_test_6`, `_ == "Hi+++"`));
300
301     enum wstring ctfe_pad_test_7 = ctfe_pad("Hi"w, 5);
302     mixin(deferEnsure!(`ctfe_pad_test_7`, `_ == "   Hi"w`));
303
304     enum dstring ctfe_pad_test_8 = ctfe_pad("Hi"d, 5);
305     mixin(deferEnsure!(`ctfe_pad_test_8`, `_ == "   Hi"d`));
306
307 /+
308     // Fails right now
309     enum ctfe_pad_test_9 = ctfe_pad("日本語", 5, "五");
310     mixin(deferEnsure!(`ctfe_pad_test_9`, `_ == "五五日本語"`));
311 +/
312
313     // ctfe_repeat ---------------------------
314     enum ctfe_repeat_test_aneg1 = ctfe_repeat("a", -1);
315     mixin(deferEnsure!(`ctfe_repeat_test_aneg1`, `_ == ""`));
316
317     enum ctfe_repeat_test_a2 = ctfe_repeat("a", 2);
318     mixin(deferEnsure!(`ctfe_repeat_test_a2`, `_ == "aa"`));
319
320     enum ctfe_repeat_test_Ab5 = ctfe_repeat("Ab", 5);
321     mixin(deferEnsure!(`ctfe_repeat_test_Ab5`, `_ == "AbAbAbAbAb"`));
322
323     enum ctfe_repeat_test_Ab0 = ctfe_repeat("Ab", 0);
324     mixin(deferEnsure!(`ctfe_repeat_test_Ab0`, `_ == ""`));
325
326     enum wstring ctfe_repeat_test_a4w = ctfe_repeat("a"w, 4);
327     mixin(deferEnsure!(`ctfe_repeat_test_a4w`, `_ == "aaaa"w`));
328
329     enum dstring ctfe_repeat_test_a4d = ctfe_repeat("a"d, 4);
330     mixin(deferEnsure!(`ctfe_repeat_test_a4d`, `_ == "aaaa"d`));
331
332     enum ctfe_repeat_test_日本語3 = ctfe_repeat("日本語", 3);
333     mixin(deferEnsure!(`ctfe_repeat_test_日本語3`, `_ == "日本語日本語日本語"`));
334
335     // ctfe_subMapJoin ---------------------------
336     enum ctfe_subMapJoin_test_c = ctfe_subMapJoin("Hi WHO. ", "WHO", ["Joey", "Q", "Sue"]);
337     mixin(deferEnsure!(`ctfe_subMapJoin_test_c`, `_ == "Hi Joey. Hi Q. Hi Sue. "`));
338    
339     enum wstring ctfe_subMapJoin_test_w = ctfe_subMapJoin("Hi WHO. "w, "WHO"w, ["Joey"w, "Q"w, "Sue"w]);
340     mixin(deferEnsure!(`ctfe_subMapJoin_test_w`, `_ == "Hi Joey. Hi Q. Hi Sue. "w`));
341    
342     enum dstring ctfe_subMapJoin_test_d = ctfe_subMapJoin("Hi WHO. "d, "WHO"d, ["Joey"d, "Q"d, "Sue"d]);
343     mixin(deferEnsure!(`ctfe_subMapJoin_test_d`, `_ == "Hi Joey. Hi Q. Hi Sue. "d`));
344
345     enum ctfe_subMapJoin_test_cj = ctfe_subMapJoin("こんにちわ、 だれさん。 ", "だれ", ["わたなべ", "ニク", "あおい"]);
346     mixin(deferEnsure!(`ctfe_subMapJoin_test_cj`, `_ == "こんにちわ、 わたなべさん。 こんにちわ、 ニクさん。 こんにちわ、 あおいさん。 "`));
347
348     // ctfe_to!uint(string) ---------------------------
349     enum ctfe_to_uint_string_1 = ctfe_to!uint("0");
350     mixin(deferEnsure!(`ctfe_to_uint_string_1`, `_ == 0`));
351    
352     enum ctfe_to_uint_string_2 = ctfe_to!uint("9");
353     mixin(deferEnsure!(`ctfe_to_uint_string_2`, `_ == 9`));
354    
355     enum ctfe_to_uint_string_3 = ctfe_to!uint("42");
356     mixin(deferEnsure!(`ctfe_to_uint_string_3`, `_ == 42`));
357    
358     enum ctfe_to_uint_string_4 = ctfe_to!uint("65536");
359     mixin(deferEnsure!(`ctfe_to_uint_string_4`, `_ == 65536`));
360
361     // ctfe_strip ---------------------------
362     enum ctfe_strip_test_1 = ctfe_strip(" \tHi \r\n");
363     mixin(deferEnsure!(`ctfe_strip_test_1`, `_ == "Hi"`));
364    
365     enum ctfe_strip_test_2 = ctfe_strip("Hi");
366     mixin(deferEnsure!(`ctfe_strip_test_2`, `_ == "Hi"`));
367    
368     enum ctfe_strip_test_3 = ctfe_strip(" \t \r\n");
369     mixin(deferEnsure!(`ctfe_strip_test_3`, `_ == ""`));
370    
371     enum ctfe_strip_test_4 = ctfe_strip("");
372     mixin(deferEnsure!(`ctfe_strip_test_4`, `_ == ""`));
373    
374     enum ctfe_strip_test_5 = ctfe_strip(" \tHi \r\n"w);
375     mixin(deferEnsure!(`ctfe_strip_test_5`, `_ == "Hi"w`));
376    
377     enum ctfe_strip_test_6 = ctfe_strip(" \tHi \r\n"d);
378     mixin(deferEnsure!(`ctfe_strip_test_6`, `_ == "Hi"d`));
379
380 }));
Note: See TracBrowser for help on using the browser.