-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathArrayBuffer.php
More file actions
147 lines (133 loc) · 3.47 KB
/
ArrayBuffer.php
File metadata and controls
147 lines (133 loc) · 3.47 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
<?php
declare(strict_types=1);
namespace LargeArrayBuffer;
/**
* @template E of object|array|scalar|null
* @implements ArrayBufferInterface<E>
* @author Andreas Wahlen
*/
class ArrayBuffer implements ArrayBufferInterface {
/**
* @readonly
* @var int<1, max>
*/
private int $itemThreshold;
/**
* @readonly
* @var LargeArrayBuffer<E>
*/
private LargeArrayBuffer $buffer;
/**
* @var list<E>
*/
private array $array = [];
/**
* @param int<1, max> $itemThreshold
* @param int $maxMemoryMiB maximum memory usage in MiB, when more data is pushed, disk space is used
* @psalm-param int<1,max> $maxMemoryMiB
* @psalm-param LargeArrayBuffer::SERIALIZER_* $serializer
* @psalm-param LargeArrayBuffer::COMPRESSION_* $compression
*/
public function __construct(int $itemThreshold, int $maxMemoryMiB = 1024, int $serializer = LargeArrayBuffer::SERIALIZER_PHP, int $compression = LargeArrayBuffer::COMPRESSION_NONE) {
$this->itemThreshold = $itemThreshold;
/** @var LargeArrayBuffer<E> $buffer */
$buffer = new LargeArrayBuffer($maxMemoryMiB, $serializer, $compression);
$this->buffer = $buffer;
}
public function next(): void {
if($this->buffer->count() > 0){
$this->buffer->next();
} else {
next($this->array);
}
}
public function valid(): bool {
if($this->buffer->count() > 0){
return $this->buffer->valid();
} else {
return key($this->array) !== null;
}
}
public function current(): mixed {
if($this->buffer->count() > 0){
return $this->buffer->current();
} else {
return current($this->array);
}
}
public function rewind(): void {
if($this->buffer->count() > 0){
$this->buffer->rewind();
} else {
reset($this->array);
}
}
public function count(): int {
if($this->buffer->count() > 0){
return $this->buffer->count();
} else {
return count($this->array);
}
}
public function key(): int {
if($this->buffer->count() > 0){
return $this->buffer->key();
} else {
/** @var int $res */
$res = key($this->array);
return $res;
}
}
public function push(mixed $item): void {
// switch to buffer if threshold is reached
if(count($this->array) >= $this->itemThreshold){
foreach($this->array as $tmpItem){
$this->buffer->push($tmpItem);
}
$this->array = []; // save some memory
}
// add new item
if($this->buffer->count() > 0){
$this->buffer->push($item);
} else {
$this->array[] = $item;
}
}
public function toArray(): array {
if($this->buffer->count() > 0){
return $this->buffer->toArray();
} else {
return $this->array;
}
}
/**
* @psalm-return \SplFixedArray<E>
*/
public function toFixedArray(): \SplFixedArray {
if($this->buffer->count() > 0){
return $this->buffer->toFixedArray();
} else {
$res = new \SplFixedArray(count($this->array));
foreach($this->array as $idx => $item){
$res[$idx] = $item;
}
return $res;
}
}
/**
* @return \Generator send something other than null to terminate
* @psalm-return \Generator<int, E, mixed, void>
*/
public function toGenerator(): \Generator {
if($this->buffer->count() > 0){
yield from $this->buffer->toGenerator();
} else {
foreach($this->array as $item){
$cmd = yield $item;
if($cmd !== null){
break;
}
}
}
}
}