/runtime/array.d

http://github.com/wilkie/djehuty · D · 334 lines · 115 code · 30 blank · 189 comment · 20 complexity · 8d11c59bdffddcc59560f8a95208e873 MD5 · raw file

  1. /*
  2. * array.d
  3. *
  4. * This module implements the runtime functions related
  5. * to arrays.
  6. *
  7. */
  8. module runtime.array;
  9. import core.unicode;
  10. import data.iterable;
  11. import runtime.common;
  12. import math.random;
  13. import core.util;
  14. import io.console;
  15. // Arrays in D are represented as such:
  16. // align(size_t.sizeof)
  17. // struct Array {
  18. // size_t length;
  19. // void* ptr;
  20. // }
  21. extern(C):
  22. // Description: This runtime function reverses a char array in place and is invoked with
  23. // the reverse property: array.reverse
  24. // Returns: The reference to the input.
  25. char[] _adReverseChar(char[] a) {
  26. return a.reverse();
  27. }
  28. // Description: This runtime function reverses a wchar array in place and is invoked with
  29. // the reverse property: array.reverse
  30. // Returns: The reference to the input.
  31. wchar[] _adReverseWchar(wchar[] a) {
  32. return a.reverse();
  33. }
  34. // Description: This runtime function reverses an array in place and
  35. // is invoked with the reverse property: array.reverse
  36. // array: The generic array struct that contains the array items.
  37. // elementSize: The size of an individual element.
  38. // Returns: The reference to the input.
  39. void[] _adReverse(ubyte[] array, size_t elementSize) {
  40. size_t front, end;
  41. // Go from front to end, and swap each index
  42. // Note: Since the array passed has a length measured in a factor
  43. // of elementSize, we need to account for that when we treat
  44. // it is a byte array.
  45. if (array.length == 0) {
  46. return array;
  47. }
  48. front = 0;
  49. end = array.length * elementSize;
  50. ubyte[] cmp = (array.ptr)[0..end];
  51. end -= elementSize;
  52. while(front < end) {
  53. for(size_t i=0; i < elementSize; i++) {
  54. // xor swap elements
  55. cmp[i+front] ^= cmp[i+end];
  56. cmp[i+end] ^= cmp[i+front];
  57. cmp[i+front] ^= cmp[i+end];
  58. }
  59. front += elementSize;
  60. end -= elementSize;
  61. }
  62. return array;
  63. }
  64. // Description: This runtime function will compare two arrays.
  65. // Returns: 0 when equal, positive when first array is larger, negative otherwise.
  66. int _adCmp(void[] a1, void[] a2, TypeInfo ti) {
  67. return ti.compare(&a1, &a2);
  68. }
  69. // Description: This runtime function will compare two utf8 arrays.
  70. // Returns: 0 when equal, positive when first array is larger, negative otherwise.
  71. int _adCmpChar(void[] a1, void[] a2) {
  72. return _adCmp(a1, a2, typeid(char));
  73. }
  74. // Description: This runtime function will compare two arrays for equality.
  75. // Returns: 1 when equal, 0 otherwise
  76. int _adEq(void[] a1, void[] a2, TypeInfo ti) {
  77. return ti.equals(&a1, &a2);
  78. }
  79. // Description: This runtime function sorts an array and is invoked with
  80. // the sort property: array.sort
  81. ubyte[] _adSort(ubyte[] array, TypeInfo ti) {
  82. ubyte[] cmp = (array.ptr)[0..array.length * ti.tsize()];
  83. _qsort(cmp, ti.tsize(), ti);
  84. return array;
  85. }
  86. // Special quicksort implementation
  87. private void _qsort(ubyte[] array, size_t size, TypeInfo ti, Random rnd = null) {
  88. if (rnd is null) {
  89. rnd = new Random();
  90. }
  91. // Base case
  92. if ((array.length/size) < 2) {
  93. return;
  94. }
  95. // Selecting a pivot
  96. size_t length = array.length / size;
  97. size_t element = cast(size_t)rnd.nextLong(length);
  98. element *= size;
  99. //Console.putln("pivot: ", element/size, " array.length: ", array.length/size);
  100. // Move things
  101. size_t end = array.length - size;
  102. for(size_t i = 0; i < array.length; i += size) {
  103. if (i == element) {
  104. continue;
  105. }
  106. if (i > end) {
  107. break;
  108. }
  109. // compare array[i..i+size] to array[element..element+size]
  110. // if < and i < element
  111. // Just continue (this is normal)
  112. // if < and i > element
  113. // Swap i and element ('i' can only be the next element, that is, element+size)
  114. // if > and end == element
  115. // Swap i and element (This will place element to the left of 'i'), decrement end
  116. // if > and end > element
  117. // Swap i with end, decrement end (this is normal)
  118. int cmp = ti.compare(&array[i], &array[element]);
  119. //Console.putln("comparing ", i/size, " against ", element/size, " : ", cmp);
  120. if (cmp < 0) {
  121. // array[i] < array[element]
  122. if (i > element) {
  123. // swap with element
  124. for(size_t idx; idx < size; idx++) {
  125. array[i+idx] ^= array[element+idx];
  126. array[element+idx] ^= array[i+idx];
  127. array[i+idx] ^= array[element+idx];
  128. }
  129. element = i;
  130. }
  131. }
  132. else if (cmp > 0) {
  133. if (end > element) {
  134. if (end != i) {
  135. for(size_t idx; idx < size; idx++) {
  136. array[i+idx] ^= array[end+idx];
  137. array[end+idx] ^= array[i+idx];
  138. array[i+idx] ^= array[end+idx];
  139. }
  140. }
  141. // we need to compare with the item at end
  142. i -= size;
  143. }
  144. else {
  145. // swap with element
  146. for(size_t idx; idx < size; idx++) {
  147. array[i+idx] ^= array[element+idx];
  148. array[element+idx] ^= array[i+idx];
  149. array[i+idx] ^= array[element+idx];
  150. }
  151. element = i;
  152. }
  153. end -= size;
  154. }
  155. }
  156. _qsort(array[0..element], size, ti, rnd);
  157. _qsort(array[element+size..$], size, ti, rnd);
  158. }//*/
  159. // Description: This runtime function sorts a char array and is invoked with
  160. // the sort property: array.sort
  161. ubyte[] _adSortChar(ubyte[] array) {
  162. return _adSort(array, typeid(char[]));
  163. }
  164. // Description: This runtime function sorts a wchar array and is invoked with
  165. // the sort property: array.sort
  166. ubyte[] _adSortWchar(ubyte[] array) {
  167. return _adSort(array, typeid(wchar[]));
  168. }
  169. private template _array_init(T) {
  170. void _array_init(T[] array, T value) {
  171. foreach(ref element; array) {
  172. element = value;
  173. }
  174. }
  175. }
  176. /*
  177. void _d_array_init_i1(bool* array, size_t length, bool value) {
  178. _array_init(array[0..length], value);
  179. }
  180. void _d_array_init_i8(ubyte[] array, ubyte value) {
  181. _array_init(array[0..length], value);
  182. }
  183. void _d_array_init_i16(ushort[] array, ushort value) {
  184. _array_init(array[0..length], value);
  185. }
  186. void _d_array_init_i32(uint[] array, uint value) {
  187. _array_init(array[0..length], value);
  188. }
  189. void _d_array_init_i64(ulong[] array, ulong value) {
  190. _array_init(array[0..length], value);
  191. }
  192. void _d_array_init_float(float[] array, float value) {
  193. _array_init(array[0..length], value);
  194. }
  195. void _d_array_init_double(double* array, size_t length, double value) {
  196. _array_init(array[0..length], value);
  197. }
  198. void _d_array_init_pointer(void** array, size_t length, void* value) {
  199. _array_init(array[0..length], value);
  200. }
  201. void _d_array_init_mem(ubyte* array, size_t length, ubyte* value, size_t valueLength) {
  202. if (valueLength == 0 || length == 0) {
  203. return;
  204. }
  205. ubyte[] cmp = array[0..length*valueLength];
  206. size_t valueIndex = 0;
  207. foreach(ref element; cmp) {
  208. element = value[valueIndex];
  209. valueIndex++;
  210. if (valueIndex == valueLength) {
  211. valueIndex = 0;
  212. }
  213. }
  214. }
  215. //*/
  216. /*
  217. size_t _d_array_cast_len(size_t length, size_t elementSize, size_t newElementSize) {
  218. if (newElementSize == 1) {
  219. return length * elementSize;
  220. }
  221. else if (length % newElementSize != 0) {
  222. // Probably bad
  223. }
  224. return (length * elementSize) / newElementSize;
  225. }
  226. // Description: This runtime function will simply set the length to reflect storing a different type.
  227. void[] _d_arraycast(size_t toElementSize, size_t fromElementSize, void[] array) {
  228. if (toElementSize == fromElementSize) {
  229. return array;
  230. }
  231. if (toElementSize == 0) {
  232. // Technically does not divide evenly
  233. throw new Exception("Array cast misalignment");
  234. }
  235. size_t numbytes = array.length * fromElementSize;
  236. // Can we divide this array up into equal parts of the new elements?
  237. if (numbytes % toElementSize != 0) {
  238. // Error
  239. throw new Exception("Array cast misalignment");
  240. }
  241. size_t newLength = numbytes / toElementSize;
  242. // Set the new length
  243. *cast(size_t*)&array = newLength;
  244. return array;
  245. }
  246. byte[] _d_arraycopy(size_t size, byte[] from, byte[] to) {
  247. // The arrays should be of equal size
  248. if (to.length != from.length) {
  249. throw new Exception("Length mismatch for array copy");
  250. }
  251. // Get the memory bounds for the array
  252. byte* toEnd = to.ptr + (to.length * size);
  253. byte* fromEnd = from.ptr + (from.length * size);
  254. // Check for overlapping copy
  255. if (toEnd > from.ptr && fromEnd > to.ptr) {
  256. // Overlapping...
  257. throw new Exception("Array copy overlaps");
  258. }
  259. // Perform the copy
  260. foreach(size_t idx, ref element; to) {
  261. element = from[idx];
  262. }
  263. return to;
  264. }
  265. void _d_array_slice_copy(ubyte* dst, size_t dstLength, ubyte* src, size_t srcLength) {
  266. if (dstLength != srcLength) {
  267. throw new Exception("Length mismatch for array copy");
  268. }
  269. if (dst + dstLength > src && src + srcLength > dst) {
  270. // Overlapping copy
  271. throw new Exception("Array copy overlaps");
  272. }
  273. // Perform the copy
  274. foreach(size_t idx, ref element; dst[0..dstLength]) {
  275. element = src[idx];
  276. }
  277. }
  278. //*/