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