2022-10-02 16:22:05 +00:00
window . RING _BUFF _CONSECUTIVE _SET = 0 ;
window . RING _BUFF _NON _CONSECUTIVE _SET = 1 ;
window . RING _BUFF _FAILED _TO _SET = 2 ;
2022-09-24 04:01:50 +00:00
var RingBuffer = function ( capacity ) {
this . ed = 0 ; // write index, open index
this . st = 0 ; // read index, closed index
this . edFrameId = 0 ;
this . stFrameId = 0 ;
this . n = capacity ;
this . cnt = 0 ; // the count of valid elements in the buffer, used mainly to distinguish what "st == ed" means for "Pop" and "Get" methods
this . eles = new Array ( capacity ) . fill ( null ) ;
} ;
RingBuffer . prototype . put = function ( item ) {
this . eles [ this . ed ] = item
this . edFrameId ++ ;
this . cnt ++ ;
this . ed ++ ;
if ( this . ed >= this . n ) {
this . ed -= this . n ; // Deliberately not using "%" operator for performance concern
}
} ;
RingBuffer . prototype . pop = function ( ) {
if ( 0 == this . cnt ) {
return null ;
}
const item = this . eles [ this . st ] ;
this . stFrameId ++ ;
this . cnt -- ;
this . st ++ ;
if ( this . st >= this . n ) {
this . st -= this . n ;
}
return item ;
} ;
2022-10-02 16:22:05 +00:00
RingBuffer . prototype . getArrIdxByOffset = function ( offsetFromSt ) {
if ( 0 > offsetFromSt || 0 == this . cnt ) {
2022-09-24 04:01:50 +00:00
return null ;
}
let arrIdx = this . st + offsetFromSt ;
if ( this . st < this . ed ) {
// case#1: 0...st...ed...n-1
if ( this . st <= arrIdx && arrIdx < this . ed ) {
2022-10-02 16:22:05 +00:00
return arrIdx ;
2022-09-24 04:01:50 +00:00
}
} else {
// if this.st >= this.sd
// case#2: 0...ed...st...n-1
if ( arrIdx >= this . n ) {
arrIdx -= this . n
}
if ( arrIdx >= this . st || arrIdx < this . ed ) {
2022-10-02 16:22:05 +00:00
return arrIdx ;
2022-09-24 04:01:50 +00:00
}
}
return null ;
} ;
RingBuffer . prototype . getByFrameId = function ( frameId ) {
2022-10-02 16:22:05 +00:00
const arrIdx = this . getArrIdxByOffset ( frameId - this . stFrameId ) ;
return ( null == arrIdx ? null : this . eles [ arrIdx ] ) ;
} ;
// [WARNING] During a battle, frontend could receive non-consecutive frames (either renderFrame or inputFrame) due to resync, the buffer should handle these frames properly.
RingBuffer . prototype . setByFrameId = function ( item , frameId ) {
if ( frameId < this . stFrameId ) {
console . error ( "Invalid putByFrameId#1: stFrameId=" , stFrameId , ", edFrameId=" , edFrameId , ", incoming item=" , item ) ;
return window . RING _BUFF _FAILED _TO _SET ;
}
const arrIdx = this . getArrIdxByOffset ( frameId - this . stFrameId ) ;
if ( null != arrIdx ) {
this . eles [ arrIdx ] = item ;
return window . RING _BUFF _CONSECUTIVE _SET ;
}
// When "null == arrIdx", should it still be deemed consecutive if "frameId == edFrameId" prior to the reset?
let ret = window . RING _BUFF _CONSECUTIVE _SET ;
if ( this . edFrameId < frameId ) {
this . st = this . ed = 0 ;
this . stFrameId = this . edFrameId = frameId ;
this . cnt = 0 ;
ret = window . RING _BUFF _NON _CONSECUTIVE _SET ;
}
this . eles [ this . ed ] = item
this . edFrameId ++ ;
this . cnt ++ ;
this . ed ++ ;
if ( this . ed >= this . n ) {
this . ed -= this . n ; // Deliberately not using "%" operator for performance concern
}
return ret ;
2022-09-24 04:01:50 +00:00
} ;
module . exports = RingBuffer ;