1 /** 2 Memory-pool-based dynamic arrays. Optimized for memory usage, can’t fragment the memory. 3 4 Copyright: 5 Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. 6 Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) 7 Copyright (c) 2017-2018 Godot-D contributors 8 9 License: $(LINK2 https://opensource.org/licenses/MIT, MIT License) 10 11 12 */ 13 module godot.core.poolarrays; 14 15 import godot.c; 16 import godot.core.array; 17 import godot.core.defs; 18 import godot.core.string; 19 import godot.core.color; 20 import godot.core.vector2; 21 import godot.core.vector3; 22 23 import std.range.primitives; 24 import std.meta, std.traits; 25 26 private alias PoolArrayTypes = AliasSeq!( 27 ubyte, 28 int, 29 real_t, 30 String, 31 Vector2, 32 Vector3, 33 Color 34 ); 35 36 private template nameOverride(T) 37 { 38 import std.uni : toLower; 39 static if(is(T==ubyte)) enum string nameOverride = "byte"; 40 else static if(is(T==real_t)) enum string nameOverride = "real"; 41 else enum string nameOverride = T.stringof.toLower; 42 } 43 44 private enum string typeName(T) = "godot_pool_"~(nameOverride!T)~"_array"; 45 private enum string readName(T) = "godot_pool_"~(nameOverride!T)~"_array_read_access"; 46 private enum string writeName(T) = "godot_pool_"~(nameOverride!T)~"_array_write_access"; 47 48 alias PoolByteArray = PoolArray!ubyte; 49 alias PoolIntArray = PoolArray!int; 50 alias PoolRealArray = PoolArray!real_t; 51 alias PoolStringArray = PoolArray!String; 52 alias PoolVector2Array = PoolArray!Vector2; 53 alias PoolVector3Array = PoolArray!Vector3; 54 alias PoolColorArray = PoolArray!Color; 55 56 /++ 57 Copy-on-write array for some Godot types, allocated with a memory pool. 58 +/ 59 struct PoolArray(T) 60 { 61 @nogc nothrow: 62 63 static assert(staticIndexOf!(T, PoolArrayTypes) != -1, 64 "Cannot make a Godot PoolArray for a non-Godot type"); 65 66 mixin("package(godot) "~(typeName!T)~" _godot_array;"); 67 68 this(this) 69 { 70 mixin("auto n = _godot_api."~(typeName!T)~"_new_copy;"); 71 const auto tmp = _godot_array; 72 n(&_godot_array, &tmp); 73 } 74 75 PoolArray opAssign(in PoolArray other) 76 { 77 mixin("auto d = _godot_api."~(typeName!T)~"_destroy;"); 78 mixin("auto n = _godot_api."~(typeName!T)~"_new_copy;"); 79 d(&_godot_array); 80 n(&_godot_array, &other._godot_array); 81 return this; 82 } 83 84 /++ 85 C API type to pass to/from C functions 86 +/ 87 static if(is(T==Vector2)) private alias InternalType = godot_vector2; 88 else static if(is(T==Vector3)) private alias InternalType = godot_vector3; 89 else static if(is(T==Color)) private alias InternalType = godot_color; 90 else private alias InternalType = T; 91 92 this(Array arr) 93 { 94 mixin("auto n = _godot_api."~(typeName!T)~"_new_with_array;"); 95 n(&_godot_array, &arr._godot_array); 96 } 97 98 void append_array(in ref PoolArray arr) 99 { 100 mixin("auto a = _godot_api."~(typeName!T)~"_append_array;"); 101 a(&_godot_array, &arr._godot_array); 102 } 103 104 void invert() 105 { 106 mixin("auto i = _godot_api."~(typeName!T)~"_invert;"); 107 i(&_godot_array); 108 } 109 110 void remove(size_t idx) 111 { 112 mixin("auto r = _godot_api."~(typeName!T)~"_remove;"); 113 r(&_godot_array, cast(int)idx); 114 } 115 116 void resize(size_t size) 117 { 118 mixin("auto r = _godot_api."~(typeName!T)~"_resize;"); 119 r(&_godot_array, cast(int)size); 120 } 121 122 size_t size() const 123 { 124 mixin("auto s = _godot_api."~(typeName!T)~"_size;"); 125 return s(&_godot_array); 126 } 127 alias length = size; // D-style name for size 128 alias opDollar = size; 129 130 /// Returns: true if length is 0. 131 bool empty() const 132 { 133 return length == 0; 134 } 135 136 ~this() 137 { 138 mixin("auto d = _godot_api."~(typeName!T)~"_destroy;"); 139 d(&_godot_array); 140 } 141 142 143 // a few functions are different for Strings than for the others: 144 static if(is(T == String)) 145 { 146 void pushBack(in String data) 147 { 148 _godot_api.godot_pool_string_array_push_back(&_godot_array, &data._godot_string); 149 } 150 void insert(size_t idx, in String data) 151 { 152 _godot_api.godot_pool_string_array_insert(&_godot_array, cast(int)idx, &data._godot_string); 153 } 154 void set(size_t idx, in String data) 155 { 156 _godot_api.godot_pool_string_array_set(&_godot_array, cast(int)idx, &data._godot_string); 157 } 158 void opIndexAssign(in String data, size_t idx) 159 { 160 _godot_api.godot_pool_string_array_set(&_godot_array, cast(int)idx, &data._godot_string); 161 } 162 String opIndex(size_t idx) const 163 { 164 String ret = void; 165 ret._godot_string = _godot_api.godot_pool_string_array_get(&_godot_array, cast(int)idx); 166 return ret; 167 } 168 } 169 else 170 { 171 void pushBack(in T data) 172 { 173 mixin("auto p = _godot_api."~(typeName!T)~"_push_back;"); 174 static if(is(T==Vector2) || is(T==Vector3) || is(T==Color)) 175 p(&_godot_array, cast(InternalType*)&data); 176 else p(&_godot_array, data); 177 } 178 void insert(size_t idx, in T data) 179 { 180 mixin("auto i = _godot_api."~(typeName!T)~"_insert;"); 181 static if(is(T==Vector2) || is(T==Vector3) || is(T==Color)) 182 i(&_godot_array, cast(int)idx, cast(InternalType*)&data); 183 else i(&_godot_array, cast(int)idx, data); 184 } 185 void set(size_t idx, in T data) 186 { 187 mixin("auto s = _godot_api."~(typeName!T)~"_set;"); 188 static if(is(T==Vector2) || is(T==Vector3) || is(T==Color)) 189 s(&_godot_array, cast(int)idx, cast(InternalType*)&data); 190 else s(&_godot_array, cast(int)idx, data); 191 } 192 void opIndexAssign(in T data, size_t idx) 193 { 194 mixin("auto s = _godot_api."~(typeName!T)~"_set;"); 195 static if(is(T==Vector2) || is(T==Vector3) || is(T==Color)) 196 s(&_godot_array, cast(int)idx, cast(InternalType*)&data); 197 else s(&_godot_array, cast(int)idx, data); 198 } 199 T opIndex(size_t idx) const 200 { 201 mixin("auto g = _godot_api."~(typeName!T)~"_get;"); 202 static union V 203 { 204 T t; 205 InternalType r; 206 } 207 V v; 208 v.r = g(&_godot_array, cast(int)idx); 209 return v.t; 210 } 211 } 212 213 alias append = pushBack; 214 alias opOpAssign(string op : "~") = pushBack; 215 216 /// Slice-like view of the PoolArray 217 /// TODO: implement this with Read/Write? 218 static struct Range 219 { 220 private 221 { 222 PoolArray* arr; 223 size_t start, end; 224 } 225 226 bool empty() const { return start == end; } 227 size_t length() const { return end - start; } 228 alias opDollar = length; 229 T front() { return (*arr)[start]; } 230 void popFront() { ++start; } 231 T back() { return (*arr)[end-1]; } 232 void popBack() { --end; } 233 T opIndex(size_t index) { return (*arr)[index+start]; } 234 235 Range save() { return this; } 236 } 237 static assert(isRandomAccessRange!Range); 238 239 Range opSlice() { return Range(&this, 0, length); } 240 Range opSlice(size_t start, size_t end) { return Range(&this, start, end); } 241 } 242