Cycles: Cleanup, silence strict compiler warning
[blender.git] / intern / cycles / util / util_vector.h
1 /*
2  * Copyright 2011-2013 Blender Foundation
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 __UTIL_VECTOR_H__
18 #define __UTIL_VECTOR_H__
19
20 /* Vector */
21
22 #include <cassert>
23 #include <cstring>
24 #include <vector>
25
26 #include "util/util_aligned_malloc.h"
27 #include "util/util_guarded_allocator.h"
28 #include "util/util_types.h"
29
30 CCL_NAMESPACE_BEGIN
31
32 /* Vector
33  *
34  * Own subclass-ed vestion of std::vector. Subclass is needed because:
35  *
36  * - Use own allocator which keeps track of used/peak memory.
37  *
38  * - Have method to ensure capacity is re-set to 0.
39  */
40 template<typename value_type,
41          typename allocator_type = GuardedAllocator<value_type> >
42 class vector : public std::vector<value_type, allocator_type>
43 {
44 public:
45         /* Default constructor. */
46         explicit vector() : std::vector<value_type, allocator_type>() {  }
47
48         /* Fill constructor. */
49         explicit vector(size_t n, const value_type& val = value_type())
50                 : std::vector<value_type, allocator_type>(n, val) {  }
51
52         /* Range constructor. */
53         template <class InputIterator>
54         vector(InputIterator first, InputIterator last)
55                 : std::vector<value_type, allocator_type>(first, last) {  }
56
57         /* Copy constructor. */
58         vector(const vector &x) : std::vector<value_type, allocator_type>(x) {  }
59
60         void shrink_to_fit(void)
61         {
62 #if __cplusplus < 201103L
63                 vector<value_type>().swap(*this);
64 #else
65                 std::vector<value_type, allocator_type>::shrink_to_fit();
66 #endif
67         }
68
69         void free_memory(void)
70         {
71                 std::vector<value_type, allocator_type>::resize(0);
72                 shrink_to_fit();
73         }
74
75         /* Some external API might demand working with std::vector. */
76         operator std::vector<value_type>()
77         {
78                 return std::vector<value_type>(this->begin(), this->end());
79         }
80 };
81
82 /* Array
83  *
84  * Simplified version of vector, serving multiple purposes:
85  * - somewhat faster in that it does not clear memory on resize/alloc,
86  *   this was actually showing up in profiles quite significantly. it
87  *   also does not run any constructors/destructors
88  * - if this is used, we are not tempted to use inefficient operations
89  * - aligned allocation for CPU native data types */
90
91 template<typename T, size_t alignment = MIN_ALIGNMENT_CPU_DATA_TYPES>
92 class array
93 {
94 public:
95         array()
96         : data_(NULL),
97           datasize_(0),
98           capacity_(0)
99         {}
100
101         explicit array(size_t newsize)
102         {
103                 if(newsize == 0) {
104                         data_ = NULL;
105                         datasize_ = 0;
106                         capacity_ = 0;
107                 }
108                 else {
109                         data_ = mem_allocate(newsize);
110                         datasize_ = newsize;
111                         capacity_ = datasize_;
112                 }
113         }
114
115         array(const array& from)
116         {
117                 if(from.datasize_ == 0) {
118                         data_ = NULL;
119                         datasize_ = 0;
120                         capacity_ = 0;
121                 }
122                 else {
123                         data_ = mem_allocate(from.datasize_);
124                         memcpy(data_, from.data_, from.datasize_*sizeof(T));
125                         datasize_ = from.datasize_;
126                         capacity_ = datasize_;
127                 }
128         }
129
130         array& operator=(const array& from)
131         {
132                 if(this != &from) {
133                         resize(from.size());
134                         memcpy((void*)data_, from.data_, datasize_*sizeof(T));
135                 }
136
137                 return *this;
138         }
139
140         array& operator=(const vector<T>& from)
141         {
142                 resize(from.size());
143
144                 if(from.size() > 0) {
145                         memcpy(data_, &from[0], datasize_*sizeof(T));
146                 }
147
148                 return *this;
149         }
150
151         ~array()
152         {
153                 mem_free(data_, capacity_);
154         }
155
156         bool operator==(const array<T>& other) const
157         {
158                 if(datasize_ != other.datasize_) {
159                         return false;
160                 }
161
162                 return memcmp(data_, other.data_, datasize_*sizeof(T)) == 0;
163         }
164
165         bool operator!=(const array<T>& other) const
166         {
167                 return !(*this == other);
168         }
169
170         void steal_data(array& from)
171         {
172                 if(this != &from) {
173                         clear();
174
175                         data_ = from.data_;
176                         datasize_ = from.datasize_;
177                         capacity_ = from.capacity_;
178
179                         from.data_ = NULL;
180                         from.datasize_ = 0;
181                         from.capacity_ = 0;
182                 }
183         }
184
185         T *steal_pointer()
186         {
187                 T *ptr = data_;
188                 data_ = NULL;
189                 clear();
190                 return ptr;
191         }
192
193         T* resize(size_t newsize)
194         {
195                 if(newsize == 0) {
196                         clear();
197                 }
198                 else if(newsize != datasize_) {
199                         if(newsize > capacity_) {
200                                 T *newdata = mem_allocate(newsize);
201                                 if(newdata == NULL) {
202                                         /* Allocation failed, likely out of memory. */
203                                         clear();
204                                         return NULL;
205                                 }
206                                 else if(data_ != NULL) {
207                                         memcpy((void *)newdata,
208                                                data_,
209                                                ((datasize_ < newsize)? datasize_: newsize)*sizeof(T));
210                                         mem_free(data_, capacity_);
211                                 }
212                                 data_ = newdata;
213                                 capacity_ = newsize;
214                         }
215                         datasize_ = newsize;
216                 }
217                 return data_;
218         }
219
220         T* resize(size_t newsize, const T& value)
221         {
222                 size_t oldsize = size();
223                 resize(newsize);
224
225                 for(size_t i = oldsize; i < size(); i++) {
226                         data_[i] = value;
227                 }
228
229                 return data_;
230         }
231
232         void clear()
233         {
234                 if(data_ != NULL) {
235                         mem_free(data_, capacity_);
236                         data_ = NULL;
237                 }
238                 datasize_ = 0;
239                 capacity_ = 0;
240         }
241
242         size_t empty() const
243         {
244                 return datasize_ == 0;
245         }
246
247         size_t size() const
248         {
249                 return datasize_;
250         }
251
252         T* data()
253         {
254                 return data_;
255         }
256
257         const T* data() const
258         {
259                 return data_;
260         }
261
262         T& operator[](size_t i) const
263         {
264                 assert(i < datasize_);
265                 return data_[i];
266         }
267
268         void reserve(size_t newcapacity)
269         {
270                 if(newcapacity > capacity_) {
271                         T *newdata = mem_allocate(newcapacity);
272                         if(data_ != NULL) {
273                                 memcpy(newdata, data_, ((datasize_ < newcapacity)? datasize_: newcapacity)*sizeof(T));
274                                 mem_free(data_, capacity_);
275                         }
276                         data_ = newdata;
277                         capacity_ = newcapacity;
278                 }
279         }
280
281         size_t capacity() const
282         {
283                 return capacity_;
284         }
285
286         // do not use this method unless you are sure the code is not performance critical
287         void push_back_slow(const T& t)
288         {
289                 if(capacity_ == datasize_)
290                 {
291                         reserve(datasize_ == 0 ? 1 : (size_t)((datasize_ + 1) * 1.2));
292                 }
293
294                 data_[datasize_++] = t;
295         }
296
297         void push_back_reserved(const T& t)
298         {
299                 assert(datasize_ < capacity_);
300                 push_back_slow(t);
301         }
302
303         void append(const array<T>& from)
304         {
305                 if(from.size()) {
306                         size_t old_size = size();
307                         resize(old_size + from.size());
308                         memcpy(data_ + old_size, from.data(), sizeof(T) * from.size());
309                 }
310         }
311
312 protected:
313         inline T* mem_allocate(size_t N)
314         {
315                 if(N == 0) {
316                         return NULL;
317                 }
318                 T *mem = (T*)util_aligned_malloc(sizeof(T)*N, alignment);
319                 if(mem != NULL) {
320                         util_guarded_mem_alloc(sizeof(T)*N);
321                 }
322                 else {
323                         throw std::bad_alloc();
324                 }
325                 return mem;
326         }
327
328         inline void mem_free(T *mem, size_t N)
329         {
330                 if(mem != NULL) {
331                         util_guarded_mem_free(sizeof(T)*N);
332                         util_aligned_free(mem);
333                 }
334         }
335
336         T *data_;
337         size_t datasize_;
338         size_t capacity_;
339 };
340
341 CCL_NAMESPACE_END
342
343 #endif /* __UTIL_VECTOR_H__ */
344