Created
March 23, 2023 14:38
-
-
Save martian17/95f4ee3756415ce4ad1b357f26836a94 to your computer and use it in GitHub Desktop.
meta programming in ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//util functions | |
const isNode = typeof window === "undefined"; | |
const U8FromView = function(view: ArrayBufferView): Uint8Array{ | |
if(view instanceof Uint8Array){ | |
return view; | |
} | |
return new Uint8Array(view.buffer,view.byteOffset,view.byteLength); | |
}; | |
const allocUnsafe: (n: number) => Uint8Array = isNode?function(n){ | |
return new Uint8Array(Buffer.allocUnsafe(n).buffer,0,n); | |
}:function(n){ | |
return new Uint8Array(new ArrayBuffer(n)); | |
}; | |
const BE_writer_2 = function(u81: Uint8Array, u82: Uint8Array, offset: number){ | |
u81[offset] = u82[1]; | |
u81[offset+1] = u82[0]; | |
}; | |
const BE_writer_4 = function(u81: Uint8Array, u82: Uint8Array, offset: number){ | |
u81[offset] = u82[3]; | |
u81[offset+1] = u82[2]; | |
u81[offset+2] = u82[1]; | |
u81[offset+3] = u82[0]; | |
}; | |
const BE_writer_8 = function(u81: Uint8Array, u82: Uint8Array, offset: number){ | |
u81[offset] = u82[7]; | |
u81[offset+1] = u82[6]; | |
u81[offset+2] = u82[5]; | |
u81[offset+3] = u82[4]; | |
u81[offset+4] = u82[3]; | |
u81[offset+5] = u82[2]; | |
u81[offset+6] = u82[1]; | |
u81[offset+7] = u82[0]; | |
}; | |
// constants | |
const VERBOSE = false; | |
##@import constants from autogen_methods | |
export class BufferBuilder{ | |
length:number = 0; | |
u8: Uint8Array; | |
constructor(size: number = 512,length: number = 0){ | |
this.u8 = allocUnsafe(size); | |
this.length = length; | |
if(length !== 0){ | |
this.u8.fill(0,0,length); | |
} | |
} | |
alloc(){ | |
if(this.length < this.u8.length){ | |
return; | |
} | |
let len = this.u8.length; | |
while(len < this.length){ | |
len *= 2; | |
} | |
const u8n = allocUnsafe(len); | |
u8n.set(this.u8); | |
this.u8 = u8n; | |
} | |
grow(n: number){ | |
this.length += n; | |
this.alloc(); | |
} | |
growIfNoSpace(offset: number, insertLength: number){ | |
const newalloc = offset + insertLength - this.length; | |
if(newalloc > 0){ | |
this.grow(newalloc); | |
} | |
} | |
set_buffer(view: ArrayBufferView, offset: number = 0){ | |
const u8 = U8FromView(view); | |
this.growIfNoSpace(offset,u8.length); | |
this.u8.set(u8,offset); | |
} | |
set_BE16_buffer(view: ArrayBufferView, offset: number = 0){ | |
const u8 = U8FromView(view); | |
this.growIfNoSpace(offset,u8.length); | |
for(let i = 0; i+1 < u8.length; i+=2){ | |
this.u8[offset+i] = u8[i+1]; | |
this.u8[offset+i+1] = u8[i]; | |
} | |
} | |
set_BE32_buffer(view: ArrayBufferView, offset: number = 0){ | |
const u8 = U8FromView(view); | |
this.growIfNoSpace(offset,u8.length); | |
for(let i = 0; i+3 < u8.length; i+=4){ | |
this.u8[offset+i] = u8[i+3]; | |
this.u8[offset+i+1] = u8[i+2]; | |
this.u8[offset+i+2] = u8[i+1]; | |
this.u8[offset+i+3] = u8[i]; | |
} | |
} | |
set_BE64_buffer(view: ArrayBufferView, offset: number = 0){ | |
const u8 = U8FromView(view); | |
this.growIfNoSpace(offset,u8.length); | |
for(let i = 0; i+7 < u8.length; i+=8){ | |
this.u8[offset+i] = u8[i+7]; | |
this.u8[offset+i+1] = u8[i+6]; | |
this.u8[offset+i+2] = u8[i+5]; | |
this.u8[offset+i+3] = u8[i+4]; | |
this.u8[offset+i+4] = u8[i+3]; | |
this.u8[offset+i+5] = u8[i+2]; | |
this.u8[offset+i+6] = u8[i+1]; | |
this.u8[offset+i+7] = u8[i]; | |
} | |
} | |
append_buffer(buff: ArrayBufferView){ | |
this.set_buffer(buff,this.length); | |
} | |
append_BE16_buffer(buff: ArrayBufferView){ | |
this.set_BE16_buffer(buff,this.length); | |
} | |
append_BE32_buffer(buff: ArrayBufferView){ | |
this.set_BE32_buffer(buff,this.length); | |
} | |
append_BE64_buffer(buff: ArrayBufferView){ | |
this.set_BE64_buffer(buff,this.length); | |
} | |
export_u8(): Uint8Array { | |
if(VERBOSE)console.log("exported length:",this.length); | |
if(VERBOSE)console.log("background buffer length:",this.u8.length); | |
return this.u8.subarray(0,this.length); | |
} | |
export_buffer(): Buffer { | |
return Buffer.from(this.u8,0,this.length); | |
} | |
export(): Uint8Array | Buffer { | |
if(isNode){ | |
return Buffer.from(this.u8,0,this.length); | |
}else{ | |
return this.u8.subarray(0,this.length); | |
} | |
} | |
// methods are auto generated using build script at index.pts | |
##@import methods from autogen_methods | |
}; | |
##@begin autogen_methods | |
const types = [ | |
["U8" , "Uint8Array" ], | |
["U16", "Uint16Array" ], | |
["U32", "Uint32Array" ], | |
["U64", "BigUint64Array"], | |
["I8" , "Int8Array" ], | |
["I16", "Int16Array" ], | |
["I32", "Int32Array" ], | |
["I64", "BigInt64Array" ], | |
["F32", "Float32Array" ], | |
["F64", "Float64Array" ]]; | |
export const methods = new CodeBlock({spacing:2});// default 0 | |
export const globals = new CodeBlock; | |
for(let [name,constructor] of types){ | |
const itemType = constructor[0] === "B" ? "bigint" : "number"; | |
const typeSize = parseInt(name.slice(1))/8; | |
if(typeSize === 1){ | |
methods.add(` | |
append_${name}(val: number){ | |
this.grow(1); | |
this.u8[this.length-1] = val; | |
} | |
set_${name}(val: number, offset: number){ | |
this.growIfNoSpace(offset, ${typeSize}); | |
this.u8[offset] = val; | |
} | |
`); | |
}else{ | |
const BE_writer = `BE_writer_${typesize}`; | |
globals.add(` | |
const view_${name} = new ${constructor}(1); | |
const view_${name}_u8 = new Uint8Array(view_${name}); | |
`); | |
methods.add(` | |
append_${name}(val: ${itemType}){ | |
view_${name}[0] = val; | |
this.grow(${typeSize}); | |
this.u8.set(view_${name}_u8,this.length-${typeSize}); | |
} | |
set_${name}(val: ${itemType}, offset: number){ | |
view_${name}[0] = val; | |
this.growIfNoSpace(offset, ${typeSize}); | |
this.set_buffer(view_${name}_u8,offset); | |
} | |
set_${name}_aligned(val: ${itemType}, offset: number){ | |
view_${name}[0] = val; | |
offset *= ${typeSize}; | |
this.growIfNoSpace(offset, ${typeSize}); | |
this.set_buffer(view_${name}_u8,offset); | |
} | |
append_${name}BE(val: ${itemType}){ | |
view_${name}[0] = val; | |
this.grow(${typeSize}); | |
${BE_writer}(this.u8,view_${name}_u8,this.length-${typeSize}); | |
} | |
set_${name}BE(val: ${itemType}, offset: number){ | |
view_${name}[0] = val; | |
this.growIfNoSpace(offset, ${typeSize}); | |
${BE_writer}(this.u8,view_${name}_u8,offset); | |
} | |
set_${name}BE_aligned(val: ${itemType}, offset: number){ | |
view_${name}[0] = val; | |
offset *= ${typeSize}; | |
this.growIfNoSpace(offset, ${typeSize}); | |
${BE_writer}(this.u8,view_${name}_u8,offset); | |
} | |
`); | |
} | |
} | |
##@end autogen_methods | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment