项目作者: tonton81

项目描述 :
Circular Buffer/ Circular Array
高级语言: C++
项目地址: git://github.com/tonton81/Circular_Buffer.git
创建时间: 2018-03-18T16:22:37Z
项目社区:https://github.com/tonton81/Circular_Buffer

开源协议:MIT License

下载


Circular_Buffer

This is pretty much an advanced version of a circular buffer that
follows the STL naming conventions of std::queue,deque,vector, etc…

It supports multiple circular buffer creations without the use of
reallocation, new, or malloc. The system uses a template for the
configuration of the buffers for the class.

Both circular buffers and circular arrays all support FIFO, LIFO, and
MIXED (FIFO+LIFO); This can lead you to design a priority queue system
where front entries for priority items and back entries for least
priority.

The library is capable of inserting and reading from both the front and
the back of the queue.

The buffer system this library supports is not just for ring buffer
usage. There is an even more powerful array system. Both buffer types
have advanced feature sets of their own we will talk about.

Methods for circular ring buffer

  1. void print(const char *p);
  2. void println(const char *p);
  3. void push_front(const T *buffer, uint16_t length);
  4. void push_front(T value);
  5. void push_back(T value) { return write(value); }
  6. void push_back(const T *buffer, uint16_t length) { write(buffer, length); }
  7. T pop_front() { return read(); }
  8. T pop_front(T *buffer, uint16_t length) { return readBytes(buffer,length); }
  9. T pop_back();
  10. void write(T value);
  11. void write(const T *buffer, uint16_t length);
  12. T peek(uint16_t pos = 0);
  13. T peekBytes(T *buffer, uint16_t length);
  14. T read();
  15. T read(T *buffer, uint16_t length) { return readBytes(buffer,length); }
  16. T readBytes(T *buffer, uint16_t length);
  17. T variance();
  18. T deviation();
  19. T average();
  20. T median(bool override = 0);
  21. void sort_ascending();
  22. void sort_descending();
  23. T sum();
  24. T min();
  25. T max();
  26. T mean() { return average(); }
  27. T capacity() { return _size; }
  28. void flush() { clear(); }
  29. void clear() { head = tail = _available = 0; }
  30. uint16_t size() { return _available; }
  31. uint16_t available() { return _available; }
  32. T list();

Methods for circular array buffer

  1. uint16_t size() { return _available; }
  2. uint16_t available() { return _available; }
  3. T capacity() { return _size; }
  4. T length_back() { return ((T)(_cabuf[_cbuf[(head+size()-1)&(_size-1)]][0] << 8*sizeof(T)) | _cabuf[_cbuf[(head+size()-1)&(_size-1)]][1]); }
  5. T length_front() { return ((T)(_cabuf[_cbuf[(head)&(_size-1)]][0] << 8*sizeof(T)) | _cabuf[_cbuf[(head)&(_size-1)]][1]); }
  6. T list();
  7. T max_size() { return multi; }
  8. T pop_back(T *buffer, uint16_t length);
  9. T* peek_front() { return front(); }
  10. T* peek_back() { return back(); }
  11. T* front() { return _cabuf[_cbuf[(head)&(_size-1)]]+2; }
  12. T* back() { return _cabuf[(tail-1)&(_size-1)]+2; }
  13. bool replace(T *buffer, uint16_t length, int pos1, int pos2, int pos3, int pos4 = -1, int pos5 = -1);
  14. T pop_back();
  15. void flush() { clear(); }
  16. void clear() { head = tail = _available = 0; }
  17. void push_back(const T *buffer, uint16_t length) { write(buffer, length); }
  18. void push_front(const T *buffer, uint16_t length);
  19. T pop_front(T *buffer, uint16_t length) { return readBytes(buffer,length); }
  20. T read();
  21. T read(T *buffer, uint16_t length) { return readBytes(buffer,length); }
  22. T peek_front(T *buffer, uint16_t length, uint32_t entry = 0);
  23. bool isEqual(const T *buffer);
  24. T readBytes(T *buffer, uint16_t length);
  25. void write(const T *buffer, uint16_t length);
  26. bool find(T *buffer, uint16_t length, int pos1, int pos2, int pos3, int pos4 = -1, int pos5 = -1);
  27. bool findRemove(T *buffer, uint16_t length, int pos1, int pos2, int pos3, int pos4 = -1, int pos5 = -1);
  28. bool isEqual(const T *buffer);

