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_DYNAMIC_VECTOR_H_
18 #define CHRE_UTIL_DYNAMIC_VECTOR_H_
19 
20 #include <cstddef>
21 
22 #include "chre/util/non_copyable.h"
23 
24 namespace chre {
25 
26 /**
27  * A container for storing a sequential array of elements. This container
28  * resizes dynamically using heap allocations.
29  */
30 template<typename ElementType>
31 class DynamicVector : public NonCopyable {
32  public:
33   /**
34    * Default-constructs a dynamic vector.
35    */
36   DynamicVector();
37 
38   /**
39    * Move-constructs a dynamic vector from another. The other dynamic vector is
40    * left in an empty state.
41    *
42    * @param other The other vector to move from.
43    */
44   DynamicVector(DynamicVector<ElementType>&& other);
45 
46   /**
47    * Destructs the objects and releases the memory owned by the vector.
48    */
49   ~DynamicVector();
50 
51   /**
52    * Removes all elements from the vector, but does not change the capacity.
53    * All iterators and references are invalidated.
54    */
55   void clear();
56 
57   /**
58    * Returns a pointer to the underlying buffer. Note that this should not be
59    * considered to be persistent as the vector will be moved and resized
60    * automatically.
61    *
62    * @return The pointer to the underlying buffer.
63    */
64   ElementType *data();
65 
66   /**
67    * Returns a const pointer to the underlying buffer. Note that this should not
68    * be considered to be persistent as the vector will be moved and resized
69    * automatically.
70    *
71    * @return The const pointer to the underlying buffer.
72    */
73   const ElementType *data() const;
74 
75   /**
76    * Returns the current number of elements in the vector.
77    *
78    * @return The number of elements in the vector.
79    */
80   size_t size() const;
81 
82   /**
83    * Returns the maximum number of elements that can be stored in this vector
84    * without a resize operation.
85    *
86    * @return The capacity of the vector.
87    */
88   size_t capacity() const;
89 
90   /**
91    * Determines whether the vector is empty or not.
92    *
93    * @return true if the vector is empty.
94    */
95   bool empty() const;
96 
97   /**
98    * Copy- or move-constructs an element onto the back of the vector. If the
99    * vector requires a resize and that allocation fails this function will
100    * return false. All iterators and references are invalidated if the container
101    * has been resized. Otherwise, only the past-the-end iterator is invalidated.
102    *
103    * @param The element to push onto the vector.
104    * @return true if the element was pushed successfully.
105    */
106   bool push_back(const ElementType& element);
107   bool push_back(ElementType&& element);
108 
109   /**
110    * Constructs an element onto the back of the vector. All iterators and
111    * references are invalidated if the container has been resized. Otherwise,
112    * only the past-the-end iterator is invalidated.
113    *
114    * @param The arguments to the constructor
115    * @return true is the element is constructed successfully.
116    */
117   template<typename... Args>
118   bool emplace_back(Args&&... args);
119 
120   /**
121    * Obtains an element of the vector given an index. It is illegal to index
122    * this vector out of bounds and the user of the API must check the size()
123    * function prior to indexing this vector to ensure that they will not read
124    * out of bounds.
125    *
126    * @param The index of the element.
127    * @return The element.
128    */
129   ElementType& operator[](size_t index);
130 
131   /**
132    * Obtains a const element of the vector given an index. It is illegal to
133    * index this vector out of bounds and the user of the API must check the
134    * size() function prior to indexing this vector to ensure that they will not
135    * read out of bounds.
136    *
137    * @param The index of the element.
138    * @return The element.
139    */
140   const ElementType& operator[](size_t index) const;
141 
142   /**
143    * Resizes the vector to a new capacity returning true if allocation was
144    * successful. If the new capacity is smaller than the current capacity,
145    * the operation is a no-op and true is returned. If a memory allocation
146    * fails, the contents of the vector are not modified and false is returned.
147    * This is intended to be similar to the reserve function of the std::vector.
148    * All iterators and references are invalidated unless the container did not
149    * resize.
150    *
151    * @param The new capacity of the vector.
152    * @return true if the resize operation was successful.
153    */
154   bool reserve(size_t newCapacity);
155 
156   /**
157    * Inserts an element into the vector at a given index. If a resize of the
158    * vector is required and the allocation fails, false will be returned. This
159    * will shift all vector elements after the given index one position backward
160    * in the list. The supplied index must be <= the size of the vector. It is
161    * not possible to have a sparse list of items. If the index is > the current
162    * size of the vector, false will be returned. All iterators and references
163    * to and after the indexed element are invalidated. Iterators and references
164    * to before the indexed elements are unaffected if the container did not resize.
165    *
166    * @param index The index to insert an element at.
167    * @param element The element to insert.
168    * @return Whether or not the insert operation was successful.
169    */
170   bool insert(size_t index, const ElementType& element);
171   bool insert(size_t index, ElementType&& element);
172 
173   /**
174    * Similar to wrap(), except makes a copy of the supplied C-style array,
175    * maintaining ownership of the buffer within the DynamicVector container. The
176    * vector's capacity is increased if necessary to fit the given array, though
177    * note that this function will not cause the capacity to shrink. Upon
178    * successful reservation of necessary capacity, any pre-existing items in the
179    * vector are removed (via clear()), the supplied array is copied, and the
180    * vector's size is set to elementCount. All iterators and references are
181    * invalidated unless the container did not resize.
182    *
183    * This is essentially equivalent to calling these functions from std::vector:
184    *   vector.clear();
185    *   vector.insert(vector.begin(), array, &array[elementCount]);
186    *
187    * This function is not valid to call on a vector where owns_data() is false.
188    * Use unwrap() first in that case.
189    *
190    * @param array Pointer to the start of an array
191    * @param elementCount Number of elements in the supplied array to copy
192    *
193    * @return true if capacity was reserved to fit the supplied array (or the
194    *         vector already had sufficient capacity), and the supplied array was
195    *         copied into the vector. If false, the vector is not modified.
196    */
197   bool copy_array(const ElementType *array, size_t elementCount);
198 
199   /**
200    * Removes an element from the vector given an index. All elements after the
201    * indexed one are moved forward one position. The destructor is invoked on
202    * on the invalid item left at the end of the vector. The index passed in
203    * must be less than the size() of the vector. If the index is greater than or
204    * equal to the size no operation is performed. All iterators and references
205    * to and after the indexed element are invalidated.
206    *
207    * @param index The index to remove an element at.
208    */
209   void erase(size_t index);
210 
211   /**
212    * Searches the vector for an element.
213    *
214    * @param element The element to comare against.
215    * @return The index of the element found. If the return is equal to size()
216    *         then the element was not found.
217    */
218   size_t find(const ElementType& element) const;
219 
220   /**
221    * Swaps the location of two elements stored in the vector. The indices
222    * passed in must be less than the size() of the vector. If the index is
223    * greater than or equal to the size, no operation is performed. All
224    * iterators and references to these two indexed elements are invalidated.
225    *
226    * @param index0 The index of the first element
227    * @param index1 The index of the second element
228    */
229   void swap(size_t index0, size_t index1);
230 
231   /**
232    * Wraps an existing C-style array so it can be used as a DynamicVector. A
233    * reference to the supplied array is kept, as opposed to making a copy. The
234    * caller retains ownership of the memory. Calling code must therefore ensure
235    * that the lifetime of the supplied array is at least as long as that of this
236    * vector, and that the memory is released after this vector is destructed, as
237    * the vector will not attempt to free the memory itself.
238    *
239    * Once a vector wraps another buffer, it cannot be resized except through
240    * another call to wrap(). However, elements can be erased to make room for
241    * adding new elements.
242    *
243    * Destruction of elements within a wrapped array remains the responsibility
244    * of the calling code. While the vector may invoke the element destructor as
245    * a result of explicit calls to functions like erase() or clear(), it will
246    * not destruct elements remaining in the array when the vector is destructed.
247    * Therefore, special care must be taken when wrapping an array of elements
248    * that have a non-trivial destructor.
249    *
250    * @param array Pointer to a pre-allocated array
251    * @param elementCount Number of elements in the array (NOT the array's size
252    *        in bytes); will become the vector's size() and capacity()
253    */
254   void wrap(ElementType *array, size_t elementCount);
255 
256 
257   /**
258    * Returns a vector that is wrapping an array to the newly-constructed state,
259    * with capacity equal to 0, and owns_data() is true.
260    */
261   void unwrap();
262 
263   /**
264    * @return false if this vector is wrapping an array passed in via wrap()
265    */
266   bool owns_data() const;
267 
268   /**
269    * Returns a reference to the first element in the vector. It is illegal to
270    * call this on an empty vector.
271    *
272    * @return The first element in the vector.
273    */
274   ElementType& front();
275 
276   /**
277    * Returns a const reference to the first element in the vector. It is illegal
278    * to call this on an empty vector.
279    *
280    * @return The first element in the vector.
281    */
282   const ElementType& front() const;
283 
284   /**
285    * Returns a reference to the last element in the vector. It is illegal to
286    * call this on an empty vector.
287    *
288    * @return The last element in the vector.
289    */
290   ElementType& back();
291 
292   /**
293    * Returns a const reference to the last element in the vector. It is illegal
294    * to call this on an empty vector.
295    *
296    * @return The last element in the vector.
297    */
298   const ElementType& back() const;
299 
300   /**
301    * Prepares a vector to push a minimum of one element onto the back. The
302    * vector may be resized if required. The capacity of the vector increases
303    * with the growth policy of this vector (doubles for each resize for now).
304    *
305    * @return Whether or not the resize was successful.
306    */
307   bool prepareForPush();
308 
309   /**
310    * Random-access iterator that points to some element in the container.
311    */
312   typedef ElementType* iterator;
313   typedef const ElementType* const_iterator;
314 
315   /**
316    * @return A random-access iterator to the beginning.
317    */
318   typename DynamicVector<ElementType>::iterator begin();
319   typename DynamicVector<ElementType>::const_iterator begin() const;
320   typename DynamicVector<ElementType>::const_iterator cbegin() const;
321 
322   /**
323    * @return A random-access iterator to the end.
324    */
325   typename DynamicVector<ElementType>::iterator end();
326   typename DynamicVector<ElementType>::const_iterator end() const;
327   typename DynamicVector<ElementType>::const_iterator cend() const;
328 
329  private:
330   //! A pointer to the underlying data buffer.
331   ElementType *mData = nullptr;
332 
333   //! The current size of the vector, as in the number of elements stored.
334   size_t mSize = 0;
335 
336   //! The current capacity of the vector, as in the maximum number of elements
337   //! that can be stored.
338   size_t mCapacity = 0;
339 
340   //! Set to true when the buffer (mData) was supplied via wrap()
341   bool mDataIsWrapped = false;
342 
343   /**
344    * Prepares the vector for insertion - upon successful return, the memory at
345    * the given index will be allocated but uninitialized
346    *
347    * @param index
348    * @return true
349    */
350   bool prepareInsert(size_t index);
351 };
352 
353 }  // namespace chre
354 
355 #include "chre/util/dynamic_vector_impl.h"
356 
357 #endif  // CHRE_UTIL_DYNAMIC_VECTOR_H_
358