9
9
# Generic array implementation
11
import crack.lang cmp, free, IndexError, InvalidArgumentError, AssertionError, Formatter;
12
import crack.io cout, Writer, FStr, StandardFormatter;
13
11
import crack.algorithm QuickSort;
12
import crack.io cout, FStr, StandardFormatter, Writer;
13
import crack.lang cmp, free, AssertionError, Formatter, IndexError,
15
16
# we use poormac here because the standard macro mechanism depends on this
19
20
void _bind(Object obj) { obj.oper bind(); }
20
21
void _release(Object obj) { obj.oper release(); }
21
22
bool _isObject(Object obj) { return true; }
22
bool _isNull(Object obj) {
23
bool _isNull(Object obj) { return (obj is null); }
27
26
void _bind($1 i) { }
50
49
## An Array is a sequence backed by a low-level array. It supports the
51
## bracket operators and adding items at the end.
50
## bracket operators, iteration, and insertion and append of new elements.
52
## Array supports negative indexes. a[-1] is the last item in the array 'a'.
52
53
class Array[Elem] {
56
57
throw IndexError(FStr() I`Index out of range in Array.oper []= \
57
(index = $index, size = $__size)`);
58
(index = $index, size = $__size)`
68
69
if ($1 >= __size) {
70
71
throw IndexError(FStr() I`Index out of range in Array.oper [] \
71
(index = $_i, size = $__size)`);
72
(index = $_i, size = $__size)`
83
85
# the unsigned case) if we want to report the index correctly.
85
87
throw IndexError(FStr() I`Index out of range in Array.oper \
86
[]= (index = $index, size = $__size)`);
88
[]= (index = $index, size = $__size)`
94
97
uint __cap, __size;
97
Elem oper []=(int index, Elem elem) {
99
## Sets the element at the specified index. There must already be an
100
## element at the index.
101
@final Elem oper []=(int index, Elem elem) {
103
Elem oper []=(uint index, Elem elem) { @_setItem index }
106
uint count() { return __size; }
108
@static bool elemIsNull(Elem e) { return _isNull(e); }
111
Elem oper [](int index) {
106
## Sets the element at the specified index. There must already be an
107
## element at the index.
108
@final Elem oper []=(uint index, Elem elem) { @_setItem index }
110
## Returns the number of elements in the array.
111
@final uint count() { return __size; }
113
## Returns the element at the specified index.
114
@final Elem oper [](int index) {
117
Elem oper [](uint index) {
119
## Returns the element at the specified index.
120
@final Elem oper [](uint index) {
124
## Returns the last element in the array.
124
127
throw IndexError('last() called on an empty array.');
125
128
return __rep[__size - 1];
128
## convert negative indexes.
130
int __adjust(int index) {
131
## Converts a negative (end-relative) index to a positive one.
132
@final int __adjust(int index) {
132
134
index = __size + index;
169
## The iterator class.
167
170
class ArrayIter {
170
173
bool __first = true;
172
175
oper init(Array arr) : __arr = arr {}
177
## Returns the element referenced by the iterator.
175
179
return __arr[__index];
182
## Forwards the iterator to the next element, returns true if it is
183
## still valid, false if it has fallen off the end.
180
185
cnt := __arr.count();
181
186
if (__index < cnt) {
182
187
__index = __index + 1;
193
return __index < __arr.count();
194
## Returns the index of the element currently referenced by the
199
196
@final uint _getIndex() { return __index; }
198
## Returns true if the iterator is valid.
202
200
return __index < __arr.count();
204
## Constructs an array given its initial capacity.
206
205
oper init(uint initCapacity) :
207
206
__rep = array[Elem](initCapacity),
208
207
__cap = initCapacity,
211
## Constructs an array with the default initial capacity (currently 16).
213
213
__rep = array[Elem](16),
218
oper init(array[Elem] rep, uint cap, uint size, bool takeOwnership):
218
## Constructs and array from an existing low-level representation ('rep')
219
## of the specified size. If 'takeOwnership' is true, takes ownership of
220
## the representation, otherwise makes a copy.
221
oper init(array[Elem] rep, uint cap, uint size, bool takeOwnership) :
249
254
## Increase the capacity of the array (doesn't increase the size).
250
255
## newCapacity must be greater than the existing capacity.
251
void grow(uint newCapacity) {
256
@final void grow(uint newCapacity) {
252
257
uint newCap = newCapacity;
253
258
if (newCap < __cap)
254
259
throw InvalidArgumentError('Array.grow() - decreasing capacity');
274
280
return Array(newRep, __cap, __size, true);
278
void append(Elem elem) {
283
## Append the element to the array.
284
@final void append(Elem elem) {
279
285
if (__size == __cap)
281
287
__rep[__size++] = elem;
319
## Sort the array (using quicksort).
313
321
QuickSort[Array].sort(this);
316
void sort(function[int, Elem, Elem] cmp) {
324
## Sort the array with the given comparison function.
325
@final void sort(function[int, Elem, Elem] cmp) {
317
326
QuickSort[Array].sort(this, cmp);
329
## Returns a sorted copy of the array.
330
@final Array sorted() {
321
331
Array newArray = this.clone();
322
332
QuickSort[Array].sort(newArray);
326
Array sorted(function[int, Elem, Elem] cmp) {
336
## Returns a copy of the array sorted with the given comparison function.
337
@final Array sorted(function[int, Elem, Elem] cmp) {
327
338
Array newArray = this.clone();
328
339
QuickSort[Array].sort(newArray, cmp);
332
bool contains(Elem e) {
333
for (uint i = 0; i < __size; i++){
343
## Returns true if the array contains the specified element.
344
@final bool contains(Elem e) {
345
for (uint i = 0; i < __size; i++) {
334
346
if (cmp(e, __rep[i]) == 0)
340
void map(function[Elem, Elem] f){
352
## Applies the function 'f' to every element of the array.
353
## 'for i < this.count(), this[i] = f(this[i])'
354
@final void map(function[Elem, Elem] f) {
342
356
for (uint i = 0; i < __size; i++){
343
357
newElem = f(__rep[i]);
349
Array mapped(function[Elem, Elem] f){
363
## Returns a copy of the array with f applied to all elements (see map()).
364
@final Array mapped(function[Elem, Elem] f){
350
365
newRep := array[Elem](__cap);
351
366
Array newArray = Array(newRep, __cap, __size, true);
387
## Do a reduce on tha array. 'for elem in array, result = f(result, elem)'
372
388
@final Elem reduce(function[Elem, Elem, Elem] f, Elem initialValue) {
373
389
return __reduce(f, initialValue, 0);
377
Elem reduce(function[Elem, Elem, Elem] f){
392
## Do a reduce on tha array. 'for elem in array, result = f(result, elem)'
393
## Uses the first element as an initial value.
394
@final Elem reduce(function[Elem, Elem, Elem] f) {
378
395
if (__size == 0) throw AssertionError(I"reduce of zero-length Array \
380
397
return __reduce(f, __rep[0], 1);
383
400
## Remove all elements from the array where f(elem) returns false.
384
void filter(function[bool, Elem] f) {
401
@final void filter(function[bool, Elem] f) {
386
403
for (uint i = 0; i < __size; i++) {
400
Array filtered(function[bool, Elem] f) {
417
## Returns a copy of the array with all elements where f(elem) returns
419
@final Array filtered(function[bool, Elem] f) {
401
420
retval := Array();
402
421
for (uint i = 0; i < __size; i++)
403
422
if (f(__rep[i])) retval.append(__rep[i]);
407
void _setSize(uint newSize){
426
## Sets the new size of the array.
427
@final void _setSize(uint newSize) {
408
428
if (newSize > __cap)
409
429
throw IndexError('Index out of range in Array.setSize');
410
430
__size = newSize;
433
## Returns an iterator over the array.
413
434
@final ArrayIter iter() {
414
435
return ArrayIter(this);
438
## returns the capacity of the array.
439
@final uint capacity() {
434
Array _subarray(uint pos, uint len) {
456
@final Array _subarray(uint pos, uint len) {
435
457
if (pos > __size || pos + len > __size)
436
458
throw IndexError(FStr() I`Sub-array index out of range \
437
459
(pos = $pos, len = $len, size = $__size`
450
472
return Array(newRep, newCap, len, true);
454
Array subarray(int pos, uint len) {
476
## Returns a subset of the array of length 'len' beginning at 'pos'.
477
@final Array subarray(int pos, uint len) {
455
478
# adjust a negative position
457
480
pos = int(__size) + pos;
466
489
return _subarray(uint(pos), len);
469
Array subarray(uint pos, uint len) {
492
## Returns a subset of the array of length 'len' beginning at 'pos'.
493
@final Array subarray(uint pos, uint len) {
470
494
return _subarray(pos, len);
473
Array subarray(int pos) {
498
## Returns a subset of the array beginning at 'pos' and extending to the
500
@final Array subarray(int pos) {
474
501
# adjust a negative position
476
503
pos = int(__size) + pos;
478
505
return _subarray(uint(pos), __size - uint(pos));
481
Array subarray(uint pos) {
508
## Returns a subset of the array beginning at 'pos' and extending to the
510
@final Array subarray(uint pos) {
482
511
return _subarray(pos, __size - pos);
485
Array slice(int start, int end) {
514
## Returns a slice of the array beginning at the start index and ending at
515
## the element before the end index.
516
@final Array slice(int start, int end) {
486
517
# adjust negative offsets
488
519
start = int(__size) + start;
511
542
return _subarray(uint(start), uint(end - start));
514
Array slice(uint start, uint end) {
545
## Returns a slice of the array beginning at the start index and ending at
546
## the element before the end index.
547
@final Array slice(uint start, uint end) {
515
548
# bounds checking
517
550
throw IndexError('Start of slice is after end.');
519
552
return _subarray(start, end - start);
523
Array slice(int start) {
555
## Returns a slice of the array beginning at the start index and ending at
556
## the end of the array.
557
@final Array slice(int start) {
524
558
# adjust negative offsets
526
560
start = int(__size) + start;
578
void insert(int index, Elem elem) {
613
## Insert the element at the specified index (elements after the index are
614
## shifted up one slot).
615
@final void insert(int index, Elem elem) {
579
616
index = __adjust(index);
580
617
if (uint(index) > __size)
581
618
throw IndexError('Index out of range in Array.insert()');
596
void insert(ArrayIter i, Elem elem) {
633
## Insert the element at the position of the iterator.
634
@final void insert(ArrayIter i, Elem elem) {
597
635
insert(i._getIndex(), elem);