vfs: check userland buffers before reading them.
[haiku.git] / headers / private / shared / Array.h
blob89e9934ace56d8b81cc2dad16568ab2948ea3c60
1 /*
2 * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5 #ifndef _ARRAY_H
6 #define _ARRAY_H
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
13 #include <SupportDefs.h>
15 #if DEBUG
16 # include <OS.h>
17 #endif
20 namespace BPrivate {
23 template<typename Element>
24 class Array {
25 public:
26 inline Array();
27 Array(const Array<Element>& other);
28 inline ~Array();
30 inline int32 Size() const { return fSize; }
31 inline int32 Count() const { return fSize; }
32 inline bool IsEmpty() const { return fSize == 0; }
33 inline Element* Elements() const { return fElements; }
35 inline bool Add(const Element& element);
36 inline bool AddUninitialized(int32 elementCount);
37 inline bool Insert(const Element& element, int32 index);
38 inline bool InsertUninitialized(int32 index, int32 count);
39 inline bool Remove(int32 index, int32 count = 1);
41 void Clear();
42 inline void MakeEmpty();
44 inline Element& ElementAt(int32 index);
45 inline const Element& ElementAt(int32 index) const;
47 inline Element& operator[](int32 index);
48 inline const Element& operator[](int32 index) const;
50 Array<Element>& operator=(const Array<Element>& other);
52 private:
53 static const int32 kMinCapacity = 8;
55 bool _Resize(int32 index, int32 delta);
57 private:
58 Element* fElements;
59 int32 fSize;
60 int32 fCapacity;
64 template<typename Element>
65 Array<Element>::Array()
67 fElements(NULL),
68 fSize(0),
69 fCapacity(0)
74 template<typename Element>
75 Array<Element>::Array(const Array<Element>& other)
77 fElements(NULL),
78 fSize(0),
79 fCapacity(0)
81 *this = other;
85 template<typename Element>
86 Array<Element>::~Array()
88 free(fElements);
92 template<typename Element>
93 bool
94 Array<Element>::Add(const Element& element)
96 if (!_Resize(fSize, 1))
97 return false;
99 fElements[fSize] = element;
100 fSize++;
101 return true;
105 template<typename Element>
106 inline bool
107 Array<Element>::AddUninitialized(int32 elementCount)
109 return InsertUninitialized(fSize, elementCount);
113 template<typename Element>
114 bool
115 Array<Element>::Insert(const Element& element, int32 index)
117 if (index < 0 || index > fSize)
118 index = fSize;
120 if (!_Resize(index, 1))
121 return false;
123 fElements[index] = element;
124 fSize++;
125 return true;
129 template<typename Element>
130 bool
131 Array<Element>::InsertUninitialized(int32 index, int32 count)
133 if (index < 0 || index > fSize || count < 0)
134 return false;
135 if (count == 0)
136 return true;
138 if (!_Resize(index, count))
139 return false;
141 fSize += count;
142 return true;
146 template<typename Element>
147 bool
148 Array<Element>::Remove(int32 index, int32 count)
150 if (index < 0 || count < 0 || index + count > fSize) {
151 #if DEBUG
152 char buffer[128];
153 snprintf(buffer, sizeof(buffer), "Array::Remove(): index: %" B_PRId32
154 ", count: %" B_PRId32 ", size: %" B_PRId32, index, count, fSize);
155 debugger(buffer);
156 #endif
157 return false;
159 if (count == 0)
160 return true;
162 if (index + count < fSize) {
163 memmove(fElements + index, fElements + index + count,
164 sizeof(Element) * (fSize - index - count));
167 _Resize(index, -count);
169 fSize -= count;
170 return true;
174 template<typename Element>
175 void
176 Array<Element>::Clear()
178 if (fSize == 0)
179 return;
181 free(fElements);
183 fElements = NULL;
184 fSize = 0;
185 fCapacity = 0;
189 template<typename Element>
190 void
191 Array<Element>::MakeEmpty()
193 Clear();
197 template<typename Element>
198 Element&
199 Array<Element>::ElementAt(int32 index)
201 return fElements[index];
205 template<typename Element>
206 const Element&
207 Array<Element>::ElementAt(int32 index) const
209 return fElements[index];
213 template<typename Element>
214 Element&
215 Array<Element>::operator[](int32 index)
217 return fElements[index];
221 template<typename Element>
222 const Element&
223 Array<Element>::operator[](int32 index) const
225 return fElements[index];
229 template<typename Element>
230 Array<Element>&
231 Array<Element>::operator=(const Array<Element>& other)
233 Clear();
235 if (other.fSize > 0 && _Resize(0, other.fSize)) {
236 fSize = other.fSize;
237 memcpy(fElements, other.fElements, fSize * sizeof(Element));
240 return *this;
244 template<typename Element>
245 bool
246 Array<Element>::_Resize(int32 index, int32 delta)
248 // determine new capacity
249 int32 newSize = fSize + delta;
250 int32 newCapacity = kMinCapacity;
251 while (newCapacity < newSize)
252 newCapacity *= 2;
254 if (newCapacity == fCapacity) {
255 // the capacity doesn't change -- still make room for/remove elements
256 if (index < fSize) {
257 if (delta > 0) {
258 // leave a gap of delta elements
259 memmove(fElements + index + delta, fElements + index,
260 (fSize - index) * sizeof(Element));
261 } else if (index < fSize + delta) {
262 // drop -delta elements
263 memcpy(fElements + index, fElements + index - delta,
264 (fSize - index + delta) * sizeof(Element));
268 return true;
271 // allocate new array
272 Element* elements = (Element*)malloc(newCapacity * sizeof(Element));
273 if (elements == NULL)
274 return false;
276 if (index > 0)
277 memcpy(elements, fElements, index * sizeof(Element));
278 if (index < fSize) {
279 if (delta > 0) {
280 // leave a gap of delta elements
281 memcpy(elements + index + delta, fElements + index,
282 (fSize - index) * sizeof(Element));
283 } else if (index < fSize + delta) {
284 // drop -delta elements
285 memcpy(elements + index, fElements + index - delta,
286 (fSize - index + delta) * sizeof(Element));
290 free(fElements);
291 fElements = elements;
292 fCapacity = newCapacity;
293 return true;
297 } // namespace BPrivate
300 using BPrivate::Array;
303 #endif // _ARRAY_H