• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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