summaryrefslogtreecommitdiff
path: root/libphobos/libdruntime/core/internal/util/array.d
blob: 6136cfef17d2f20a1d2d268df3d60030907ba8ee (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
/**
 * Array utilities.
 *
 * Copyright: Denis Shelomovskij 2013
 * License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
 * Authors: Denis Shelomovskij
 * Source: $(DRUNTIMESRC core/internal/util/_array.d)
 */
module core.internal.util.array;


import core.internal.string;
import core.stdc.stdint;


// TLS storage shared for all error messages.
private align(2 * size_t.sizeof) char[256] _store;

private char[] errorMessage(Args...)(scope const(char*) format,
    const char[] action, Args args) @trusted
{
    import core.stdc.stdio : snprintf;
    snprintf(&_store[0], _store.sizeof, format, &action[0], args);
    return _store;
}

@safe /* pure dmd @@@BUG11461@@@ */ nothrow:

void enforceTypedArraysConformable(T)(const char[] action,
    const T[] a1, const T[] a2, const bool allowOverlap = false)
{
    _enforceSameLength(action, a1.length, a2.length);
    if (!allowOverlap)
        _enforceNoOverlap(action, arrayToPtr(a1), arrayToPtr(a2), T.sizeof * a1.length);
}

void enforceRawArraysConformable(const char[] action, const size_t elementSize,
    const void[] a1, const void[] a2, const bool allowOverlap = false)
{
    _enforceSameLength(action, a1.length, a2.length);
    if (!allowOverlap)
        _enforceNoOverlap(action, arrayToPtr(a1), arrayToPtr(a2), elementSize * a1.length);
}

private void _enforceSameLength(const char[] action,
    const size_t length1, const size_t length2)
{
    if (length1 == length2)
        return;

    UnsignedStringBuf tmpBuff = void;
    string msg = "Array lengths don't match for ";
    msg ~= action;
    msg ~= ": ";
    msg ~= length1.unsignedToTempString(tmpBuff);
    msg ~= " != ";
    msg ~= length2.unsignedToTempString(tmpBuff);
    assert(0, msg);
}

private void _enforceNoOverlap(const char[] action,
    uintptr_t ptr1, uintptr_t ptr2, const size_t bytes)
{
    const d = ptr1 > ptr2 ? ptr1 - ptr2 : ptr2 - ptr1;
    if (d >= bytes)
        return;
    const overlappedBytes = bytes - d;

    UnsignedStringBuf tmpBuff = void;
    string msg = "Overlapping arrays in ";
    msg ~= action;
    msg ~= ": ";
    msg ~= overlappedBytes.unsignedToTempString(tmpBuff);
    msg ~= " byte(s) overlap of ";
    msg ~= bytes.unsignedToTempString(tmpBuff);
    assert(0, msg);
}

void enforceTypedArraysConformableNogc(T)(const char[] action,
    const T[] a1, const T[] a2, const bool allowOverlap = false)
{
    _enforceSameLengthNogc(action, a1.length, a2.length);
    if (!allowOverlap)
        _enforceNoOverlapNogc(action, arrayToPtr(a1), arrayToPtr(a2), T.sizeof * a1.length);
}

void enforceRawArraysConformableNogc(const char[] action, const size_t elementSize,
    const void[] a1, const void[] a2, const bool allowOverlap = false)
{
    _enforceSameLengthNogc(action, a1.length, a2.length);
    if (!allowOverlap)
        _enforceNoOverlapNogc(action, arrayToPtr(a1), arrayToPtr(a2), elementSize * a1.length);
}

private void _enforceNoOverlapNogc(const ref char[] action,
    uintptr_t ptr1, uintptr_t ptr2, const size_t bytes)
{
    const d = ptr1 > ptr2 ? ptr1 - ptr2 : ptr2 - ptr1;
    if (d >= bytes)
        return;
    const overlappedBytes = bytes - d;

    assert(0, errorMessage("Overlapping arrays in %s: %zu byte(s) overlap of %zu",
        action, overlappedBytes, bytes));
}

private void _enforceSameLengthNogc(const ref char[] action,
    const size_t length1, const size_t length2)
{
    if (length1 == length2)
        return;

    assert(0, errorMessage("Array lengths don't match for %s: %zu != %zu",
        action, length1, length2));
}

private uintptr_t arrayToPtr(const void[] array) @trusted
{
    // Ok because the user will never dereference the pointer
    return cast(uintptr_t)array.ptr;
}