import bit, { Bit } from "./bit" import { range, zip } from "lodash" type GreaterThan = number type LessOrEqual = number export interface Word { plus: (other: Word) => Word> bits: Bit[] length: Width } // function greaterOf(value: Value, other: Other){ // return value > other ? value as Value : other as Other // } type LessThan = number type GreaterOrEqual = number function isLessThan(value: number, other: number): value is LessThan { return value < other } function isGreaterThanOrEqual(value: number, other: number): value is GreaterOrEqual { return value >= other } function greaterOf(value: LessThan, other: B): LessThan function greaterOf(value: GreaterOrEqual, other: B): GreaterOrEqual function greaterOf(value: A, other: B): LessThan | GreaterOrEqual { const result = Math.max(value, other) return isLessThan(value, other) ? value as GreaterThan : other as LessThan } const duh = wordFromBits([bit(0)] as const).plus(wordFromBits([bit(0), bit(0)])) type FixedLengthArray = Readonly & { length: Length}> export function wordFromBits>(bits: readonly FixedLengthArray) { function plus>(other: Word): Word function plus>(other: Word): Word { const newBits = addBits(bits, other.bits) return wordFromBits(newBits.bits) } function subword(start: number, length?: number) { return wordFromBits(bits.slice(start, length !== undefined ? start + length : undefined)) } return { plus, subword, bits, length: bits.length } } function addBits(bits: Bit[], otherBits: Bit[]) { const bigEndianBits = [...bits].reverse() const bigEndianOtherBits = [...otherBits].reverse() const pairedBits = zip(bigEndianBits, bigEndianOtherBits).reverse() const denulledBits = pairedBits.map(([a, b]) => [a ?? bit(0), b ?? bit(0)] as const) const sumResults = denulledBits.reduce(({bits, carry}, [a, b]) => { const aPlusB = a.add(b) const aPlusBPlusCarry = aPlusB.ones.add(carry) const thisCarry = aPlusB.carry.add(aPlusBPlusCarry.carry).ones bits.push(aPlusBPlusCarry.ones) return sumResult(bits, thisCarry) }, sumResult([], bit(0))) return sumResults } interface SumResult { bits: Bit[] carry: Bit } function sumResult(bits: Bit[], carry: Bit) { return { bits, carry} } } export function emptyWord(width: Width): Word { const bits = range(0, width).map(() => bit(0)) return wordFromBits(bits) }