Files
tatsuki/node/src/flagsets/base64.ts

126 lines
4.1 KiB
TypeScript

import type { FlagSet } from '.'
import { decodeB64Byte, encodeB64Byte, normaliseB64String, ZERO_STRING } from '../base64'
import { Base64BitflagIterator, EnumerateFlags, useIterator } from '../enumeration'
/**
* Provides flags that are stored in strings using a little-endian base 64
* representation.
*
* This format is compact, easily serializable and allows for an unlimited
* number of flags, but it is specific to Tatsuki. Use {@link CollectionFlagSet}
* instead if you need the data to be easily understandable by other systems.
*/
export class Base64BitFlagSet implements FlagSet<number, string> {
/*protected wrapValue(value: number): string {
if (value < 1) {
throw new RangeError(
'Indices should be greater than or equal to 1.'
)
}
const indexFromZero = value - 1
const leadingBytes = ZERO_STRING.repeat(indexFromZero / 6)
const bigEnd = encodeByte(1 << indexFromZero % 6)
return leadingBytes + bigEnd
}*/
public none(): string {
return ''
}
public union(first: string, second: string): string {
let result = ''
let shorter, longer
if (first.length < second.length) {
shorter = first
longer = second
} else {
shorter = second
longer = first
}
let i = 0
// OR the bytes one by one
for (; i < shorter.length; i++) {
const value = decodeB64Byte(shorter[i]) | decodeB64Byte(longer[i])
result += encodeB64Byte(value)
}
// if one string is longer than the other, append the remaining bytes (x | 0 = x)
for (; i < longer.length; i++) {
result += longer[i]
}
return normaliseB64String(result)
}
public intersection(first: string, second: string): string {
let result = ''
const shorterLength = Math.min(first.length, second.length)
let i = 0
// AND the bytes one by one
for (; i < shorterLength; i++) {
const value = decodeB64Byte(first[i]) & decodeB64Byte(second[i])
result += encodeB64Byte(value)
}
// if one string is longer than the other, don't add anything else (x & 0 = 0)
return normaliseB64String(result)
}
public difference(first: string, second: string): string {
let result = ''
const shorterLength = Math.min(first.length, second.length)
let i = 0
// AND the bytes one by one
for (; i < shorterLength; i++) {
const value = decodeB64Byte(first[i]) & ~decodeB64Byte(second[i])
result += encodeB64Byte(value)
}
// if the first string is longer than the other, append its remaining bytes (x & ~0 = x)
// if the second string is longer, don't add anything (0 & ~y = 0)
for (; i < first.length; i++) {
result += first[i]
}
return normaliseB64String(result)
}
public isSuperset(first: string, second: string): boolean {
let result = true
const shorterLength = Math.min(first.length, second.length)
let i = 0
// AND the bytes one by one and check
// if one is false we don't need to decode further
for (; i < shorterLength && result; i++) {
const secondValue = decodeB64Byte(second[i])
result = (decodeB64Byte(first[i]) & secondValue) == secondValue
}
// if there are more characters in the second string, they must all be zeros
// (0 & x is only equal to x when x is also 0)
for (; i < second.length && result; i++) {
result = second[i] == ZERO_STRING
}
return result
}
public enumerate(flags: string): EnumerateFlags<number> {
return useIterator(flags, Base64BitflagIterator)
}
maximum(flags: string): string {
throw new Error('not implemented')
}
minimum(flags: string): string {
throw new Error('not implemented')
}
public getFlag(alias: string): FlagDefinition<number, number> | undefined {
return this._dictionary.lookUp(alias)
}
}