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