Wiki Roadmap Timeline Tickets New Ticket Source Search Help / Guide About Trac Login

root/runtime/internal/adi.d

Revision 855:e78e1d559a76, 14.1 kB (checked in by Christian Kamm <kamm incasoftware de>, 3 years ago)

Apply fix for #151.

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