///////////////////////////////////////////////////////////// // CINEMA 4D SDK // ///////////////////////////////////////////////////////////// // (c) MAXON Computer GmbH, all rights reserved // ///////////////////////////////////////////////////////////// #ifndef _GEDYNAMICARRAY_H_ #define _GEDYNAMICARRAY_H_ #ifdef __API_INTERN__ #include "hyperfile.h" #include "lib_zipfile.h" #else #include "ge_math.h" #include "c4d_file.h" #include "c4d_memory.h" #include "c4d_baselist.h" #include "c4d_general.h" #include "lib_zipfile.h" #endif #if defined __LINUX #include #elif defined __MAC #include #else #include #endif #include enum GeDynamicArrayType { DATYPE_NONE = 0, DATYPE_CHAR = -1, DATYPE_UCHAR = -2, DATYPE_WORD = -3, DATYPE_UWORD = -4, DATYPE_LONG = -5, DATYPE_ULONG = -6, DATYPE_REAL = -7, DATYPE_LREAL = -8, DATYPE_BOOL = -9, DATYPE_TIME = -10, DATYPE_VECTOR = -11, DATYPE_LVECTOR = -12, DATYPE_MATRIX = -13, DATYPE_LMATRIX = -14, DATYPE_STRING = -15, DATYPE_FILENAME = -16, DATYPE_LLONG = -17, DATYPE_SREAL = -18, DATYPE_CONTAINER = -19, DATYPE_SVECTOR = -20, DATYPE_SMATRIX = -21 } ENUM_END_LIST(GeDynamicArrayType); #if 0 #define CHECKMEM(x) GeCheck(x) #else #define CHECKMEM(x) #endif class GeDynamicArrayFileData { public: GeDynamicArrayFileData(GeDynamicArrayType type = DATYPE_NONE, Int32 offset = 0) : d_type(type), d_offset(offset) { } ~GeDynamicArrayFileData() { } GeDynamicArrayType d_type; //The type, e.g. DATYPE_CHAR Int32 d_offset; //The offset from the start of the structure }; //GeDynamicArray file structure helper, arguments are s = Struct, m = Member, t = type #define GeDynamicArrayFile(s, m, t) GeDynamicArrayFileData(t, offsetof(s, m)) inline Bool GeDynamicArrayWriteable(Int32 type) { switch (type) { case DATYPE_CHAR: case DATYPE_WORD: case DATYPE_LONG: case DATYPE_REAL: case DATYPE_LREAL: case DATYPE_SREAL: case DATYPE_LLONG: return true; default: break; } return false; } inline Int GeDynamicArrayStructSizeCheck(GeDynamicArrayFileData* list, Int count) { if (!list) return 0; Int size = 0, i = 0; for (i = count - 1; i >= 0; --i) { switch (list[i].d_type) { default: case DATYPE_NONE: break; case DATYPE_CHAR: size += sizeof(Char); break; case DATYPE_UCHAR: size += sizeof(UChar); break; case DATYPE_WORD: size += sizeof(Int16); break; case DATYPE_UWORD: size += sizeof(UInt16); break; case DATYPE_LONG: size += sizeof(Int32); break; case DATYPE_ULONG: size += sizeof(UInt32); break; case DATYPE_REAL: size += sizeof(Float); break; case DATYPE_LREAL: size += sizeof(Float64); break; case DATYPE_BOOL: size += sizeof(Bool); break; case DATYPE_TIME: size += sizeof(BaseTime); break; case DATYPE_VECTOR: size += sizeof(Vector); break; case DATYPE_LVECTOR: size += sizeof(Vector64); break; case DATYPE_SVECTOR: size += sizeof(Vector32); break; case DATYPE_MATRIX: size += sizeof(Matrix); break; case DATYPE_LMATRIX: size += sizeof(Matrix64); break; case DATYPE_SMATRIX: size += sizeof(Matrix32); break; case DATYPE_STRING: size += sizeof(String); break; case DATYPE_FILENAME: size += sizeof(Filename); break; case DATYPE_LLONG: size += sizeof(Int64); break; case DATYPE_SREAL: size += sizeof(Float32); break; case DATYPE_CONTAINER: size += sizeof(BaseContainer); break; } } return size; } //dynamic array template template class GeDynamicArray { protected: TYPE* ptr; TYPE* l_ptr; Int l_cnt; Int totcnt; Int blocksize; Int count; public: GeDynamicArray(); GeDynamicArray(Int size); GeDynamicArray(Int size, Int block); GeDynamicArray(const GeDynamicArray& g); ~GeDynamicArray(void); typedef void GeDynamicArrayCallback (Int index, TYPE * value, void* data); TYPE* Release(void); void FreeArray(void); GeDynamicArray& operator =(const GeDynamicArray& t); GeDynamicArray& operator =(const TYPE* t); //friend Bool operator !(const GeDynamicArray &t) { return t.count == 0; } //operator TYPE * () { return l_ptr; } //TYPE * const *operator &() { return &l_ptr; } Bool Content() { return l_ptr != nullptr; } TYPE* GetPtr() { return l_ptr; } TYPE& operator[] (Int32 i) const { DebugAssert(i >= 0 && i < count); return l_ptr[i]; } TYPE& operator[] (Int64 i) const { DebugAssert(i >= 0 && i < count); return l_ptr[i]; } Int GetCount(void) const { return count; } void SetCount(Int c); Int GetTotCount(void) const { return totcnt - l_cnt; } void SetBlockSize(Int size); Int GetBlockSize(void) const { return blocksize; } Bool ReadUsingFunction(HyperFile* hf, Int32 level); Bool WriteUsingFunction(HyperFile* hf); Bool Read(HyperFile* hf, GeDynamicArray& typelist); Bool Write(HyperFile* hf, GeDynamicArray& typelist); void DoToAll(GeDynamicArrayCallback* callback, void* data); void DoToSome(GeDynamicArrayCallback* callback, void* data, Int do_start, Int do_end); void DoToSearch(GeDynamicArrayCallback* callback, void* data, TYPE p); Bool ReScopeNC(Int cnt, Bool make_new = true); Bool ReScope(Int cnt); Bool ReSizeNC(Int cnt, Bool make_new = true); Bool ReSize(Int cnt); Bool ReSize(Int c_from, Int c_to); inline void Fill(Int c_from, Int c_to, TYPE t); inline void Fill(TYPE t); Bool Insert(TYPE p, Int index); Bool Insert(const TYPE* p, Int index, Int cnt); Bool MergeIn(GeDynamicArray& p, Int index); Bool InsertSpace(Int index, Int amount, Bool clear = true, Bool makenew = true); inline Bool Push(TYPE p); Bool Remove(Int index, Int amount = 1); inline void RemoveAll(TYPE p); TYPE Pop(void); inline Int Find(TYPE p); inline Int Find(TYPE p, Int index); void Shift(Int index, Int cnt); void ShiftBlock(Int b_from, Int b_to, Int amount); void Grab(TYPE* p, Int amount); }; template GeDynamicArray::GeDynamicArray(void) { ptr = nullptr; blocksize = 4; FreeArray(); } template GeDynamicArray::GeDynamicArray(Int size) { ptr = nullptr; blocksize = 4; FreeArray(); ReScope(size); } template GeDynamicArray::GeDynamicArray(Int size, Int block) { ptr = nullptr; blocksize = block; FreeArray(); ReScope(size); } template GeDynamicArray::GeDynamicArray(const GeDynamicArray& g) { ptr = nullptr; blocksize = g.blocksize; FreeArray(); *this = g; } template GeDynamicArray::~GeDynamicArray(void) { FreeArray(); } template TYPE* GeDynamicArray::Release(void) { CHECKMEM(ptr); memmove(ptr, l_ptr, sizeof(TYPE) * count); blocksize = 4; Int cnt = count; count += l_cnt; l_ptr = ptr; CHECKMEM(ptr); l_cnt = 0; ReSizeNC(cnt); TYPE* tmp = ptr; ptr = nullptr; l_ptr = nullptr; totcnt = 0; count = 0; l_cnt = 0; return tmp; } template void GeDynamicArray::FreeArray(void) { if (ptr) { Int i = 0; TYPE* buf = l_ptr; CHECKMEM(ptr); for (i = 0; i < count; i++, buf++) buf->~TYPE(); DeleteMem(ptr); } ptr = nullptr; l_ptr = nullptr; count = 0; totcnt = 0; l_cnt = 0; } template GeDynamicArray& GeDynamicArray::operator =(const GeDynamicArray& t) { CHECKMEM(ptr); if (t.blocksize != blocksize) { FreeArray(); SetBlockSize(t.blocksize); } if (!ReScopeNC(t.count)) return *this; Int i = 0; TYPE* pbuf = l_ptr; TYPE* tbuf = t.l_ptr; for (i = 0; i < count; i++, pbuf++, tbuf++) *pbuf = *tbuf; CHECKMEM(ptr); return *this; } template GeDynamicArray& GeDynamicArray::operator =(const TYPE* t) { CHECKMEM(ptr); FreeArray(); Int cnt = sizeof(*t) / sizeof(TYPE); if (!ReScopeNC(cnt)) return *this; Int i = 0; TYPE* pbuf = l_ptr; const TYPE* tbuf = t; for (i = 0; i < count; i++, pbuf++, tbuf++) *pbuf = *tbuf; CHECKMEM(ptr); return *this; } template void GeDynamicArray::SetCount(Int c) { DebugAssert(c >= 0 && c <= totcnt - l_cnt); if (c > totcnt - l_cnt) return; CHECKMEM(ptr); TYPE* buf = &l_ptr[c]; for (Int i = c; i < count; i++, buf++) buf->~TYPE(); count = c; } template void GeDynamicArray::SetBlockSize(Int size) { blocksize = size; } template Bool GeDynamicArray::ReadUsingFunction(HyperFile* hf, Int32 level) { Int32 dlevel = 0; if (!hf->ReadInt32(&dlevel)) return false; if (dlevel >= 1) { FreeArray(); Int64 p; if (!hf->ReadInt64(&p)) return false; blocksize = Int(p); if (!hf->ReadInt64(&p)) return false; if (!ReScope(Int(p))) return false; for (p = 0; p < count; p++) { if (!l_ptr[p].Read(hf, level)) return false; } } return true; } template Bool GeDynamicArray::WriteUsingFunction(HyperFile* hf) { if (!hf->WriteInt32(1)) return false; //Level if (!hf->WriteInt64(Int64(blocksize))) return false; if (!hf->WriteInt64(Int64(count))) return false; Int i = 0; for (i = 0; i < count; i++) { if (!l_ptr[i].Write(hf)) return false; } return true; } //Read array from hyperfile with list of types in order of how they appear in structures template Bool GeDynamicArray::Read(HyperFile* hf, GeDynamicArray& typelist) { if (typelist.GetCount() == 0 || !hf) return false; Int64 r_count = 0, r_blocksize = 0; Int32 r_level = 0; Int tsize = sizeof(TYPE); DebugAssert(GeDynamicArrayStructSizeCheck(typelist.GetPtr(), typelist.GetCount()) <= tsize); if (!hf->ReadInt32(&r_level)) return false; if (r_level < 0) { r_level = -r_level; if (!hf->ReadInt64(&r_count)) return false; if (!hf->ReadInt64(&r_blocksize)) return false; } else { r_count = r_level; if (!hf->ReadInt32(&r_level)) return false; r_blocksize = r_level; r_level = 0; } SetBlockSize(Int(r_blocksize)); if (!ReScopeNC(Int(r_count))) return false; if (count == 0) return true; if (!tsize) return true; CHECKMEM(ptr); if (r_level > 0 && typelist.GetCount() == 1 && GeDynamicArrayWriteable(typelist[0].d_type)) { //Write arrays when there's only one type being written Char* ttbuf = &((Char*)l_ptr)[typelist[0].d_offset]; switch (typelist[0].d_type) { case DATYPE_CHAR: if (!hf->ReadArray((void*)ttbuf, HYPERFILEARRAY_CHAR, tsize, count)) return false; break; case DATYPE_WORD: if (!hf->ReadArray((void*)ttbuf, HYPERFILEARRAY_WORD, tsize, count)) return false; break; case DATYPE_LONG: if (!hf->ReadArray((void*)ttbuf, HYPERFILEARRAY_LONG, tsize, count)) return false; break; case DATYPE_REAL: if (!hf->ReadArray((void*)ttbuf, HYPERFILEARRAY_REAL, tsize, count)) return false; break; case DATYPE_SREAL: if (!hf->ReadArray((void*)ttbuf, HYPERFILEARRAY_SREAL, tsize, count)) return false; break; case DATYPE_LREAL: if (!hf->ReadArray((void*)ttbuf, HYPERFILEARRAY_LREAL, tsize, count)) return false; break; case DATYPE_LLONG: if (!hf->ReadArray((void*)ttbuf, HYPERFILEARRAY_LLONG, tsize, count)) return false; break; default: break; } } else { TYPE* tbuf = l_ptr; Int i = 0, o = 0; Char* ttbuf = nullptr; for (i = 0; i < count; i++, tbuf++) { for (o = 0; o < typelist.GetCount(); o++) { ttbuf = &((Char*)tbuf)[typelist[o].d_offset]; switch (typelist[o].d_type) { case DATYPE_CHAR: if (!hf->ReadChar(ttbuf)) return false; break; case DATYPE_UCHAR: if (!hf->ReadUChar((UChar*) ttbuf)) return false; break; case DATYPE_WORD: if (!hf->ReadInt16((Int16*) ttbuf)) return false; break; case DATYPE_UWORD: if (!hf->ReadUInt16((UInt16*) ttbuf)) return false; break; case DATYPE_LONG: if (!hf->ReadInt32((Int32*) ttbuf)) return false; break; case DATYPE_ULONG: if (!hf->ReadUInt32((UInt32*) ttbuf)) return false; break; case DATYPE_REAL: if (!hf->ReadFloat((Float*) ttbuf)) return false; break; case DATYPE_LREAL: if (!hf->ReadFloat64((Float64*) ttbuf)) return false; break; case DATYPE_SREAL: if (!hf->ReadFloat32((Float32*) ttbuf)) return false; break; case DATYPE_BOOL: if (!hf->ReadBool((Bool*) ttbuf)) return false; break; case DATYPE_TIME: if (!hf->ReadTime((BaseTime*) ttbuf)) return false; break; case DATYPE_VECTOR: if (!hf->ReadVector((Vector*) ttbuf)) return false; break; case DATYPE_SVECTOR: if (!hf->ReadVector32((Vector32*) ttbuf)) return false; break; case DATYPE_LVECTOR: if (!hf->ReadVector64((Vector64*) ttbuf)) return false; break; case DATYPE_MATRIX: if (!hf->ReadMatrix((Matrix*) ttbuf)) return false; break; case DATYPE_SMATRIX: if (!hf->ReadMatrix32((Matrix32*) ttbuf)) return false; break; case DATYPE_LMATRIX: if (!hf->ReadMatrix64((Matrix64*) ttbuf)) return false; break; case DATYPE_STRING: if (!hf->ReadString((String*) ttbuf)) return false; break; case DATYPE_FILENAME: if (!hf->ReadFilename((Filename*) ttbuf)) return false; break; case DATYPE_LLONG: if (!hf->ReadInt64((Int64*) ttbuf)) return false; break; case DATYPE_CONTAINER: if (!hf->ReadContainer((BaseContainer*) ttbuf, true)) return false; break; default: break; } } } } CHECKMEM(ptr); return true; } //Write array to hyperfile template Bool GeDynamicArray::Write(HyperFile* hf, GeDynamicArray& typelist) { if (typelist.GetCount() == 0 || !hf) return false; Int64 r_count = Int64(count), r_blocksize = Int64(blocksize); Int tsize = sizeof(TYPE); DebugAssert(GeDynamicArrayStructSizeCheck(typelist.GetPtr(), typelist.GetCount()) <= tsize); if (!hf->WriteInt32(-1)) return false; //Level if (!hf->WriteInt64(r_count)) return false; if (!hf->WriteInt64(r_blocksize)) return false; if (!ptr || count == 0) return true; if (!tsize) return true; CHECKMEM(ptr); if (typelist.GetCount() == 1 && GeDynamicArrayWriteable(typelist[0].d_type)) { //Write arrays when there's only one type being written Char* ttbuf = &((Char*)l_ptr)[typelist[0].d_offset]; switch (typelist[0].d_type) { case DATYPE_CHAR: if (!hf->WriteArray((void*)ttbuf, HYPERFILEARRAY_CHAR, tsize, count)) return false; break; case DATYPE_WORD: if (!hf->WriteArray((void*)ttbuf, HYPERFILEARRAY_WORD, tsize, count)) return false; break; case DATYPE_LONG: if (!hf->WriteArray((void*)ttbuf, HYPERFILEARRAY_LONG, tsize, count)) return false; break; case DATYPE_REAL: if (!hf->WriteArray((void*)ttbuf, HYPERFILEARRAY_REAL, tsize, count)) return false; break; case DATYPE_LREAL: if (!hf->WriteArray((void*)ttbuf, HYPERFILEARRAY_LREAL, tsize, count)) return false; break; case DATYPE_SREAL: if (!hf->WriteArray((void*)ttbuf, HYPERFILEARRAY_SREAL, tsize, count)) return false; break; case DATYPE_LLONG: if (!hf->WriteArray((void*)ttbuf, HYPERFILEARRAY_LLONG, tsize, count)) return false; break; default: break; } } else { Int i = 0, o = 0; TYPE* tbuf = l_ptr; Char* ttbuf = nullptr; for (i = 0; i < count; i++, tbuf++) { for (o = 0; o < typelist.GetCount(); o++) { ttbuf = &((Char*)tbuf)[typelist[o].d_offset]; switch (typelist[o].d_type) { case DATYPE_CHAR: if (!hf->WriteChar(ttbuf[0])) return false; break; case DATYPE_UCHAR: if (!hf->WriteUChar(((UChar*) ttbuf)[0])) return false; break; case DATYPE_WORD: if (!hf->WriteInt16(((Int16*) ttbuf)[0])) return false; break; case DATYPE_UWORD: if (!hf->WriteUInt16(((UInt16*) ttbuf)[0])) return false; break; case DATYPE_LONG: if (!hf->WriteInt32(((Int32*) ttbuf)[0])) return false; break; case DATYPE_ULONG: if (!hf->WriteUInt32(((UInt32*) ttbuf)[0])) return false; break; case DATYPE_REAL: if (!hf->WriteFloat(((Float*) ttbuf)[0])) return false; break; case DATYPE_SREAL: if (!hf->WriteFloat32(((Float32*) ttbuf)[0])) return false; break; case DATYPE_LREAL: if (!hf->WriteFloat64(((Float64*) ttbuf)[0])) return false; break; case DATYPE_BOOL: if (!hf->WriteBool(((Bool*) ttbuf)[0])) return false; break; case DATYPE_TIME: if (!hf->WriteTime(((BaseTime*) ttbuf)[0])) return false; break; case DATYPE_VECTOR: if (!hf->WriteVector(((Vector*) ttbuf)[0])) return false; break; case DATYPE_SVECTOR: if (!hf->WriteVector32(((Vector32*) ttbuf)[0])) return false; break; case DATYPE_LVECTOR: if (!hf->WriteVector64(((Vector64*) ttbuf)[0])) return false; break; case DATYPE_MATRIX: if (!hf->WriteMatrix(((Matrix*) ttbuf)[0])) return false; break; case DATYPE_SMATRIX: if (!hf->WriteMatrix32(((Matrix32*) ttbuf)[0])) return false; break; case DATYPE_LMATRIX: if (!hf->WriteMatrix64(((Matrix64*) ttbuf)[0])) return false; break; case DATYPE_STRING: if (!hf->WriteString(((String*) ttbuf)[0])) return false; break; case DATYPE_FILENAME: if (!hf->WriteFilename(((Filename*) ttbuf)[0])) return false; break; case DATYPE_LLONG: if (!hf->WriteInt64(((Int64*) ttbuf)[0])) return false; break; case DATYPE_CONTAINER: if (!hf->WriteContainer(((BaseContainer*) ttbuf)[0])) return false; break; default: break; } } } } CHECKMEM(ptr); return true; } //routine to execute code on all entries in ptr array template void GeDynamicArray::DoToAll(GeDynamicArrayCallback* callback, void* data) { if (!ptr) return; CHECKMEM(ptr); Int i = 0; TYPE* buf = l_ptr; for (i = 0; i < count; i++, buf++) { callback(i, buf, data); } CHECKMEM(ptr); } //routine to execute code on some entries in ptr array template void GeDynamicArray::DoToSome(GeDynamicArrayCallback* callback, void* data, Int do_start, Int do_end) { if (!ptr) return; CHECKMEM(ptr); Int dend = do_end; Int dsta = do_start; if (dend < dsta) dend = do_start, dsta = do_end; if (dend > count) dend = count; if (dsta < 0) dsta = 0; TYPE* buf = &l_ptr[dsta]; Int i = 0; for (i = dsta; i < dend; i++, buf++) { callback(i, buf, data); } CHECKMEM(ptr); } //routine to execute code on entries that match TYPE p in ptr array template void GeDynamicArray::DoToSearch(GeDynamicArrayCallback* callback, void* data, TYPE p) { if (!ptr) return; CHECKMEM(ptr); TYPE* buf = l_ptr; Int i = 0; for (i = 0; i < count; i++, buf++) { if (*buf == p) callback(i, buf, data); } CHECKMEM(ptr); } //Resizes the array without retatining the data and without clearing the data template Bool GeDynamicArray::ReScopeNC(Int cnt, Bool make_new) { if (cnt <= 0) { FreeArray(); return true; } if (!blocksize) { CriticalStop(); return false; } Int64 nsize = (((cnt + l_cnt - 1) / blocksize) + 1) * blocksize, i = 0; TYPE* buf = nullptr; CHECKMEM(ptr); if (count) { for (i = 0, buf = l_ptr; i < count; i++, buf++) buf->~TYPE(); } if (nsize != totcnt && !(cnt > count && nsize < totcnt)) { //Check against massive numbers Int64 tsize = nsize * Int64(sizeof(TYPE)); if (tsize != Int(tsize) || tsize < nsize || tsize < cnt) { DebugAssert(false); //To avoid people allocating more memory than is possible on the system return false; // } if (!ptr) ptr = NewMem(TYPE, (Int)nsize); else ptr = ReallocMem(ptr, (Int)nsize); if (!ptr) return false; l_ptr = &ptr[l_cnt]; totcnt = (Int)nsize; } if (make_new) { for (i = 0, buf = l_ptr; i < cnt; i++, buf++) new(buf)TYPE; } count = cnt; CHECKMEM(ptr); return true; } //Resizes the array without retaining the data template Bool GeDynamicArray::ReScope(Int cnt) { if (cnt <= 0) { FreeArray(); return true; } if (!blocksize) { CriticalStop(); return false; } Int64 nsize = (((cnt + l_cnt - 1) / blocksize) + 1) * blocksize, i = 0; TYPE* buf = nullptr; CHECKMEM(ptr); if (count) { for (i = 0, buf = l_ptr; i < count; i++, buf++) buf->~TYPE(); } if (nsize != totcnt && !(cnt > count && nsize < totcnt)) { //Check against massive numbers Int64 tsize = nsize * Int64(sizeof(TYPE)); if (tsize != Int(tsize) || tsize < nsize || tsize < cnt) { DebugAssert(false); //To avoid people allocating more memory than is possible on the system return false; // } if (!ptr) ptr = NewMem(TYPE, (Int)nsize); else ptr = ReallocMem(ptr, (Int)nsize); if (!ptr) return false; l_ptr = &ptr[l_cnt]; totcnt = (Int)nsize; } ClearMemType(l_ptr, cnt); for (i = 0, buf = l_ptr; i < cnt; i++, buf++) new(buf)TYPE; count = cnt; CHECKMEM(ptr); return true; } //Resizes the array without clearing the memory used template Bool GeDynamicArray::ReSizeNC(Int cnt, Bool make_new) { if (cnt == count) return true; if (cnt < count) return Remove(cnt, count - cnt); return InsertSpace(count, cnt - count, false, make_new); } template Bool GeDynamicArray::ReSize(Int cnt) { if (cnt == count) return true; if (cnt < count) return Remove(cnt, count - cnt); return InsertSpace(count, cnt - count, true); } //Reize the array down template Bool GeDynamicArray::ReSize(Int c_from, Int c_to) { Int t_from = VCut(c_from, 0, count), t_to = VCut(c_to + 1, 0, count); if (t_from == t_to) return ReSize(0); if (t_from > t_to) { Int temp = t_from; t_from = t_to; t_to = temp; } Shift(t_from, -t_from); return ReSize(t_to - t_from); } //Fill the array with TYPE t between c_from and c_to template inline void GeDynamicArray::Fill(Int c_from, Int c_to, TYPE t) { Int t_from = VCut(c_from, 0, count), t_to = VCut(c_to + 1, 0, count); if (t_from == t_to) return; if (t_from > t_to) { Int temp = t_from; t_from = t_to; t_to = temp; } TYPE* buf = nullptr; Int i = 0; CHECKMEM(ptr); for (i = t_from, buf = &l_ptr[t_from]; i < t_to; i++, buf++) *buf = t; CHECKMEM(ptr); } //Fill the array with TYPE t template inline void GeDynamicArray::Fill(TYPE t) { TYPE* buf = l_ptr; Int i = 0; CHECKMEM(ptr); for (i = 0; i < count; i++, buf++) *buf = t; CHECKMEM(ptr); } //Add value to the array at index //and shifts array up template Bool GeDynamicArray::Insert(TYPE p, Int index) { if (index < 0) return false; CHECKMEM(ptr); if (!InsertSpace(index, 1, true)) return false; l_ptr[index] = p; CHECKMEM(ptr); return true; } //Inserts (copies) an existing array into this one template Bool GeDynamicArray::Insert(const TYPE* p, Int index, Int cnt) { if (cnt <= 0) return true; if (index < 0 || index > count || !p) return false; CHECKMEM(ptr); if (!InsertSpace(index, cnt, true)) return false; Int i = 0; TYPE* buf = &l_ptr[index]; const TYPE* pbuf = p; for (i = 0; i < cnt; i++, pbuf++, buf++) (*buf) = (*pbuf); CHECKMEM(ptr); return true; } //Merges an existing dynamic array into this one, this array becomes the owner template Bool GeDynamicArray::MergeIn(GeDynamicArray& p, Int index) { if (p.GetCount() <= 0) return true; if (index < 0 || index > count) return false; CHECKMEM(ptr); if (!InsertSpace(index, p.GetCount(), false, false)) return false; Int cnt = p.GetCount(); TYPE* data = p.Release(); if (!data) return false; CopyMemType(data, &l_ptr[index], cnt); DeleteMem(data); CHECKMEM(ptr); return true; } //Inserts a gap in the array template Bool GeDynamicArray::InsertSpace(Int index, Int amount, Bool clear, Bool makenew) { if (index < 0) return false; if (amount <= 0) return true; CHECKMEM(ptr); Int cnt = ((count > index) ? count : index) + amount; if (!blocksize) { CriticalStop(); return false; } if (index < (count >> 1)) //Insert space low { l_cnt -= amount; if (l_cnt < 0) //resize it's larger { Int64 nadd = (((-l_cnt - 1) / blocksize) + 1) * blocksize; //Check against massive numbers Int64 tsize = (Int64(totcnt) + nadd) * Int64(sizeof(TYPE)); if (tsize != Int(tsize) || tsize < (nadd + totcnt) || tsize < amount) { DebugAssert(false); //To avoid people allocating more memory than is possible on the system return false; // } totcnt += (Int)nadd; l_cnt += (Int)nadd; if (!ptr) ptr = NewMem(TYPE, (Int)totcnt); else ptr = ReallocMem(ptr, totcnt); if (!ptr) return false; l_ptr = &ptr[l_cnt]; if (index > 0) { memmove(&l_ptr[index + amount], &l_ptr[(amount - nadd) + index], sizeof(TYPE) * (count - index)); memmove(l_ptr, &l_ptr[amount - nadd], sizeof(TYPE) * index); } else { memmove(&l_ptr[amount], &l_ptr[amount - nadd], sizeof(TYPE) * count); } } else //just shift space in { if (index > 0) memmove(&ptr[l_cnt], l_ptr, sizeof(TYPE) * index); l_ptr = &ptr[l_cnt]; } } else //Insert space high { Int64 nsize = (((cnt + l_cnt - 1) / blocksize) + 1) * blocksize; if (nsize > totcnt) //Resize it's larger { //Check against massive numbers Int64 tsize = nsize * Int64(sizeof(TYPE)); if (tsize != Int(tsize) || tsize < nsize || tsize < amount) { DebugAssert(false); //To avoid people allocating more memory than is possible on the system return false; } if (!ptr) ptr = NewMem(TYPE, (Int)nsize); else ptr = ReallocMem(ptr, (Int)nsize); if (!ptr) return false; l_ptr = &ptr[l_cnt]; totcnt = (Int)nsize; } //Shift space in if (index < count) { memmove(&(l_ptr[index + amount]), &(l_ptr[index]), sizeof(TYPE) * (count - index)); } } Int i = 0; TYPE* buf = nullptr; if (clear) { if (count < index) //Clear space up till index ClearMemType(&l_ptr[count], (index - count)); //Clear space from index over amount ClearMemType(&l_ptr[index], amount); } if (makenew) { if (count < index) //Placement new from end of array to index for (i = count, buf = &l_ptr[count]; i < index; i++, buf++) new(buf)TYPE; // Placement new over amount for (i = 0, buf = &l_ptr[index]; i < amount; i++, buf++) new(buf)TYPE; } count = cnt; CHECKMEM(ptr); return true; } //Add value to the end of the array template Bool GeDynamicArray::Push(TYPE p) { return Insert(p, count); } //Remove value from the array at index //and shifts array down template Bool GeDynamicArray::Remove(Int index, Int amount) { if (amount <= 0) return true; if (index < 0 || index >= count || !ptr) return false; if (!blocksize) { CriticalStop(); return false; } if (index <= 0 && amount >= count) { FreeArray(); return true; } Int top = VMin(index + amount, count), amt = top - index; Int i = 0; TYPE* buf = nullptr; CHECKMEM(ptr); for (i = 0, buf = &l_ptr[index]; i < amt; i++, buf++) buf->~TYPE(); if (index < (count >> 1)) { l_cnt += amt; if (index > 0) memmove(&l_ptr[amt], l_ptr, sizeof(TYPE) * index); //shift l_ptr up l_ptr = &ptr[l_cnt]; if (l_cnt >= blocksize) { Int nsub = (l_cnt / blocksize) * blocksize; totcnt -= nsub; l_cnt -= nsub; memmove(&l_ptr[-nsub], l_ptr, sizeof(TYPE) * (count - amt)); //Shift down ptr = ReallocMem(ptr, totcnt); if (!ptr) return false; l_ptr = &ptr[l_cnt]; } } else { Int nsize = ((((count + l_cnt - 1) - amt) / blocksize) + 1) * blocksize; if (index < count - 1) memmove(&(l_ptr[index]), &(l_ptr[index + amt]), sizeof(TYPE) * (count - (index + amt))); if (nsize < totcnt) { ptr = ReallocMem(ptr, nsize); if (!ptr) return false; l_ptr = &ptr[l_cnt]; totcnt = nsize; } } count -= amt; CHECKMEM(ptr); return true; } //Removes all that match p from the array template inline void GeDynamicArray::RemoveAll(TYPE p) { Int index = 0; while (true) { index = Find(p, index); if (index == NOTOK) break; Remove(index); } } //Remove value from the end of the array template TYPE GeDynamicArray::Pop(void) { if (count <= 0) return TYPE(); TYPE result = l_ptr[count - 1]; Remove(count - 1); return result; } //Find the index of type that matches type p template inline Int GeDynamicArray::Find(TYPE p) { return Find(p, 0); } //Try to find an object from index onwards that matches type p template inline Int GeDynamicArray::Find(TYPE p, Int index) { if (index >= count || !ptr) return NOTOK; CHECKMEM(ptr); TYPE* buf = &l_ptr[index]; Int i = 0; for (i = index; i < count; i++, buf++) { if (*buf == p) return i; } CHECKMEM(ptr); return NOTOK; } //Shift array down or up from index value // negative to move down, positive to move up template void GeDynamicArray::Shift(Int index, Int cnt) { ShiftBlock(index, count, cnt); } //Shift a block of the array up or down // negative to move down, positive to move up template void GeDynamicArray::ShiftBlock(Int b_from, Int b_to, Int amount) { Int block_start = VMin(b_from, b_to); Int block_end = VMax(b_from, b_to); if (amount == 0 || block_start == block_end || block_start < 0 || block_end > count) return; CHECKMEM(ptr); TYPE* buf = nullptr; Int i = 0; if (amount > 0) { Int istart = block_start; Int iend = block_end - amount; if (iend < istart) iend = istart; Int m_min = VMin(count, VMax(block_end, istart + amount)); Int m_max = VMin(count, block_end + amount); for (i = m_min, buf = &l_ptr[m_min]; i < m_max; i++, buf++) buf->~TYPE(); m_min = VMin(count, istart + amount); if (m_max - m_min > 0) memmove(&(l_ptr[m_min]), &(l_ptr[istart]), sizeof(TYPE) * (m_max - m_min)); iend = VMin(istart + amount, block_end); ClearMemType(&l_ptr[istart], (iend - istart)); for (i = istart, buf = &l_ptr[istart]; i < iend; i++, buf++) new(buf)TYPE; } else { Int istart = block_start; Int iend = block_end; Int m_shift = 0; Int m_end = VMax(0, iend + amount), m_max = VMin(m_end, istart); Int m_to = istart + amount; if (m_to < 0) { m_to = 0; m_shift = -(istart + amount); } for (i = m_to, buf = &l_ptr[m_to]; i < m_max; i++, buf++) buf->~TYPE(); if (m_end - m_to > 0) memmove(&(l_ptr[m_to]), &(l_ptr[istart + m_shift]), sizeof(TYPE) * (m_end - m_to)); istart = VMax(block_start, m_end); ClearMemType(&l_ptr[istart], (iend - istart)); for (i = istart, buf = &l_ptr[istart]; i < iend; i++, buf++) new(buf)TYPE; } CHECKMEM(ptr); } //Dynamic Array takes control of a datablock given to it template void GeDynamicArray::Grab(TYPE* p, Int amount) { CHECKMEM(ptr); FreeArray(); ptr = l_ptr = p; l_cnt = 0; if (ptr) totcnt = count = amount; else totcnt = count = 0; CHECKMEM(ptr); } //----------------------------------------- //Safe Variant, this can be accessed via [] safely and will never get out of bounds template class GeSafeDynamicArray : public GeDynamicArray { INSTANCEOF(GeSafeDynamicArray, GeDynamicArray ) public: GeSafeDynamicArray(void) { this->ptr = nullptr; this->blocksize = 4; this->FreeArray(); } GeSafeDynamicArray(Int size) { this->ptr = nullptr; this->blocksize = 4; this->FreeArray(); this->ReScope(size); } GeSafeDynamicArray(Int size, Int block) { this->ptr = nullptr; this->blocksize = block; this->FreeArray(); this->ReScope(size); } ~GeSafeDynamicArray(void) { this->FreeArray(); } GeSafeDynamicArray& operator =(const GeSafeDynamicArray& t) { this->FreeArray(); this->SetBlockSize(t.GetBlockSize()); this->ReScopeNC(t.count); CHECKMEM(ptr); Int i = 0; TYPE* buf = this->l_ptr, *buf2 = t.l_ptr; for (i = 0; i < this->count; i++, buf++, buf2++) (*buf) = (*buf2); CHECKMEM(ptr); return *this; } TYPE& operator[](Int32 i) const { CHECKMEM(ptr); if (this->count == 0) { ((GeDynamicArray*) this)->ReScope(1); return this->l_ptr[0]; } if (i < 0) return this->l_ptr[0]; if (i >= this->count) return this->l_ptr[this->count - 1]; return this->l_ptr[i]; } TYPE& operator[](Int64 i) const { CHECKMEM(ptr); if (this->count == 0) { ((GeDynamicArray*) this)->ReScope(1); return this->l_ptr[0]; } if (i < 0) return this->l_ptr[0]; if (i >= this->count) return this->l_ptr[this->count - 1]; return this->l_ptr[i]; } }; //-------------------------------------------------------- //Automatic variant, this will resize based on the index you specify in array[index] #define DEFAULT_ADR_BLOCK_SIZE 16 template class GeAutoDynamicArray : public GeDynamicArray { INSTANCEOF(GeAutoDynamicArray, GeDynamicArray ) public: GeAutoDynamicArray(void) { this->ptr = nullptr; this->blocksize = DEFAULT_ADR_BLOCK_SIZE; this->FreeArray(); } GeAutoDynamicArray(Int size) { this->ptr = nullptr; this->blocksize = DEFAULT_ADR_BLOCK_SIZE; this->FreeArray(); this->ReScope(size); } GeAutoDynamicArray(Int size, Int block) { this->ptr = nullptr; this->blocksize = block; this->FreeArray(); this->ReScope(size); } ~GeAutoDynamicArray(void) { this->FreeArray(); } GeAutoDynamicArray& operator =(const GeAutoDynamicArray& t) { this->FreeArray(); this->SetBlockSize(t.GetBlockSize()); this->ReScopeNC(t.count); CHECKMEM(ptr); Int i = 0; TYPE* buf = this->l_ptr, *buf2 = t.l_ptr; for (i = 0; i < this->count; i++, buf++, buf2++) (*buf) = (*buf2); CHECKMEM(ptr); return *this; } GeAutoDynamicArray& operator =(TYPE* t) { this->FreeArray(); this->ptr = t; this->count = sizeof(this->ptr) / sizeof(TYPE); this->totcnt = this->count; this->l_ptr = &(this->ptr[this->l_cnt]); CHECKMEM(ptr); return *this; } TYPE& operator[](Int32 i) const { CHECKMEM(ptr); if (this->count == 0) { ((GeDynamicArray*) this)->ReScope(1); } if (i < 0) return this->l_ptr[0]; if (i >= this->count) { ((GeDynamicArray*) this)->ReSize(i + 1); } return this->l_ptr[i]; } TYPE& operator[](Int64 i) const { CHECKMEM(ptr); if (this->count == 0) { ((GeDynamicArray*) this)->ReScope(1); } if (i < 0) return this->l_ptr[0]; if (i >= this->count) { ((GeDynamicArray*) this)->ReSize(i + 1); } return this->l_ptr[i]; } }; #endif