Skip to content

Commit bdab705

Browse files
committed
added non safe ring buffer
1 parent b2b7d21 commit bdab705

File tree

3 files changed

+181
-0
lines changed

3 files changed

+181
-0
lines changed

lib/concurrent.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
require 'concurrent/channel/channel'
3737
require 'concurrent/channel/unbuffered_channel'
3838
require 'concurrent/channel/buffered_channel'
39+
require 'concurrent/channel/ring_buffer'
3940
require 'concurrent/channel/blocking_ring_buffer'
4041

4142
require 'concurrent/cached_thread_pool'

lib/concurrent/channel/ring_buffer.rb

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
module Concurrent
2+
3+
# not thread safe buffer
4+
class RingBuffer
5+
6+
def initialize(capacity)
7+
@buffer = Array.new(capacity)
8+
@first = @last = 0
9+
@count = 0
10+
end
11+
12+
def capacity
13+
@buffer.size
14+
end
15+
16+
def count
17+
@count
18+
end
19+
20+
def empty?
21+
@count == 0
22+
end
23+
24+
def full?
25+
@count == capacity
26+
end
27+
28+
# @param [Object] value
29+
# @return [Boolean] true if value has been inserted, false otherwise
30+
def offer(value)
31+
return false if full?
32+
33+
@buffer[@last] = value
34+
@last = (@last + 1) % @buffer.size
35+
@count += 1
36+
true
37+
end
38+
39+
# @return [Object] the first available value and removes it from the buffer. If buffer is empty returns nil
40+
def poll
41+
result = @buffer[@first]
42+
@buffer[@first] = nil
43+
@first = (@first + 1) % @buffer.size
44+
@count -= 1
45+
result
46+
end
47+
48+
# @return [Object] the first available value and without removing it from the buffer. If buffer is empty returns nil
49+
def peek
50+
@buffer[@first]
51+
end
52+
53+
end
54+
end
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
require 'spec_helper'
2+
3+
module Concurrent
4+
5+
describe RingBuffer do
6+
7+
let(:capacity) { 3 }
8+
let(:buffer) { RingBuffer.new(capacity) }
9+
10+
def fill_buffer
11+
capacity.times { buffer.offer 3 }
12+
end
13+
14+
describe '#capacity' do
15+
it 'returns the value passed in constructor' do
16+
buffer.capacity.should eq capacity
17+
end
18+
end
19+
20+
describe '#count' do
21+
it 'is zero when created' do
22+
buffer.count.should eq 0
23+
end
24+
25+
it 'increases when an element is added' do
26+
buffer.offer 5
27+
buffer.count.should eq 1
28+
29+
buffer.offer 1
30+
buffer.count.should eq 2
31+
end
32+
33+
it 'decreases when an element is removed' do
34+
buffer.offer 10
35+
buffer.poll
36+
37+
buffer.count.should eq 0
38+
end
39+
end
40+
41+
describe '#empty?' do
42+
it 'is true when count is zero' do
43+
buffer.empty?.should be_true
44+
end
45+
46+
it 'is false when count is not zero' do
47+
buffer.offer 82
48+
buffer.empty?.should be_false
49+
end
50+
end
51+
52+
describe '#full?' do
53+
it 'is true when count is capacity' do
54+
fill_buffer
55+
buffer.full?.should be_true
56+
end
57+
58+
it 'is false when count is not capacity' do
59+
buffer.full?.should be_false
60+
end
61+
end
62+
63+
describe '#offer' do
64+
it 'returns false when buffer is full' do
65+
fill_buffer
66+
buffer.offer(3).should be_false
67+
end
68+
69+
it 'returns true when the buffer is not full' do
70+
buffer.offer(5).should be_true
71+
end
72+
73+
end
74+
75+
describe '#poll' do
76+
it 'returns the first added value' do
77+
buffer.offer 'hi'
78+
buffer.offer 'foo'
79+
buffer.offer 'bar'
80+
81+
buffer.poll.should eq 'hi'
82+
buffer.poll.should eq 'foo'
83+
buffer.poll.should eq 'bar'
84+
end
85+
86+
it 'returns nil when buffer is empty' do
87+
buffer.poll.should be_nil
88+
end
89+
end
90+
91+
describe '#peek' do
92+
context 'buffer empty' do
93+
it 'returns nil when buffer is empty' do
94+
buffer.peek.should be_nil
95+
end
96+
end
97+
98+
context 'not empty' do
99+
100+
before(:each) { buffer.offer 'element' }
101+
102+
it 'returns the first value' do
103+
buffer.peek.should eq 'element'
104+
end
105+
106+
it 'does not change buffer' do
107+
buffer.peek
108+
buffer.count.should eq 1
109+
end
110+
end
111+
end
112+
113+
context 'circular condition' do
114+
it 'can filled many times' do
115+
fill_buffer
116+
capacity.times { buffer.poll }
117+
118+
buffer.offer 'hi'
119+
120+
buffer.poll.should eq 'hi'
121+
buffer.capacity.should eq capacity
122+
end
123+
end
124+
125+
end
126+
end

0 commit comments

Comments
 (0)