dvector.h
1 /*************************************************************************/
2 /* dvector.h */
3 /*************************************************************************/
4 /* This file is part of: */
5 /* GODOT ENGINE */
6 /* http://www.godotengine.org */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
9 /* */
10 /* Permission is hereby granted, free of charge, to any person obtaining */
11 /* a copy of this software and associated documentation files (the */
12 /* "Software"), to deal in the Software without restriction, including */
13 /* without limitation the rights to use, copy, modify, merge, publish, */
14 /* distribute, sublicense, and/or sell copies of the Software, and to */
15 /* permit persons to whom the Software is furnished to do so, subject to */
16 /* the following conditions: */
17 /* */
18 /* The above copyright notice and this permission notice shall be */
19 /* included in all copies or substantial portions of the Software. */
20 /* */
21 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
22 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
23 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
24 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
25 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
26 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
27 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
28 /*************************************************************************/
29 #ifndef DVECTOR_H
30 #define DVECTOR_H
31 
32 #include "os/memory.h"
33 
34 
40 extern Mutex* dvector_lock;
41 
42 template<class T>
43 class DVector {
44 
45  mutable MID mem;
46 
47 
48  void copy_on_write() {
49 
50  if (!mem.is_valid())
51  return;
52 
53  if (dvector_lock)
54  dvector_lock->lock();
55 
56  MID_Lock lock( mem );
57 
58 
59  if ( *(int*)lock.data() == 1 ) {
60  // one reference, means no refcount changes
61  if (dvector_lock)
62  dvector_lock->unlock();
63  return;
64  }
65 
66  MID new_mem= dynalloc( mem.get_size() );
67 
68  if (!new_mem.is_valid()) {
69 
70  if (dvector_lock)
71  dvector_lock->unlock();
72  ERR_FAIL_COND( new_mem.is_valid() ); // out of memory
73  }
74 
75  MID_Lock dst_lock( new_mem );
76 
77  int *rc = (int*)dst_lock.data();
78 
79  *rc=1;
80 
81  T * dst = (T*)(rc + 1 );
82 
83  T * src =(T*) ((int*)lock.data() + 1 );
84 
85  int count = (mem.get_size() - sizeof(int)) / sizeof(T);
86 
87  for (int i=0;i<count;i++) {
88 
89  memnew_placement( &dst[i], T(src[i]) );
90  }
91 
92  (*(int*)lock.data())--;
93 
94  // unlock all
95  dst_lock=MID_Lock();
96  lock=MID_Lock();
97 
98  mem=new_mem;
99 
100  if (dvector_lock)
101  dvector_lock->unlock();
102 
103  }
104 
105  void reference( const DVector& p_dvector ) {
106 
107  unreference();
108 
109  if (dvector_lock)
110  dvector_lock->lock();
111 
112  if (!p_dvector.mem.is_valid()) {
113 
114  if (dvector_lock)
115  dvector_lock->unlock();
116  return;
117  }
118 
119  MID_Lock lock(p_dvector.mem);
120 
121  int * rc = (int*)lock.data();
122  (*rc)++;
123 
124  lock = MID_Lock();
125  mem=p_dvector.mem;
126 
127  if (dvector_lock)
128  dvector_lock->unlock();
129 
130  }
131 
132 
133  void unreference() {
134 
135  if (dvector_lock)
136  dvector_lock->lock();
137 
138  if (!mem.is_valid()) {
139 
140  if (dvector_lock)
141  dvector_lock->unlock();
142  return;
143  }
144 
145  MID_Lock lock(mem);
146 
147  int * rc = (int*)lock.data();
148  (*rc)--;
149 
150  if (*rc==0) {
151  // no one else using it, destruct
152 
153  T * t= (T*)(rc+1);
154  int count = (mem.get_size() - sizeof(int)) / sizeof(T);
155 
156  for (int i=0;i<count;i++) {
157 
158  t[i].~T();
159  }
160 
161  }
162 
163 
164  lock = MID_Lock();
165 
166  mem = MID ();
167 
168  if (dvector_lock)
169  dvector_lock->unlock();
170 
171  }
172 
173 public:
174 
175  class Read {
176  friend class DVector;
177  MID_Lock lock;
178  const T * mem;
179  public:
180 
181  _FORCE_INLINE_ const T& operator[](int p_index) const { return mem[p_index]; }
182  _FORCE_INLINE_ const T *ptr() const { return mem; }
183 
184  Read() { mem=NULL; }
185  };
186 
187  class Write {
188  friend class DVector;
189  MID_Lock lock;
190  T * mem;
191  public:
192 
193  _FORCE_INLINE_ T& operator[](int p_index) { return mem[p_index]; }
194  _FORCE_INLINE_ T *ptr() { return mem; }
195 
196  Write() { mem=NULL; }
197  };
198 
199 
200  Read read() const {
201 
202  Read r;
203  if (mem.is_valid()) {
204  r.lock = MID_Lock( mem );
205  r.mem = (const T*)((int*)r.lock.data()+1);
206  }
207  return r;
208  }
209  Write write() {
210 
211  Write w;
212  if (mem.is_valid()) {
213  copy_on_write();
214  w.lock = MID_Lock( mem );
215  w.mem = (T*)((int*)w.lock.data()+1);
216  }
217  return w;
218  }
219 
220  template<class MC>
221  void fill_with(const MC& p_mc) {
222 
223 
224  int c=p_mc.size();
225  resize(c);
226  Write w=write();
227  int idx=0;
228  for(const typename MC::Element *E=p_mc.front();E;E=E->next()) {
229 
230  w[idx++]=E->get();
231  }
232  }
233 
234 
235  void remove(int p_index) {
236 
237  int s = size();
238  ERR_FAIL_INDEX(p_index, s);
239  Write w = write();
240  for (int i=p_index; i<s-1; i++) {
241 
242  w[i]=w[i+1];
243  };
244  w = Write();
245  resize(s-1);
246  }
247 
248  inline int size() const;
249  T get(int p_index) const;
250  void set(int p_index, const T& p_val);
251  void push_back(const T& p_val);
252  void append(const T& p_val) { push_back(p_val); }
253  void append_array(const DVector<T>& p_arr) {
254  int ds = p_arr.size();
255  if (ds==0)
256  return;
257  int bs = size();
258  resize( bs + ds);
259  Write w = write();
260  Read r = p_arr.read();
261  for(int i=0;i<ds;i++)
262  w[bs+i]=r[i];
263  }
264 
265 
266  Error insert(int p_pos,const T& p_val) {
267 
268  int s=size();
269  ERR_FAIL_INDEX_V(p_pos,s+1,ERR_INVALID_PARAMETER);
270  resize(s+1);
271  {
272  Write w = write();
273  for (int i=s;i>p_pos;i--)
274  w[i]=w[i-1];
275  w[p_pos]=p_val;
276  }
277 
278  return OK;
279  }
280 
281 
282  bool is_locked() const { return mem.is_locked(); }
283 
284  inline const T operator[](int p_index) const;
285 
286  Error resize(int p_size);
287 
288 
289  void operator=(const DVector& p_dvector) { reference(p_dvector); }
290  DVector() {}
291  DVector(const DVector& p_dvector) { reference(p_dvector); }
292  ~DVector() { unreference(); }
293 
294 };
295 
296 template<class T>
297 int DVector<T>::size() const {
298 
299  return mem.is_valid() ? ((mem.get_size() - sizeof(int)) / sizeof(T) ) : 0;
300 }
301 
302 template<class T>
303 T DVector<T>::get(int p_index) const {
304 
305  return operator[](p_index);
306 }
307 
308 template<class T>
309 void DVector<T>::set(int p_index, const T& p_val) {
310 
311  if (p_index<0 || p_index>=size()) {
312  ERR_FAIL_COND(p_index<0 || p_index>=size());
313  }
314 
315  Write w = write();
316  w[p_index]=p_val;
317 }
318 
319 template<class T>
320 void DVector<T>::push_back(const T& p_val) {
321 
322  resize( size() + 1 );
323  set( size() -1, p_val );
324 }
325 
326 template<class T>
327 const T DVector<T>::operator[](int p_index) const {
328 
329  if (p_index<0 || p_index>=size()) {
330  T& aux=*((T*)0); //nullreturn
331  ERR_FAIL_COND_V(p_index<0 || p_index>=size(),aux);
332  }
333 
334  Read r = read();
335 
336  return r[p_index];
337 }
338 
339 
340 template<class T>
341 Error DVector<T>::resize(int p_size) {
342 
343  if (dvector_lock)
344  dvector_lock->lock();
345 
346  bool same = p_size==size();
347 
348  if (dvector_lock)
349  dvector_lock->unlock();
350  // no further locking is necesary because we are supposed to own the only copy of this (using copy on write)
351 
352  if (same)
353  return OK;
354 
355  if (p_size == 0 ) {
356 
357  unreference();
358  return OK;
359  }
360 
361 
362  copy_on_write(); // make it unique
363 
364  ERR_FAIL_COND_V( mem.is_locked(), ERR_LOCKED ); // if after copy on write, memory is locked, fail.
365 
366  if (p_size > size() ) {
367 
368  int oldsize=size();
369 
370  MID_Lock lock;
371 
372  if (oldsize==0) {
373 
374  mem = dynalloc( p_size * sizeof(T) + sizeof(int) );
375  lock=MID_Lock(mem);
376  int *rc = ((int*)lock.data());
377  *rc=1;
378 
379  } else {
380 
381  if (dynrealloc( mem, p_size * sizeof(T) + sizeof(int) )!=OK ) {
382 
383  ERR_FAIL_V(ERR_OUT_OF_MEMORY); // out of memory
384  }
385 
386  lock=MID_Lock(mem);
387  }
388 
389 
390 
391 
392  T *t = (T*)((int*)lock.data() + 1);
393 
394  for (int i=oldsize;i<p_size;i++) {
395 
396  memnew_placement(&t[i], T );
397  }
398 
399  lock = MID_Lock(); // clear
400  } else {
401 
402  int oldsize=size();
403 
404  MID_Lock lock(mem);
405 
406 
407  T *t = (T*)((int*)lock.data() + 1);
408 
409  for (int i=p_size;i<oldsize;i++) {
410 
411  t[i].~T();
412  }
413 
414  lock = MID_Lock(); // clear
415 
416  if (dynrealloc( mem, p_size * sizeof(T) + sizeof(int) )!=OK ) {
417 
418  ERR_FAIL_V(ERR_OUT_OF_MEMORY); // wtf error
419  }
420 
421 
422  }
423 
424  return OK;
425 }
426 
427 
428 
429 #endif
Definition: dvector.h:187
Definition: mutex.h:45
Definition: memory.h:42
Definition: dvector.h:175
virtual void unlock()=0
Unlock the mutex, let other threads continue.
virtual void lock()=0
Lock the mutex, block if locked by someone else.
Definition: dvector.h:43
Definition: memory.h:157