| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #ifndef CHRE_UTIL_ARRAY_QUEUE_H_ |
| #define CHRE_UTIL_ARRAY_QUEUE_H_ |
| |
| #include <cstddef> |
| #include <iterator> |
| #include <type_traits> |
| |
| #include "chre/util/non_copyable.h" |
| #include "chre/util/raw_storage.h" |
| |
| /** |
| * @file |
| * ArrayQueue is a templated fixed-size FIFO queue implemented around a |
| * contiguous array. Two variations on how the |
| * |
| * 1) ArrayQueue<ElementType, kCapacity> allocates the underlying array within |
| * the ArrayQueue object itself. |
| * 2) ArrayQueueExt<ElementType> accepts a pointer to the storage at |
| * construction time. Since this variation maintains the capacity of the array |
| * as a member variable rather than template parameter, it can be useful in |
| * situations where it'd be inconvenient to include the array capacity in the |
| * type specification, for example when processing multiple array queues with |
| * different capacities in a loop or similar construct. |
| * |
| * This variability is accomplished through a base class which provides the |
| * underlying storage, which is attached to the array queue implementation in |
| * ArrayQueueCore via a template parameter, then the two storage options are |
| * composed into public APIs as ArrayQueue and ArrayQueueExt. Users of this |
| * container are not expected to reference ArrayQueueCore or ArrayQueue*Storage |
| * directly, but developers should refer to ArrayQueueCore for API |
| * documentation. |
| */ |
| |
| namespace chre { |
| |
| // Forward declaration to support declarations in ArrayQueueCore |
| template <typename ValueType> |
| class ArrayQueueIterator; |
| |
| namespace internal { |
| |
| /** |
| * The core implementation of an array queue, from which the public interfaces |
| * (ArrayQueue and ArrayQueueExt) are derived. |
| * |
| * The StorageType template parameter must be a class supplying data() and |
| * capacity() methods used to access the underlying array storage. |
| */ |
| template <typename ElementType, class StorageType> |
| class ArrayQueueCore : public StorageType { |
| public: |
| // Inherit constructors from StorageType |
| using StorageType::StorageType; |
| |
| /** |
| * Calls the destructor of all the elements in the array queue. |
| */ |
| ~ArrayQueueCore(); |
| |
| // data() and capacity() functions are inherited from StorageType |
| |
| /** |
| * @return true if the array queue is empty. |
| */ |
| bool empty() const; |
| |
| /** |
| * @return true if the array queue is full. |
| */ |
| bool full() const; |
| |
| /** |
| * @return The number of elements currently stored in the array queue. |
| */ |
| size_t size() const; |
| |
| /** |
| * Obtains the front element of the array queue. It is illegal to access the |
| * front element when the array queue is empty. The user of the API must check |
| * the size() or empty() function prior to accessing the front element to |
| * ensure that they will not read out of bounds. |
| * |
| * @return The front element. |
| */ |
| ElementType &front(); |
| const ElementType &front() const; |
| |
| /** |
| * Obtains the last element in the queue. Illegal to call when empty() is |
| * true. |
| * |
| * @return The last element in the queue. |
| */ |
| ElementType &back(); |
| const ElementType &back() const; |
| |
| /** |
| * Obtains an element of the array queue given an index. It is illegal to |
| * index this array queue out of bounds and the user of the API must check the |
| * size() function prior to indexing this array queue to ensure that they will |
| * not read out of bounds. |
| * |
| * @param index Requested index in range [0,size()-1] |
| * @return The element. |
| */ |
| ElementType &operator[](size_t index); |
| |
| /** |
| * Obtains an element of the array queue given an index. It is illegal to |
| * index this array queue out of bounds and the user of the API must check the |
| * size() function prior to indexing this array queue to ensure that they will |
| * not read out of bounds. |
| * |
| * @param index Requested index in range [0,size()-1] |
| * @return The element. |
| */ |
| const ElementType &operator[](size_t index) const; |
| |
| /** |
| * Pushes an element onto the back of the array queue via copy or move |
| * construction. It returns false if the array queue is full already and there |
| * is no room for the elements. All iterators and references are unaffected. |
| * |
| * @param element The element to push onto the array queue. |
| * @return true if the element is pushed successfully. |
| */ |
| bool push(const ElementType &element); |
| bool push(ElementType &&element); |
| |
| /** |
| * Pushes an element onto the back of the array queue via copy or move |
| * construction. If the array queue is full the front element is removed |
| * to make room for the new element. |
| * |
| * @param element The element to push onto the array queue. |
| */ |
| void kick_push(const ElementType &element); |
| void kick_push(ElementType &&element); |
| |
| /** |
| * Removes the front element from the array queue if the array queue is not |
| * empty. Only iterators and references to the front of the queue are |
| * invalidated. |
| */ |
| void pop(); |
| |
| /** |
| * Removes the back element from the array queue if the array queue is not |
| * empty. Only iterators and references to the back of the queue are |
| * invalidated. |
| */ |
| void pop_back(); |
| |
| /** |
| * Removes an element from the array queue given an index. It returns false if |
| * the array queue contains fewer items than the index. All iterators and |
| * references to elements before the removed one are unaffected. Iterators |
| * and references to the removed element or any elements after it are |
| * invalidated. |
| * |
| * @param index Requested index in range [0,size()-1] |
| * @return true if the indexed element has been removed successfully. |
| */ |
| bool remove(size_t index); |
| |
| /** |
| * Constructs an element onto the back of the array queue. All iterators and |
| * references are unaffected. |
| * |
| * @param The arguments to the constructor |
| * @return true if the element is constructed successfully. |
| */ |
| template <typename... Args> |
| bool emplace(Args &&... args); |
| |
| /** |
| * Removes all the elements of the queue. |
| */ |
| void clear(); |
| |
| /** |
| * Forward iterator that points to some element in the container. |
| */ |
| typedef ArrayQueueIterator<ElementType> iterator; |
| typedef ArrayQueueIterator<const ElementType> const_iterator; |
| |
| /** |
| * @return A forward iterator to the beginning. |
| */ |
| iterator begin(); |
| const_iterator begin() const; |
| const_iterator cbegin() const; |
| |
| /** |
| * @return A forward iterator to the end. |
| */ |
| iterator end(); |
| const_iterator end() const; |
| const_iterator cend() const; |
| |
| private: |
| /* |
| * Initialize mTail to be (capacity-1). When an element is pushed in, |
| * mHead and mTail will align. Also, this is consistent with |
| * mSize = (mTail - mHead)%capacity + 1 for mSize > 0. |
| */ |
| //! Index of the front element |
| size_t mHead = 0; |
| |
| //! Index of the back element |
| size_t mTail = StorageType::capacity() - 1; |
| |
| //! Number of elements in the array queue |
| size_t mSize = 0; |
| |
| /** |
| * Converts relative index with respect to mHead to absolute index in the |
| * storage array. |
| * |
| * @param index Relative index in range [0,size()-1] |
| * @return The index of the storage array in range [0,kCapacity-1] |
| */ |
| size_t relativeIndexToAbsolute(size_t index) const; |
| |
| /* |
| * Pulls mHead to the next element in the array queue and decrements mSize |
| * accordingly. It is illegal to call this function on an empty array queue. |
| */ |
| void pullHead(); |
| |
| /* |
| * Pulls mTail to the previous element in the array queue and decrements mSize |
| * accordingly. It is illegal to call this function on an empty array queue. |
| */ |
| void pullTail(); |
| |
| /* |
| * Pushes mTail to the next available storage space and increments mSize |
| * accordingly. |
| * |
| * @return true if the array queue is not full. |
| */ |
| bool pushTail(); |
| }; |
| |
| /** |
| * Storage for ArrayQueue based on a pointer to an array allocated elsewhere. |
| */ |
| template <typename ElementType> |
| class ArrayQueueExternalStorage : public NonCopyable { |
| public: |
| ArrayQueueExternalStorage(ElementType *storage, size_t capacity) |
| : mData(storage), kCapacity(capacity) {} |
| |
| ElementType *data() { |
| return mData; |
| } |
| |
| const ElementType *data() const { |
| return mData; |
| } |
| |
| size_t capacity() const { |
| return kCapacity; |
| } |
| |
| private: |
| ElementType *mData; |
| const size_t kCapacity; |
| }; |
| |
| } // namespace internal |
| |
| /** |
| * Alias to the array queue implementation with storage allocated inside the |
| * object. This is the interface that most code is expected to use. |
| */ |
| template <typename ElementType, size_t kCapacity> |
| class ArrayQueue |
| : public internal::ArrayQueueCore<ElementType, |
| RawStorage<ElementType, kCapacity>> { |
| public: |
| typedef ElementType value_type; |
| }; |
| |
| /** |
| * Wrapper for the array queue implementation with storage allocated elsewhere. |
| * This is useful in instances where it's inconvenient to have the array's |
| * capacity form part of the type specification. |
| */ |
| template <typename ElementType> |
| class ArrayQueueExt |
| : public internal::ArrayQueueCore< |
| ElementType, internal::ArrayQueueExternalStorage<ElementType>> { |
| public: |
| ArrayQueueExt(ElementType *storage, size_t capacity) |
| : internal::ArrayQueueCore< |
| ElementType, internal::ArrayQueueExternalStorage<ElementType>>( |
| storage, capacity) {} |
| }; |
| |
| /** |
| * A template class that implements a forward iterator for the array queue. |
| */ |
| template <typename ValueType> |
| class ArrayQueueIterator { |
| public: |
| typedef ValueType value_type; |
| typedef ValueType &reference; |
| typedef ValueType *pointer; |
| typedef std::ptrdiff_t difference_type; |
| typedef std::forward_iterator_tag iterator_category; |
| |
| ArrayQueueIterator() = default; |
| ArrayQueueIterator(ValueType *start, ValueType *base, size_t tail, |
| size_t capacity) |
| : mPointer(start), mBase(base), mTail(tail), mCapacity(capacity) {} |
| |
| bool operator==(const ArrayQueueIterator &right) const { |
| return (mPointer == right.mPointer); |
| } |
| |
| bool operator!=(const ArrayQueueIterator &right) const { |
| return (mPointer != right.mPointer); |
| } |
| |
| ValueType &operator*() { |
| return *mPointer; |
| } |
| |
| ValueType *operator->() { |
| return mPointer; |
| } |
| |
| ArrayQueueIterator &operator++() { |
| if (mPointer == (mBase + mTail)) { |
| // Jump to end() if at tail |
| mPointer = mBase + mCapacity; |
| } else if (mPointer == (mBase + mCapacity - 1)) { |
| // Wrap around in the memory |
| mPointer = mBase; |
| } else { |
| mPointer++; |
| } |
| return *this; |
| } |
| |
| ArrayQueueIterator operator++(int) { |
| ArrayQueueIterator it(*this); |
| operator++(); |
| return it; |
| } |
| |
| private: |
| //! Pointer of the iterator. |
| ValueType *mPointer; |
| |
| //! The memory base address of this container. |
| ValueType *mBase; |
| |
| //! The tail offset relative to the memory base address. |
| size_t mTail; |
| |
| //! Number of elements the underlying ArrayQueue can hold |
| size_t mCapacity; |
| }; |
| |
| } // namespace chre |
| |
| #include "chre/util/array_queue_impl.h" |
| |
| #endif // CHRE_UTIL_ARRAY_QUEUE_H_ |