Class: Philiprehberger::RingBuffer
- Inherits:
-
Object
- Object
- Philiprehberger::RingBuffer
- Includes:
- Enumerable
- Defined in:
- lib/philiprehberger/ring_buffer.rb,
lib/philiprehberger/ring_buffer/version.rb
Defined Under Namespace
Classes: Error
Constant Summary collapse
- VERSION =
'0.5.0'
Instance Attribute Summary collapse
-
#capacity ⇒ Object
readonly
Returns the value of attribute capacity.
Instance Method Summary collapse
-
#[](index) ⇒ Object?
Access element by index (0 = oldest, -1 = newest).
-
#average ⇒ Float
Calculate average of numeric elements.
-
#clear ⇒ self
Remove all elements and reset internal state.
-
#concat(*values) ⇒ self
Push multiple values at once.
-
#each {|element| ... } ⇒ Object
Iterate over elements (oldest first).
-
#empty? ⇒ Boolean
Check if the buffer is empty.
-
#first(n = 1) ⇒ Object, Array
Return the oldest n elements.
-
#full? ⇒ Boolean
Check if the buffer is full.
-
#initialize(capacity) ⇒ RingBuffer
constructor
Create a new ring buffer with fixed capacity.
-
#inspect ⇒ String
Human-readable string representation.
-
#last(n = 1) ⇒ Array
Return the last n elements (most recent).
-
#max ⇒ Object
Find maximum element.
-
#median ⇒ Float?
Median value of numeric elements.
-
#min ⇒ Object
Find minimum element.
-
#newest ⇒ Object?
Return the newest element without removing it.
-
#oldest ⇒ Object?
Return the oldest element without removing it.
-
#percentile(p) ⇒ Float?
Calculate the p-th percentile of numeric elements.
-
#pop ⇒ Object?
Remove and return the newest element.
-
#push(value) ⇒ self
Push a value into the buffer, overwriting oldest if full.
-
#resize(new_capacity) ⇒ self
Change the buffer capacity, preserving elements.
-
#sample(n = nil) ⇒ Object, ...
Return a random element or array of random elements.
-
#shift ⇒ Object?
Remove and return the oldest element.
-
#size ⇒ Integer
Number of elements currently in the buffer.
-
#stddev ⇒ Float
Population standard deviation of numeric elements.
-
#sum ⇒ Numeric
Calculate sum of numeric elements.
-
#to_a ⇒ Array
Convert buffer contents to an array (oldest first).
-
#variance ⇒ Float
Population variance of numeric elements.
Constructor Details
#initialize(capacity) ⇒ RingBuffer
Create a new ring buffer with fixed capacity
16 17 18 19 20 21 22 23 |
# File 'lib/philiprehberger/ring_buffer.rb', line 16 def initialize(capacity) raise Error, 'capacity must be a positive integer' unless capacity.is_a?(Integer) && capacity.positive? @capacity = capacity @buffer = Array.new(capacity) @head = 0 @count = 0 end |
Instance Attribute Details
#capacity ⇒ Object (readonly)
Returns the value of attribute capacity.
11 12 13 |
# File 'lib/philiprehberger/ring_buffer.rb', line 11 def capacity @capacity end |
Instance Method Details
#[](index) ⇒ Object?
Access element by index (0 = oldest, -1 = newest)
161 162 163 164 165 166 167 |
# File 'lib/philiprehberger/ring_buffer.rb', line 161 def [](index) arr = to_a return nil if arr.empty? return nil if index >= arr.length || index < -arr.length arr[index] end |
#average ⇒ Float
Calculate average of numeric elements
115 116 117 118 119 |
# File 'lib/philiprehberger/ring_buffer.rb', line 115 def average raise Error, 'buffer is empty' if empty? sum.to_f / @count end |
#clear ⇒ self
Remove all elements and reset internal state
183 184 185 186 187 188 |
# File 'lib/philiprehberger/ring_buffer.rb', line 183 def clear @buffer = Array.new(@capacity) @head = 0 @count = 0 self end |
#concat(*values) ⇒ self
Push multiple values at once
251 252 253 254 |
# File 'lib/philiprehberger/ring_buffer.rb', line 251 def concat(*values) values.each { |v| push(v) } self end |
#each {|element| ... } ⇒ Object
Iterate over elements (oldest first)
300 301 302 |
# File 'lib/philiprehberger/ring_buffer.rb', line 300 def each(&) to_a.each(&) end |
#empty? ⇒ Boolean
Check if the buffer is empty
108 109 110 |
# File 'lib/philiprehberger/ring_buffer.rb', line 108 def empty? @count.zero? end |
#first(n = 1) ⇒ Object, Array
Return the oldest n elements
173 174 175 176 177 178 |
# File 'lib/philiprehberger/ring_buffer.rb', line 173 def first(n = 1) arr = to_a return arr.first if n == 1 arr.first(n) end |
#full? ⇒ Boolean
Check if the buffer is full
101 102 103 |
# File 'lib/philiprehberger/ring_buffer.rb', line 101 def full? @count == @capacity end |
#inspect ⇒ String
Human-readable string representation
293 294 295 |
# File 'lib/philiprehberger/ring_buffer.rb', line 293 def inspect "#<#{self.class} capacity=#{@capacity} size=#{@count} elements=#{to_a.inspect}>" end |
#last(n = 1) ⇒ Array
Return the last n elements (most recent)
152 153 154 155 |
# File 'lib/philiprehberger/ring_buffer.rb', line 152 def last(n = 1) arr = to_a arr.last(n) end |
#max ⇒ Object
Find maximum element
142 143 144 145 146 |
# File 'lib/philiprehberger/ring_buffer.rb', line 142 def max raise Error, 'buffer is empty' if empty? to_a.max end |
#median ⇒ Float?
Median value of numeric elements
211 212 213 214 215 216 217 218 219 220 221 222 |
# File 'lib/philiprehberger/ring_buffer.rb', line 211 def median return nil if empty? sorted = to_a.sort mid = sorted.length / 2 if sorted.length.odd? sorted[mid].to_f else (sorted[mid - 1] + sorted[mid]) / 2.0 end end |
#min ⇒ Object
Find minimum element
133 134 135 136 137 |
# File 'lib/philiprehberger/ring_buffer.rb', line 133 def min raise Error, 'buffer is empty' if empty? to_a.min end |
#newest ⇒ Object?
Return the newest element without removing it
85 86 87 88 89 |
# File 'lib/philiprehberger/ring_buffer.rb', line 85 def newest return nil if empty? @buffer[(@head - 1) % @capacity] end |
#oldest ⇒ Object?
Return the oldest element without removing it
76 77 78 79 80 |
# File 'lib/philiprehberger/ring_buffer.rb', line 76 def oldest return nil if empty? @buffer[(@head - @count) % @capacity] end |
#percentile(p) ⇒ Float?
Calculate the p-th percentile of numeric elements
Uses linear interpolation between nearest ranks.
263 264 265 266 267 268 269 270 271 272 273 274 275 276 |
# File 'lib/philiprehberger/ring_buffer.rb', line 263 def percentile(p) raise Error, 'percentile must be between 0 and 100' unless p.is_a?(Numeric) && p >= 0 && p <= 100 return nil if empty? sorted = to_a.sort return sorted.first.to_f if sorted.length == 1 rank = (p / 100.0) * (sorted.length - 1) lower = rank.floor upper = rank.ceil return sorted[lower].to_f if lower == upper sorted[lower] + ((sorted[upper] - sorted[lower]) * (rank - lower)) end |
#pop ⇒ Object?
Remove and return the newest element
62 63 64 65 66 67 68 69 70 71 |
# File 'lib/philiprehberger/ring_buffer.rb', line 62 def pop return nil if empty? newest_idx = (@head - 1) % @capacity value = @buffer[newest_idx] @buffer[newest_idx] = nil @head = newest_idx @count -= 1 value end |
#push(value) ⇒ self
Push a value into the buffer, overwriting oldest if full
29 30 31 32 33 34 |
# File 'lib/philiprehberger/ring_buffer.rb', line 29 def push(value) @buffer[@head] = value @head = (@head + 1) % @capacity @count += 1 if @count < @capacity self end |
#resize(new_capacity) ⇒ self
Change the buffer capacity, preserving elements
If the new capacity is smaller than the current element count, the oldest elements are discarded and only the most recent new_capacity elements are kept.
232 233 234 235 236 237 238 239 240 241 242 243 244 245 |
# File 'lib/philiprehberger/ring_buffer.rb', line 232 def resize(new_capacity) raise Error, 'capacity must be a positive integer' unless new_capacity.is_a?(Integer) && new_capacity.positive? return self if new_capacity == @capacity elements = to_a elements = elements.last(new_capacity) if elements.length > new_capacity @capacity = new_capacity @buffer = Array.new(new_capacity) @head = 0 @count = 0 elements.each { |e| push(e) } self end |
#sample(n = nil) ⇒ Object, ...
Return a random element or array of random elements
282 283 284 285 286 287 288 |
# File 'lib/philiprehberger/ring_buffer.rb', line 282 def sample(n = nil) arr = to_a return nil if arr.empty? && n.nil? return [] if arr.empty? && n n.nil? ? arr.sample : arr.sample(n) end |
#shift ⇒ Object?
Remove and return the oldest element
49 50 51 52 53 54 55 56 57 |
# File 'lib/philiprehberger/ring_buffer.rb', line 49 def shift return nil if empty? start = (@head - @count) % @capacity value = @buffer[start] @buffer[start] = nil @count -= 1 value end |
#size ⇒ Integer
Number of elements currently in the buffer
94 95 96 |
# File 'lib/philiprehberger/ring_buffer.rb', line 94 def size @count end |
#stddev ⇒ Float
Population standard deviation of numeric elements
204 205 206 |
# File 'lib/philiprehberger/ring_buffer.rb', line 204 def stddev Math.sqrt(variance) end |
#sum ⇒ Numeric
Calculate sum of numeric elements
124 125 126 127 128 |
# File 'lib/philiprehberger/ring_buffer.rb', line 124 def sum raise Error, 'buffer is empty' if empty? to_a.sum end |
#to_a ⇒ Array
Convert buffer contents to an array (oldest first)
39 40 41 42 43 44 |
# File 'lib/philiprehberger/ring_buffer.rb', line 39 def to_a return [] if @count.zero? start = (@head - @count) % @capacity Array.new(@count) { |i| @buffer[(start + i) % @capacity] } end |
#variance ⇒ Float
Population variance of numeric elements
193 194 195 196 197 198 199 |
# File 'lib/philiprehberger/ring_buffer.rb', line 193 def variance return 0.0 if @count <= 1 avg = average arr = to_a arr.sum { |v| (v - avg)**2 } / arr.length.to_f end |