1 /** 2 * Generic resizeable array 3 * 4 * Compiler implementation of the 5 * $(LINK2 https://www.dlang.org, D programming language). 6 * 7 * Copyright: Copyright (C) 2018-2023 by The D Language Foundation, All Rights Reserved 8 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) 9 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 10 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/barrayf.d, backend/barray.d) 11 * Documentation: https://dlang.org/phobos/dmd_backend_barray.html 12 */ 13 14 module dmd.backend.barray; 15 16 import core.stdc.stdio; 17 import core.stdc.stdlib; 18 import core.stdc.string; 19 20 nothrow: 21 @safe: 22 23 24 import dmd.backend.global : err_nomem; 25 26 /************************************* 27 * A reusable array that ratchets up in capacity. 28 */ 29 struct Barray(T) 30 { 31 /********************** 32 * Set useable length of array. 33 * Params: 34 * length = minimum number of elements in array 35 */ 36 @trusted 37 void setLength(size_t length) 38 { 39 static void enlarge(ref Barray barray, size_t length) 40 { 41 pragma(inline, false); 42 assert(length < size_t.max / (2 * T.sizeof)); // conservative overflow check 43 auto newcap = (barray.capacity == 0) ? length : length + (length >> 1); 44 barray.capacity = (newcap + 15) & ~15; 45 T* p = cast(T*)realloc(barray.array.ptr, barray.capacity * T.sizeof); 46 if (length && !p) 47 { 48 version (unittest) 49 assert(0); 50 else 51 err_nomem(); 52 } 53 barray.array = p[0 .. length]; 54 } 55 56 if (length <= capacity) 57 array = array.ptr[0 .. length]; // the fast path 58 else 59 enlarge(this, length); // the slow path 60 } 61 62 /********************** 63 * Resets length of array to 0 without 64 * free'ing the array memory. This 65 * sets it up for re-using the memory. 66 */ 67 void reset() 68 { 69 setLength(0); 70 } 71 72 /******************* 73 * Append element t to array. 74 * Params: 75 * t = element to append 76 */ 77 void push(T t) 78 { 79 const i = length; 80 setLength(i + 1); 81 array[i] = t; 82 } 83 84 /******************* 85 * Append a 0-initialized element of T to array 86 * Returns: 87 * pointer to appended element 88 */ 89 @trusted 90 T* push() 91 { 92 const i = length; 93 setLength(i + 1); 94 auto p = &array[i]; 95 memset(p, 0, T.sizeof); 96 return p; 97 } 98 99 /********************** 100 * Move the last element from the array into [i]. 101 * Reduce the array length by one. 102 * Params: 103 * i = index of element to remove 104 */ 105 void remove(size_t i) 106 { 107 const len = length - 1; 108 if (i != len) 109 { 110 array[i] = array[len]; 111 } 112 setLength(len); 113 } 114 115 /****************** 116 * Release all memory used. 117 */ 118 @trusted 119 void dtor() 120 { 121 free(array.ptr); 122 array = null; 123 capacity = 0; 124 } 125 126 alias array this; 127 T[] array; 128 129 private: 130 size_t capacity; 131 } 132 133 unittest 134 { 135 Barray!int a; 136 a.setLength(10); 137 assert(a.length == 10); 138 a.setLength(4); 139 assert(a.length == 4); 140 foreach (i, ref v; a[]) 141 v = cast(int) i * 2; 142 foreach (i, ref const v; a[]) 143 assert(v == i * 2); 144 a.remove(3); 145 assert(a.length == 3); 146 a.push(50); 147 a.remove(1); 148 assert(a[1] == 50); 149 a.dtor(); 150 assert(a.length == 0); 151 } 152 153 /************************************** 154 * While Barray is good for reusing a Barray's previous allocation, 155 * it doesn't work if an element of the Barray is itself a Barray. 156 * Rarray aims to fix that. 157 */ 158 159 struct Rarray(T) 160 { 161 /******************* 162 * Append an uninitialized element of T to array. 163 * This leaves allocations used by T intact. 164 * Returns: 165 * pointer to appended element 166 */ 167 T* push() 168 { 169 const i = length; 170 ++length; 171 if (i < barray.length) 172 { 173 return &barray.array[i]; 174 } 175 return barray.push(); 176 } 177 178 ref inout(T) opIndex(size_t i) inout nothrow pure @nogc 179 { 180 assert(i < length); 181 return barray[i]; 182 } 183 184 extern (D) inout(T)[] opSlice() inout nothrow pure @nogc 185 { 186 return barray[0 .. length]; 187 } 188 189 extern (D) inout(T)[] opSlice(size_t a, size_t b) inout nothrow pure @nogc 190 { 191 assert(a <= b && b <= length); 192 return barray[a .. b]; 193 } 194 195 /********************** 196 * Resets length of array to 0 without 197 * free'ing the array memory. This 198 * sets it up for re-using the memory. 199 */ 200 void reset() 201 { 202 length = 0; 203 } 204 205 /****************** 206 * Release all memory used. 207 */ 208 void dtor() 209 { 210 reset(); 211 barray.dtor(); 212 } 213 214 alias opDollar = length; 215 216 /* barray[0 .. barray.capacity] allocated length 217 * barray[0 .. barray.length] initialized length 218 * barray[0 .. length] in use length 219 * 0 <= length <= barray.length <= barray.capacity 220 */ 221 Barray!T barray; 222 223 size_t length; // <= barray.length 224 }