| /** |
| * Implementation of dynamic array property support routines. |
| * |
| * Copyright: Copyright Digital Mars 2000 - 2015. |
| * License: Distributed under the |
| * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). |
| * (See accompanying file LICENSE) |
| * Authors: Walter Bright |
| * Source: $(DRUNTIMESRC src/rt/_adi.d) |
| */ |
| |
| module rt.adi; |
| |
| //debug=adi; // uncomment to turn on debugging printf's |
| |
| private |
| { |
| debug(adi) import core.stdc.stdio; |
| import core.stdc.string; |
| import core.stdc.stdlib; |
| import core.memory; |
| import rt.util.utf; |
| |
| extern (C) void[] _adSort(void[] a, TypeInfo ti); |
| } |
| |
| private dchar[] mallocUTF32(C)(in C[] s) |
| { |
| size_t j = 0; |
| auto p = cast(dchar*)malloc(dchar.sizeof * s.length); |
| auto r = p[0..s.length]; // r[] will never be longer than s[] |
| foreach (dchar c; s) |
| r[j++] = c; |
| return r[0 .. j]; |
| } |
| |
| /********************************************** |
| * Sort array of chars. |
| */ |
| |
| extern (C) char[] _adSortChar(char[] a) |
| { |
| if (a.length > 1) |
| { |
| auto da = mallocUTF32(a); |
| _adSort(*cast(void[]*)&da, typeid(da[0])); |
| size_t i = 0; |
| foreach (dchar d; da) |
| { char[4] buf; |
| auto t = toUTF8(buf, d); |
| a[i .. i + t.length] = t[]; |
| i += t.length; |
| } |
| free(da.ptr); |
| } |
| return a; |
| } |
| |
| /********************************************** |
| * Sort array of wchars. |
| */ |
| |
| extern (C) wchar[] _adSortWchar(wchar[] a) |
| { |
| if (a.length > 1) |
| { |
| auto da = mallocUTF32(a); |
| _adSort(*cast(void[]*)&da, typeid(da[0])); |
| size_t i = 0; |
| foreach (dchar d; da) |
| { wchar[2] buf; |
| auto t = toUTF16(buf, d); |
| a[i .. i + t.length] = t[]; |
| i += t.length; |
| } |
| free(da.ptr); |
| } |
| return a; |
| } |
| |
| /*************************************** |
| * Support for array equality test. |
| * Returns: |
| * 1 equal |
| * 0 not equal |
| */ |
| |
| extern (C) int _adEq(void[] a1, void[] a2, TypeInfo ti) |
| { |
| debug(adi) printf("_adEq(a1.length = %d, a2.length = %d)\n", a1.length, a2.length); |
| if (a1.length != a2.length) |
| return 0; // not equal |
| auto sz = ti.tsize; |
| auto p1 = a1.ptr; |
| auto p2 = a2.ptr; |
| |
| if (sz == 1) |
| // We should really have a ti.isPOD() check for this |
| return (memcmp(p1, p2, a1.length) == 0); |
| |
| for (size_t i = 0; i < a1.length; i++) |
| { |
| if (!ti.equals(p1 + i * sz, p2 + i * sz)) |
| return 0; // not equal |
| } |
| return 1; // equal |
| } |
| |
| extern (C) int _adEq2(void[] a1, void[] a2, TypeInfo ti) |
| { |
| debug(adi) printf("_adEq2(a1.length = %d, a2.length = %d)\n", a1.length, a2.length); |
| if (a1.length != a2.length) |
| return 0; // not equal |
| if (!ti.equals(&a1, &a2)) |
| return 0; |
| return 1; |
| } |
| unittest |
| { |
| debug(adi) printf("array.Eq unittest\n"); |
| |
| auto a = "hello"c; |
| |
| assert(a != "hel"); |
| assert(a != "helloo"); |
| assert(a != "betty"); |
| assert(a == "hello"); |
| assert(a != "hxxxx"); |
| |
| float[] fa = [float.nan]; |
| assert(fa != fa); |
| } |
| |
| /*************************************** |
| * Support for array compare test. |
| */ |
| |
| extern (C) int _adCmp(void[] a1, void[] a2, TypeInfo ti) |
| { |
| debug(adi) printf("adCmp()\n"); |
| auto len = a1.length; |
| if (a2.length < len) |
| len = a2.length; |
| auto sz = ti.tsize; |
| void *p1 = a1.ptr; |
| void *p2 = a2.ptr; |
| |
| if (sz == 1) |
| { // We should really have a ti.isPOD() check for this |
| auto c = memcmp(p1, p2, len); |
| if (c) |
| return c; |
| } |
| else |
| { |
| for (size_t i = 0; i < len; i++) |
| { |
| auto c = ti.compare(p1 + i * sz, p2 + i * sz); |
| if (c) |
| return c; |
| } |
| } |
| if (a1.length == a2.length) |
| return 0; |
| return (a1.length > a2.length) ? 1 : -1; |
| } |
| |
| extern (C) int _adCmp2(void[] a1, void[] a2, TypeInfo ti) |
| { |
| debug(adi) printf("_adCmp2(a1.length = %d, a2.length = %d)\n", a1.length, a2.length); |
| return ti.compare(&a1, &a2); |
| } |
| unittest |
| { |
| debug(adi) printf("array.Cmp unittest\n"); |
| |
| auto a = "hello"c; |
| |
| assert(a > "hel"); |
| assert(a >= "hel"); |
| assert(a < "helloo"); |
| assert(a <= "helloo"); |
| assert(a > "betty"); |
| assert(a >= "betty"); |
| assert(a == "hello"); |
| assert(a <= "hello"); |
| assert(a >= "hello"); |
| assert(a < "я"); |
| } |
| |
| /*************************************** |
| * Support for array compare test. |
| */ |
| |
| extern (C) int _adCmpChar(void[] a1, void[] a2) |
| { |
| version (D_InlineAsm_X86) |
| { |
| asm |
| { naked ; |
| |
| push EDI ; |
| push ESI ; |
| |
| mov ESI,a1+4[4+ESP] ; |
| mov EDI,a2+4[4+ESP] ; |
| |
| mov ECX,a1[4+ESP] ; |
| mov EDX,a2[4+ESP] ; |
| |
| cmp ECX,EDX ; |
| jb GotLength ; |
| |
| mov ECX,EDX ; |
| |
| GotLength: |
| cmp ECX,4 ; |
| jb DoBytes ; |
| |
| // Do alignment if neither is dword aligned |
| test ESI,3 ; |
| jz Aligned ; |
| |
| test EDI,3 ; |
| jz Aligned ; |
| DoAlign: |
| mov AL,[ESI] ; //align ESI to dword bounds |
| mov DL,[EDI] ; |
| |
| cmp AL,DL ; |
| jnz Unequal ; |
| |
| inc ESI ; |
| inc EDI ; |
| |
| test ESI,3 ; |
| |
| lea ECX,[ECX-1] ; |
| jnz DoAlign ; |
| Aligned: |
| mov EAX,ECX ; |
| |
| // do multiple of 4 bytes at a time |
| |
| shr ECX,2 ; |
| jz TryOdd ; |
| |
| repe ; |
| cmpsd ; |
| |
| jnz UnequalQuad ; |
| |
| TryOdd: |
| mov ECX,EAX ; |
| DoBytes: |
| // if still equal and not end of string, do up to 3 bytes slightly |
| // slower. |
| |
| and ECX,3 ; |
| jz Equal ; |
| |
| repe ; |
| cmpsb ; |
| |
| jnz Unequal ; |
| Equal: |
| mov EAX,a1[4+ESP] ; |
| mov EDX,a2[4+ESP] ; |
| |
| sub EAX,EDX ; |
| pop ESI ; |
| |
| pop EDI ; |
| ret ; |
| |
| UnequalQuad: |
| mov EDX,[EDI-4] ; |
| mov EAX,[ESI-4] ; |
| |
| cmp AL,DL ; |
| jnz Unequal ; |
| |
| cmp AH,DH ; |
| jnz Unequal ; |
| |
| shr EAX,16 ; |
| |
| shr EDX,16 ; |
| |
| cmp AL,DL ; |
| jnz Unequal ; |
| |
| cmp AH,DH ; |
| Unequal: |
| sbb EAX,EAX ; |
| pop ESI ; |
| |
| or EAX,1 ; |
| pop EDI ; |
| |
| ret ; |
| } |
| } |
| else |
| { |
| debug(adi) printf("adCmpChar()\n"); |
| auto len = a1.length; |
| if (a2.length < len) |
| len = a2.length; |
| auto c = memcmp(cast(char *)a1.ptr, cast(char *)a2.ptr, len); |
| if (!c) |
| c = cast(int)a1.length - cast(int)a2.length; |
| return c; |
| } |
| } |
| |
| unittest |
| { |
| debug(adi) printf("array.CmpChar unittest\n"); |
| |
| auto a = "hello"c; |
| |
| assert(a > "hel"); |
| assert(a >= "hel"); |
| assert(a < "helloo"); |
| assert(a <= "helloo"); |
| assert(a > "betty"); |
| assert(a >= "betty"); |
| assert(a == "hello"); |
| assert(a <= "hello"); |
| assert(a >= "hello"); |
| } |