Skip to content

Commit

Permalink
Add a NumberRepr class that represents f/i/u 64/32/16/8 (gpuweb#747)
Browse files Browse the repository at this point in the history
  • Loading branch information
kainino0x authored Sep 21, 2021
1 parent cd2e358 commit 2d57b60
Showing 1 changed file with 106 additions and 0 deletions.
106 changes: 106 additions & 0 deletions src/webgpu/util/conversion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,3 +222,109 @@ export function uint32ToInt32(u32: number): number {
const i32Arr = new Int32Array(u32Arr.buffer);
return i32Arr[0];
}

/** A type of number representable by NumberRepr. */
type NumberType =
| 'f64'
| 'f32'
| 'f16'
| 'u64'
| 'u32'
| 'u16'
| 'u8'
| 'i64'
| 'i32'
| 'i16'
| 'i8';

/** Figures out the type that NumberRepr uses to represent its numeric value. */
type NumberReprValue<T extends NumberType> = T extends 'u64' | 'i64' ? bigint : number;
/** Figures out the TypedArray type that NumberRepr uses to represent its bit representation. */
type NumberReprBits<T extends NumberType> = T extends 'u64' | 'i64' | 'f64'
? BigUint64Array
: T extends 'u32' | 'i32' | 'f32'
? Uint32Array
: T extends 'u16' | 'i16' | 'f16'
? Uint16Array
: Uint8Array;

/**
* Class that encapsulates a single number of various types. Exposes:
* - the actual numeric value (as a JS `number`, or `bigint` if it's u64/i64)
* - the bit representation of the number, as a TypedArray of size 1 with the appropriate type.
*/
export class NumberRepr<T extends NumberType> {
readonly value: NumberReprValue<T>;
readonly bits: NumberReprBits<T>;

private constructor(value: NumberReprValue<T>, bits: NumberReprBits<T>) {
this.value = value;
this.bits = bits;
}

/** Create an f64 from a numeric value, a JS `number`. */
static fromF64(value: number) {
return new NumberRepr<'f64'>(value, new BigUint64Array(new Float64Array([value]).buffer));
}
/** Create an f32 from a numeric value, a JS `number`. */
static fromF32(value: number) {
return new NumberRepr<'f32'>(value, new Uint32Array(new Float32Array([value]).buffer));
}

/** Create an f64 from a bit representation, a uint64 represented as a JS `bigint`. */
static fromF64Bits(bits: bigint) {
const abv = new BigUint64Array([bits]);
return new NumberRepr<'f64'>(new Float64Array(abv.buffer)[0], abv);
}
/** Create an f32 from a bit representation, a uint32 represented as a JS `number`. */
static fromF32Bits(bits: number) {
const abv = new Uint32Array([bits]);
return new NumberRepr<'f32'>(new Float32Array(abv.buffer)[0], abv);
}
/** Create an f16 from a bit representation, a uint16 represented as a JS `number`. */
static fromF16Bits(bits: number) {
return new NumberRepr<'f16'>(float16BitsToFloat32(bits), new Uint16Array(bits));
}

/** Create an i32 from a numeric value, a JS `number`. */
static fromI32(value: number) {
return new NumberRepr<'i32'>(value, new Uint32Array(new Int32Array([value]).buffer));
}
/** Create an i16 from a numeric value, a JS `number`. */
static fromI16(value: number) {
return new NumberRepr<'i16'>(value, new Uint16Array(new Int16Array([value]).buffer));
}
/** Create an i8 from a numeric value, a JS `number`. */
static fromI8(value: number) {
return new NumberRepr<'i8'>(value, new Uint8Array(new Int8Array([value]).buffer));
}

/** Create an i32 from a bit representation, a uint32 represented as a JS `number`. */
static fromI32Bits(bits: number) {
const abv = new Uint32Array([bits]);
return new NumberRepr<'i32'>(new Int32Array(abv.buffer)[0], abv);
}
/** Create an i16 from a bit representation, a uint16 represented as a JS `number`. */
static fromI16Bits(bits: number) {
const abv = new Uint16Array([bits]);
return new NumberRepr<'i16'>(new Int16Array(abv.buffer)[0], abv);
}
/** Create an i8 from a bit representation, a uint8 represented as a JS `number`. */
static fromI8Bits(bits: number) {
const abv = new Uint8Array([bits]);
return new NumberRepr<'i8'>(new Int8Array(abv.buffer)[0], abv);
}

/** Create a u32 from a numeric value, a JS `number`. */
static fromU32(value: number) {
return new NumberRepr<'u32'>(value, new Uint32Array(value));
}
/** Create a u16 from a numeric value, a JS `number`. */
static fromU16(value: number) {
return new NumberRepr<'u16'>(value, new Uint16Array(value));
}
/** Create a u8 from a numeric value, a JS `number`. */
static fromU8(value: number) {
return new NumberRepr<'u8'>(value, new Uint8Array(value));
}
}

0 comments on commit 2d57b60

Please sign in to comment.