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 */
9module core.internal.util.array;
10
11
12import core.internal.string;
13import core.stdc.stdint;
14
15
16// TLS storage shared for all error messages.
17private align(2 * size_t.sizeof) char[256] _store;
18
19private 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
29void enforceTypedArraysConformable(T)(const char[] action,
30    const T[] a1, const T[] a2, const bool allowOverlap = false)
31{
32    _enforceSameLength(action, a1.length, a2.length);
33    if (!allowOverlap)
34        _enforceNoOverlap(action, arrayToPtr(a1), arrayToPtr(a2), T.sizeof * a1.length);
35}
36
37void enforceRawArraysConformable(const char[] action, const size_t elementSize,
38    const void[] a1, const void[] a2, const bool allowOverlap = false)
39{
40    _enforceSameLength(action, a1.length, a2.length);
41    if (!allowOverlap)
42        _enforceNoOverlap(action, arrayToPtr(a1), arrayToPtr(a2), elementSize * a1.length);
43}
44
45private void _enforceSameLength(const char[] action,
46    const size_t length1, const size_t length2)
47{
48    if (length1 == length2)
49        return;
50
51    UnsignedStringBuf tmpBuff = void;
52    string msg = "Array lengths don't match for ";
53    msg ~= action;
54    msg ~= ": ";
55    msg ~= length1.unsignedToTempString(tmpBuff);
56    msg ~= " != ";
57    msg ~= length2.unsignedToTempString(tmpBuff);
58    assert(0, msg);
59}
60
61private void _enforceNoOverlap(const char[] action,
62    uintptr_t ptr1, uintptr_t ptr2, const size_t bytes)
63{
64    const d = ptr1 > ptr2 ? ptr1 - ptr2 : ptr2 - ptr1;
65    if (d >= bytes)
66        return;
67    const overlappedBytes = bytes - d;
68
69    UnsignedStringBuf tmpBuff = void;
70    string msg = "Overlapping arrays in ";
71    msg ~= action;
72    msg ~= ": ";
73    msg ~= overlappedBytes.unsignedToTempString(tmpBuff);
74    msg ~= " byte(s) overlap of ";
75    msg ~= bytes.unsignedToTempString(tmpBuff);
76    assert(0, msg);
77}
78
79void enforceTypedArraysConformableNogc(T)(const char[] action,
80    const T[] a1, const T[] a2, const bool allowOverlap = false)
81{
82    _enforceSameLengthNogc(action, a1.length, a2.length);
83    if (!allowOverlap)
84        _enforceNoOverlapNogc(action, arrayToPtr(a1), arrayToPtr(a2), T.sizeof * a1.length);
85}
86
87void enforceRawArraysConformableNogc(const char[] action, const size_t elementSize,
88    const void[] a1, const void[] a2, const bool allowOverlap = false)
89{
90    _enforceSameLengthNogc(action, a1.length, a2.length);
91    if (!allowOverlap)
92        _enforceNoOverlapNogc(action, arrayToPtr(a1), arrayToPtr(a2), elementSize * a1.length);
93}
94
95private void _enforceNoOverlapNogc(const ref char[] action,
96    uintptr_t ptr1, uintptr_t ptr2, const size_t bytes)
97{
98    const d = ptr1 > ptr2 ? ptr1 - ptr2 : ptr2 - ptr1;
99    if (d >= bytes)
100        return;
101    const overlappedBytes = bytes - d;
102
103    assert(0, errorMessage("Overlapping arrays in %s: %zu byte(s) overlap of %zu",
104        action, overlappedBytes, bytes));
105}
106
107private void _enforceSameLengthNogc(const ref char[] action,
108    const size_t length1, const size_t length2)
109{
110    if (length1 == length2)
111        return;
112
113    assert(0, errorMessage("Array lengths don't match for %s: %zu != %zu",
114        action, length1, length2));
115}
116
117private uintptr_t arrayToPtr(const void[] array) @trusted
118{
119    // Ok because the user will never dereference the pointer
120    return cast(uintptr_t)array.ptr;
121}
122