1 /** 2 DataNode Array Abstraction 3 4 Copyright: 5 Copyright © 2020-2026, Inochi2D Project 6 7 License: 8 $(LINK2 https://github.com/Inochi2D/inochi2d/blob/main/LICENSE, BSD 2-clause License) 9 10 Authors: 11 Luna Nielsen 12 */ 13 module inp.format.array; 14 import nulib.collections.internal.marray; 15 import numem.core.traits; 16 import numem.core.memory; 17 import numem.rc; 18 import numem; 19 20 /** 21 A refcounted array 22 */ 23 struct RcArray(T) { 24 private: 25 @nogc: 26 alias VStoreT = ManagedArray!T; 27 Rc!VStoreT values; 28 29 public: 30 alias data this; 31 32 /** 33 Length of the array. 34 */ 35 @property size_t length() pure => values ? values.length : 0; 36 37 /** 38 The data stored in the refcounted array. 39 */ 40 @property T[] data() => values ? values.value : null; 41 42 /** 43 Makes a new array. 44 */ 45 static typeof(this) make() { 46 typeof(this) result; 47 result.values = Rc!(VStoreT)(VStoreT()); 48 return result; 49 } 50 51 /// Destructor 52 ~this() nothrow @trusted { 53 if (values) { 54 values.release(); 55 } 56 } 57 58 /** 59 Creates a new RC array with values copied from the given slice. 60 61 Params: 62 values = Slice of values to put into the array 63 */ 64 this(T[] values) { 65 this.values = Rc!(VStoreT)(VStoreT()); 66 this.values.resize(values.length); 67 nu_memcpy(&this.values, &values, values.length*T.sizeof); 68 } 69 70 /** 71 Copy-constructor 72 */ 73 this()(auto ref return scope inout(typeof(this)) rhs) pure nothrow @trusted { 74 nu_memmove(&values, &rhs.values, typeof(values).sizeof); 75 if (values) 76 values.retain(); 77 } 78 79 /** 80 Assigns an element of the array. 81 82 Params: 83 i = The index to set. 84 value = The value to set. 85 */ 86 void opIndexAssign()(auto ref TValue value, size_t i) { 87 assert(values); 88 assert(i < length); 89 90 this.values[i] = value; 91 } 92 93 /** 94 Assignment operator 95 */ 96 void opAssign()(auto ref return scope inout(typeof(this)) rhs) { 97 if (values) 98 values.release(); 99 100 nu_memmove(&values, &rhs.values, typeof(values).sizeof); 101 if (values) 102 values.retain(); 103 } 104 105 /** 106 Adds the given entry into the array. 107 108 Params: 109 rhs = Value to append 110 */ 111 void opOpAssign(string op)(T rhs) 112 if (op == "~") { 113 this.values.resize(values.length+1); 114 this.values[$-1] = rhs; 115 } 116 117 /** 118 Adds the given entry into the array. 119 120 Params: 121 rhs = Value to append 122 */ 123 void opOpAssign(string op)(T[] rhs) 124 if (op == "~") { 125 assert(rhs.ptr-values.ptr >= 0); 126 127 ptrdiff_t copyStart = rhs.ptr-values.ptr; 128 ptrdiff_t copyLength = rhs.length; 129 ptrdiff_t copyEnd = copyOffset+copyLength; 130 bool overlap = nu_is_overlapping(values.ptr, values.length, rhs.ptr, rhs.length); 131 this.values.resize(values.length+rhs.length); 132 133 // On overlap we need to readjust our input slice. 134 if (overlap) 135 rhs = values[copyStart..copyEnd]; 136 137 this.values[copyEnd..copyEnd+copyLength] = rhs[copyStart..copyEnd]; 138 } 139 140 /** 141 Removes the given key from the object. 142 143 Params: 144 i = The index to remove. 145 */ 146 void remove()(size_t i) { 147 assert(i < values.length); 148 values.deleteRange(values[i..i+1]); 149 } 150 151 /** 152 Resizes the reference counted array. 153 154 Params: 155 length = The new length. 156 */ 157 void resize(size_t length) { 158 this.values.resize(length); 159 } 160 161 /** 162 Indexes the array. 163 164 Params: 165 i = The index. 166 167 Returns: 168 The item at the index. 169 */ 170 auto ref T opIndex()(size_t i) { 171 assert(i < values.value.length); 172 return values[i]; 173 } 174 175 /** 176 Dict-iterator 177 */ 178 int opApply(scope int delegate(ref size_t index, ref T value) dg) { 179 if (!values) 180 return 0; 181 182 auto dgf = cast(int delegate(ref size_t index, ref T value) @nogc scope)dg; 183 foreach (i; 0..values.length) { 184 int result = dgf(i, values[i]); 185 if (result) 186 return result; 187 } 188 return 0; 189 } 190 191 /** 192 Dict-iterator 193 */ 194 int opApply(scope int delegate(ref T value) dg) { 195 if (!values) 196 return 0; 197 198 auto dgf = cast(int delegate(ref T value) @nogc scope)dg; 199 foreach (i; 0..values.length) { 200 int result = dgf(values[i]); 201 if (result) 202 return result; 203 } 204 return 0; 205 } 206 } 207 208 /// UTF8 refcounted string 209 alias RcString = RcArray!char;