1 /**
2  * Compiler implementation of the
3  * $(LINK2 http://www.dlang.org, D programming language).
4  *
5  * Copyright:   Copyright (C) 2018-2020 by The D Language Foundation, All Rights Reserved
6  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
7  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
8  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/barrayf.d, backend/barray.d)
9  * Documentation: https://dlang.org/phobos/dmd_backend_barray.html
10  */
11 
12 module dmd.backend.barray;
13 
14 import core.stdc.stdio;
15 import core.stdc.stdlib;
16 import core.stdc.string;
17 
18 nothrow:
19 
20 extern (C++): void err_nomem();
21 
22 /*************************************
23  * A reusable array that ratchets up in capacity.
24  */
25 struct Barray(T)
26 {
27     /**********************
28      * Set useable length of array.
29      * Params:
30      *  length = minimum number of elements in array
31      */
32     void setLength(size_t length)
33     {
34         static void enlarge(ref Barray barray, size_t length)
35         {
36             pragma(inline, false);
37             auto newcap = (barray.capacity == 0) ? length : length + (length >> 1);
38             barray.capacity = (newcap + 15) & ~15;
39             T* p = cast(T*)realloc(barray.array.ptr, barray.capacity * T.sizeof);
40             if (length && !p)
41             {
42                 version (unittest)
43                     assert(0);
44                 else
45                     err_nomem();
46             }
47             barray.array = p[0 .. length];
48         }
49 
50         if (length <= capacity)
51             array = array.ptr[0 .. length];     // the fast path
52         else
53             enlarge(this, length);              // the slow path
54     }
55 
56 
57     /*******************
58      * Append element t to array.
59      * Params:
60      *  t = element to append
61      */
62     void push(T t)
63     {
64         const i = length;
65         setLength(i + 1);
66         array[i] = t;
67     }
68 
69     /**********************
70      * Move the last element from the array into [i].
71      * Reduce the array length by one.
72      * Params:
73      *  i = index of element to remove
74      */
75     void remove(size_t i)
76     {
77         const len = length - 1;
78         if (i != len)
79         {
80             array[i] = array[len];
81         }
82         setLength(len);
83     }
84 
85     /******************
86      * Release all memory used.
87      */
88     ~this()
89     {
90         free(array.ptr);
91         array = null;
92         capacity = 0;
93     }
94 
95     alias array this;
96     T[] array;
97 
98   private:
99     size_t capacity;
100 }
101 
102 unittest
103 {
104     Barray!int a;
105     a.setLength(10);
106     assert(a.length == 10);
107     a.setLength(4);
108     assert(a.length == 4);
109     foreach (i, ref v; a[])
110         v = cast(int) i * 2;
111     foreach (i, ref const v; a[])
112         assert(v == i * 2);
113     a.remove(3);
114     assert(a.length == 3);
115     a.push(50);
116     a.remove(1);
117     assert(a[1] == 50);
118 }