import * as Decimal from "./decimal" ; import * as Identifier from "./identifier" ; import { cons , head , rest } from "./utils" ; export interface t { position : Identifier . t [ ] ; lamport : number ; value : string ; } export type Serial = [ Array < [ number , number ] > , number , string ] ; export function create ( position , lamport , value ) { const obj = { position , lamport , value } ; Object . freeze ( obj ) ; return obj ; } export function startOfFile ( ) { return create ( [ Identifier . create ( 1 , 0 ) ] , 0 , "^" ) ; } export function endOfFile ( ) { return create ( [ Identifier . create ( 255 , 0 ) ] , 0 , "$" ) ; } export function ofArray ( array ) { return create ( array [ 0 ] . map ( Identifier . ofArray ) , array [ 1 ] , array [ 2 ] ) ; } export function toArray ( obj ) { const position = obj . position . map ( Identifier . toArray ) ; return [ position , obj . lamport , obj . value ] ; } export function comparePosition ( p1 , p2 ) { for ( let i = 0 ; i < Math . min ( p1 . length , p2 . length ) ; i ++ ) { const comp = Identifier . compare ( p1 [ i ] , p2 [ i ] ) ; if ( comp !== 0 ) { return comp ; } } if ( p1 . length < p2 . length ) { return - 1 ; } else if ( p1 . length > p2 . length ) { return 1 ; } else { return 0 ; } } export function compare ( c1 , c2 ) { return comparePosition ( c1 . position , c2 . position ) ; } export function generatePositionBetween ( position1 , position2 , site ) { const head1 = head ( position1 ) || Identifier . create ( 0 , site ) ; const head2 = head ( position2 ) || Identifier . create ( Decimal . BASE , site ) ; if ( head1 . digit !== head2 . digit ) { const n1 = Decimal . fromIdentifierList ( position1 ) ; const n2 = Decimal . fromIdentifierList ( position2 ) ; const delta = Decimal . subtractGreaterThan ( n2 , n1 ) ; const next = Decimal . increment ( n1 , delta ) ; return Decimal . toIdentifierList ( next , position1 , position2 , site ) ; } else { if ( head1 . site < head2 . site ) { return cons ( head1 , generatePositionBetween ( rest ( position1 ) , [ ] , site ) ) ; } else if ( head1 . site === head2 . site ) { return cons ( head1 , generatePositionBetween ( rest ( position1 ) , rest ( position2 ) , site ) ) ; } else { throw new Error ( "invalid site ordering" ) ; } } } export function equals ( c1 , c2 ) { if ( c1 . position . length !== c2 . position . length ) return false ; if ( c1 . lamport !== c2 . lamport ) return false ; if ( c1 . value !== c2 . value ) return false ; for ( let i = 0 ; i < c1 . position . length ; i ++ ) { if ( ! Identifier . equals ( c1 . position [ i ] , c2 . position [ i ] ) ) return false ; } return true ; }