This repository was archived by the owner on Apr 5, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.ts
More file actions
158 lines (127 loc) · 4.93 KB
/
Copy pathindex.ts
File metadata and controls
158 lines (127 loc) · 4.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
import { FixedArray } from "../fixed-array";
export class ArrayList<T> {
private _array: FixedArray<T>;
private _size = 0;
constructor(initialSize = 256) {
this._array = new FixedArray(initialSize);
}
private isInBounds = (i: number) => !(i < 0) && i < this._size;
/** Returns true if this list has an element with the given index */
public has = (i: number) => this.isInBounds(i);
public size = () => this._size;
/** Get an element by index — throws if out of bounds */
public get(i: number) {
if (!this.isInBounds(i)) throw ReferenceError(`Index out of bounds for List size ${this._size}: ${i}`);
return this._array.get(i);
}
/** Set an element by index — throws if out of bounds */
public set(i: number, v: T) {
if (!this.isInBounds(i)) throw ReferenceError(`Index out of bounds for List size ${this._size}: ${i}`);
this._array.set(i, v);
}
/** Get an element by index – returns the second parameter if trying to get out of bounds */
public getSafe<D>(i: number, defaultValue: D) {
return this.has(i)
? this._array.get(i)
: defaultValue;
}
/** Set an element by index — trying to set out of bounds will be ignored */
public setSafe(i: number, v: T) {
if (this.isInBounds(i)) this._array.set(i, v);
}
/**
* Returns the value and the index of the head element as
* ```typescript
* { value: T, index: 0 }
* ```
* */
public getHead = () => {
if (this._size < 1) throw ReferenceError("Cannot get head of an empty array");
return {
value: this._array.get(0),
index: 0
};
}
/**
* Returns the value and the index of the tail element as
* ```typescript
* { value: T, index: number }
* ```
**/
public getTail = () => {
if (this._size < 1) throw ReferenceError("Cannot get tail of an empty array");
return {
value: this._array.get(this._size - 1),
index: this._size - 1
};
}
/** Add a value to the end of the list */
public add(v: T) {
const newIdx = this._size;
const size = this._array.size();
// Standard ArrayList behaviour:
// If adding the element would go out of bounds for the underlying array,
// we make more room by creating a copy of the array with twice the capacity
if (newIdx === size)
this._array = this._array.copy(size * 2);
this._array.set(newIdx, v);
this._size++;
return this;
}
/** Remove an element from the list by index */
public remove(i: number) {
if (!this.isInBounds(i)) throw ReferenceError(`Index out of bounds for List size ${this._size}: ${i}`);
// We move right from the removed element's position,
// shifting all remaining elements one step to the left.
for (let j = i + 1; j < this._array.size(); j++)
this._array.set(j - 1, this._array.get(j));
this._size--;
return this;
}
/** Removes and returns the last element in the list */
public popTail = () => {
if (this._size < 1) throw ReferenceError("Cannot pop from an empty array");
const value = this.get(this._size - 1);
this.remove(this._size - 1);
return value;
}
/** Swap two elements in the list by their indices */
public swapByIndex(aIdx: number, bIdx: number) {
if (!this.isInBounds(aIdx)) throw ReferenceError(`Index out of bounds for List size ${this._size}: ${aIdx}`);
if (!this.isInBounds(bIdx)) throw ReferenceError(`Index out of bounds for List size ${this._size}: ${bIdx}`);
const a = this._array.get(aIdx);
const b = this._array.get(bIdx);
this._array.set(aIdx, b);
this._array.set(bIdx, a);
}
/** Call the given function with all of this list's elements in order */
public forEach(fn: (value: T, index: number, array: this) => void) {
for (let i = 0; i < this._size; i++) {
fn(this.get(i), i, this);
}
}
/** Test each element with the given predicate and return the first element it return true for */
public find(predicate: (value: T, index: number, array: this) => boolean) {
for (let i = 0; i < this._size; i++) {
const value = this.get(i);
if (predicate(value, i, this)) {
return value;
}
}
}
public isEqual(to: ArrayList<T>) {
if (this.size() !== to.size()) return false;
for (let i = 0; i < this._size; i++) {
if (this.get(i) !== to.get(i)) return false;
}
return true;
}
public copy() {
const newList = new ArrayList<T>(this.size() === 0 ? 1 : this.size());
this.forEach(v => newList.add(v));
return newList;
}
public concat(list: ArrayList<T>) {
list.forEach(t => this.add(t));
}
}