Code refactor: add generic Cycles node infrastructure.
[blender-staging.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_aligned_malloc.h"
27 #include "util_guarded_allocator.h"
28 #include "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 SSE data types */
90
91 template<typename T, size_t alignment = 16>
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(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         void steal_data(array& from)
166         {
167                 if(this != &from) {
168                         clear();
169
170                         data_ = from.data_;
171                         datasize_ = from.datasize_;
172                         capacity_ = from.capacity_;
173
174                         from.data_ = NULL;
175                         from.datasize_ = 0;
176                         from.capacity_ = 0;
177                 }
178         }
179
180         T* resize(size_t newsize)
181         {
182                 if(newsize == 0) {
183                         clear();
184                 }
185                 else if(newsize != datasize_) {
186                         if(newsize > capacity_) {
187                                 T *newdata = mem_allocate(newsize);
188                                 if(newdata == NULL) {
189                                         /* Allocation failed, likely out of memory. */
190                                         clear();
191                                         return NULL;
192                                 }
193                                 else if(data_ != NULL) {
194                                         memcpy(newdata, data_, ((datasize_ < newsize)? datasize_: newsize)*sizeof(T));
195                                         mem_free(data_, capacity_);
196                                 }
197                                 data_ = newdata;
198                                 capacity_ = newsize;
199                         }
200                         datasize_ = newsize;
201                 }
202                 return data_;
203         }
204
205         void clear()
206         {
207                 if(data_ != NULL) {
208                         mem_free(data_, capacity_);
209                         data_ = NULL;
210                 }
211                 datasize_ = 0;
212                 capacity_ = 0;
213         }
214
215         size_t empty() const
216         {
217                 return datasize_ == 0;
218         }
219
220         size_t size() const
221         {
222                 return datasize_;
223         }
224
225         const T* data() const
226         {
227                 return data_;
228         }
229
230         T& operator[](size_t i) const
231         {
232                 assert(i < datasize_);
233                 return data_[i];
234         }
235
236         void reserve(size_t newcapacity)
237         {
238                 if(newcapacity > capacity_) {
239                         T *newdata = mem_allocate(newcapacity);
240                         if(data_ != NULL) {
241                                 memcpy(newdata, data_, ((datasize_ < newcapacity)? datasize_: newcapacity)*sizeof(T));
242                                 mem_free(data_, capacity_);
243                         }
244                         data_ = newdata;
245                         capacity_ = newcapacity;
246                 }
247         }
248
249         size_t capacity() const
250         {
251                 return capacity_;
252         }
253
254         // do not use this method unless you are sure the code is not performance critical
255         void push_back_slow(const T& t)
256         {
257                 if(capacity_ == datasize_)
258                 {
259                         reserve(datasize_ == 0 ? 1 : (size_t)((datasize_ + 1) * 1.2));
260                 }
261
262                 data_[datasize_++] = t;
263         }
264
265         void push_back_reserved(const T& t)
266         {
267                 assert(datasize_ < capacity_);
268                 push_back_slow(t);
269         }
270
271 protected:
272         inline T* mem_allocate(size_t N)
273         {
274                 if(N == 0) {
275                         return NULL;
276                 }
277                 T *mem = (T*)util_aligned_malloc(sizeof(T)*N, alignment);
278                 if(mem != NULL) {
279                         util_guarded_mem_alloc(sizeof(T)*N);
280                 }
281                 else {
282                         throw std::bad_alloc();
283                 }
284                 return mem;
285         }
286
287         inline void mem_free(T *mem, size_t N)
288         {
289                 if(mem != NULL) {
290                         util_guarded_mem_free(sizeof(T)*N);
291                         util_aligned_free(mem);
292                 }
293         }
294
295         T *data_;
296         size_t datasize_;
297         size_t capacity_;
298 };
299
300 CCL_NAMESPACE_END
301
302 #endif /* __UTIL_VECTOR_H__ */
303