/* Crystal Space utility library: vector class interface Copyright (C) 1998,1999,2000 by Andrew Zabolotny This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __PS_GROWARRAY_H__ #define __PS_GROWARRAY_H__ /**\file * vector class interface */ /**\internal * Default growstep for growing arrays. */ #define PS_GARRAY_GROWSTEP 16 /**\internal * If SetLength() is called and the new length is PS_GARRAY_SHRINKLIMIT * smaller than the limit then the new array will be shrinked. */ #define PS_GARRAY_SHRINKLIMIT 1000 /// \internal Common macro for declarations in this file. #define PS_TYPEDEF_GROWING_ARRAY_EXT(Name, Type, ExtraConstructor, Extra) \ class Name \ { \ typedef Type ga_type; \ ga_type *root; \ int limit; \ int length; \ public: \ int Limit () const \ { return limit; } \ void SetLimit (int inlimit) \ { \ if (limit == inlimit) return; \ if ((limit = inlimit)!=0) \ root = (ga_type *)realloc (root, limit * sizeof (ga_type)); \ else \ { if (root) { free (root); root = NULL; } } \ } \ Name () \ { limit = length = 0; root = NULL; ExtraConstructor; } \ ~Name () \ { SetLimit (0); } \ int Length () const \ { return length; } \ void SetLength (int inlength, int growstep = PS_GARRAY_GROWSTEP) \ { \ length = inlength; \ int newlimit = ((length + (growstep - 1)) / growstep) * growstep; \ if (newlimit > limit || newlimit < limit-PS_GARRAY_SHRINKLIMIT) \ SetLimit (newlimit); \ } \ ga_type &operator [] (int n) \ { CS_ASSERT (n >= 0 && n < limit); return root [n]; } \ const ga_type &operator [] (int n) const \ { CS_ASSERT (n >= 0 && n < limit); return root [n]; } \ ga_type &Get (int n) \ { CS_ASSERT (n >= 0 && n < limit); return root [n]; } \ void Delete (int n) \ { CS_ASSERT (n >= 0 && n < limit); \ memmove (root + n, root + n + 1, (length - n - 1) * sizeof (ga_type)); \ SetLength (length-1); } \ ga_type *GetArray () \ { return root; } \ int Push (const ga_type &val, int growstep = PS_GARRAY_GROWSTEP) \ { \ SetLength (length + 1, growstep); \ memcpy (root + length - 1, &val, sizeof (ga_type)); \ return length-1; \ } \ void Insert (int pos, const ga_type &val, int growstep=PS_GARRAY_GROWSTEP)\ { \ CS_ASSERT (pos>=0 && pos<=length); \ SetLength (length + 1, growstep); \ memmove (root+pos+1, root+pos, sizeof(ga_type) * (length-pos-1)); \ memcpy (root + pos, &val, sizeof (ga_type)); \ } \ Extra \ } /** A Set of Availables Extra for PS_TYPEDEF_GROWING_ARRAY_EXT * * */ // HANDLECHUNKS allows to insert or delete segments arrays into the array #define HANDLECHUNKS \ bool InsertChunk (int n, int size , Type* Item) \ { /* no run-time checks here, just in debug mode */ \ CS_ASSERT( n <= count ); \ CS_ASSERT( size>0 ); \ SetLength ( length + size); /* Increments 'count' as a side-effect */ \ const int nmove = (length - (n + size)); \ if (nmove > 0) \ memmove ( &root [ n + size ] , &root [ n ] , nmove * sizeof (Type) ); \ \ memcpy ( &root [ n ] , Item , size * sizeof (Type) ); \ return true; \ } \ bool DeleteChunk (int n, int size) \ { /* no run-time checks here, just in debug mode */ \ CS_ASSERT( (n >= 0) && (n < length) ); \ CS_ASSERT( (size > 0) && ( n + size <= length ) ); \ const int nmove = length - n - size; \ if ( nmove > 0 ) \ memmove (&root [ n ] , &root [ n + size ] , nmove * sizeof (Type) ); \ \ SetLength ( length - size ); \ return true; \ } /** * This is a macro that will declare a growable array variable that is able to * contain a number of elements of given type.

* Methods: *

* Usage examples: *
 * PS_TYPEDEF_GROWING_ARRAY (csLightArray, csLight*);
 * PS_TYPEDEF_GROWING_ARRAY (csIntArray, int);
 * static csLightArray la;
 * static csIntArray ia;
 * 
*/ #define PS_TYPEDEF_GROWING_ARRAY(Name, Type) \ PS_TYPEDEF_GROWING_ARRAY_EXT (Name, Type, ;, ;) /** * Same as TYPEDEF_GROWING_ARRAY but contains additionally an reference * counter, so that the object can be shared among different clients. * If you do an IncRef each time you make use of it and an DecRef when you're * done, the array will be automatically freed when there are no more * references to it.

* Methods: *

*/ #define PS_TYPEDEF_GROWING_ARRAY_REF(Name, Type) \ PS_TYPEDEF_GROWING_ARRAY_EXT (Name, Type, RefCount = 0, \ int RefCount; \ void IncRef () \ { RefCount++; } \ void DecRef () \ { \ if (RefCount == 1) SetLimit (0); \ RefCount--; \ }) /** * This is a shortcut for above to declare a dummy class and a single * instance of that class. *

* Usage examples: *

 * PS_DECLARE_GROWING_ARRAY (la, csLight*);
 * PS_DECLARE_GROWING_ARRAY (ia, int);
 * 
*/ #define PS_DECLARE_GROWING_ARRAY(Name, Type) \ PS_TYPEDEF_GROWING_ARRAY(__##Name##_##Type,Type) Name /** * Same as above but declares an object which has a reference counter. */ #define PS_DECLARE_GROWING_ARRAY_REF(Name, Type) \ PS_TYPEDEF_GROWING_ARRAY_REF(__##Name,Type) Name #endif // __PS_GROWARRAY_H__