1 /**
2  * Array utilities.
3  *
4  * Copyright: Denis Shelomovskij 2013
5  * License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
6  * Authors: Denis Shelomovskij
7  * Source: $(DRUNTIMESRC core/internal/util/_array.d)
8  */
9 module core.internal.util.array;
10 
11 
12 import core.internal.string;
13 import core.stdc.stdint;
14 
15 
16 // TLS storage shared for all error messages.
17 private align(2 * size_t.sizeof) char[256] _store;
18 
19 private char[] errorMessage(Args...)(scope const(char*) format,
20     const char[] action, Args args) @trusted
21 {
22     import core.stdc.stdio : snprintf;
23     snprintf(&_store[0], _store.sizeof, format, &action[0], args);
24     return _store;
25 }
26 
27 @safe /* pure dmd @@@BUG11461@@@ */ nothrow:
28 
29 void enforceRawArraysConformable(const char[] action, const size_t elementSize,
30     const void[] a1, const void[] a2, const bool allowOverlap = false)
31 {
32     _enforceSameLength(action, a1.length, a2.length);
33     if (!allowOverlap)
34         _enforceNoOverlap(action, arrayToPtr(a1), arrayToPtr(a2), elementSize * a1.length);
35 }
36 
37 private void _enforceSameLength(const char[] action,
38     const size_t length1, const size_t length2)
39 {
40     if (length1 == length2)
41         return;
42 
43     UnsignedStringBuf tmpBuff = void;
44     string msg = "Array lengths don't match for ";
45     msg ~= action;
46     msg ~= ": ";
47     msg ~= length1.unsignedToTempString(tmpBuff);
48     msg ~= " != ";
49     msg ~= length2.unsignedToTempString(tmpBuff);
50     assert(0, msg);
51 }
52 
53 private void _enforceNoOverlap(const char[] action,
54     uintptr_t ptr1, uintptr_t ptr2, const size_t bytes)
55 {
56     const d = ptr1 > ptr2 ? ptr1 - ptr2 : ptr2 - ptr1;
57     if (d >= bytes)
58         return;
59     const overlappedBytes = bytes - d;
60 
61     UnsignedStringBuf tmpBuff = void;
62     string msg = "Overlapping arrays in ";
63     msg ~= action;
64     msg ~= ": ";
65     msg ~= overlappedBytes.unsignedToTempString(tmpBuff);
66     msg ~= " byte(s) overlap of ";
67     msg ~= bytes.unsignedToTempString(tmpBuff);
68     assert(0, msg);
69 }
70 
71 void enforceRawArraysConformableNogc(const char[] action, const size_t elementSize,
72     const void[] a1, const void[] a2, const bool allowOverlap = false)
73 {
74     _enforceSameLengthNogc(action, a1.length, a2.length);
75     if (!allowOverlap)
76         _enforceNoOverlapNogc(action, arrayToPtr(a1), arrayToPtr(a2), elementSize * a1.length);
77 }
78 
79 private void _enforceNoOverlapNogc(const ref char[] action,
80     uintptr_t ptr1, uintptr_t ptr2, const size_t bytes)
81 {
82     const d = ptr1 > ptr2 ? ptr1 - ptr2 : ptr2 - ptr1;
83     if (d >= bytes)
84         return;
85     const overlappedBytes = bytes - d;
86 
87     assert(0, errorMessage("Overlapping arrays in %s: %zu byte(s) overlap of %zu",
88         action, overlappedBytes, bytes));
89 }
90 
91 private void _enforceSameLengthNogc(const ref char[] action,
92     const size_t length1, const size_t length2)
93 {
94     if (length1 == length2)
95         return;
96 
97     assert(0, errorMessage("Array lengths don't match for %s: %zu != %zu",
98         action, length1, length2));
99 }
100 
101 private uintptr_t arrayToPtr(const void[] array) @trusted
102 {
103     // Ok because the user will never dereference the pointer
104     return cast(uintptr_t)array.ptr;
105 }