2021-03-02 21:54:42 +00:00
|
|
|
import { Encoder, Preservable } from "./encoder";
|
2021-02-17 15:52:01 +00:00
|
|
|
import { Tag } from "./constants";
|
|
|
|
import { AsPreserve, PreserveOn } from "./symbols";
|
|
|
|
import { DefaultPointer, Value } from "./values";
|
|
|
|
|
|
|
|
export type FloatType = 'Single' | 'Double';
|
|
|
|
export const FloatType = Symbol.for('FloatType');
|
|
|
|
|
|
|
|
export abstract class Float {
|
|
|
|
readonly value: number;
|
|
|
|
|
|
|
|
constructor(value: number | Float) {
|
|
|
|
this.value = typeof value === 'number' ? value : value.value;
|
|
|
|
}
|
|
|
|
|
|
|
|
toString() {
|
|
|
|
return this.asPreservesText();
|
|
|
|
}
|
|
|
|
|
|
|
|
equals(other: any): boolean {
|
|
|
|
return Object.is(other.constructor, this.constructor) && (other.value === this.value);
|
|
|
|
}
|
|
|
|
|
|
|
|
hashCode(): number {
|
|
|
|
return (this.value | 0); // TODO: something better?
|
|
|
|
}
|
|
|
|
|
|
|
|
abstract asPreservesText(): string;
|
|
|
|
abstract get [FloatType](): FloatType;
|
|
|
|
|
|
|
|
static isFloat = (x: any): x is Float => x?.[FloatType] !== void 0;
|
|
|
|
static isSingle = (x: any): x is SingleFloat => x?.[FloatType] === 'Single';
|
|
|
|
static isDouble = (x: any): x is DoubleFloat => x?.[FloatType] === 'Double';
|
|
|
|
}
|
|
|
|
|
|
|
|
export function floatValue(f: any): number {
|
|
|
|
if (typeof f === 'number') {
|
|
|
|
return f;
|
|
|
|
} else if (Float.isFloat(f)) {
|
|
|
|
return f.value;
|
|
|
|
} else {
|
|
|
|
return NaN;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export class SingleFloat extends Float implements Preservable<never> {
|
2021-03-10 22:14:26 +00:00
|
|
|
[AsPreserve]<T = DefaultPointer>(): Value<T> {
|
2021-02-17 15:52:01 +00:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
[PreserveOn](encoder: Encoder<never>) {
|
|
|
|
encoder.emitbyte(Tag.Float);
|
|
|
|
encoder.makeroom(4);
|
|
|
|
encoder.view.setFloat32(encoder.index, this.value, false);
|
|
|
|
encoder.index += 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
get [FloatType](): 'Single' {
|
|
|
|
return 'Single';
|
|
|
|
}
|
|
|
|
|
|
|
|
asPreservesText(): string {
|
|
|
|
return '' + this.value + 'f';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export function Single(value: number | Float): SingleFloat {
|
|
|
|
return new SingleFloat(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
export class DoubleFloat extends Float implements Preservable<never> {
|
2021-03-10 22:14:26 +00:00
|
|
|
[AsPreserve]<T = DefaultPointer>(): Value<T> {
|
2021-02-17 15:52:01 +00:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
[PreserveOn](encoder: Encoder<never>) {
|
|
|
|
encoder.emitbyte(Tag.Double);
|
|
|
|
encoder.makeroom(8);
|
|
|
|
encoder.view.setFloat64(encoder.index, this.value, false);
|
|
|
|
encoder.index += 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
get [FloatType](): 'Double' {
|
|
|
|
return 'Double';
|
|
|
|
}
|
|
|
|
|
|
|
|
asPreservesText(): string {
|
|
|
|
return '' + this.value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export function Double(value: number | Float): DoubleFloat {
|
|
|
|
return new DoubleFloat(value);
|
|
|
|
}
|