]> git.saurik.com Git - schoinion.git/blob - src/index.ts
Initial implementation (cleaved from orchid-core).
[schoinion.git] / src / index.ts
1 /* Schoinion - Scatter-Gather Buffer Routines
2 * Copyright (C) 2017 Jay Freeman (saurik)
3 */
4
5 /* GNU Affero General Public License, Version 3 {{{ */
6 /*
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
16
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 **/
20 /* }}} */
21
22 import * as assert from 'assert';
23 import atob = require('atob');
24 import btoa = require('btoa');
25 import * as te from 'text-encoding';
26
27 const encoder = new te.TextEncoder();
28 const decoder = new te.TextDecoder();
29
30 export function utf8encode(data: string): Uint8Array {
31 return encoder.encode(data);
32 }
33
34 export function utf8decode(data: Uint8Array): string {
35 return decoder.decode(data);
36 }
37
38 export function asc2encode(data: string): Uint8Array {
39 const buffer = new ArrayBuffer(data.length);
40 const array = new Uint8Array(buffer);
41 for (let i = 0; i !== data.length; ++i)
42 array[i] = data.charCodeAt(i);
43 return array;
44 }
45
46 export function asc2decode(data: Uint8Array): string {
47 return String.fromCharCode.apply(null, data);
48 }
49
50 export function js1encode(data: any): Uint8Array {
51 return utf8encode(JSON.stringify(data));
52 }
53
54 export function js1decode(data: Uint8Array): any {
55 return JSON.parse(utf8decode(data));
56 }
57
58 export function b64encode(data: Uint8Array): string {
59 return btoa(asc2decode(data)).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
60 }
61
62 export function b64decode(data: string): Uint8Array {
63 return asc2encode(atob(data.replace(/-/g, "+").replace(/_/g, "/")));
64 }
65
66
67 export function ie3encode(data: number): Uint8Array {
68 const array = new Float64Array(1);
69 array[0] = data;
70 return new Uint8Array(array.buffer);
71 }
72
73 export function ie3decode(data: Uint8Array): number {
74 assert.ok(data.length === 8);
75 const array = new Float64Array(data.buffer, data.byteOffset, 1);
76 return array[0];
77 }
78
79
80 export function join(parts: Uint8Array[]): Uint8Array {
81 let total = 0;
82 parts.forEach((part) => total += part.length);
83 const joined = new Uint8Array(total);
84
85 let offset = 0;
86 parts.forEach((part) => {
87 if (part.constructor !== Uint8Array)
88 part = new Uint8Array(part.buffer, part.byteOffset, part.byteLength);
89 joined.set(part, offset);
90 offset += part.length;
91 });
92
93 return joined;
94 }
95
96 export function part(data: Uint8Array, sizes: number[]): Uint8Array[] {
97 const parted = new Array<Uint8Array>();
98 let offset = 0;
99 sizes.forEach((size) => {
100 if (size === 0)
101 size = data.length - offset;
102 const end = offset + size;
103 assert.ok(data.length >= end);
104 parted.push(data.subarray(offset, end));
105 offset = end;
106 });
107 assert.ok(data.length === offset);
108 return parted;
109 }
110
111 export function concat<T>(data: T[][]): T[] {
112 return Array.prototype.concat.apply([], data);
113 }
114
115
116 export interface Kind {
117 readonly BYTES_PER_ELEMENT: number;
118 new(length: number): ArrayLike<number> & ArrayBufferView;
119 new(array: ArrayLike<number>): ArrayLike<number> & ArrayBufferView;
120 new(buffer: ArrayBufferLike, offset?: number, length?: number): ArrayLike<number> & ArrayBufferView;
121 }
122
123 export function num(kind: Kind, data: Uint8Array): number {
124 assert.ok(data.length === kind.BYTES_PER_ELEMENT);
125 return new kind(data.buffer, data.byteOffset, 1)[0];
126 }
127
128 export function buf(kind: Kind, value: number): Uint8Array {
129 return new Uint8Array(new kind([value]).buffer);
130 }
131
132
133 export function xor(lhs: Uint8Array, rhs: Uint8Array): Uint8Array {
134 const length = lhs.length;
135 assert.ok(rhs.length === length);
136 const value = new Uint8Array(length);
137 for (let index = length; index-- !== 0; )
138 value[index] = lhs[index] ^ rhs[index];
139 return value;
140 }
141
142 export function add(lhs: Uint8Array, rhs: Uint8Array): Uint8Array {
143 const length = lhs.length;
144 assert.ok(rhs.length === length);
145 const value = new Uint8Array(length);
146 let carry = 0;
147 for (let index = length; index-- !== 0; ) {
148 const next = lhs[index] + (rhs[index] + carry);
149 value[index] = next;
150 carry = (next & 0x100) !== 0 ? 1 : 0;
151 }
152 return value;
153 }
154
155 export function sub(lhs: Uint8Array, rhs: Uint8Array): Uint8Array {
156 const length = lhs.length;
157 assert.ok(rhs.length === length);
158 const value = new Uint8Array(length);
159 let carry = 0;
160 for (let index = length; index-- !== 0; ) {
161 const next = lhs[index] - (rhs[index] + carry);
162 value[index] = next;
163 carry = (next & 0x100) !== 0 ? 1 : 0;
164 }
165 return value;
166 }
167
168 export function cmp(lhs: Uint8Array, rhs: Uint8Array): number {
169 const length = lhs.length;
170 assert.ok(rhs.length === length);
171 for (let index = 0; index !== length; ++index)
172 if (lhs[index] !== rhs[index])
173 return lhs[index] < rhs[index] ? -1 : 1;
174 return 0;
175 }
176
177 export function max(length: number): Uint8Array {
178 return new Uint8Array(length).fill(0xff);
179 }