Method explanations

If you ever used queues before, you will notice some similarities. Here
is the full list of both buffers combined above since they share quite a
few methods but run differently depending on which buffer calls it.

  1. void push_back(T value) { return write(value); } // adds a value to the back of the queue
  2. void push_front(T value); // adds a value to the front of the queue
  3. T pop_front() { return read(); } // read and remove an item from the front queue
  4. T pop_back(); // read and remove an item from the back of the queue
  5. void write(T value); // write an item to the back of the queue
  6. void push_back(const T *buffer, uint16_t length) { write(buffer, length); } // write a buffer to the back of the queue
  7. void write(const T *buffer, uint16_t length); // write a buffer to the back of the queue
  8. void push_front(const T *buffer, uint16_t length); // write a buffer to the front of the queue
  9. T peek(uint16_t pos = 0); // show whats currently in queue, but don't remove. default 1st entry shown.
  10. T peekBytes(T *buffer, uint16_t length); // updates the buffer passed into the function with whats currently in queue, up to the length, or whatevers available, whichever comes first.
  11. T read(); // read an item from front of the queue and remove it
  12. T pop_front(T *buffer, uint16_t length) { return readBytes(buffer,length); } // read the front of the queue into a buffer and remove it
  13. T read(T *buffer, uint16_t length) { return readBytes(buffer,length); } // read the front of the queue into a buffer and remove it
  14. T readBytes(T *buffer, uint16_t length); // read the front of the queue into a buffer and remove it
  15. void flush() { clear(); } // clears the queue
  16. void clear() { head = tail = _available = 0; } // clears the queue
  17. void print(const char *p); // print("text") to the queue
  18. void println(const char *p); // println("text") to the queue, function appends the newline
  19. uint16_t size() { return _available; } // returns the size of the queue
  20. uint16_t available() { return _available; } // returns the size of the queue
  21. T capacity() { return _size; } // returns the size of the ring buffer or the count of circular arrays
  22. T length_back() { return ((T)(_cabuf[_cbuf[(head+size()-1)&(_size-1)]][0] << 8*sizeof(T)) | _cabuf[_cbuf[(head+size()-1)&(_size-1)]][1]); } // gives the length of the actual array (not raw size of array) of the back queue
  23. T length_front() { return ((T)(_cabuf[_cbuf[(head)&(_size-1)]][0] << 8*sizeof(T)) | _cabuf[_cbuf[(head)&(_size-1)]][1]); } // gives the length of the actual array (not raw size of array) of the front queue
  24. T list(); // prints out a list of your array entries stats on Serial. (only for circular arrays)
  25. T variance(); // calculates variance of entries stored in ring buffer
  26. T deviation(); // calculates standard deviation of entries stored in ring buffer
  27. T average(); // calculates average of entries stored in ring buffer
  28. T median(bool override = 0); // calculates median of entries stored in ring buffer, overload it to leave ring buffer sorted ascendingly
  29. void sort_ascending(); // sort ring buffer by ascending values
  30. void sort_descending(); // sort ring buffer by descending values
  31. T sum(); // sum of all entries in ring buffer
  32. T min(); // smallest value of all entries in ring buffer
  33. T max(); // largest value of all entries in ring buffer
  34. T mean() { return average(); } // average/mean of all entries in ring buffer
  35. T max_size() { return multi; } // max size of the internal buffer for the circular array, not the actual input array
  36. T pop_back(T *buffer, uint16_t length); // update a passed in buffer with the contents of the queue and remove it from queue
  37. T* peek_front() { return front(); } // look through the items of the front queued circular array
  38. T* peek_back() { return back(); } // look through the items of the back queued circular array
  39. T* front() { return _cabuf[_cbuf[(head)&(_size-1)]]+2; } // look through the items of the front queued circular array
  40. T* back() { return _cabuf[(tail-1)&(_size-1)]+2; } // look through the items of the back queued circular array
  41. T peek_front(T *buffer, uint16_t length, uint32_t entry = 0); // peek front buffer into array but don't dequeue. use read() to drop queue item. "entry" is used to shift into the queue level when peeking the array.
  42. bool isEqual(const T *buffer); // returns 1 if an array passed in matches one exactly in queue
  43. bool replace(T *buffer, uint16_t length, int pos1, int pos2, int pos3, int pos4 = -1, int pos5 = -1); // This replaces an array if 3-5 patterns match
  44. bool find(T *buffer, uint16_t length, int pos1, int pos2, int pos3, int pos4 = -1, int pos5 = -1); // finds an entry in queue and memmoves it to the user buffer. The usage of the method is same as the ::replace(...) method
  45. bool findRemove(T *buffer, uint16_t length, int pos1, int pos2, int pos3, int pos4 = -1, int pos5 = -1); // like find and replace, this will removed a found entry from the queue.

