• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef CHRE_UTIL_ARRAY_QUEUE_H_
18 #define CHRE_UTIL_ARRAY_QUEUE_H_
19 
20 #include <cstddef>
21 #include <iterator>
22 #include <type_traits>
23 
24 #include "chre/util/non_copyable.h"
25 
26 namespace chre {
27 
28 /**
29  * A fixed-size FIFO queue for storing elements. When the FIFO is full, new
30  * element will not be able to be pushed in.
31  */
32 template<typename ElementType, size_t kCapacity>
33 class ArrayQueue : public NonCopyable {
34  public:
35   /**
36    * Calls the destructor of all the elements in the array queue.
37    */
38   ~ArrayQueue();
39 
40   /**
41    * Determines whether the array queue is empty or not.
42    *
43    * @return true if the array queue is empty.
44    */
45   bool empty() const;
46 
47   /**
48    * @return true if the array queue is full.
49    */
50   bool full() const;
51 
52   /**
53    * Obtains the number of elements currently stored in the array queue.
54    *
55    * @return The number of elements currently stored in the array queue.
56    */
57   size_t size() const;
58 
59   /**
60    * Obtains the front element of the array queue. It is illegal to access the
61    * front element when the array queue is empty. The user of the API must check
62    * the size() or empty() function prior to accessing the front element to
63    * ensure that they will not read out of bounds.
64    *
65    * @return The front element.
66    */
67   ElementType& front();
68   const ElementType& front() const;
69 
70   /**
71    * Obtains the last element in the queue. Illegal to call when empty() is
72    * true.
73    *
74    * @return The last element in the queue.
75    */
76   ElementType& back();
77   const ElementType& back() const;
78 
79   /**
80    * Obtains an element of the array queue given an index. It is illegal to
81    * index this array queue out of bounds and the user of the API must check the
82    * size() function prior to indexing this array queue to ensure that they will
83    * not read out of bounds.
84    *
85    * @param index Requested index in range [0,size()-1]
86    * @return The element.
87    */
88   ElementType& operator[](size_t index);
89 
90   /**
91    * Obtains an element of the array queue given an index. It is illegal to
92    * index this array queue out of bounds and the user of the API must check the
93    * size() function prior to indexing this array queue to ensure that they will
94    * not read out of bounds.
95    *
96    * @param index Requested index in range [0,size()-1]
97    * @return The element.
98    */
99   const ElementType& operator[](size_t index) const;
100 
101   /**
102    * Pushes an element onto the back of the array queue via copy or move
103    * construction. It returns false if the array queue is full already and there
104    * is no room for the elements. All iterators and references are unaffected.
105    *
106    * @param element The element to push onto the array queue.
107    * @return true if the element is pushed successfully.
108    */
109   bool push(const ElementType& element);
110   bool push(ElementType&& element);
111 
112   /**
113    * Removes the front element from the array queue if the array queue is not
114    * empty. Only iterators and references to the front of the queue are
115    * invalidated.
116    */
117   void pop();
118 
119   /**
120    * Removes the back element from the array queue if the array queue is not
121    * empty. Only iterators and references to the back of the queue are
122    * invalidated.
123    */
124   void pop_back();
125 
126   /**
127    * Removes an element from the array queue given an index. It returns false if
128    * the array queue contains fewer items than the index. All iterators and
129    * references to elements before the removed one are unaffected. Iterators
130    * and references to the removed element or any elements after it are
131    * invalidated.
132    *
133    * @param index Requested index in range [0,size()-1]
134    * @return true if the indexed element has been removed successfully.
135    */
136   bool remove(size_t index);
137 
138   /**
139    * Constructs an element onto the back of the array queue. All iterators and
140    * references are unaffected.
141    *
142    * @param The arguments to the constructor
143    * @return true if the element is constructed successfully.
144    */
145   template<typename... Args>
146   bool emplace(Args&&... args);
147 
148   /**
149    * A template class that implements a forward iterator for the array queue.
150    */
151   template<typename ValueType>
152   class ArrayQueueIterator {
153    public:
154     typedef ValueType value_type;
155     typedef ValueType& reference;
156     typedef ValueType* pointer;
157     typedef std::ptrdiff_t difference_type;
158     typedef std::forward_iterator_tag iterator_category;
159 
160     ArrayQueueIterator() = default;
ArrayQueueIterator(ValueType * pointer,ValueType * base,size_t tail)161     ArrayQueueIterator(
162         ValueType *pointer, ValueType *base, size_t tail)
163         : mPointer(pointer), mBase(base), mTail(tail) {}
164 
165     bool operator==(const ArrayQueueIterator& right) const {
166       return (mPointer == right.mPointer);
167     }
168 
169     bool operator!=(const ArrayQueueIterator& right) const {
170       return (mPointer != right.mPointer);
171     }
172 
173     ValueType& operator*() {
174       return *mPointer;
175     }
176 
177     ValueType *operator->() {
178       return mPointer;
179     }
180 
181     ArrayQueueIterator& operator++() {
182       if (mPointer == (mBase + mTail)) {
183         // Jump to end() if at tail
184         mPointer = mBase + kCapacity;
185       } else if (mPointer == (mBase + kCapacity - 1)) {
186         // Wrap around in the memory
187         mPointer = mBase;
188       } else {
189         mPointer++;
190       }
191       return *this;
192     }
193 
194     ArrayQueueIterator operator++(int) {
195       ArrayQueueIterator it(*this);
196       operator++();
197       return it;
198     }
199 
200    private:
201     //! Pointer of the iterator.
202     ValueType *mPointer;
203 
204     //! The memory base address of this container.
205     ValueType *mBase;
206 
207     //! The tail offset relative to the memory base address.
208     size_t mTail;
209   };
210 
211   /**
212    * Forward iterator that points to some element in the container.
213    */
214   typedef ArrayQueueIterator<ElementType> iterator;
215   typedef ArrayQueueIterator<const ElementType> const_iterator;
216 
217   /**
218    * @return A forward iterator to the beginning.
219    */
220   typename ArrayQueue<ElementType, kCapacity>::iterator begin();
221   typename ArrayQueue<ElementType, kCapacity>::const_iterator begin() const;
222   typename ArrayQueue<ElementType, kCapacity>::const_iterator cbegin() const;
223 
224   /**
225    * @return A forward iterator to the end.
226    */
227   typename ArrayQueue<ElementType, kCapacity>::iterator end();
228   typename ArrayQueue<ElementType, kCapacity>::const_iterator end() const;
229   typename ArrayQueue<ElementType, kCapacity>::const_iterator cend() const;
230 
231  private:
232   /**
233    * Storage for array queue elements. To avoid static initialization of
234    * members, std::aligned_storage is used.
235    */
236   typename std::aligned_storage<sizeof(ElementType),
237                                 alignof(ElementType)>::type mData[kCapacity];
238 
239   /*
240    * Initialize mTail to be (kCapacity-1). When an element is pushed in,
241    * mHead and mTail will align. Also, this is consistent with
242    * mSize = (mTail - mHead)%kCapacity + 1 for mSize > 0.
243    */
244   //! Index of the front element
245   size_t mHead = 0;
246 
247   //! Index of the back element
248   size_t mTail = kCapacity - 1;
249 
250   //! Number of elements in the array queue
251   size_t mSize = 0;
252 
253   /**
254    * Obtains a pointer to the underlying storage for the vector.
255    *
256    * @return A pointer to the storage used for elements in this vector.
257    */
258   ElementType *data();
259 
260   /**
261    * Obtains a pointer to the underlying storage for the vector.
262    *
263    * @return A pointer to the storage used for elements in this vector.
264    */
265   const ElementType *data() const;
266 
267   /**
268    * Converts relative index with respect to mHead to absolute index in the
269    * storage array.
270    *
271    * @param index Relative index in range [0,size()-1]
272    * @return The index of the storage array in range [0,kCapacity-1]
273    */
274   size_t relativeIndexToAbsolute(size_t index) const;
275 
276   /*
277    * Pulls mHead to the next element in the array queue and decrements mSize
278    * accordingly. It is illegal to call this function on an empty array queue.
279    */
280   void pullHead();
281 
282   /*
283    * Pulls mTail to the previous element in the array queue and decrements mSize
284    * accordingly. It is illegal to call this function on an empty array queue.
285    */
286   void pullTail();
287 
288   /*
289    * Pushes mTail to the next available storage space and increments mSize
290    * accordingly.
291    *
292    * @return true if the array queue is not full.
293    */
294   bool pushTail();
295 };
296 
297 }  // namespace chre
298 
299 #include "chre/util/array_queue_impl.h"
300 
301 #endif  // CHRE_UTIL_ARRAY_QUEUE_H_
302