1 // Copyright 2012 Emilie Gillet.
2 //
3 // Author: Emilie Gillet (emilie.o.gillet@gmail.com)
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to deal
7 // in the Software without restriction, including without limitation the rights
8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 // THE SOFTWARE.
22 //
23 // See http://creativecommons.org/licenses/MIT/ for more information.
24 //
25 // -----------------------------------------------------------------------------
26 //
27 // Basic ringbuffer template
28 
29 #ifndef STMLIB_UTILS_RING_BUFFER_H_
30 #define STMLIB_UTILS_RING_BUFFER_H_
31 
32 #include "stmlib/stmlib.h"
33 #include <algorithm>
34 
35 namespace stmlib {
36 
37 template<typename T, size_t size>
38 class RingBuffer {
39  public:
RingBuffer()40   RingBuffer() { }
41 
Init()42   inline void Init() {
43     read_ptr_ = write_ptr_ = 0;
44   }
45 
capacity()46   inline size_t capacity() const { return size; }
47 
writable()48   inline size_t writable() const {
49     return (read_ptr_ - write_ptr_ - 1) % size;
50   }
51 
readable()52   inline size_t readable() const {
53     return (write_ptr_ - read_ptr_) % size;
54   }
55 
Write(T v)56   inline void Write(T v) {
57     while (!writable());
58     Overwrite(v);
59   }
60 
Overwrite(T v)61   inline void Overwrite(T v) {
62     size_t w = write_ptr_;
63     buffer_[w] = v;
64     write_ptr_ = (w + 1) % size;
65   }
66 
Read()67   inline T Read() {
68     while (!readable());
69     return ImmediateRead();
70   }
71 
ImmediateRead()72   inline T ImmediateRead() {
73     size_t r = read_ptr_;
74     T result = buffer_[r];
75     read_ptr_ = (r + 1) % size;
76     return result;
77   }
78 
Flush()79   inline void Flush() {
80     write_ptr_ = read_ptr_;
81   }
82 
Swallow(size_t n)83   inline void Swallow(size_t n) {
84     // Read enough samples to make it possible to read 1 sample.
85     if (writable() >= n) {
86       return;
87     }
88     read_ptr_ = (write_ptr_ + 1 + n) % size;
89   }
90 
ImmediateRead(T * destination,size_t num_elements)91   inline void ImmediateRead(T* destination, size_t num_elements) {
92     size_t r = read_ptr_;
93     size_t read = num_elements;
94 
95     if (r + read > size) {
96       read = size - r;
97     }
98     std::copy(&buffer_[r], &buffer_[r + read], destination);
99     if (read != num_elements) {
100       std::copy(&buffer_[0], &buffer_[num_elements - read], destination + read);
101     }
102     read_ptr_ = (r + num_elements) % size;
103   }
104 
Overwrite(const T * source,size_t num_elements)105   inline void Overwrite(const T* source, size_t num_elements) {
106     size_t w = write_ptr_;
107     size_t written = num_elements;
108 
109     if (w + written > size) {
110       written = size - w;
111     }
112     std::copy(source, source + written, &buffer_[w]);
113     if (written != num_elements) {
114       std::copy(source + written, source + num_elements, &buffer_[0]);
115     }
116 
117     write_ptr_ = (w + num_elements) % size;
118   }
119 
120  private:
121   T buffer_[size];
122   volatile size_t read_ptr_;
123   volatile size_t write_ptr_;
124 
125   DISALLOW_COPY_AND_ASSIGN(RingBuffer);
126 };
127 
128 template<typename T>
129 class RingBuffer<T, 0> {
130  public:
RingBuffer()131   RingBuffer() { }
132 
Init()133   inline void Init() { }
capacity()134   inline size_t capacity() const { return 0; }
writable()135   inline size_t writable() const { return 0; }
readable()136   inline size_t readable() const { return 0; }
Write(T v)137   inline void Write(T v) { }
Overwrite(T v)138   inline void Overwrite(T v) { }
Read()139   inline T Read() { return T(0); }
ImmediateRead()140   inline T ImmediateRead() { return T(0); }
Flush()141   inline void Flush() { }
ImmediateRead(T * destination,size_t num_elements)142   inline void ImmediateRead(T* destination, size_t num_elements) { }
Overwrite(const T * source,size_t num_elements)143   inline void Overwrite(const T* source, size_t num_elements) { }
144 
145  private:
146   DISALLOW_COPY_AND_ASSIGN(RingBuffer);
147 };
148 
149 }  // namespace stmlib
150 
151 #endif   // STMLIB_UTILS_RING_BUFFER_H_
152