The replace function is special. It searches all your “available” queues and replaces the entry thats found for a match.
This is good when your running async code and if the buffer wasnt written yet before the next queue addition, this will
replace your queue with the current one rather than adding a duplicate command to the queue. It returns 0 if there was no match.
If a match was found, it would be updated and a 1 returned indicating it was updated.

An example is as follows:

  1. uint8_t checksum = 0, buffer[4] = { (uint8_t)Form, WRITE_CMD, value, 0 };
  2. for ( uint8_t i = 1; i < 3; i++ ) checksum ^= buffer[i];
  3. buffer[3] = checksum;
  4. if ( !_outgoing_queue.replace(buffer,4,1,1,1) ) _outgoing_queue.push_back(buffer,4);
  5. return 0;
  6. }

That simple line above demonstrates that if no match is found “!_outgoing_queue.replace(buffer,4,1,2,3)”,
in this case, it’s comparing “buffer” against all your circular arrays in queue.
(buffer being the buffer to compare, 4 being it’s size, 1,2,3 being the 3 indices to verify).
In this case, I’ll mention byte[1] store the command, byte[2] stores object, byte[3] stores index, 4 and 5 actually contain the value, which is not our concern.
So if a buffer command, index, and object all match up, the buffer is replaced with one of updated values (_outgoing_queue.push_back(buffer,4);).

The library has a tracking system for the actual size of your arrays in the circular array raw buffer.
When you create a circular array buffer, of lets say, 200 per array in size, the library actually creates 202.
This is because the 2 first entries of the array internally are used when you buffer write the length of the array to queue.
The length is stored in the first 2 positions of the raw array space. Why 2? When dealing with char or uint8_t or other 8 bit buffers, going beyond 255 byte array indexing wont be possible…

The library supports many types, ones that have been tested are floats, uint8_t, uint16_t, uint32_t, and uint64_t.

Construction

Theres 2 ways to construct the buffer of your choice.

  1. Circular_Buffer<uint8_t, 16, 300> myBuffer; // creates a circular array system with 16 queue slots of arrays capable of storing 300 8bit entries
  2. Circular_Buffer<float, 8, 200> myBuffer; // creates a circular array system with 8 queue slots of arrays capable of storing 200 float entries
  3. Circular_Buffer<uint16_t, 4, 100> myBuffer; // creates a circular array system with 4 queue slots of arrays capable of storing 100 16bit entries
  4. Circular_Buffer<uint16_t_t, 4> myBuffer; // creates a ring buffer holding 16bit x 4 entries max
  5. Circular_Buffer<float, 32> myBuffer; // creates a ring buffer holding floats x 32 entries max
  6. Circular_Buffer<uint32_t, 64> myBuffer; // creates a ring buffer holding 32bit x 64 entries max

ALL YOUR SIZES MUST BE A POWER OF 2 FOR THE FIRST FIELD!!! IMPORTANT!

If you don’t heed this warning, undefined behaviour will result!

There is a demo in the examples folder, hope you all enjoy it.