├── README.md ├── ringbuffer.h └── test.cpp /README.md: -------------------------------------------------------------------------------- 1 | # Ring buffer C++ template 2 | 3 | A simple ring buffer implementation as C++ template 4 | 5 | ## License 6 | 7 | This source code is licensed under the 8 | [MIT license](http://www.opensource.org/licenses/MIT). 9 | That license permits commercial use without publishing your source code. 10 | 11 | Also, forks and pull requests are welcome. 12 | 13 | ## License text 14 | 15 | Copyright (c) 2012 Hannes Flicka 16 | 17 | Permission is hereby granted, free of charge, to any person obtaining a copy 18 | of this software and associated documentation files (the "Software"), to deal 19 | in the Software without restriction, including without limitation the rights 20 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 21 | copies of the Software, and to permit persons to whom the Software is 22 | furnished to do so, subject to the following conditions: 23 | 24 | The above copyright notice and this permission notice shall be included in 25 | all copies or substantial portions of the Software. 26 | 27 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 28 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 29 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 30 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 31 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 32 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 33 | THE SOFTWARE. 34 | 35 | ## Contact 36 | 37 | For questions you may contact me via GitHub. 38 | -------------------------------------------------------------------------------- /ringbuffer.h: -------------------------------------------------------------------------------- 1 | /* 2 | A simple ring buffer implementation as C++ template. 3 | 4 | Copyright (c) 2011 Hannes Flicka 5 | Licensed under the terms of the MIT license (given below). 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | THE SOFTWARE. 24 | */ 25 | 26 | #ifndef RINGBUFFER_H 27 | #define RINGBUFFER_H 28 | 29 | #include 30 | #include 31 | 32 | 33 | template class ringbuffer { 34 | public: 35 | /** 36 | * create a ringbuffer with space for up to size elements. 37 | */ 38 | explicit ringbuffer(size_t size) 39 | : size(size) 40 | , begin(0) 41 | , end(0) 42 | , wrap(false) 43 | { 44 | buffer = new T[size]; 45 | } 46 | 47 | /** 48 | * copy constructor 49 | */ 50 | ringbuffer(const ringbuffer & rb) 51 | { 52 | this(rb.size); 53 | begin = rb.begin; 54 | end = rb.end; 55 | memcpy(buffer, rb.buffer, sizeof(T) * size); 56 | } 57 | 58 | /** 59 | * destructor 60 | */ 61 | ~ringbuffer() 62 | { 63 | delete[] buffer; 64 | } 65 | 66 | size_t write(const T * data, size_t n) 67 | { 68 | n = std::min(n, getFree()); 69 | 70 | if (n == 0) { 71 | return n; 72 | } 73 | 74 | const size_t first_chunk = std::min(n, size - end); 75 | memcpy(buffer + end, data, first_chunk * sizeof(T)); 76 | end = (end + first_chunk) % size; 77 | 78 | if (first_chunk < n) { 79 | const size_t second_chunk = n - first_chunk; 80 | memcpy(buffer + end, data + first_chunk, second_chunk * sizeof(T)); 81 | end = (end + second_chunk) % size; 82 | } 83 | 84 | if (begin == end) { 85 | wrap = true; 86 | } 87 | 88 | return n; 89 | } 90 | 91 | size_t read(T * dest, size_t n) 92 | { 93 | n = std::min(n, getOccupied()); 94 | 95 | if (n == 0) { 96 | return n; 97 | } 98 | 99 | if (wrap) { 100 | wrap = false; 101 | } 102 | 103 | const size_t first_chunk = std::min(n, size - begin); 104 | memcpy(dest, buffer + begin, first_chunk * sizeof(T)); 105 | begin = (begin + first_chunk) % size; 106 | 107 | if (first_chunk < n) { 108 | const size_t second_chunk = n - first_chunk; 109 | memcpy(dest + first_chunk, buffer + begin, second_chunk * sizeof(T)); 110 | begin = (begin + second_chunk) % size; 111 | } 112 | return n; 113 | } 114 | 115 | size_t getOccupied() { 116 | if (end == begin) { 117 | return wrap ? size : 0; 118 | } else if (end > begin) { 119 | return end - begin; 120 | } else { 121 | return size + end - begin; 122 | } 123 | } 124 | 125 | size_t getFree() { 126 | return size - getOccupied(); 127 | } 128 | private: 129 | T * buffer; 130 | size_t size; 131 | size_t begin; 132 | size_t end; 133 | bool wrap; 134 | }; 135 | 136 | #endif // RINGBUFFER_H 137 | -------------------------------------------------------------------------------- /test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | #include "ringbuffer.h" 6 | 7 | #define DATALEN 100000 8 | #define SIZE 10 9 | 10 | #define ASSERT(cond) do { if (!(cond)) {printf("assertion \"%s\" failed\n", #cond); exit(1); }} while (0) 11 | 12 | int main() { 13 | ringbuffer buf(SIZE); 14 | int databuf[SIZE]; 15 | int readbuf[SIZE]; 16 | int data[DATALEN]; 17 | 18 | for (int i = 0; i < DATALEN; i++) { 19 | data[i] = rand(); 20 | } 21 | 22 | srand(123); 23 | int readindex = 0; 24 | int i = 0; 25 | while (readindex < DATALEN) { 26 | //printf("free: %d\n", buf.getFree()); 27 | size_t wcount = rand() % SIZE; 28 | for (int j = 0; j < wcount; j++) { 29 | databuf[j] = data[i]; 30 | i++; 31 | } 32 | i -= wcount; 33 | wcount = std::min(wcount, buf.getFree()); 34 | wcount = std::min(wcount, (size_t)(DATALEN - i)); 35 | i += wcount; 36 | size_t x = buf.write(databuf, wcount); 37 | ASSERT(x == wcount); 38 | //printf("free: %d\n", buf.getFree()); 39 | 40 | int rcount = rand() % SIZE; 41 | x = buf.read(readbuf, rcount); 42 | for (int j = 0; j < x; j++) { 43 | ASSERT(readbuf[j] == data[readindex + j]); 44 | } 45 | readindex += x; 46 | } 47 | 48 | return 0; 49 | } 50 | --------------------------------------------------------------------------------