/
LoopedArray.ts
189 lines (165 loc) · 3.92 KB
/
LoopedArray.ts
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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
import IArrayFacade from "../../types/IArrayFacade";
import ValueOutOfRangeException from "../../exceptions/ValueOutOfRangeException";
import IsNotFoundException from "../../exceptions/IsNotFoundException";
import CollectionIsEmptyException from "../../exceptions/CollectionIsEmptyException";
/**
* Linear data structure
* Facade above array
* After reaching full array new pushed elements will be overwritten over old elements
*/
export default class LoopedArray<T> implements IArrayFacade<T> {
private readonly _capacity: number;
private _realLength = 0;
private _array: Array<T>;
/**
* Create empty instance
* @throws {ValueOutOfRangeException} when given capacity is not valid
*/
constructor(capacity: number) {
if (capacity <= 0) {
throw new ValueOutOfRangeException("Capacity must be larger than 0");
}
this._capacity = capacity;
this._array = new Array<T>(0);
}
/**
* Push into end
*/
public push(value: T): void {
if (this._realLength % this._capacity === 0) {
this._array = new Array<T>(0);
}
this._realLength++;
if (!this.isFull()) {
this._array.push(value);
} else {
const indexToPush = (this._realLength % this._capacity) - 1;
this._array.splice(indexToPush, 1, value);
}
}
/**
* Push into start
*/
public unshift(value: T): void {
if (this._realLength % this._capacity === 0) {
this._array = new Array<T>(0);
}
this._realLength++;
if (!this.isFull()) {
this._array.unshift(value);
} else {
this._array.splice(this._capacity - 1);
this._array.unshift(value);
}
}
/**
* Delete node from array's end
* @throws {CollectionIsEmptyException} when array is empty
*/
public pop(): T {
if (this.isEmpty()) {
throw new CollectionIsEmptyException(
"cannot delete because array is empty"
);
}
this._realLength--;
const deletedItem = this._array.pop();
return deletedItem!;
}
/**
* Delete node from array's start
* @throws {CollectionIsEmptyException} when array is empty
*/
public shift(): T {
if (this.isEmpty()) {
throw new CollectionIsEmptyException(
"cannot delete because array is empty"
);
}
this._realLength--;
const deletedItem = this._array.shift();
return deletedItem!;
}
/**
* Get head element data
*/
public peek(): T {
return this._array[this._array.length - 1];
}
/**
* Get tail element data
*/
public peekFromStart(): T {
return this._array[0];
}
/**
* Get array element by index from start
*/
peekByIndex(index: number): T {
return this._array[index];
}
/**
* Push from index
*/
pushFromIndex(value: T, fromIndex: number): void {
this._array[fromIndex] = value;
}
/**
* Get elements as array
*/
public getAsArray(): Array<T> {
return this._array;
}
/**
* Check if element exists in array
*/
public has(item: T): boolean {
return this._array.includes(item);
}
/**
* Is array empty
*/
public isEmpty(): boolean {
return this._array.length === 0;
}
/**
* Is array full
*/
public isFull(): boolean {
return this._array.length >= this._capacity;
}
/**
* List length
*/
public length(): number {
return this._array.length;
}
/**
* Remove all elements from array
*/
public clear(): void {
this._array = new Array<T>(0);
}
/**
* Delete node from array by index from start
*/
deleteFromIndex(fromIndex: number): T {
const deletedElement = this._array[fromIndex];
delete this._array[fromIndex];
return deletedElement;
}
/**
* Add elements to array from array
* */
pushFromArray(elements: Array<T>): void {
elements.forEach((element: T) => {
this.push(element);
});
}
/**
* Reverse array nodes links and swap head with tail
*/
reverse(): void {
this._array = this._array.reverse();
}
}