TCPSPSuite
circular_vector.hpp
1 #ifndef CIRCULAR_VECTOR_HPP
2 #define CIRCULAR_VECTOR_HPP
3 
4 #include <vector>
5 #include <cstdlib>
6 #include <cstring>
7 
8 template<class T>
9 class CircularVector {
10 public:
11  // TODO configurable default size?
12  CircularVector() : is_empty(true), data(nullptr), i_start(0), i_end(0) {
13  this->data = (T*)malloc(16 * sizeof(T));
14  this->allocated = 16;
15  };
16 
17  ~CircularVector() {
18  free(this->data);
19  }
20 
21  void clear() noexcept {
22  this->i_end = this->i_start;
23  this->is_empty = true;
24  }
25 
26  T & back() const {
27  if (this->i_end > 0) {
28  return this->data[this->i_end - 1];
29  } else {
30  return this->data[this->allocated - 1];
31  }
32  }
33 
34  T & front() const {
35  return this->data[this->i_start];
36  }
37 
38  template<class InnerT>
39  void push_back(InnerT && value) {
40  if (__builtin_expect((i_end == i_start) && (!this->is_empty), false)) {
41  this->grow();
42  }
43 
44  this->data[i_end] = std::forward<InnerT>(value);
45  this->i_end++;
46  if (this->i_end == this->allocated) {
47  this->i_end = 0;
48  }
49 
50  this->is_empty = false;
51  }
52 
53  void pop_back() noexcept {
54  if (__builtin_expect(this->i_end == 0, false)) {
55  this->i_end = this->allocated - 1;
56  } else {
57  this->i_end--;
58  }
59 
60  if (__builtin_expect(this->i_end == this->i_start, false)) {
61  this->is_empty = true;
62  }
63  }
64 
65  void pop_front() noexcept {
66  if (__builtin_expect(this->i_start == this->allocated - 1, false)) {
67  this->i_start = 0;
68  } else {
69  this->i_start++;
70  }
71 
72  if (__builtin_expect(this->i_end == this->i_start, false)) {
73  this->is_empty = true;
74  }
75  }
76 
77  template<class InnerT>
78  void push_front(InnerT && value) {
79  if (__builtin_expect((i_end == i_start) && (!this->is_empty), false)) {
80  this->grow();
81  }
82 
83  // TODO after growing, the expectation is wrong.
84  if (__builtin_expect((this->i_start == 0), false)) {
85  this->i_start = this->allocated - 1;
86  } else {
87  this->i_start--;
88  }
89 
90  this->data[this->i_start] = std::forward<InnerT>(value);
91 
92  this->is_empty = false;
93  }
94 
95  T & operator[](size_t index) noexcept {
96  return this->data[(this->i_start + index) % this->allocated];
97  }
98 
99  size_t size() const noexcept {
100  if (this->i_start < this->i_end) {
101  return this->i_end - this->i_start;
102  } else if (this->i_start > this->i_end) {
103  return (this->allocated - this->i_start + this->i_end);
104  } else if (!this->is_empty) {
105  return this->allocated;
106  } else {
107  return 0;
108  }
109  }
110 
111  bool empty() const noexcept {
112  return this->is_empty;
113  }
114 
115 private:
116  void grow() {
117  T * new_data = (T*) malloc(sizeof(T) * this->allocated * 2);
118 
119  // TODO copy into the middle?
120  std::memcpy(new_data, this->data + this->i_start, this->allocated - this->i_start);
121  std::memcpy(new_data + (this->allocated - this->i_start), this->data, this->i_end);
122 
123  free(this->data);
124  this->data = new_data;
125  }
126 
127  bool is_empty;
128  T * data;
129  size_t allocated;
130  size_t i_start;
131  size_t i_end;
132 };
133 
134 
135 #endif