1 | // Copyright 2009-2021 Intel Corporation |
2 | // SPDX-License-Identifier: Apache-2.0 |
3 | |
4 | #pragma once |
5 | |
6 | #include "alloc.h" |
7 | #include <algorithm> |
8 | |
9 | namespace embree |
10 | { |
11 | template<typename T, typename allocator> |
12 | class vector_t |
13 | { |
14 | public: |
15 | typedef T value_type; |
16 | typedef T* iterator; |
17 | typedef const T* const_iterator; |
18 | |
19 | __forceinline vector_t () |
20 | : size_active(0), size_alloced(0), items(nullptr) {} |
21 | |
22 | __forceinline explicit vector_t (size_t sz) |
23 | : size_active(0), size_alloced(0), items(nullptr) { internal_resize_init(sz); } |
24 | |
25 | template<typename M> |
26 | __forceinline explicit vector_t (M alloc, size_t sz) |
27 | : alloc(alloc), size_active(0), size_alloced(0), items(nullptr) { internal_resize_init(sz); } |
28 | |
29 | __forceinline ~vector_t() { |
30 | clear(); |
31 | } |
32 | |
33 | __forceinline vector_t (const vector_t& other) |
34 | { |
35 | size_active = other.size_active; |
36 | size_alloced = other.size_alloced; |
37 | items = alloc.allocate(size_alloced); |
38 | for (size_t i=0; i<size_active; i++) |
39 | ::new (&items[i]) value_type(other.items[i]); |
40 | } |
41 | |
42 | __forceinline vector_t (vector_t&& other) |
43 | : alloc(std::move(other.alloc)) |
44 | { |
45 | size_active = other.size_active; other.size_active = 0; |
46 | size_alloced = other.size_alloced; other.size_alloced = 0; |
47 | items = other.items; other.items = nullptr; |
48 | } |
49 | |
50 | __forceinline vector_t& operator=(const vector_t& other) |
51 | { |
52 | resize(other.size_active); |
53 | for (size_t i=0; i<size_active; i++) |
54 | items[i] = value_type(other.items[i]); |
55 | return *this; |
56 | } |
57 | |
58 | __forceinline vector_t& operator=(vector_t&& other) |
59 | { |
60 | clear(); |
61 | alloc = std::move(other.alloc); |
62 | size_active = other.size_active; other.size_active = 0; |
63 | size_alloced = other.size_alloced; other.size_alloced = 0; |
64 | items = other.items; other.items = nullptr; |
65 | return *this; |
66 | } |
67 | |
68 | /********************** Iterators ****************************/ |
69 | |
70 | __forceinline iterator begin() { return items; }; |
71 | __forceinline const_iterator begin() const { return items; }; |
72 | |
73 | __forceinline iterator end () { return items+size_active; }; |
74 | __forceinline const_iterator end () const { return items+size_active; }; |
75 | |
76 | |
77 | /********************** Capacity ****************************/ |
78 | |
79 | __forceinline bool empty () const { return size_active == 0; } |
80 | __forceinline size_t size () const { return size_active; } |
81 | __forceinline size_t capacity () const { return size_alloced; } |
82 | |
83 | |
84 | __forceinline void resize(size_t new_size) { |
85 | internal_resize(new_size,internal_grow_size(new_size)); |
86 | } |
87 | |
88 | __forceinline void reserve(size_t new_alloced) |
89 | { |
90 | /* do nothing if container already large enough */ |
91 | if (new_alloced <= size_alloced) |
92 | return; |
93 | |
94 | /* resize exact otherwise */ |
95 | internal_resize(size_active,new_alloced); |
96 | } |
97 | |
98 | __forceinline void shrink_to_fit() { |
99 | internal_resize(size_active,size_active); |
100 | } |
101 | |
102 | /******************** Element access **************************/ |
103 | |
104 | __forceinline T& operator[](size_t i) { assert(i < size_active); return items[i]; } |
105 | __forceinline const T& operator[](size_t i) const { assert(i < size_active); return items[i]; } |
106 | |
107 | __forceinline T& at(size_t i) { assert(i < size_active); return items[i]; } |
108 | __forceinline const T& at(size_t i) const { assert(i < size_active); return items[i]; } |
109 | |
110 | __forceinline T& front() const { assert(size_active > 0); return items[0]; }; |
111 | __forceinline T& back () const { assert(size_active > 0); return items[size_active-1]; }; |
112 | |
113 | __forceinline T* data() { return items; }; |
114 | __forceinline const T* data() const { return items; }; |
115 | |
116 | |
117 | /******************** Modifiers **************************/ |
118 | |
119 | __forceinline void push_back(const T& nt) |
120 | { |
121 | const T v = nt; // need local copy as input reference could point to this vector |
122 | internal_resize(size_active,internal_grow_size(size_active+1)); |
123 | ::new (&items[size_active++]) T(v); |
124 | } |
125 | |
126 | __forceinline void pop_back() |
127 | { |
128 | assert(!empty()); |
129 | size_active--; |
130 | items[size_active].~T(); |
131 | } |
132 | |
133 | __forceinline void clear() |
134 | { |
135 | /* destroy elements */ |
136 | for (size_t i=0; i<size_active; i++){ |
137 | items[i].~T(); |
138 | } |
139 | |
140 | /* free memory */ |
141 | alloc.deallocate(items,size_alloced); |
142 | items = nullptr; |
143 | size_active = size_alloced = 0; |
144 | } |
145 | |
146 | /******************** Comparisons **************************/ |
147 | |
148 | friend bool operator== (const vector_t& a, const vector_t& b) |
149 | { |
150 | if (a.size() != b.size()) return false; |
151 | for (size_t i=0; i<a.size(); i++) |
152 | if (a[i] != b[i]) |
153 | return false; |
154 | return true; |
155 | } |
156 | |
157 | friend bool operator!= (const vector_t& a, const vector_t& b) { |
158 | return !(a==b); |
159 | } |
160 | |
161 | private: |
162 | |
163 | __forceinline void internal_resize_init(size_t new_active) |
164 | { |
165 | assert(size_active == 0); |
166 | assert(size_alloced == 0); |
167 | assert(items == nullptr); |
168 | if (new_active == 0) return; |
169 | items = alloc.allocate(new_active); |
170 | for (size_t i=0; i<new_active; i++) ::new (&items[i]) T(); |
171 | size_active = new_active; |
172 | size_alloced = new_active; |
173 | } |
174 | |
175 | __forceinline void internal_resize(size_t new_active, size_t new_alloced) |
176 | { |
177 | assert(new_active <= new_alloced); |
178 | |
179 | /* destroy elements */ |
180 | if (new_active < size_active) |
181 | { |
182 | for (size_t i=new_active; i<size_active; i++){ |
183 | items[i].~T(); |
184 | } |
185 | size_active = new_active; |
186 | } |
187 | |
188 | /* only reallocate if necessary */ |
189 | if (new_alloced == size_alloced) { |
190 | for (size_t i=size_active; i<new_active; i++) ::new (&items[i]) T; |
191 | size_active = new_active; |
192 | return; |
193 | } |
194 | |
195 | /* reallocate and copy items */ |
196 | T* old_items = items; |
197 | items = alloc.allocate(new_alloced); |
198 | for (size_t i=0; i<size_active; i++) { |
199 | ::new (&items[i]) T(std::move(old_items[i])); |
200 | old_items[i].~T(); |
201 | } |
202 | |
203 | for (size_t i=size_active; i<new_active; i++) { |
204 | ::new (&items[i]) T; |
205 | } |
206 | |
207 | alloc.deallocate(old_items,size_alloced); |
208 | size_active = new_active; |
209 | size_alloced = new_alloced; |
210 | } |
211 | |
212 | __forceinline size_t internal_grow_size(size_t new_alloced) |
213 | { |
214 | /* do nothing if container already large enough */ |
215 | if (new_alloced <= size_alloced) |
216 | return size_alloced; |
217 | |
218 | /* resize to next power of 2 otherwise */ |
219 | size_t new_size_alloced = size_alloced; |
220 | while (new_size_alloced < new_alloced) { |
221 | new_size_alloced = std::max(size_t(1),2*new_size_alloced); |
222 | } |
223 | return new_size_alloced; |
224 | } |
225 | |
226 | private: |
227 | allocator alloc; |
228 | size_t size_active; // number of valid items |
229 | size_t size_alloced; // number of items allocated |
230 | T* items; // data array |
231 | }; |
232 | |
233 | /*! vector class that performs standard allocations */ |
234 | template<typename T> |
235 | using vector = vector_t<T,std::allocator<T>>; |
236 | |
237 | /*! vector class that performs aligned allocations */ |
238 | template<typename T> |
239 | using avector = vector_t<T,aligned_allocator<T,std::alignment_of<T>::value> >; |
240 | |
241 | /*! vector class that performs OS allocations */ |
242 | template<typename T> |
243 | using ovector = vector_t<T,os_allocator<T> >; |
244 | } |
245 | |