97 lines
3.0 KiB
TypeScript
97 lines
3.0 KiB
TypeScript
import bit, { Bit } from "./bit"
|
|
import { range, zip } from "lodash"
|
|
|
|
type GreaterThan<Threshold extends number> = number
|
|
type LessOrEqual<Threshold extends number> = number
|
|
|
|
export interface Word<Width extends number> {
|
|
|
|
plus: <OtherWidth extends number, ResultWidth = >(other: Word<OtherWidth>) => Word<GreaterOf<Width, OtherWidth>>
|
|
bits: Bit[]
|
|
length: Width
|
|
}
|
|
|
|
// function greaterOf<Value extends number, Other extends number>(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<A extends LessThan, B>(value: LessThan, other: B): LessThan
|
|
function greaterOf<A extends GreaterOrEqual, B>(value: GreaterOrEqual, other: B): GreaterOrEqual
|
|
function greaterOf<A extends number, B extends number>(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<T, Length extends number> = Readonly<Array<T> & { length: Length}>
|
|
|
|
export function wordFromBits<Width extends Readonly<number>>(bits: readonly FixedLengthArray<Bit, Width>) {
|
|
|
|
function plus<OtherWidth extends GreaterThan<Width>>(other: Word<OtherWidth>): Word<OtherWidth>
|
|
function plus<OtherWidth extends LessOrEqual<Width>>(other: Word<OtherWidth>): Word<Width> {
|
|
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<SumResult>(({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 extends number>(width: Width): Word<Width> {
|
|
const bits = range(0, width).map(() => bit(0))
|
|
return wordFromBits(bits)
|
|
} |