UNPKG

@qooxdoo/framework

Version:

The JS Framework for Coders

236 lines (190 loc) 6.29 kB
/* ************************************************************************ qooxdoo - the new era of web development http://qooxdoo.org Copyright: 2006 STZ-IDA, Germany, http://www.stz-ida.de 2009 1&1 Internet AG, Germany, http://www.1und1.de License: MIT: https://opensource.org/licenses/MIT See the LICENSE file in the project's top-level directory for details. Authors: * Carsten Lergenmueller (carstenl) * Fabian Jakobs (fjakobs) ************************************************************************ */ /** * An memory container which stores arbitrary data up to a maximum number of * entries. When new entries come in an the maximum is reached, the oldest * entries are deleted. * * A mark feature also exists which can be used to remember a point in time. * When retrieving entries, it is possible to get only those entries * after the marked time. This is useful if data from the buffer is extracted * and processed. Whenever this happens, a mark() call can be used so that the * next extraction will only get new data. */ qx.Bootstrap.define("qx.util.RingBuffer", { extend : Object, /** * Constructor. * * @param maxEntries {Integer ? 50} Maximum number of entries in the buffer */ construct : function(maxEntries) { this.setMaxEntries(maxEntries || 50); }, members : { //Next slot in ringbuffer to use __nextIndexToStoreTo : 0, //Number of elements in ring buffer __entriesStored : 0, //Was a mark set? __isMarkActive: false, //How many elements were stored since setting of mark? __entriesStoredSinceMark : 0, //ring buffer __entries : null, //Maximum number of messages to store. Could be converted to a qx property. __maxEntries : null, /** * Set the maximum number of messages to hold. If null the number of * messages is not limited. * * Warning: Changing this property will clear the events logged so far. * * @param maxEntries {Integer} the maximum number of messages to hold */ setMaxEntries : function(maxEntries) { this.__maxEntries = maxEntries; this.clear(); }, /** * Get the maximum number of entries to hold * * @return {Integer} */ getMaxEntries : function() { return this.__maxEntries; }, /** * Adds a single entry * * @param entry {var} The data to store */ addEntry : function(entry) { this.__entries[this.__nextIndexToStoreTo] = entry; this.__nextIndexToStoreTo = this.__addToIndex(this.__nextIndexToStoreTo, 1); //Count # of stored entries var max = this.getMaxEntries(); if (this.__entriesStored < max){ this.__entriesStored++; } //Count # of stored elements since last mark call if (this.__isMarkActive && (this.__entriesStoredSinceMark < max)){ this.__entriesStoredSinceMark++; } }, /** * Returns the number of entries stored * @return {Integer} */ getNumEntriesStored: function() { return this.__entriesStored; }, /** * Remembers the current position in the ring buffer * */ mark : function(){ this.__isMarkActive = true; this.__entriesStoredSinceMark = 0; }, /** * Removes the current mark position */ clearMark : function(){ this.__isMarkActive = false; }, /** * Returns all stored entries. Mark is ignored. * * @return {Array} array of stored entries */ getAllEntries : function() { return this.getEntries(this.getMaxEntries(), false); }, /** * Returns entries which have been added previously. * * @param count {Integer} The number of entries to retrieve. If there are * more entries than the given count, the oldest ones will not be returned. * * @param startingFromMark {Boolean ? false} If true, only entries since * the last call to mark() will be returned * @return {Array} array of stored entries */ getEntries : function(count, startingFromMark) { //Trim count so it does not exceed ringbuffer size if (count > this.__entriesStored) { count = this.__entriesStored; } // Trim count so it does not exceed last call to mark (if mark was called // and startingFromMark was true) if ( startingFromMark && this.__isMarkActive && (count > this.__entriesStoredSinceMark) ) { count = this.__entriesStoredSinceMark; } if (count > 0){ var indexOfYoungestElementInHistory = this.__addToIndex(this.__nextIndexToStoreTo, -1); var startIndex = this.__addToIndex(indexOfYoungestElementInHistory, - count + 1); var result; if (startIndex <= indexOfYoungestElementInHistory) { //Requested segment not wrapping around ringbuffer boundary, get in one run result = this.__entries.slice(startIndex, indexOfYoungestElementInHistory + 1); } else { //Requested segment wrapping around ringbuffer boundary, get two parts & concat result = this.__entries.slice(startIndex, this.__entriesStored).concat(this.__entries.slice(0, indexOfYoungestElementInHistory + 1)); } } else { result = []; } return result; }, /** * Clears all entries */ clear : function() { this.__entries = new Array(this.getMaxEntries()); this.__entriesStored = 0; this.__entriesStoredSinceMark = 0; this.__nextIndexToStoreTo = 0; }, /** * Adds a number to an ringbuffer index. Does a modulus calculation, * i. e. if the index leaves the ringbuffer space it will wrap around to * the other end of the ringbuffer. * * @param idx {Number} The current index. * @param addMe {Number} The number to add. * @return {Number} The new index */ __addToIndex : function (idx, addMe){ var max = this.getMaxEntries(); var result = (idx + addMe) % max; //If negative, wrap up into the ringbuffer space if (result < 0){ result += max; } return result; } } });