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