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