-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathRingBuffer.js
133 lines (112 loc) · 3.74 KB
/
RingBuffer.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/**
* RingBuffer implements a simple "ring" buffer based on the native node.js
* buffer. It basically keeps track of the current position in the buffer (mark)
* and the remaining bytes based on how much data has been inserted so far. It
* will also automatically "rotate" the buffer to the zero position when the
* buffer doesn't have enough free space to put additional data.
*/
var RingBuffer = function(size) {
this.buffer_ = new Buffer(size);
/// Maximum size in bytes that the ring buffer can hold.
this.size_ = size;
/// Current offset into the ring buffer.
this.position_ = 0;
/// Remaining bytes in the ring buffer to be read.
this.remaining_ = 0;
};
/**
* Returns the number of remaining bytes in the internal buffer.
*/
RingBuffer.prototype.remaining = function() {
return this.remaining_;
};
/**
* Copies a slice of the internal buffer into a new buffer so the user can
* inspect it. Does not consume the buffer.
*/
RingBuffer.prototype.peek = function(buffer, size) {
if (size > this.remaining_)
return false;
this.buffer_.copy(buffer, 0, this.position_, this.position_ + size);
return true;
};
/**
* Puts bytes from a source buffer into the internal buffer. Compacts the buffer
* if needed. Returns if the operation was successful. put() will fail if the
* internal buffer (after compaction) does not have space to hold the source
* buffer.
*/
RingBuffer.prototype.put = function(buffer) {
var size = buffer.length;
if (this.position_ + this.remaining_ + size >= this.size_)
this.compact(size);
if (this.position_ + this.remaining_ + size >= this.size_)
return false;
buffer.copy(this.buffer_, this.position_ + this.remaining_);
this.remaining_ += size;
return true;
};
/**
* Shifts the remaining data so that it is aligned at zero.
*/
RingBuffer.prototype.compact = function(size) {
/*
console.log(this.position_);
console.log(size);
console.log(this.position_ + size);
console.log(this.position_ + this.remaining_);
*/
this.buffer_.copy(this.buffer_, 0, this.position_ + size, this.position_ + this.remaining_);
this.remaining_ = this.remaining_ - size;
this.position_ = 0;
};
/**
* Rewinds the current marker a set number of bytes. Fails if the size requested
* is larger than the current marker.
*/
RingBuffer.prototype.rewind = function(size) {
if (size > this.position_)
return false;
this.position_ -= size;
this.remaining_ += size;
return true;
};
/**
* Does the same thing as peek but moves the position marker forward if there's
* enough bytes in the internal buffer.
*/
RingBuffer.prototype.get = function(buffer, size) {
var state = this.peek(buffer, size);
if (state) {
this.position_ += size;
this.remaining_ += size;
}
return state;
};
/**
* Gets a specified length and formats it as a string.
*/
RingBuffer.prototype.getString = function(size, encoding) {
// Default parameter for encoding is 'utf8'
encoding = encoding || 'utf8';
var buffer = new Buffer(size);
var state = this.peek(buffer, size);
if (state) {
this.position_ += size;
this.remaining_ -= size;
return buffer.toString(encoding);
}
return null;
};
// This a bit tricky, but it's to generate the ability call any of the
// underlying buffer's useful integer reading capabilities.
[16, 32, 64].forEach(function(bits) {
var unsigned_function_name = 'readUInt' + bits + 'BE';
RingBuffer.prototype[unsigned_function_name] = function() {
var value = this.buffer_[unsigned_function_name](this.position_);
this.position_ += bits / 8;
this.remaining_ -= bits / 8;
return value;
};
});
module.exports = RingBuffer;