Skip to content

Commit

Permalink
feat: pass index into encoders/decoders from type
Browse files Browse the repository at this point in the history
  • Loading branch information
yamiteru committed May 15, 2024
1 parent 8b325cd commit 136e6b9
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 73 deletions.
57 changes: 28 additions & 29 deletions src/decode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,46 +14,46 @@ const DecodeError = error("DecodeError");

const TYPES = [
// Boolean
(state: DecodeState) => {
(state) => {
return state.view.getUint8(state.offset) === 1;
},
// UInt
(state: DecodeState, type: Protocol.UInt) => {
const result = state.view[
`getUint${((type.type - 10) * 8) as 8 | 16 | 32}`
](state.offset);
(state, _, index) => {
const result = state.view[`getUint${((index - 10) * 8) as 8 | 16 | 32}`](
state.offset,
);

state.offset += type.type - 10;
state.offset += index - 10;

return result;
},
// Int
(state: DecodeState, type: Protocol.Int) => {
const result = state.view[`getInt${((type.type - 20) * 8) as 8 | 16 | 32}`](
(state, _, index) => {
const result = state.view[`getInt${((index - 20) * 8) as 8 | 16 | 32}`](
state.offset,
);

state.offset += type.type - 20;
state.offset += index - 20;

return result;
},
// Float
(state: DecodeState, type: Protocol.Float) => {
const result = state.view[`getFloat${((type.type - 30) * 8) as 32 | 64}`](
(state, _, index) => {
const result = state.view[`getFloat${((index - 30) * 8) as 32 | 64}`](
state.offset,
);

state.offset += type.type - 30;
state.offset += index - 30;

return result;
},
// Ascii
(state: DecodeState, type: Protocol.Ascii) => {
const length = state.view[`getUint${((type.type - 40) * 8) as 8 | 16}`](
(state, _, index) => {
const length = state.view[`getUint${((index - 40) * 8) as 8 | 16}`](
state.offset,
);

state.offset += type.type - 40;
state.offset += index - 40;

const result = ascii.decode(
new Uint8Array(state.buffer, state.offset, length),
Expand All @@ -64,12 +64,12 @@ const TYPES = [
return result;
},
// Unicode
(state: DecodeState, type: Protocol.Unicode) => {
const length = state.view[`getUint${((type.type - 50) * 8) as 8 | 16}`](
(state, _, index) => {
const length = state.view[`getUint${((index - 50) * 8) as 8 | 16}`](
state.offset,
);

state.offset += type.type - 50;
state.offset += index - 50;

const result = utf8.decode(
new Uint8Array(state.buffer, state.offset, length),
Expand All @@ -80,7 +80,7 @@ const TYPES = [
return result;
},
// Object
(state: DecodeState, type: Protocol.Object) => {
(state, type) => {
const result: Record<string, unknown> = {};

for (let i = 0; i < type.value.length; ++i) {
Expand All @@ -90,12 +90,12 @@ const TYPES = [
return result;
},
// Array
(state: DecodeState, type: Protocol.Array) => {
const length = state.view[`getUint${((type.type - 70) * 8) as 8 | 16}`](
(state, type, index) => {
const length = state.view[`getUint${((index - 70) * 8) as 8 | 16}`](
state.offset,
);

state.offset += type.type - 70;
state.offset += index - 70;

const result: unknown[] = [];

Expand All @@ -106,11 +106,11 @@ const TYPES = [
return result;
},
// Enum
(state: DecodeState, type: Protocol.Enum) => {
(state, type) => {
return type.value[state.view.getUint8(state.offset++)];
},
// Tuple
(state: DecodeState, type: Protocol.Tuple) => {
(state, type) => {
const result: unknown[] = [];

for (let i = 0; i < type.value.length; ++i) {
Expand All @@ -122,19 +122,18 @@ const TYPES = [
] satisfies Decoders;

const run = (state: DecodeState, type: AnyProtocolType) => {
// TODO: get rid of this heresy
const typeCopy = { ...type };
let index = type.type;

if (((typeCopy.type - 100) >>> 31) ^ 1) {
typeCopy.type -= 100;
if (((index - 100) >>> 31) ^ 1) {
index -= 100;

if (state.view.getUint8(state.offset++) === 1) {
state.offset++;
return null;
}
}

const result = (TYPES[(typeCopy.type / 10) | 0] as any)(state, typeCopy);
const result = (TYPES[(index / 10) | 0] as any)(state, type, index);

type.assert?.(result);

Expand Down
69 changes: 29 additions & 40 deletions src/encode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import type {
EncodeState,
Encoders,
Infer,
Protocol,
} from "./types/index.js";
import { alloc, free } from "./utils.js";

Expand All @@ -14,101 +13,91 @@ const EncodeError = error("EncodeError");

const TYPES = [
// Boolean
(state: EncodeState, _: Protocol.Boolean, value: boolean) => {
(state, _1, _2, value) => {
state.view.setUint8(state.offset++, +value);
},
// Uint
(state: EncodeState, type: Protocol.UInt, value: number) => {
state.view[`setUint${((type.type - 10) * 8) as 8 | 16 | 32}`](
(state, _, index, value) => {
state.view[`setUint${((index - 10) * 8) as 8 | 16 | 32}`](
state.offset,
value,
);

state.offset += type.type - 10;
state.offset += index - 10;
},
// Int
(state: EncodeState, type: Protocol.Int, value: number) => {
state.view[`setInt${((type.type - 20) * 8) as 8 | 16 | 32}`](
(state, _, index, value) => {
state.view[`setInt${((index - 20) * 8) as 8 | 16 | 32}`](
state.offset,
value,
);
state.offset += type.type - 20;
state.offset += index - 20;
},
// Float
(state: EncodeState, type: Protocol.Float, value: number) => {
state.view[`setFloat${((type.type - 30) * 8) as 32 | 64}`](
state.offset,
value,
);
state.offset += type.type - 30;
(state, _, index, value) => {
state.view[`setFloat${((index - 30) * 8) as 32 | 64}`](state.offset, value);
state.offset += index - 30;
},
// Ascii
(state: EncodeState, type: Protocol.Ascii, value: string) => {
state.view[`setUint${((type.type - 40) * 8) as 8 | 16}`](
(state, _, index, value) => {
state.view[`setUint${((index - 40) * 8) as 8 | 16}`](
state.offset,
value.length,
);

state.offset += type.type - 40;
state.offset += index - 40;

for (let i = 0; i < value.length; ++i) {
state.view.setUint8(state.offset++, value.charCodeAt(i));
}
},
// Unicode
(state: EncodeState, type: Protocol.Unicode, value: string) => {
(state, _, index, value) => {
const written = encoder.encodeInto(
value,
new Uint8Array(state.buffer, state.offset + (type.type - 50)),
new Uint8Array(state.buffer, state.offset + (index - 50)),
).written;

state.view[`setUint${((type.type - 50) * 8) as 8 | 16}`](
state.offset,
written,
);
state.offset += type.type - 50 + written;
state.view[`setUint${((index - 50) * 8) as 8 | 16}`](state.offset, written);
state.offset += index - 50 + written;
},
// Object
(
state: EncodeState,
type: Protocol.Object,
value: Record<string, unknown>,
) => {
(state, type, _, value) => {
for (let i = 0; i < type.value.length; ++i) {
run(state, type.value[i], value[type.value[i].key]);
}
},
// Array
(state: EncodeState, type: Protocol.Array, value: unknown[]) => {
state.view[`setUint${((type.type - 70) * 8) as 8 | 16}`](
(state, type, index, value) => {
state.view[`setUint${((index - 70) * 8) as 8 | 16}`](
state.offset,
value.length,
);

state.offset += type.type - 70;
state.offset += index - 70;

for (let i = 0; i < value.length; ++i) {
run(state, type.value, value[i]);
}
},
// Enum
(state: EncodeState, type: Protocol.Enum, value: unknown) => {
(state, type, _, value) => {
state.view.setUint8(state.offset++, type.value.indexOf(value));
},
// Tuple
(state: EncodeState, type: Protocol.Tuple, value: unknown[]) => {
(state, type, _, value) => {
for (let i = 0; i < type.value.length; ++i) {
run(state, type.value[i], value[i]);
}
},
] satisfies Encoders;

const run = (state: EncodeState, type: AnyProtocolType, value: unknown) => {
// TODO: get rid of this heresy
const typeCopy = { ...type };
let index = type.type;

if (((index - 100) >>> 31) ^ 1) {
index -= 100;

if (((typeCopy.type - 100) >>> 31) ^ 1) {
typeCopy.type -= 100;
state.view.setUint8(state.offset++, +(value === null));

if (value === null) {
Expand All @@ -118,9 +107,9 @@ const run = (state: EncodeState, type: AnyProtocolType, value: unknown) => {
}
}

typeCopy.assert?.(value);
type.assert?.(value);

(TYPES[(typeCopy.type / 10) | 0] as any)(state, typeCopy, value);
(TYPES[(index / 10) | 0] as any)(state, type, index, value);
};

export const encode = (<const $Type extends AnyProtocolType>(
Expand Down
1 change: 1 addition & 0 deletions src/types/decode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ export type Decoders = [
export type Decoder<$Type extends AnyProtocolType, $Value> = (
state: DecodeState,
type: $Type,
index: number,
) => $Value;
1 change: 1 addition & 0 deletions src/types/encode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,6 @@ export type Encoders = [
export type Encoder<$Type extends AnyProtocolType, $Value> = (
state: EncodeState,
type: $Type,
index: number,
value: $Value,
) => void;
8 changes: 4 additions & 4 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import type { State } from "./types/index.js";
import type { EncodeState } from "./types/encode.js";

const POOL_SIZE = 128_000;
const CHUNK_SIZE = 1_000;
const CHUNK_SIZE = 8_000;
const LAYOUT_SIZE = POOL_SIZE / CHUNK_SIZE;

let POOL_BUFFER = new Uint8Array(POOL_SIZE);
let POOL_LAYOUT = new Uint8Array(LAYOUT_SIZE);
let FREE_CHUNKS = LAYOUT_SIZE;

export const alloc = (chunks: number): State => {
export const alloc = (chunks: number): EncodeState => {
if (FREE_CHUNKS < chunks) {
refill();
}
Expand Down Expand Up @@ -54,7 +54,7 @@ const refill = () => {
FREE_CHUNKS = LAYOUT_SIZE;
};

export const free = (state: State) => {
export const free = (state: EncodeState) => {
if (POOL_BUFFER === state.id) {
POOL_LAYOUT.fill(0, state.layout_start, state.layout_end);
FREE_CHUNKS += state.chunks;
Expand Down

0 comments on commit 136e6b9

Please sign in to comment.