From 7ead89a146c2d90eee6f6833caabbe42db547875 Mon Sep 17 00:00:00 2001 From: Anthony Green Date: Fri, 16 May 2014 11:33:31 +0100 Subject: [PATCH] Add circular buffer exercism --- EXERCISES.txt | 1 + circular-buffer/circular-buffer_test.spec.js | 103 +++++++++++++++++++ circular-buffer/example.js | 99 ++++++++++++++++++ 3 files changed, 203 insertions(+) create mode 100644 circular-buffer/circular-buffer_test.spec.js create mode 100644 circular-buffer/example.js diff --git a/EXERCISES.txt b/EXERCISES.txt index 94d9a5d8..321269ee 100644 --- a/EXERCISES.txt +++ b/EXERCISES.txt @@ -16,6 +16,7 @@ gigasecond triangle scrabble-score roman-numerals +circular-buffer binary prime-factors raindrops diff --git a/circular-buffer/circular-buffer_test.spec.js b/circular-buffer/circular-buffer_test.spec.js new file mode 100644 index 00000000..cf27f17d --- /dev/null +++ b/circular-buffer/circular-buffer_test.spec.js @@ -0,0 +1,103 @@ +var circularBuffer = require('./circular-buffer').circularBuffer; +var bufferEmptyException = require('./circular-buffer').bufferEmptyException; +var bufferFullException = require('./circular-buffer').bufferFullException; + +describe("CircularBuffer", function() { + + it("reading an empty buffer throws a BufferEmptyException", function() { + var buffer = circularBuffer(1); + expect(buffer.read).toThrow(bufferEmptyException()); + }); + + xit("write and read back one item", function() { + var buffer = circularBuffer(1); + buffer.write('1'); + expect(buffer.read()).toBe('1'); + expect(buffer.read).toThrow(bufferEmptyException()); + }); + + xit("write and read back multiple items", function() { + var buffer = circularBuffer(2); + buffer.write('1'); + buffer.write('2'); + expect(buffer.read()).toBe('1'); + expect(buffer.read()).toBe('2'); + expect(buffer.read).toThrow(bufferEmptyException()); + }); + + xit("clearing a buffer", function() { + var buffer = circularBuffer(2); + buffer.write('1'); + buffer.write('2'); + buffer.clear(); + expect(buffer.read).toThrowError + buffer.write('3'); + buffer.write('4'); + expect(buffer.read()).toBe('3'); + expect(buffer.read()).toBe('4'); + }); + + xit("alternate write and read", function() { + var buffer = circularBuffer(2); + buffer.write('1'); + expect(buffer.read()).toBe('1'); + buffer.write('2'); + expect(buffer.read()).toBe('2'); + }); + + xit("reads back oldest item", function() { + var buffer = circularBuffer(3); + buffer.write('1'); + buffer.write('2'); + buffer.read(); + buffer.write('3'); + expect(buffer.read()).toBe('2'); + expect(buffer.read()).toBe('3'); + }); + + xit("writes of undefined or null don't occupy buffer", function() { + var buffer = circularBuffer(3); + buffer.write(null); + buffer.write(undefined); + [1,2,3].map(function(i) { buffer.write(i.toString()) }) + expect(buffer.read()).toBe('1'); + }); + + xit("writing to a full buffer throws a BufferFullException", function() { + var buffer = circularBuffer(2); + buffer.write('1'); + buffer.write('2'); + expect(function() { + buffer.write('A'); + }).toThrow(bufferFullException()); + }); + + xit("forced writes over write oldest item in a full buffer", function() { + var buffer = circularBuffer(2); + buffer.write('1'); + buffer.write('2'); + buffer.forceWrite('A'); + expect(buffer.read()).toBe('2'); + expect(buffer.read()).toBe('A'); + expect(buffer.read).toThrow(bufferEmptyException()); + }); + + xit("alternate force write and read into full buffer", function() { + var buffer = circularBuffer(5); + [1,2,3].map(function(i) { buffer.write(i.toString()) }) + buffer.read(); + buffer.read(); + buffer.write('4'); + buffer.read(); + [5,6,7,8].map(function(i) { buffer.write(i.toString()) }) + buffer.forceWrite('A'); + buffer.forceWrite('B'); + expect(buffer.read()).toBe('6'); + expect(buffer.read()).toBe('7'); + expect(buffer.read()).toBe('8'); + expect(buffer.read()).toBe('A'); + expect(buffer.read()).toBe('B'); + expect(buffer.read).toThrow(bufferEmptyException()); + }); + +}); \ No newline at end of file diff --git a/circular-buffer/example.js b/circular-buffer/example.js new file mode 100644 index 00000000..909532fc --- /dev/null +++ b/circular-buffer/example.js @@ -0,0 +1,99 @@ +function CircularBuffer(capacity) { + + var readPoint = 0; + var writePoint = 0; + var buffer = new Array(capacity); + + return { + read: function() { + if (isBufferEmpty()) { throw new BufferEmptyException(); } + var data = buffer[readPoint]; + buffer[readPoint] = null; + updateReadPoint(); + return data; + }, + + write: function(data) { + updateBuffer(data, function() { + if (isBufferFull()) { throw new BufferFullException(); } + buffer[writePoint] = data; + }) + }, + + forceWrite: function(data) { + updateBuffer(data, function(){ + buffer[writePoint] = data; + if (isBufferFull()) { updateReadPoint() } + }) + }, + + clear: function() { + readPoint = 0; + writePoint = 0; + buffer = new Array(capacity); + }, + + isFull: function() { + return isBufferFull(); + }, + + isEmpty: function() { + return isBufferEmpty(); + } + }; + + function isBufferEmpty() { + return buffer.every(isEmpty); + }; + + function isBufferFull() { + return buffer.filter(isFull).length === capacity; + }; + + function updateBuffer(data, callback) { + if (isEmpty(data)) { return; } + callback(); + updateWritePoint(); + }; + + function updateWritePoint() { + writePoint = (writePoint + 1) % capacity; + }; + + function updateReadPoint() { + readPoint = (readPoint + 1) % capacity; + }; + + function isFull(data) { + return !isEmpty(data); + }; + + function isEmpty(data) { + return data === null || data === undefined; + }; + +}; + +function BufferEmptyException() { + this.name = "BufferEmptyException"; + this.message = "Buffer is empty."; +}; + +function BufferFullException() { + this.name = "BufferFullException"; + this.message = "Buffer is full."; +}; + +module.exports = { + circularBuffer: function(capacity) { + return new CircularBuffer(capacity); + }, + + bufferEmptyException: function() { + return new BufferEmptyException(); + }, + + bufferFullException: function() { + return new BufferFullException(); + } +}; \ No newline at end of file