1/**
2 This module contains support for controlling dynamic arrays' capacity and length
3
4  Copyright: Copyright Digital Mars 2000 - 2019.
5  License: Distributed under the
6       $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
7     (See accompanying file LICENSE)
8  Source: $(DRUNTIMESRC core/internal/_array/_capacity.d)
9*/
10module core.internal.array.capacity;
11
12// HACK: `nothrow` and `pure` is faked.
13private extern (C) void[] _d_arraysetlengthT(const TypeInfo ti, size_t newlength, void[]* p) nothrow pure;
14private extern (C) void[] _d_arraysetlengthiT(const TypeInfo ti, size_t newlength, void[]* p) nothrow pure;
15
16/*
17 * This template is needed because there need to be a `_d_arraysetlengthTTrace!Tarr` instance for every
18 * `_d_arraysetlengthT!Tarr`. By wrapping both of these functions inside of this template we force the
19 * compiler to create a instance of both function for every type that is used.
20 */
21
22/// Implementation of `_d_arraysetlengthT` and `_d_arraysetlengthTTrace`
23template _d_arraysetlengthTImpl(Tarr : T[], T)
24{
25    import core.internal.array.utils : _d_HookTraceImpl;
26
27    private enum errorMessage = "Cannot resize arrays if compiling without support for runtime type information!";
28
29    /**
30     * Resize dynamic array
31     * Params:
32     *  arr = the array that will be resized, taken as a reference
33     *  newlength = new length of array
34     * Returns:
35     *  The new length of the array
36     * Bugs:
37     *   The safety level of this function is faked. It shows itself as `@trusted pure nothrow` to not break existing code.
38     */
39    size_t _d_arraysetlengthT(return scope ref Tarr arr, size_t newlength) @trusted pure nothrow
40    {
41        pragma(inline, false);
42        version (D_TypeInfo)
43        {
44            auto ti = typeid(Tarr);
45
46            static if (__traits(isZeroInit, T))
47                ._d_arraysetlengthT(ti, newlength, cast(void[]*)&arr);
48            else
49                ._d_arraysetlengthiT(ti, newlength, cast(void[]*)&arr);
50
51            return arr.length;
52        }
53        else
54            assert(0, errorMessage);
55    }
56
57    /**
58    * TraceGC wrapper around $(REF _d_arraysetlengthT, core,internal,array,core.internal.array.capacity).
59    * Bugs:
60    *  This function template was ported from a much older runtime hook that bypassed safety,
61    *  purity, and throwabilty checks. To prevent breaking existing code, this function template
62    *  is temporarily declared `@trusted pure nothrow` until the implementation can be brought up to modern D expectations.
63    */
64    alias _d_arraysetlengthTTrace = _d_HookTraceImpl!(Tarr, _d_arraysetlengthT, errorMessage);
65}
66
67@safe unittest
68{
69    struct S
70    {
71        float f = 1.0;
72    }
73
74    int[] arr;
75    _d_arraysetlengthTImpl!(typeof(arr))._d_arraysetlengthT(arr, 16);
76    assert(arr.length == 16);
77    foreach (int i; arr)
78        assert(i == int.init);
79
80    shared S[] arr2;
81    _d_arraysetlengthTImpl!(typeof(arr2))._d_arraysetlengthT(arr2, 16);
82    assert(arr2.length == 16);
83    foreach (s; arr2)
84        assert(s == S.init);
85}
86