-- BcdStampsImpl.mesa
-- last edit by Satterthwaite, July 30, 1983 11:27 am

DIRECTORY
  BcdStamps: TYPE USING [],
  CompilerOps: TYPE USING [LetterSwitches],
  Environment: TYPE USING [Comparison],
  Inline: TYPE USING [LongNumber],
  TimeStamp: TYPE USING [Stamp];
	
BcdStampsImpl: CEDAR PROGRAM EXPORTS BcdStamps ~ {

  StampSize: NAT ~ 3;
  Stamp: TYPE ~ RECORD [word: ARRAY[0..StampSize) OF WORD];
  
-- the directoryStamps are in the order of the DIRECTORY clause
  -- does not include the stamps for the hidden directory entries
	
  Compute: PUBLIC PROC[
	srcCreate: LONG CARDINAL, 
	switches: CompilerOps.LetterSwitches, compilerVersion: TimeStamp.Stamp, 
	directoryEnumerator: PROC[PROC[TimeStamp.Stamp]]] 
      RETURNS[bcdVers: TimeStamp.Stamp] ~ {
    stamp: Stamp;

    ForEach: PROC[time: TimeStamp.Stamp] ~ {
      stamp ← MergeStamps[stamp, TimeToStamp[time]]};
      
    switches['d] ← switches['g] ← switches['p] ← FALSE;	-- not part of the version stamp
    stamp ← TimeToStamp[[0, 0, srcCreate]];
    -- encode switches, compiler version (see DIRECTORY processing also)
      stamp ← MergeStamps[stamp, TimeToStamp[[0, 0, LOOPHOLE[switches]]]];
      stamp ← MergeStamps[stamp, TimeToStamp[compilerVersion]];
    directoryEnumerator[ForEach];
    bcdVers ← LOOPHOLE[stamp]};
	
  CompareStamps: PUBLIC PROC[s1, s2: TimeStamp.Stamp] RETURNS[Environment.Comparison] ~ {
    RETURN[SELECT s1.time FROM
      < s2.time => $less, > s2.time => $greater,
      ENDCASE => SELECT s1.host - s2.host FROM	-- can't overflow
	< 0 => $less, > 0 => $greater,
	ENDCASE => SELECT s1.net - s2.net FROM
	  < 0 => $less, > 0 => $greater, ENDCASE => $equal]
    };

  MergeStamps:  PROC[sum, item: Stamp] RETURNS[Stamp] ~ {
    RETURN[AddStamps[RotateStamp[sum], item]]};
    
  AddStamps: PROC[s1, s2: Stamp] RETURNS[sum: Stamp] ~ {
    carry: [0..1] ← 0;
    i: [0..StampSize);
    FOR i DECREASING IN [0..StampSize) DO
      t: Inline.LongNumber ~ [lc[s1.word[i].LONG + s2.word[i].LONG + carry.LONG]];
      sum.word[i] ← t.lowbits;  carry ← t.highbits;
      ENDLOOP;
    FOR i DECREASING IN [0..StampSize) WHILE carry # 0 DO
      t: Inline.LongNumber ~ [lc[sum.word[i].LONG + carry.LONG]];
      sum.word[i] ← t.lowbits;  carry ← t.highbits;
      ENDLOOP};
    
  RotateStamp: PROC[s: Stamp] RETURNS[Stamp] ~ INLINE {RETURN[AddStamps[s, s]]};
  
  TimeToStamp:  PROC[time: TimeStamp.Stamp] RETURNS[Stamp] ~ INLINE {
    RETURN[LOOPHOLE[time]]};

  }.