Brian Silverman | eda63f3 | 2017-10-08 18:57:33 -0400 | [diff] [blame] | 1 | #ifndef MOTORS_USB_QUEUE_H_ |
| 2 | #define MOTORS_USB_QUEUE_H_ |
| 3 | |
| 4 | #include <memory> |
| 5 | #include <atomic> |
| 6 | |
| 7 | namespace frc971 { |
| 8 | namespace teensy { |
| 9 | |
| 10 | // A FIFO queue which reads/writes variable-sized chunks. |
| 11 | // |
| 12 | // Reading data happens-after it is written. However, external synchronization |
| 13 | // between multiple readers/writers is required. |
| 14 | class Queue { |
| 15 | public: |
| 16 | Queue(size_t size) : size_(size), data_(new char[size]) {} |
| 17 | |
| 18 | // Writes as much of in_data as will fit to the queue. Returns the number of |
| 19 | // bytes written. |
| 20 | size_t Write(const char *in_data, size_t in_size); |
| 21 | |
| 22 | // Reads up to out_size from the queue into out_data. Returns the number of |
| 23 | // bytes read. |
| 24 | size_t Read(char *out_data, size_t out_size); |
| 25 | |
| 26 | size_t data_queued() const { |
| 27 | return space_used(read_cursor_.load(::std::memory_order_relaxed), |
| 28 | write_cursor_.load(::std::memory_order_relaxed)); |
| 29 | } |
| 30 | |
| 31 | size_t space_available() const { |
| 32 | return size_ - data_queued() - 1; |
| 33 | } |
| 34 | |
| 35 | bool empty() const { |
| 36 | return read_cursor_.load(::std::memory_order_relaxed) == |
| 37 | write_cursor_.load(::std::memory_order_relaxed); |
| 38 | } |
| 39 | |
| 40 | private: |
| 41 | size_t space_used(size_t read_cursor, size_t write_cursor) const { |
| 42 | size_t r = write_cursor - read_cursor; |
| 43 | if (r > size_) { |
| 44 | r = size_ + r; |
| 45 | } |
| 46 | return r; |
| 47 | } |
| 48 | |
| 49 | size_t wrap(size_t cursor) const { |
| 50 | if (cursor >= size_) { |
| 51 | return cursor - size_; |
| 52 | } else { |
| 53 | return cursor; |
| 54 | } |
| 55 | } |
| 56 | |
| 57 | const size_t size_; |
| 58 | const ::std::unique_ptr<char[]> data_; |
| 59 | |
| 60 | // The next index we're going to read from. |
| 61 | ::std::atomic<size_t> read_cursor_{0}; |
| 62 | // The next index we're going to write to. |
| 63 | ::std::atomic<size_t> write_cursor_{0}; |
| 64 | }; |
| 65 | |
| 66 | } // namespace teensy |
| 67 | } // namespace frc971 |
| 68 | |
| 69 | #endif // MOTORS_USB_QUEUE_H_ |