// FastStreamsB.Bcpl -- Fast Memory stream routines -- BCPL part
// Copyright Xerox Corporation 1979
// Last modified July 12, 1979  3:49 PM by Taft

get "Streams.d"

// This code works together with the machine code in FastStreamsA.asm.

// Note: positions and itemSizes in fast streams are always measured
// in bytes.  They are truncated for word streams, except that
// end positions are rounded up, so that all the data will always be
// read, along with some garbage if the length of the stream is not
// an even number of items.

external
[
// outgoing procedures
InitializeFstream; SetupFstream
SetEof; EofError; ItemSize; StreamError

// incoming procedures
Errors

// incoming statics from FastStreamsA.asm
fastChStream; fastWstream
]

manifest
[
// error codes
ecBadItemSize = 1301
ecEof = 1302
ecBadStreamOperation = 1303
]

// This declaration must agree with the machine-language declaration
// in FastStreamsA.asm
//----------------------------------------------------------------------------
structure FSx:		// internal, expanded version of FS
//----------------------------------------------------------------------------
[
@FS =
   [
   blank word offset FS.fsp/16
   // note that the length of the structure from here to the end is
   // publicly declared as 12. in Streams.d (though it is 11 actually)
   charPtr word		// 1 for left byte, 0 for right
   wordPtr word		// points to word containing the last byte, not next
   count word		// -(number of items left+1)
   dirty word
   eof word
   putOverflow word
   getOverflow word
   getCC word
   itemSize word	// in bytes; must be 1 or 2
   endPos word		// relative addr of first byte not included in count
   savedGets word
   ]
]
manifest lFSx = size FSx/16

//----------------------------------------------------------------------------
let InitializeFstream(fs, itemSize, PutOv, GetOv, GetCC; numargs na) be
//----------------------------------------------------------------------------
[
let template = selecton itemSize into
   [
   case charItem: fastChStream
   case wordItem: fastWstream
   default: Errors(fs, ecBadItemSize)
   ]
for i = 0 to lFSx-1 do
   [
   let t = template!i
   if (t & 177700b) ne 0 then t = @t
   fs!i = t
   ]
fs>>FSx.putOverflow = PutOv
fs>>FSx.getOverflow = GetOv
if na ge 5 then fs>>FSx.getCC = GetCC
]


// the following functions take advantage of the fact that if
// itemSize is 1 or 2, shifting by itemSize-1 is the same as
// multiplying or dividing by itemSize

//----------------------------------------------------------------------------
and SetupFstream(fs, wordBase, currentPos, endPos) be
//----------------------------------------------------------------------------
[
// Note that endPos is rounded up, although everything else is truncated
let m = -fs>>FSx.itemSize	// truncation mask
let i = fs>>FSx.itemSize-1

currentPos = (currentPos+i) & m
endPos = (endPos+i) & m

fs>>FSx.charPtr = 1-(currentPos & 1)
fs>>FSx.wordPtr = wordBase+(currentPos rshift 1)-fs>>FSx.charPtr
// the (+1) in the next statement reflects the fact that the
// count must be one more than the number of items left
fs>>FSx.count = -(((endPos-currentPos) rshift i)+1)
fs>>FSx.endPos = endPos
]

//----------------------------------------------------------------------------
and SetEof(fs, newValue) be  // set or reset the eof flag
//----------------------------------------------------------------------------
   if fs>>FSx.eof ne newValue then
      [
      fs>>FSx.eof = newValue
      test newValue
         ifso [ fs>>FSx.savedGets = fs>>FSx.gets; fs>>FSx.gets = EofError ]
         ifnot fs>>FSx.gets = fs>>FSx.savedGets
      ]

//----------------------------------------------------------------------------
and EofError(fs) = fs>>FS.error(fs, ecEof)
//----------------------------------------------------------------------------

//----------------------------------------------------------------------------
and StreamError(fs) be fs>>FS.error(fs, ecBadStreamOperation)
//----------------------------------------------------------------------------

//----------------------------------------------------------------------------
and ItemSize(fs) = fs>>FSx.itemSize
//----------------------------------------------------------------------------


// See FastStreamsA.asm for the following
//----------------------------------------------------------------------------
// and CurrentPos(fs) =
//----------------------------------------------------------------------------
//    fs>>FSx.endPos+((fs>>FSx.count+1) lshift (fs>>FSx.itemSize-1))

//----------------------------------------------------------------------------
// and Dirty(fs) = fs>>FSx.dirty ne 0
//----------------------------------------------------------------------------

//----------------------------------------------------------------------------
// and SetDirty(fs, flag) be fs>>FSx.dirty = flag
//----------------------------------------------------------------------------