virtualx-engine/core/dvector.h

418 lines
8.6 KiB
C++
Raw Normal View History

2014-02-10 02:10:30 +01:00
/*************************************************************************/
/* dvector.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
2014-02-10 02:10:30 +01:00
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifndef DVECTOR_H
#define DVECTOR_H
#include "os/memory.h"
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
extern Mutex *dvector_lock;
2014-02-10 02:10:30 +01:00
template <class T>
2014-02-10 02:10:30 +01:00
class DVector {
mutable MID mem;
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
void copy_on_write() {
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
if (!mem.is_valid())
return;
if (dvector_lock)
dvector_lock->lock();
2016-03-09 00:00:52 +01:00
MID_Lock lock(mem);
2014-02-10 02:10:30 +01:00
if (*(int *)lock.data() == 1) {
2014-02-10 02:10:30 +01:00
// one reference, means no refcount changes
if (dvector_lock)
dvector_lock->unlock();
return;
}
2016-03-09 00:00:52 +01:00
MID new_mem = dynalloc(mem.get_size());
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
if (!new_mem.is_valid()) {
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
if (dvector_lock)
dvector_lock->unlock();
ERR_FAIL_COND(new_mem.is_valid()); // out of memory
2014-02-10 02:10:30 +01:00
}
2016-03-09 00:00:52 +01:00
MID_Lock dst_lock(new_mem);
2016-03-09 00:00:52 +01:00
int *rc = (int *)dst_lock.data();
2016-03-09 00:00:52 +01:00
*rc = 1;
2016-03-09 00:00:52 +01:00
T *dst = (T *)(rc + 1);
2016-03-09 00:00:52 +01:00
T *src = (T *)((int *)lock.data() + 1);
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
int count = (mem.get_size() - sizeof(int)) / sizeof(T);
2016-03-09 00:00:52 +01:00
for (int i = 0; i < count; i++) {
2016-03-09 00:00:52 +01:00
memnew_placement(&dst[i], T(src[i]));
2014-02-10 02:10:30 +01:00
}
2016-03-09 00:00:52 +01:00
(*(int *)lock.data())--;
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
// unlock all
dst_lock = MID_Lock();
lock = MID_Lock();
2016-03-09 00:00:52 +01:00
mem = new_mem;
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
if (dvector_lock)
dvector_lock->unlock();
}
2016-03-09 00:00:52 +01:00
void reference(const DVector &p_dvector) {
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
unreference();
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
if (dvector_lock)
dvector_lock->lock();
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
if (!p_dvector.mem.is_valid()) {
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
if (dvector_lock)
dvector_lock->unlock();
2016-03-09 00:00:52 +01:00
return;
2014-02-10 02:10:30 +01:00
}
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
MID_Lock lock(p_dvector.mem);
2016-03-09 00:00:52 +01:00
int *rc = (int *)lock.data();
2014-02-10 02:10:30 +01:00
(*rc)++;
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
lock = MID_Lock();
mem = p_dvector.mem;
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
if (dvector_lock)
dvector_lock->unlock();
}
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
void unreference() {
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
if (dvector_lock)
dvector_lock->lock();
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
if (!mem.is_valid()) {
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
if (dvector_lock)
dvector_lock->unlock();
2016-03-09 00:00:52 +01:00
return;
2014-02-10 02:10:30 +01:00
}
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
MID_Lock lock(mem);
2016-03-09 00:00:52 +01:00
int *rc = (int *)lock.data();
2014-02-10 02:10:30 +01:00
(*rc)--;
2016-03-09 00:00:52 +01:00
if (*rc == 0) {
2014-02-10 02:10:30 +01:00
// no one else using it, destruct
2016-03-09 00:00:52 +01:00
T *t = (T *)(rc + 1);
2014-02-10 02:10:30 +01:00
int count = (mem.get_size() - sizeof(int)) / sizeof(T);
2016-03-09 00:00:52 +01:00
for (int i = 0; i < count; i++) {
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
t[i].~T();
}
}
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
lock = MID_Lock();
2016-03-09 00:00:52 +01:00
mem = MID();
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
if (dvector_lock)
dvector_lock->unlock();
}
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
public:
class Read {
friend class DVector;
2014-02-10 02:10:30 +01:00
MID_Lock lock;
const T *mem;
2016-03-09 00:00:52 +01:00
public:
_FORCE_INLINE_ const T &operator[](int p_index) const { return mem[p_index]; }
2014-02-10 02:10:30 +01:00
_FORCE_INLINE_ const T *ptr() const { return mem; }
2016-03-09 00:00:52 +01:00
Read() { mem = NULL; }
2014-02-10 02:10:30 +01:00
};
class Write {
friend class DVector;
2014-02-10 02:10:30 +01:00
MID_Lock lock;
T *mem;
2016-03-09 00:00:52 +01:00
public:
_FORCE_INLINE_ T &operator[](int p_index) { return mem[p_index]; }
2014-02-10 02:10:30 +01:00
_FORCE_INLINE_ T *ptr() { return mem; }
2016-03-09 00:00:52 +01:00
Write() { mem = NULL; }
2014-02-10 02:10:30 +01:00
};
Read read() const {
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
Read r;
2016-03-09 00:00:52 +01:00
if (mem.is_valid()) {
r.lock = MID_Lock(mem);
r.mem = (const T *)((int *)r.lock.data() + 1);
2014-02-10 02:10:30 +01:00
}
2016-03-09 00:00:52 +01:00
return r;
2014-02-10 02:10:30 +01:00
}
Write write() {
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
Write w;
if (mem.is_valid()) {
copy_on_write();
w.lock = MID_Lock(mem);
w.mem = (T *)((int *)w.lock.data() + 1);
2014-02-10 02:10:30 +01:00
}
2016-03-09 00:00:52 +01:00
return w;
2014-02-10 02:10:30 +01:00
}
template <class MC>
void fill_with(const MC &p_mc) {
2014-02-10 02:10:30 +01:00
int c = p_mc.size();
2014-02-10 02:10:30 +01:00
resize(c);
Write w = write();
int idx = 0;
for (const typename MC::Element *E = p_mc.front(); E; E = E->next()) {
2014-02-10 02:10:30 +01:00
w[idx++] = E->get();
2014-02-10 02:10:30 +01:00
}
}
void remove(int p_index) {
int s = size();
ERR_FAIL_INDEX(p_index, s);
Write w = write();
for (int i = p_index; i < s - 1; i++) {
2014-02-10 02:10:30 +01:00
w[i] = w[i + 1];
2014-02-10 02:10:30 +01:00
};
w = Write();
resize(s - 1);
2014-02-10 02:10:30 +01:00
}
inline int size() const;
T get(int p_index) const;
void set(int p_index, const T &p_val);
void push_back(const T &p_val);
void append(const T &p_val) { push_back(p_val); }
void append_array(const DVector<T> &p_arr) {
2014-02-10 02:10:30 +01:00
int ds = p_arr.size();
if (ds == 0)
2014-02-10 02:10:30 +01:00
return;
int bs = size();
resize(bs + ds);
2014-02-10 02:10:30 +01:00
Write w = write();
Read r = p_arr.read();
for (int i = 0; i < ds; i++)
w[bs + i] = r[i];
2014-02-10 02:10:30 +01:00
}
Error insert(int p_pos, const T &p_val) {
int s = size();
ERR_FAIL_INDEX_V(p_pos, s + 1, ERR_INVALID_PARAMETER);
resize(s + 1);
{
Write w = write();
for (int i = s; i > p_pos; i--)
w[i] = w[i - 1];
w[p_pos] = p_val;
}
return OK;
}
2014-02-10 02:10:30 +01:00
bool is_locked() const { return mem.is_locked(); }
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
inline const T operator[](int p_index) const;
Error resize(int p_size);
2016-03-09 00:00:52 +01:00
void invert();
2016-03-09 00:00:52 +01:00
void operator=(const DVector &p_dvector) { reference(p_dvector); }
2014-02-10 02:10:30 +01:00
DVector() {}
DVector(const DVector &p_dvector) { reference(p_dvector); }
2014-02-10 02:10:30 +01:00
~DVector() { unreference(); }
};
template <class T>
2014-02-10 02:10:30 +01:00
int DVector<T>::size() const {
return mem.is_valid() ? ((mem.get_size() - sizeof(int)) / sizeof(T)) : 0;
2014-02-10 02:10:30 +01:00
}
template <class T>
2014-02-10 02:10:30 +01:00
T DVector<T>::get(int p_index) const {
return operator[](p_index);
}
template <class T>
void DVector<T>::set(int p_index, const T &p_val) {
2014-02-10 02:10:30 +01:00
if (p_index < 0 || p_index >= size()) {
ERR_FAIL_COND(p_index < 0 || p_index >= size());
2014-02-10 02:10:30 +01:00
}
Write w = write();
w[p_index] = p_val;
2014-02-10 02:10:30 +01:00
}
template <class T>
void DVector<T>::push_back(const T &p_val) {
2014-02-10 02:10:30 +01:00
resize(size() + 1);
set(size() - 1, p_val);
2014-02-10 02:10:30 +01:00
}
template <class T>
2014-02-10 02:10:30 +01:00
const T DVector<T>::operator[](int p_index) const {
if (p_index < 0 || p_index >= size()) {
T &aux = *((T *)0); //nullreturn
ERR_FAIL_COND_V(p_index < 0 || p_index >= size(), aux);
2014-02-10 02:10:30 +01:00
}
Read r = read();
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
return r[p_index];
}
template <class T>
2014-02-10 02:10:30 +01:00
Error DVector<T>::resize(int p_size) {
if (dvector_lock)
dvector_lock->lock();
bool same = p_size == size();
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
if (dvector_lock)
dvector_lock->unlock();
2016-03-09 00:00:52 +01:00
// no further locking is necesary because we are supposed to own the only copy of this (using copy on write)
2014-02-10 02:10:30 +01:00
if (same)
return OK;
if (p_size == 0) {
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
unreference();
return OK;
}
copy_on_write(); // make it unique
2016-03-09 00:00:52 +01:00
ERR_FAIL_COND_V(mem.is_locked(), ERR_LOCKED); // if after copy on write, memory is locked, fail.
2016-03-09 00:00:52 +01:00
if (p_size > size()) {
2016-03-09 00:00:52 +01:00
int oldsize = size();
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
MID_Lock lock;
2016-03-09 00:00:52 +01:00
if (oldsize == 0) {
2014-02-10 02:10:30 +01:00
mem = dynalloc(p_size * sizeof(T) + sizeof(int));
lock = MID_Lock(mem);
int *rc = ((int *)lock.data());
*rc = 1;
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
} else {
if (dynrealloc(mem, p_size * sizeof(T) + sizeof(int)) != OK) {
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
ERR_FAIL_V(ERR_OUT_OF_MEMORY); // out of memory
}
2016-03-09 00:00:52 +01:00
lock = MID_Lock(mem);
2014-02-10 02:10:30 +01:00
}
2016-03-09 00:00:52 +01:00
T *t = (T *)((int *)lock.data() + 1);
2016-03-09 00:00:52 +01:00
for (int i = oldsize; i < p_size; i++) {
2016-03-09 00:00:52 +01:00
memnew_placement(&t[i], T);
2014-02-10 02:10:30 +01:00
}
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
lock = MID_Lock(); // clear
} else {
2016-03-09 00:00:52 +01:00
int oldsize = size();
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
MID_Lock lock(mem);
2016-03-09 00:00:52 +01:00
T *t = (T *)((int *)lock.data() + 1);
2016-03-09 00:00:52 +01:00
for (int i = p_size; i < oldsize; i++) {
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
t[i].~T();
}
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
lock = MID_Lock(); // clear
2016-03-09 00:00:52 +01:00
if (dynrealloc(mem, p_size * sizeof(T) + sizeof(int)) != OK) {
2016-03-09 00:00:52 +01:00
ERR_FAIL_V(ERR_OUT_OF_MEMORY); // wtf error
2014-02-10 02:10:30 +01:00
}
}
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
return OK;
}
template <class T>
void DVector<T>::invert() {
T temp;
Write w = write();
int s = size();
int half_s = s / 2;
2014-02-10 02:10:30 +01:00
for (int i = 0; i < half_s; i++) {
temp = w[i];
w[i] = w[s - i - 1];
w[s - i - 1] = temp;
}
}
2014-02-10 02:10:30 +01:00
#endif