blob: 669abe4a0abfbdf5bd41f0388c2c077fb6074075 [file] [log] [blame]
Brian Silvermaneda63f32017-10-08 18:57:33 -04001#ifndef MOTORS_USB_QUEUE_H_
2#define MOTORS_USB_QUEUE_H_
3
4#include <memory>
5#include <atomic>
6
7namespace frc971 {
8namespace 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.
14class 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_