array_queue_impl.h revision 9b598a5b372a47b8e30113cd5650448ce4ae3418
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_IMPL_H_ 18#define CHRE_UTIL_ARRAY_QUEUE_IMPL_H_ 19 20#include <utility> 21 22#include "chre/platform/assert.h" 23#include "chre/util/array_queue.h" 24 25namespace chre { 26 27template<typename ElementType, size_t kCapacity> 28ArrayQueue<ElementType, kCapacity>::~ArrayQueue() { 29 while (!empty()) { 30 pop(); 31 } 32} 33 34template<typename ElementType, size_t kCapacity> 35bool ArrayQueue<ElementType, kCapacity>::empty() const { 36 return (mSize == 0); 37} 38 39template<typename ElementType, size_t kCapacity> 40size_t ArrayQueue<ElementType, kCapacity>::size() const { 41 return mSize; 42} 43 44template<typename ElementType, size_t kCapacity> 45ElementType& ArrayQueue<ElementType, kCapacity>::front() { 46 CHRE_ASSERT(mSize > 0); 47 return data()[mHead]; 48} 49 50template<typename ElementType, size_t kCapacity> 51const ElementType& ArrayQueue<ElementType, kCapacity>::front() const { 52 CHRE_ASSERT(mSize > 0); 53 return data()[mHead]; 54} 55 56template<typename ElementType, size_t kCapacity> 57ElementType& ArrayQueue<ElementType, kCapacity>::operator[](size_t index) { 58 CHRE_ASSERT(index < mSize); 59 return data()[relativeIndexToAbsolute(index)]; 60} 61 62template<typename ElementType, size_t kCapacity> 63const ElementType& ArrayQueue<ElementType, kCapacity>::operator[]( 64 size_t index) const { 65 CHRE_ASSERT(index < mSize); 66 return data()[relativeIndexToAbsolute(index)]; 67} 68 69template<typename ElementType, size_t kCapacity> 70bool ArrayQueue<ElementType, kCapacity>::push(const ElementType& element) { 71 bool success = pushTail(); 72 if (success) { 73 data()[mTail] = element; 74 } 75 return success; 76} 77 78template<typename ElementType, size_t kCapacity> 79void ArrayQueue<ElementType, kCapacity>::pop() { 80 if (mSize > 0) { 81 data()[mHead].~ElementType(); 82 pullHead(); 83 } 84} 85 86// Assuming popping from the middle of the queue is rare, part of the 87// array is copied over. 88template<typename ElementType, size_t kCapacity> 89bool ArrayQueue<ElementType, kCapacity>::remove(size_t index) { 90 // If we used memmove to shift the array down when removing an element in the 91 // middle of the queue, then we'd need to add this somewhere: 92 // static_assert(std::is_trivially_copyable<ElementType>::value, 93 // "Elements within ArrayQueue must be trivially copyable"); 94 95 bool success; 96 if (index >= mSize) { 97 success = false; 98 } else { 99 // Number of elements before the one to be popped 100 size_t headLength = index; 101 102 size_t absoluteIndex = relativeIndexToAbsolute(index); 103 data()[absoluteIndex].~ElementType(); 104 105 // Move all the elements before the one just popped to the next storage 106 // space. 107 // TODO: optimize by comparing headLength to mSize/2. 108 // If headLength < mSize/2, pull heads towards tail. 109 // Otherwise, pull tails towards head. 110 for (size_t i = 0; i < headLength; ++i) { 111 size_t prev = (absoluteIndex == 0) ? (kCapacity - 1) : (absoluteIndex - 1); 112 data()[absoluteIndex] = data()[prev]; 113 absoluteIndex = prev; 114 } 115 116 pullHead(); 117 success = true; 118 } 119 return success; 120} 121 122template<typename ElementType, size_t kCapacity> 123template<typename... Args> 124bool ArrayQueue<ElementType, kCapacity>::emplace(Args&&... args) { 125 bool success = pushTail(); 126 if (success) { 127 new (&data()[mTail]) ElementType(std::forward<Args>(args)...); 128 } 129 return success; 130} 131 132template<typename ElementType, size_t kCapacity> 133typename ArrayQueue<ElementType, kCapacity>::iterator 134ArrayQueue<ElementType, kCapacity>::begin() { 135 // Align begin() and end() outside of the memory block when empty. 136 return empty() ? end() : iterator(data() + mHead, data(), mTail); 137} 138 139template<typename ElementType, size_t kCapacity> 140typename ArrayQueue<ElementType, kCapacity>::iterator 141 ArrayQueue<ElementType, kCapacity>::end() { 142 return iterator(data() + kCapacity, data(), mTail); 143} 144 145template<typename ElementType, size_t kCapacity> 146typename ArrayQueue<ElementType, kCapacity>::const_iterator 147ArrayQueue<ElementType, kCapacity>::cbegin() const { 148 // Align begin() and end() outside of the memory block when empty. 149 return empty() ? cend() : const_iterator(data() + mHead, data(), mTail); 150} 151 152template<typename ElementType, size_t kCapacity> 153typename ArrayQueue<ElementType, kCapacity>::const_iterator 154 ArrayQueue<ElementType, kCapacity>::cend() const { 155 return const_iterator(data() + kCapacity, data(), mTail); 156} 157 158template<typename ElementType, size_t kCapacity> 159ElementType *ArrayQueue<ElementType, kCapacity>::data() { 160 return reinterpret_cast<ElementType *>(mData); 161} 162 163template<typename ElementType, size_t kCapacity> 164const ElementType *ArrayQueue<ElementType, kCapacity>::data() const { 165 return reinterpret_cast<const ElementType *>(mData); 166} 167 168template<typename ElementType, size_t kCapacity> 169size_t ArrayQueue<ElementType, kCapacity>::relativeIndexToAbsolute( 170 size_t index) const { 171 size_t absoluteIndex = mHead + index; 172 if (absoluteIndex >= kCapacity) { 173 absoluteIndex -= kCapacity; 174 } 175 return absoluteIndex; 176} 177 178template<typename ElementType, size_t kCapacity> 179void ArrayQueue<ElementType, kCapacity>::pullHead() { 180 CHRE_ASSERT(mSize > 0); 181 if (++mHead == kCapacity) { 182 mHead = 0; 183 } 184 mSize--; 185} 186 187template<typename ElementType, size_t kCapacity> 188bool ArrayQueue<ElementType, kCapacity>::pushTail() { 189 bool success; 190 if (mSize >= kCapacity) { 191 success = false; 192 } else { 193 if (++mTail == kCapacity) { 194 mTail = 0; 195 } 196 mSize++; 197 success = true; 198 } 199 return success; 200} 201 202} // namespace chre 203 204#endif // CHRE_UTIL_ARRAY_QUEUE_IMPL_H_ 205