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 #include "chre/util/raw_storage.h" 26 27 /** 28 * @file 29 * ArrayQueue is a templated fixed-size FIFO queue implemented around a 30 * contiguous array. Two variations on how the 31 * 32 * 1) ArrayQueue<ElementType, kCapacity> allocates the underlying array within 33 * the ArrayQueue object itself. 34 * 2) ArrayQueueExt<ElementType> accepts a pointer to the storage at 35 * construction time. Since this variation maintains the capacity of the array 36 * as a member variable rather than template parameter, it can be useful in 37 * situations where it'd be inconvenient to include the array capacity in the 38 * type specification, for example when processing multiple array queues with 39 * different capacities in a loop or similar construct. 40 * 41 * This variability is accomplished through a base class which provides the 42 * underlying storage, which is attached to the array queue implementation in 43 * ArrayQueueCore via a template parameter, then the two storage options are 44 * composed into public APIs as ArrayQueue and ArrayQueueExt. Users of this 45 * container are not expected to reference ArrayQueueCore or ArrayQueue*Storage 46 * directly, but developers should refer to ArrayQueueCore for API 47 * documentation. 48 */ 49 50 namespace chre { 51 52 // Forward declaration to support declarations in ArrayQueueCore 53 template <typename ValueType> 54 class ArrayQueueIterator; 55 56 namespace internal { 57 58 /** 59 * The core implementation of an array queue, from which the public interfaces 60 * (ArrayQueue and ArrayQueueExt) are derived. 61 * 62 * The StorageType template parameter must be a class supplying data() and 63 * capacity() methods used to access the underlying array storage. 64 */ 65 template <typename ElementType, class StorageType> 66 class ArrayQueueCore : public StorageType { 67 public: 68 // Inherit constructors from StorageType 69 using StorageType::StorageType; 70 71 /** 72 * Calls the destructor of all the elements in the array queue. 73 */ 74 ~ArrayQueueCore(); 75 76 // data() and capacity() functions are inherited from StorageType 77 78 /** 79 * @return true if the array queue is empty. 80 */ 81 bool empty() const; 82 83 /** 84 * @return true if the array queue is full. 85 */ 86 bool full() const; 87 88 /** 89 * @return The number of elements currently stored in the array queue. 90 */ 91 size_t size() const; 92 93 /** 94 * Obtains the front element of the array queue. It is illegal to access the 95 * front element when the array queue is empty. The user of the API must check 96 * the size() or empty() function prior to accessing the front element to 97 * ensure that they will not read out of bounds. 98 * 99 * @return The front element. 100 */ 101 ElementType &front(); 102 const ElementType &front() const; 103 104 /** 105 * Obtains the last element in the queue. Illegal to call when empty() is 106 * true. 107 * 108 * @return The last element in the queue. 109 */ 110 ElementType &back(); 111 const ElementType &back() const; 112 113 /** 114 * Obtains an element of the array queue given an index. It is illegal to 115 * index this array queue out of bounds and the user of the API must check the 116 * size() function prior to indexing this array queue to ensure that they will 117 * not read out of bounds. 118 * 119 * @param index Requested index in range [0,size()-1] 120 * @return The element. 121 */ 122 ElementType &operator[](size_t index); 123 124 /** 125 * Obtains an element of the array queue given an index. It is illegal to 126 * index this array queue out of bounds and the user of the API must check the 127 * size() function prior to indexing this array queue to ensure that they will 128 * not read out of bounds. 129 * 130 * @param index Requested index in range [0,size()-1] 131 * @return The element. 132 */ 133 const ElementType &operator[](size_t index) const; 134 135 /** 136 * Pushes an element onto the back of the array queue via copy or move 137 * construction. It returns false if the array queue is full already and there 138 * is no room for the elements. All iterators and references are unaffected. 139 * 140 * @param element The element to push onto the array queue. 141 * @return true if the element is pushed successfully. 142 */ 143 bool push(const ElementType &element); 144 bool push(ElementType &&element); 145 146 /** 147 * Pushes an element onto the back of the array queue via copy or move 148 * construction. If the array queue is full the front element is removed 149 * to make room for the new element. 150 * 151 * @param element The element to push onto the array queue. 152 */ 153 void kick_push(const ElementType &element); 154 void kick_push(ElementType &&element); 155 156 /** 157 * Removes the front element from the array queue if the array queue is not 158 * empty. Only iterators and references to the front of the queue are 159 * invalidated. 160 */ 161 void pop(); 162 163 /** 164 * Removes the back element from the array queue if the array queue is not 165 * empty. Only iterators and references to the back of the queue are 166 * invalidated. 167 */ 168 void pop_back(); 169 170 /** 171 * Removes an element from the array queue given an index. It returns false if 172 * the array queue contains fewer items than the index. All iterators and 173 * references to elements before the removed one are unaffected. Iterators 174 * and references to the removed element or any elements after it are 175 * invalidated. 176 * 177 * @param index Requested index in range [0,size()-1] 178 * @return true if the indexed element has been removed successfully. 179 */ 180 bool remove(size_t index); 181 182 /** 183 * Constructs an element onto the back of the array queue. All iterators and 184 * references are unaffected. 185 * 186 * @param The arguments to the constructor 187 * @return true if the element is constructed successfully. 188 */ 189 template <typename... Args> 190 bool emplace(Args &&... args); 191 192 /** 193 * Removes all the elements of the queue. 194 */ 195 void clear(); 196 197 /** 198 * Forward iterator that points to some element in the container. 199 */ 200 typedef ArrayQueueIterator<ElementType> iterator; 201 typedef ArrayQueueIterator<const ElementType> const_iterator; 202 203 /** 204 * @return A forward iterator to the beginning. 205 */ 206 iterator begin(); 207 const_iterator begin() const; 208 const_iterator cbegin() const; 209 210 /** 211 * @return A forward iterator to the end. 212 */ 213 iterator end(); 214 const_iterator end() const; 215 const_iterator cend() const; 216 217 private: 218 /* 219 * Initialize mTail to be (capacity-1). When an element is pushed in, 220 * mHead and mTail will align. Also, this is consistent with 221 * mSize = (mTail - mHead)%capacity + 1 for mSize > 0. 222 */ 223 //! Index of the front element 224 size_t mHead = 0; 225 226 //! Index of the back element 227 size_t mTail = StorageType::capacity() - 1; 228 229 //! Number of elements in the array queue 230 size_t mSize = 0; 231 232 /** 233 * Converts relative index with respect to mHead to absolute index in the 234 * storage array. 235 * 236 * @param index Relative index in range [0,size()-1] 237 * @return The index of the storage array in range [0,kCapacity-1] 238 */ 239 size_t relativeIndexToAbsolute(size_t index) const; 240 241 /** 242 * Converts absolute index to relative index with respect to mHead. 243 * 244 * @param index absolute index showing the offset to the head of storage 245 * array. 246 * @return size_t relative index in range [0, size() - 1]. 247 */ 248 size_t absoluteIndexToRelative(size_t index) const; 249 250 /** 251 * Removes an item at index and pull the tail forward to fill gap. 252 * 253 * @param index the relative index of the item to be remove, must be smaller 254 * than mSize. 255 */ 256 void removeAndPullTail(size_t index); 257 258 /** 259 * Removes an item at index and pull the head forward to fill gap. 260 * 261 * @param index the relative index of the item to be remove, must be smaller 262 * than mSize. 263 */ 264 void removeAndPullHead(size_t index); 265 266 /* 267 * Pulls mHead to the next element in the array queue and decrements mSize 268 * accordingly. It is illegal to call this function on an empty array queue. 269 */ 270 void pullHead(); 271 272 /* 273 * Pulls mTail to the previous element in the array queue and decrements mSize 274 * accordingly. It is illegal to call this function on an empty array queue. 275 */ 276 void pullTail(); 277 278 /* 279 * Pushes mTail to the next available storage space and increments mSize 280 * accordingly. 281 * 282 * @return true if the array queue is not full. 283 */ 284 bool pushTail(); 285 286 /** 287 * Advance an index or wrap it around to the head of it is out of bound. 288 * 289 * @param index current index. 290 * @return the calculated result. 291 */ advanceOrWrapAround(size_t index)292 size_t advanceOrWrapAround(size_t index) { 293 return index >= StorageType::capacity() - 1 ? 0 : index + 1; 294 } 295 296 /** 297 * Subtract an index or wrap it around to the end of it is out of bound. 298 * 299 * @param index current index. 300 * @return the calculated result. 301 */ subtractOrWrapAround(size_t index)302 size_t subtractOrWrapAround(size_t index) { 303 return index == 0 ? StorageType::capacity() - 1 : index - 1; 304 } 305 }; 306 307 /** 308 * Storage for ArrayQueue based on a pointer to an array allocated elsewhere. 309 */ 310 template <typename ElementType> 311 class ArrayQueueExternalStorage : public NonCopyable { 312 public: ArrayQueueExternalStorage(ElementType * storage,size_t capacity)313 ArrayQueueExternalStorage(ElementType *storage, size_t capacity) 314 : mData(storage), kCapacity(capacity) {} 315 data()316 ElementType *data() { 317 return mData; 318 } 319 data()320 const ElementType *data() const { 321 return mData; 322 } 323 capacity()324 size_t capacity() const { 325 return kCapacity; 326 } 327 328 private: 329 ElementType *mData; 330 const size_t kCapacity; 331 }; 332 333 } // namespace internal 334 335 /** 336 * Alias to the array queue implementation with storage allocated inside the 337 * object. This is the interface that most code is expected to use. 338 */ 339 template <typename ElementType, size_t kCapacity> 340 class ArrayQueue 341 : public internal::ArrayQueueCore<ElementType, 342 RawStorage<ElementType, kCapacity>> { 343 public: 344 typedef ElementType value_type; 345 }; 346 347 /** 348 * Wrapper for the array queue implementation with storage allocated elsewhere. 349 * This is useful in instances where it's inconvenient to have the array's 350 * capacity form part of the type specification. 351 */ 352 template <typename ElementType> 353 class ArrayQueueExt 354 : public internal::ArrayQueueCore< 355 ElementType, internal::ArrayQueueExternalStorage<ElementType>> { 356 public: ArrayQueueExt(ElementType * storage,size_t capacity)357 ArrayQueueExt(ElementType *storage, size_t capacity) 358 : internal::ArrayQueueCore< 359 ElementType, internal::ArrayQueueExternalStorage<ElementType>>( 360 storage, capacity) {} 361 }; 362 363 /** 364 * A template class that implements a forward iterator for the array queue. 365 */ 366 template <typename ValueType> 367 class ArrayQueueIterator { 368 public: 369 typedef ValueType value_type; 370 typedef ValueType &reference; 371 typedef ValueType *pointer; 372 typedef std::ptrdiff_t difference_type; 373 typedef std::forward_iterator_tag iterator_category; 374 375 ArrayQueueIterator() = default; ArrayQueueIterator(ValueType * start,ValueType * base,size_t tail,size_t capacity)376 ArrayQueueIterator(ValueType *start, ValueType *base, size_t tail, 377 size_t capacity) 378 : mPointer(start), mBase(base), mTail(tail), mCapacity(capacity) {} 379 380 bool operator==(const ArrayQueueIterator &right) const { 381 return (mPointer == right.mPointer); 382 } 383 384 bool operator!=(const ArrayQueueIterator &right) const { 385 return (mPointer != right.mPointer); 386 } 387 388 ValueType &operator*() { 389 return *mPointer; 390 } 391 392 ValueType *operator->() { 393 return mPointer; 394 } 395 396 ArrayQueueIterator &operator++() { 397 if (mPointer == (mBase + mTail)) { 398 // Jump to end() if at tail 399 mPointer = mBase + mCapacity; 400 } else if (mPointer == (mBase + mCapacity - 1)) { 401 // Wrap around in the memory 402 mPointer = mBase; 403 } else { 404 mPointer++; 405 } 406 return *this; 407 } 408 409 ArrayQueueIterator operator++(int) { 410 ArrayQueueIterator it(*this); 411 operator++(); 412 return it; 413 } 414 415 private: 416 //! Pointer of the iterator. 417 ValueType *mPointer; 418 419 //! The memory base address of this container. 420 ValueType *mBase; 421 422 //! The tail offset relative to the memory base address. 423 size_t mTail; 424 425 //! Number of elements the underlying ArrayQueue can hold 426 size_t mCapacity; 427 }; 428 429 } // namespace chre 430 431 #include "chre/util/array_queue_impl.h" // IWYU pragma: export 432 433 #endif // CHRE_UTIL_ARRAY_QUEUE_H_ 434