deno.land / std@0.173.0 / bytes / bytes_list.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
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.// This module is browser compatible.
/** * An abstraction of multiple Uint8Arrays */export class BytesList { #len = 0; #chunks: { value: Uint8Array; start: number; // start offset from head of chunk end: number; // end offset from head of chunk offset: number; // offset of head in all bytes }[] = []; constructor() {}
/** * Total size of bytes */ size() { return this.#len; } /** * Push bytes with given offset infos */ add(value: Uint8Array, start = 0, end = value.byteLength) { if (value.byteLength === 0 || end - start === 0) { return; } checkRange(start, end, value.byteLength); this.#chunks.push({ value, end, start, offset: this.#len, }); this.#len += end - start; }
/** * Drop head `n` bytes. */ shift(n: number) { if (n === 0) { return; } if (this.#len <= n) { this.#chunks = []; this.#len = 0; return; } const idx = this.getChunkIndex(n); this.#chunks.splice(0, idx); const [chunk] = this.#chunks; if (chunk) { const diff = n - chunk.offset; chunk.start += diff; } let offset = 0; for (const chunk of this.#chunks) { chunk.offset = offset; offset += chunk.end - chunk.start; } this.#len = offset; }
/** * Find chunk index in which `pos` locates by binary-search * returns -1 if out of range */ getChunkIndex(pos: number): number { let max = this.#chunks.length; let min = 0; while (true) { const i = min + Math.floor((max - min) / 2); if (i < 0 || this.#chunks.length <= i) { return -1; } const { offset, start, end } = this.#chunks[i]; const len = end - start; if (offset <= pos && pos < offset + len) { return i; } else if (offset + len <= pos) { min = i + 1; } else { max = i - 1; } } }
/** * Get indexed byte from chunks */ get(i: number): number { if (i < 0 || this.#len <= i) { throw new Error("out of range"); } const idx = this.getChunkIndex(i); const { value, offset, start } = this.#chunks[idx]; return value[start + i - offset]; }
/** * Iterator of bytes from given position */ *iterator(start = 0): IterableIterator<number> { const startIdx = this.getChunkIndex(start); if (startIdx < 0) return; const first = this.#chunks[startIdx]; let firstOffset = start - first.offset; for (let i = startIdx; i < this.#chunks.length; i++) { const chunk = this.#chunks[i]; for (let j = chunk.start + firstOffset; j < chunk.end; j++) { yield chunk.value[j]; } firstOffset = 0; } }
/** * Returns subset of bytes copied */ slice(start: number, end: number = this.#len): Uint8Array { if (end === start) { return new Uint8Array(); } checkRange(start, end, this.#len); const result = new Uint8Array(end - start); const startIdx = this.getChunkIndex(start); const endIdx = this.getChunkIndex(end - 1); let written = 0; for (let i = startIdx; i < endIdx; i++) { const chunk = this.#chunks[i]; const len = chunk.end - chunk.start; result.set(chunk.value.subarray(chunk.start, chunk.end), written); written += len; } const last = this.#chunks[endIdx]; const rest = end - start - written; result.set(last.value.subarray(last.start, last.start + rest), written); return result; } /** * Concatenate chunks into single Uint8Array copied. */ concat(): Uint8Array { const result = new Uint8Array(this.#len); let sum = 0; for (const { value, start, end } of this.#chunks) { result.set(value.subarray(start, end), sum); sum += end - start; } return result; }}
function checkRange(start: number, end: number, len: number) { if (start < 0 || len < start || end < 0 || len < end || end < start) { throw new Error("invalid range"); }}
std

Version Info

Tagged at
a year ago