/* * Copyright 2021 Juan Cruz Viotti * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { strict as assert } from 'assert' import { UINT8_MIN, UINT8_MAX, UINT3_MIN, UINT3_MAX, UINT5_MIN, UINT5_MAX } from '../../utils/limits' // IMPORTANT! This enumeration is capped to have a maximum of 8 elements as // we use the lowest-significant 3 bits to store the type, and the remaining // 5 bits to store extra metadata about the type. export enum Type { SharedString = 0b00000000, String = 0b00000001, LongString = 0b00000010, Object = 0b00000011, Array = 0b00000100, PositiveIntegerByte = 0b00000101, NegativeIntegerByte = 0b00000110, Other = 0b00000111 } export enum Subtype { False = 0b00000000, True = 0b00000001, Null = 0b00000010, PositiveInteger = 0b00000011, NegativeInteger = 0b00000100, Number = 0b00000101, // Note that the binary values actually match the exponents LongStringBaseExponent7 = 0b00000111, LongStringBaseExponent8 = 0b00001000, LongStringBaseExponent9 = 0b00001001, LongStringBaseExponent10 = 0b00001010 } export const LONG_STRING_BASE_EXPONENT_MINIMUM: number = 7 export const LONG_STRING_BASE_EXPONENT_MAXIMUM: number = 10 export const isType = (type: Type, value: number): boolean => { assert(type >= UINT3_MIN && type <= UINT3_MAX) assert(value >= UINT8_MIN && value <= UINT8_MAX) return (value & 0b00000111) === type } export const getTypeTag = (type: Type, metadata: number): number => { assert(type >= UINT3_MIN && type <= UINT3_MAX) assert(metadata >= UINT5_MIN && metadata <= UINT5_MAX) return (metadata << 3) | type } export const getMetadata = (value: number): number => { assert(value >= UINT8_MIN && value <= UINT8_MAX) return value >>> 3 } export const isTrue = (value: number): boolean => { return isType(Type.Other, value) && getMetadata(value) === Subtype.True } export const isFalse = (value: number): boolean => { return isType(Type.Other, value) && getMetadata(value) === Subtype.False } export const isNull = (value: number): boolean => { return isType(Type.Other, value) && getMetadata(value) === Subtype.Null } export const isPositiveInteger = (value: number): boolean => { return isType(Type.Other, value) && getMetadata(value) === Subtype.PositiveInteger } export const isNegativeInteger = (value: number): boolean => { return isType(Type.Other, value) && getMetadata(value) === Subtype.NegativeInteger } export const isNumber = (value: number): boolean => { return isType(Type.Other, value) && getMetadata(value) === Subtype.Number }