Intial Commit

This commit is contained in:
valki
2020-10-17 18:42:50 +02:00
commit 664c6d8ca3
5892 changed files with 759183 additions and 0 deletions

View File

@@ -0,0 +1 @@
node_modules

View File

@@ -0,0 +1,10 @@
language: node_js
node_js:
- "0.12"
install:
- npm install -g mocha
- npm install
before_script:
- mocha --version
script:
- mocha

View File

@@ -0,0 +1,60 @@
# NodeJS Circular Buffer
<p>
<a href="https://travis-ci.org/tomsmeding/circular-buffer">
<img src="https://api.travis-ci.org/tomsmeding/circular-buffer.png?branch=master" alt="Travis CI Badge"/>
</a>
</p>
This is a simple [circular buffer](http://en.wikipedia.org/wiki/Circular_buffer) implementation for NodeJS.
The implementation can function both as a queue (which it's most suited for), and as a (forgetful) stack. Queue functionality uses `enq()` and `deq()`; stack functionality uses `push()` and `pop()`. Values are enqueued at the front of the buffer and dequeued at the back of the buffer; pushing and popping is at the back of the buffer. Indexing is front-to-back: the last-enqueued item has lowest index, which is also the first-pushed item.
## Usage
Below is a sample session with a circular buffer with this package. It should answer most questions.
```node
var CircularBuffer = require("circular-buffer");
var buf = new CircularBuffer(3);
console.log(buf.capacity()); // -> 3
buf.enq(1);
buf.enq(2);
console.log(buf.size()); // -> 2
buf.toarray(); // -> [2,1]
buf.push(3);
buf.toarray(); // -> [2,1,3]
buf.enq(4);
console.log(buf.size()); // -> 3 (despite having added a fourth item!)
buf.toarray(); // -> [4,2,1]
buf.get(0); // -> 4 (last enqueued item is at start of buffer)
buf.get(0,2); // -> [4,2,1] (2-parameter get takes start and end)
buf.toarray(); // -> [4,2,1] (equivalent to buf.get(0,buf.size() - 1) )
console.log(buf.deq()); // -> 1
buf.toarray(); // -> [4,2]
buf.pop(); // -> 2 (deq and pop are functionally the same)
buf.deq(); // -> 4
buf.toarray(); // -> []
buf.deq(); // -> throws RangeError("CircularBuffer dequeue on empty buffer")
```
## Functions
- `size()` -> `integer`
- Returns the current number of items in the buffer.
- `capacity()` -> `integer`
- Returns the maximum number of items in the buffer (specified when creating it).
- `enq(value)`
- Enqueue `value` at the front of the buffer
- `deq()` -> `value`
- Dequeue an item from the back of the buffer; returns that item. Throws `RangeError` if the buffer is empty on invocation.
- `get(idx)` -> `value`
- Get the value at index `idx`. `0` is the front of the buffer (last-enqueued item, or first-pushed item), `buf.size()-1` is the back of the buffer.
- `get(start,end)` -> `[value]`
- Gets the values from index `start` up to and including index `end`; returns an array, in front-to-back order. Equivalent to `[buf.get(start),buf.get(start+1),/*etc*/,buf.get(end)]`.
- `toarray()` -> `[value]`
- Equivalent to `buf.get(0,buf.size() - 1)`: exports all items in the buffer in front-to-back order.
## Testing
To test the package simply run `npm update && npm test` in the package's root folder.

View File

@@ -0,0 +1,78 @@
function CircularBuffer(capacity){
if(!(this instanceof CircularBuffer))return new CircularBuffer(capacity);
if(typeof capacity=="object"&&
Array.isArray(capacity["_buffer"])&&
typeof capacity._capacity=="number"&&
typeof capacity._first=="number"&&
typeof capacity._size=="number"){
for(var prop in capacity){
if(capacity.hasOwnProperty(prop))this[prop]=capacity[prop];
}
} else {
if(typeof capacity!="number"||capacity%1!=0||capacity<1)
throw new TypeError("Invalid capacity");
this._buffer=new Array(capacity);
this._capacity=capacity;
this._first=0;
this._size=0;
}
}
CircularBuffer.prototype={
size:function(){return this._size;},
capacity:function(){return this._capacity;},
enq:function(value){
if(this._first>0)this._first--; else this._first=this._capacity-1;
this._buffer[this._first]=value;
if(this._size<this._capacity)this._size++;
},
push:function(value){
if(this._size==this._capacity){
this._buffer[this._first]=value;
this._first=(this._first+1)%this._capacity;
} else {
this._buffer[(this._first+this._size)%this._capacity]=value;
this._size++;
}
},
deq:function(){
if(this._size==0)throw new RangeError("dequeue on empty buffer");
var value=this._buffer[(this._first+this._size-1)%this._capacity];
this._size--;
return value;
},
pop:function(){return this.deq();},
shift:function(){
if(this._size==0)throw new RangeError("shift on empty buffer");
var value=this._buffer[this._first];
if(this._first==this._capacity-1)this._first=0; else this._first++;
this._size--;
return value;
},
get:function(start,end){
if(this._size==0&&start==0&&(end==undefined||end==0))return [];
if(typeof start!="number"||start%1!=0||start<0)throw new TypeError("Invalid start");
if(start>=this._size)throw new RangeError("Index past end of buffer: "+start);
if(end==undefined)return this._buffer[(this._first+start)%this._capacity];
if(typeof end!="number"||end%1!=0||end<0)throw new TypeError("Invalid end");
if(end>=this._size)throw new RangeError("Index past end of buffer: "+end);
if(this._first+start>=this._capacity){
//make sure first+start and first+end are in a normal range
start-=this._capacity; //becomes a negative number
end-=this._capacity;
}
if(this._first+end<this._capacity)
return this._buffer.slice(this._first+start,this._first+end+1);
else
return this._buffer.slice(this._first+start,this._capacity).concat(this._buffer.slice(0,this._first+end+1-this._capacity));
},
toarray:function(){
if(this._size==0)return [];
return this.get(0,this._size-1);
}
};
module.exports=CircularBuffer;

View File

@@ -0,0 +1,56 @@
{
"_from": "circular-buffer@1.0.2",
"_id": "circular-buffer@1.0.2",
"_inBundle": false,
"_integrity": "sha1-+g4VLtYp92/iTd+J5y69AHhsWm4=",
"_location": "/circular-buffer",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "circular-buffer@1.0.2",
"name": "circular-buffer",
"escapedName": "circular-buffer",
"rawSpec": "1.0.2",
"saveSpec": null,
"fetchSpec": "1.0.2"
},
"_requiredBy": [
"/node-red-contrib-msg-speed"
],
"_resolved": "https://registry.npmjs.org/circular-buffer/-/circular-buffer-1.0.2.tgz",
"_shasum": "fa0e152ed629f76fe24ddf89e72ebd00786c5a6e",
"_spec": "circular-buffer@1.0.2",
"_where": "/data/node_modules/node-red-contrib-msg-speed",
"author": {
"name": "Tom Smeding",
"email": "hallo@tomsmeding.nl",
"url": "http://tomsmeding.com"
},
"bugs": {
"url": "https://github.com/tomsmeding/circular-buffer/issues"
},
"bundleDependencies": false,
"deprecated": false,
"description": "A NodeJS simple circular buffer implementation supporting indexing ",
"devDependencies": {
"chai": "^2.2.0",
"mocha": "^2.2.4"
},
"homepage": "https://github.com/tomsmeding/circular-buffer",
"keywords": [
"circular-buffer",
"data-structure"
],
"license": "ISC",
"main": "index.js",
"name": "circular-buffer",
"repository": {
"type": "git",
"url": "git+https://github.com/tomsmeding/circular-buffer.git"
},
"scripts": {
"test": "mocha"
},
"version": "1.0.2"
}

View File

@@ -0,0 +1,161 @@
var assert = require("chai").assert;
var CircularBuffer = require("../");
describe("CircularBuffer", function () {
var size = 3;
it("should be a CircularBuffer", function () {
var buf = new CircularBuffer(size);
assert.instanceOf(buf, CircularBuffer);
});
it("should have the correct capacity", function () {
var buf = new CircularBuffer(size);
assert.equal(buf.capacity(), size);
});
it("should correctly return the buffer size", function () {
var buf = new CircularBuffer(size);
assert.equal(buf.size(), 0);
buf.enq(0);
buf.enq(1);
assert.equal(buf.size(), 2);
buf.enq(3);
buf.enq(4);
assert.equal(buf.size(), 3);
});
it("should enqueue items and get them", function () {
var buf = new CircularBuffer(size);
var n = Math.random();
buf.enq(5);
buf.enq(n);
assert.equal(buf.get(0), n);
});
it("retrieve multiple values at once", function () {
var buf = new CircularBuffer(size);
for (var i = 0; i < 4; i++) {
buf.enq(i);
}
var res = buf.get(0,2); // 3,2,1
assert.instanceOf(res, Array);
assert.deepEqual(res, [3, 2, 1]);
});
it("should handle partial gets correctly", function () {
var buf = new CircularBuffer(size);
for (var i = 0; i < 4; i++) {
buf.enq(i);
}
var res = buf.get(1,2); // 2,1
assert.instanceOf(res, Array);
assert.deepEqual(res, [2, 1]);
});
it("should convert the current values to an array", function () {
var buf = new CircularBuffer(size);
assert.instanceOf(buf.toarray(), Array);
assert.lengthOf(buf.toarray(), 0);
buf.enq(42);
buf.enq("str");
buf.enq(true);
buf.enq(Math.PI);
assert.deepEqual(buf.toarray(), [Math.PI, true, "str"]);
});
it("should error when dequeuing on an empty buffer", function () {
var buf = new CircularBuffer(size);
try {
buf.deq();
} catch (e) { // yay! we caught an error
return;
}
assert.fail("No error after dequeueing empty buffer", "Error after dequeueing empty buffer");
});
it("should error when shifting on an empty buffer", function () {
var buf = new CircularBuffer(size);
try {
buf.shift();
} catch (e) { // yay! we caught an error
return;
}
assert.fail("No error after shifting empty buffer", "Error after shifting empty buffer");
});
it("should correctly distinguish push and enq", function () {
var buf = new CircularBuffer(size);
buf.enq("mid");
buf.push("last");
buf.enq("first");
assert.deepEqual(buf.toarray(), ["first", "mid", "last"]);
});
it("should shift correctly", function () {
var buf = new CircularBuffer(size);
buf.push(1);
buf.push(2);
buf.push(3);
buf.push(4);
assert.deepEqual(buf.shift(), 2);
assert.deepEqual(buf.toarray(), [3, 4]);
});
it("should dequeue and pop correctly", function () {
var buf = new CircularBuffer(size);
buf.push(1);
buf.push(2);
buf.push(3);
buf.push(4);
assert.deepEqual(buf.pop(), 4);
assert.deepEqual(buf.deq(), 3);
assert.deepEqual(buf.toarray(), [2]);
});
it("should handle the README example correctly", function () {
var buf = new CircularBuffer(3);
assert.deepEqual(buf.capacity(), 3);
buf.enq(1);
buf.enq(2);
assert.deepEqual(buf.size(), 2);
assert.deepEqual(buf.toarray(), [2,1]);
buf.push(3);
assert.deepEqual(buf.toarray(), [2,1,3]);
buf.enq(4);
assert.deepEqual(buf.size(), 3);
assert.deepEqual(buf.toarray(), [4,2,1]);
assert.deepEqual(buf.get(0), 4);
assert.deepEqual(buf.get(0,2), [4,2,1]);
assert.deepEqual(buf.toarray(), [4,2,1]);
assert.deepEqual(buf.deq(), 1);
assert.deepEqual(buf.toarray(), [4,2]);
assert.deepEqual(buf.pop(), 2);
assert.deepEqual(buf.deq(), 4);
assert.deepEqual(buf.toarray(), []);
try {
buf.deq();
} catch (e) {
return;
}
assert.fail("No error after dequeueing empty buffer", "Error after dequeueing empty buffer");
});
});