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