Note: This website is archived. For up-to-date information about D projects and development, please visit wiki.dlang.org.

root/trunk/src/rt/adi.d

Revision 493, 13.3 kB (checked in by braddr, 14 years ago)

merge fixes from d1

  • Property svn:eol-style set to native
Line 
1 /**
2  * Implementation of dynamic array property support routines.
3  *
4  * Copyright: Copyright Digital Mars 2000 - 2010.
5  * License:   <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>.
6  * Authors:   Walter Bright
7  */
8
9 /*          Copyright Digital Mars 2000 - 2010.
10  * Distributed under the Boost Software License, Version 1.0.
11  *    (See accompanying file LICENSE_1_0.txt or copy at
12  *          http://www.boost.org/LICENSE_1_0.txt)
13  */
14 module rt.adi;
15
16 //debug=adi;            // uncomment to turn on debugging printf's
17
18 private
19 {
20     debug(adi) import core.stdc.stdio;
21     import core.stdc.string;
22     import core.stdc.stdlib;
23     import rt.util.utf;
24
25     enum BlkAttr : uint
26     {
27         FINALIZE    = 0b0000_0001,
28         NO_SCAN     = 0b0000_0010,
29         NO_MOVE     = 0b0000_0100,
30         APPENDABLE  = 0b0000_1000,
31         ALL_BITS    = 0b1111_1111
32     }
33
34     extern (C) void* gc_malloc( size_t sz, uint ba = 0 );
35     extern (C) void* gc_calloc( size_t sz, uint ba = 0 );
36     extern (C) void  gc_free( void* p );
37 }
38
39
40 struct Array
41 {
42     size_t  length;
43     void*   ptr;
44 }
45
46 /**********************************************
47  * Reverse array of chars.
48  * Handled separately because embedded multibyte encodings should not be
49  * reversed.
50  */
51
52 extern (C) char[] _adReverseChar(char[] a)
53 {
54     if (a.length > 1)
55     {
56         char[6] tmp;
57         char[6] tmplo;
58         char* lo = a.ptr;
59         char* hi = &a[$ - 1];
60
61         while (lo < hi)
62         {   auto clo = *lo;
63             auto chi = *hi;
64
65             debug(adi) printf("lo = %d, hi = %d\n", lo, hi);
66             if (clo <= 0x7F && chi <= 0x7F)
67             {
68                 debug(adi) printf("\tascii\n");
69                 *lo = chi;
70                 *hi = clo;
71                 lo++;
72                 hi--;
73                 continue;
74             }
75
76             uint stridelo = UTF8stride[clo];
77
78             uint stridehi = 1;
79             while ((chi & 0xC0) == 0x80)
80             {
81                 chi = *--hi;
82                 stridehi++;
83                 assert(hi >= lo);
84             }
85             if (lo == hi)
86                 break;
87
88             debug(adi) printf("\tstridelo = %d, stridehi = %d\n", stridelo, stridehi);
89             if (stridelo == stridehi)
90             {
91
92                 memcpy(tmp.ptr, lo, stridelo);
93                 memcpy(lo, hi, stridelo);
94                 memcpy(hi, tmp.ptr, stridelo);
95                 lo += stridelo;
96                 hi--;
97                 continue;
98             }
99
100             /* Shift the whole array. This is woefully inefficient
101              */
102             memcpy(tmp.ptr, hi, stridehi);
103             memcpy(tmplo.ptr, lo, stridelo);
104             memmove(lo + stridehi, lo + stridelo , cast(size_t)((hi - lo) - stridelo));
105             memcpy(lo, tmp.ptr, stridehi);
106             memcpy(hi + stridehi - stridelo, tmplo.ptr, stridelo);
107
108             lo += stridehi;
109             hi = hi - 1 + cast(int)(stridehi - stridelo);
110         }
111     }
112     return a;
113 }
114
115 unittest
116 {
117     auto a = "abcd"c[];
118
119     auto r = a.dup.reverse;
120     //writefln(r);
121     assert(r == "dcba");
122
123     a = "a\u1235\u1234c";
124     //writefln(a);
125     r = a.dup.reverse;
126     //writefln(r);
127     assert(r == "c\u1234\u1235a");
128
129     a = "ab\u1234c";
130     //writefln(a);
131     r = a.dup.reverse;
132     //writefln(r);
133     assert(r == "c\u1234ba");
134
135     a = "\u3026\u2021\u3061\n";
136     r = a.dup.reverse;
137     assert(r == "\n\u3061\u2021\u3026");
138 }
139
140
141 /**********************************************
142  * Reverse array of wchars.
143  * Handled separately because embedded multiword encodings should not be
144  * reversed.
145  */
146
147 extern (C) wchar[] _adReverseWchar(wchar[] a)
148 {
149     if (a.length > 1)
150     {
151         wchar[2] tmp;
152         wchar* lo = a.ptr;
153         wchar* hi = &a[$ - 1];
154
155         while (lo < hi)
156         {   auto clo = *lo;
157             auto chi = *hi;
158
159             if ((clo < 0xD800 || clo > 0xDFFF) &&
160                 (chi < 0xD800 || chi > 0xDFFF))
161             {
162                 *lo = chi;
163                 *hi = clo;
164                 lo++;
165                 hi--;
166                 continue;
167             }
168
169             int stridelo = 1 + (clo >= 0xD800 && clo <= 0xDBFF);
170
171             int stridehi = 1;
172             if (chi >= 0xDC00 && chi <= 0xDFFF)
173             {
174                 chi = *--hi;
175                 stridehi++;
176                 assert(hi >= lo);
177             }
178             if (lo == hi)
179                 break;
180
181             if (stridelo == stridehi)
182             {   int stmp;
183
184                 assert(stridelo == 2);
185                 assert(stmp.sizeof == 2 * (*lo).sizeof);
186                 stmp = *cast(int*)lo;
187                 *cast(int*)lo = *cast(int*)hi;
188                 *cast(int*)hi = stmp;
189                 lo += stridelo;
190                 hi--;
191                 continue;
192             }
193
194             /* Shift the whole array. This is woefully inefficient
195              */
196             memcpy(tmp.ptr, hi, stridehi * wchar.sizeof);
197             memcpy(hi + stridehi - stridelo, lo, stridelo * wchar.sizeof);
198             memmove(lo + stridehi, lo + stridelo , (hi - (lo + stridelo)) * wchar.sizeof);
199             memcpy(lo, tmp.ptr, stridehi * wchar.sizeof);
200
201             lo += stridehi;
202             hi = hi - 1 + (stridehi - stridelo);
203         }
204     }
205     return a;
206 }
207
208 unittest
209 {
210     wstring a = "abcd";
211
212     auto r = a.dup.reverse;
213     assert(r == "dcba");
214
215     a = "a\U00012356\U00012346c";
216     r = a.dup.reverse;
217     assert(r == "c\U00012346\U00012356a");
218
219     a = "ab\U00012345c";
220     r = a.dup.reverse;
221     assert(r == "c\U00012345ba");
222 }
223
224
225 /**********************************************
226  * Support for array.reverse property.
227  */
228
229 extern (C) void[] _adReverse(Array a, size_t szelem)
230 out (result)
231 {
232     assert(result is *cast(void[]*)(&a));
233 }
234 body
235 {
236     if (a.length >= 2)
237     {
238         byte*    tmp;
239         byte[16] buffer;
240
241         void* lo = a.ptr;
242         void* hi = a.ptr + (a.length - 1) * szelem;
243
244         tmp = buffer.ptr;
245         if (szelem > 16)
246         {
247             //version (Windows)
248                 tmp = cast(byte*) alloca(szelem);
249             //else
250                 //tmp = gc_malloc(szelem);
251         }
252
253         for (; lo < hi; lo += szelem, hi -= szelem)
254         {
255             memcpy(tmp, lo,  szelem);
256             memcpy(lo,  hi,  szelem);
257             memcpy(hi,  tmp, szelem);
258         }
259
260         version (Windows)
261         {
262         }
263         else
264         {
265             //if (szelem > 16)
266                 // BUG: bad code is generate for delete pointer, tries
267                 // to call delclass.
268                 //gc_free(tmp);
269         }
270     }
271     return *cast(void[]*)(&a);
272 }
273
274 unittest
275 {
276     debug(adi) printf("array.reverse.unittest\n");
277
278     int[] a = new int[5];
279     int[] b;
280
281     for (auto i = 0; i < 5; i++)
282         a[i] = i;
283     b = a.reverse;
284     assert(b is a);
285     for (auto i = 0; i < 5; i++)
286         assert(a[i] == 4 - i);
287
288     struct X20
289     {   // More than 16 bytes in size
290         int a;
291         int b, c, d, e;
292     }
293
294     X20[] c = new X20[5];
295     X20[] d;
296
297     for (auto i = 0; i < 5; i++)
298     {   c[i].a = i;
299         c[i].e = 10;
300     }
301     d = c.reverse;
302     assert(d is c);
303     for (auto i = 0; i < 5; i++)
304     {
305         assert(c[i].a == 4 - i);
306         assert(c[i].e == 10);
307     }
308 }
309
310 /**********************************************
311  * Sort array of chars.
312  */
313
314 extern (C) char[] _adSortChar(char[] a)
315 {
316     if (a.length > 1)
317     {
318         dstring da = toUTF32(a);
319         da.sort;
320         size_t i = 0;
321         foreach (dchar d; da)
322         {   char[4] buf;
323             auto t = toUTF8(buf, d);
324             a[i .. i + t.length] = t[];
325             i += t.length;
326         }
327         delete da;
328     }
329     return a;
330 }
331
332 /**********************************************
333  * Sort array of wchars.
334  */
335
336 extern (C) wchar[] _adSortWchar(wchar[] a)
337 {
338     if (a.length > 1)
339     {
340         dstring da = toUTF32(a);
341         da.sort;
342         size_t i = 0;
343         foreach (dchar d; da)
344         {   wchar[2] buf;
345             auto t = toUTF16(buf, d);
346             a[i .. i + t.length] = t[];
347             i += t.length;
348         }
349         delete da;
350     }
351     return a;
352 }
353
354 /***************************************
355  * Support for array equality test.
356  * Returns:
357  *      1       equal
358  *      0       not equal
359  */
360
361 extern (C) int _adEq(Array a1, Array a2, TypeInfo ti)
362 {
363     debug(adi) printf("_adEq(a1.length = %d, a2.length = %d)\n", a1.length, a2.length);
364     if (a1.length != a2.length)
365         return 0; // not equal
366     auto sz = ti.tsize();
367     auto p1 = a1.ptr;
368     auto p2 = a2.ptr;
369
370     if (sz == 1)
371         // We should really have a ti.isPOD() check for this
372         return (memcmp(p1, p2, a1.length) == 0);
373
374     for (size_t i = 0; i < a1.length; i++)
375     {
376         if (!ti.equals(p1 + i * sz, p2 + i * sz))
377             return 0; // not equal
378     }
379     return 1; // equal
380 }
381
382 extern (C) int _adEq2(Array a1, Array a2, TypeInfo ti)
383 {
384     debug(adi) printf("_adEq2(a1.length = %d, a2.length = %d)\n", a1.length, a2.length);
385     if (a1.length != a2.length)
386         return 0;               // not equal
387     if (!ti.equals(&a1, &a2))
388         return 0;
389     return 1;
390 }
391 unittest
392 {
393     debug(adi) printf("array.Eq unittest\n");
394
395     auto a = "hello"c;
396
397     assert(a != "hel");
398     assert(a != "helloo");
399     assert(a != "betty");
400     assert(a == "hello");
401     assert(a != "hxxxx");
402 }
403
404 /***************************************
405  * Support for array compare test.
406  */
407
408 extern (C) int _adCmp(Array a1, Array a2, TypeInfo ti)
409 {
410     debug(adi) printf("adCmp()\n");
411     auto len = a1.length;
412     if (a2.length < len)
413         len = a2.length;
414     auto sz = ti.tsize();
415     void *p1 = a1.ptr;
416     void *p2 = a2.ptr;
417
418     if (sz == 1)
419     {   // We should really have a ti.isPOD() check for this
420         auto c = memcmp(p1, p2, len);
421         if (c)
422             return c;
423     }
424     else
425     {
426         for (size_t i = 0; i < len; i++)
427         {
428             auto c = ti.compare(p1 + i * sz, p2 + i * sz);
429             if (c)
430                 return c;
431         }
432     }
433     if (a1.length == a2.length)
434         return 0;
435     return (a1.length > a2.length) ? 1 : -1;
436 }
437
438 extern (C) int _adCmp2(Array a1, Array a2, TypeInfo ti)
439 {
440     debug(adi) printf("_adCmp2(a1.length = %d, a2.length = %d)\n", a1.length, a2.length);
441     return ti.compare(&a1, &a2);
442 }
443 unittest
444 {
445     debug(adi) printf("array.Cmp unittest\n");
446
447     auto a = "hello"c;
448
449     assert(a >  "hel");
450     assert(a >= "hel");
451     assert(a <  "helloo");
452     assert(a <= "helloo");
453     assert(a >  "betty");
454     assert(a >= "betty");
455     assert(a == "hello");
456     assert(a <= "hello");
457     assert(a >= "hello");
458 }
459
460 /***************************************
461  * Support for array compare test.
462  */
463
464 extern (C) int _adCmpChar(Array a1, Array a2)
465 {
466   version (X86)
467   {
468     asm
469     {   naked                   ;
470
471         push    EDI             ;
472         push    ESI             ;
473
474         mov    ESI,a1+4[4+ESP]  ;
475         mov    EDI,a2+4[4+ESP]  ;
476
477         mov    ECX,a1[4+ESP]    ;
478         mov    EDX,a2[4+ESP]    ;
479
480         cmp     ECX,EDX         ;
481         jb      GotLength       ;
482
483         mov     ECX,EDX         ;
484
485 GotLength:
486         cmp    ECX,4            ;
487         jb    DoBytes           ;
488
489         // Do alignment if neither is dword aligned
490         test    ESI,3           ;
491         jz    Aligned           ;
492
493         test    EDI,3           ;
494         jz    Aligned           ;
495 DoAlign:
496         mov    AL,[ESI]         ; //align ESI to dword bounds
497         mov    DL,[EDI]         ;
498
499         cmp    AL,DL            ;
500         jnz    Unequal          ;
501
502         inc    ESI              ;
503         inc    EDI              ;
504
505         test    ESI,3           ;
506
507         lea    ECX,[ECX-1]      ;
508         jnz    DoAlign          ;
509 Aligned:
510         mov    EAX,ECX          ;
511
512         // do multiple of 4 bytes at a time
513
514         shr    ECX,2            ;
515         jz    TryOdd            ;
516
517         repe                    ;
518         cmpsd                   ;
519
520         jnz    UnequalQuad      ;
521
522 TryOdd:
523         mov    ECX,EAX          ;
524 DoBytes:
525         // if still equal and not end of string, do up to 3 bytes slightly
526         // slower.
527
528         and    ECX,3            ;
529         jz    Equal             ;
530
531         repe                    ;
532         cmpsb                   ;
533
534         jnz    Unequal          ;
535 Equal:
536         mov    EAX,a1[4+ESP]    ;
537         mov    EDX,a2[4+ESP]    ;
538
539         sub    EAX,EDX          ;
540         pop    ESI              ;
541
542         pop    EDI              ;
543         ret                     ;
544
545 UnequalQuad:
546         mov    EDX,[EDI-4]      ;
547         mov    EAX,[ESI-4]      ;
548
549         cmp    AL,DL            ;
550         jnz    Unequal          ;
551
552         cmp    AH,DH            ;
553         jnz    Unequal          ;
554
555         shr    EAX,16           ;
556
557         shr    EDX,16           ;
558
559         cmp    AL,DL            ;
560         jnz    Unequal          ;
561
562         cmp    AH,DH            ;
563 Unequal:
564         sbb    EAX,EAX          ;
565         pop    ESI              ;
566
567         or     EAX,1            ;
568         pop    EDI              ;
569
570         ret                     ;
571     }
572   }
573   else
574   {
575     debug(adi) printf("adCmpChar()\n");
576     auto len = a1.length;
577     if (a2.length < len)
578         len = a2.length;
579     auto c = memcmp(cast(char *)a1.ptr, cast(char *)a2.ptr, len);
580     if (!c)
581         c = cast(int)a1.length - cast(int)a2.length;
582     return c;
583   }
584 }
585
586 unittest
587 {
588     debug(adi) printf("array.CmpChar unittest\n");
589
590     auto a = "hello"c;
591
592     assert(a >  "hel");
593     assert(a >= "hel");
594     assert(a <  "helloo");
595     assert(a <= "helloo");
596     assert(a >  "betty");
597     assert(a >= "betty");
598     assert(a == "hello");
599     assert(a <= "hello");
600     assert(a >= "hello");
601 }
Note: See TracBrowser for help on using the browser.