//////////////////////////////////////////////////////////////////////////////////////// // RAVEN STANDARD TEMPLATE LIBRARY // (c) 2002 Activision // // // Common // ------ // The raven libraries contain a number of common defines, enums, and typedefs which // need to be accessed by all templates. Each of these is included here. // // Also included is a safeguarded assert file for all the asserts in RTL. // // This file is included in EVERY TEMPLATE, so it should be very light in order to // reduce compile times. // // // Format // ------ // In order to simplify code and provide readability, the template library has some // standard formats. Any new templates or functions should adhere to these formats: // // - All memory is statically allocated, usually by parameter SIZE // - All classes provide an enum which defines constant variables, including CAPACITY // - All classes which moniter the number of items allocated provide the following functions: // size() - the number of objects // empty() - does the container have zero objects // full() - does the container have any room left for more objects // clear() - remove all objects // // // - Functions are defined in the following order: // Capacity // Constructors (copy, from string, etc...) // Range (size(), empty(), full(), clear(), etc...) // Access (operator[], front(), back(), etc...) // Modification (add(), remove(), push(), pop(), etc...) // Iteration (begin(), end(), insert(), erase(), find(), etc...) // // // NOTES: // // // //////////////////////////////////////////////////////////////////////////////////////// #if !defined(RATL_COMMON_INC) #define RATL_COMMON_INC //////////////////////////////////////////////////////////////////////////////////////// // In VC++, Don't Bother With These Warnings //////////////////////////////////////////////////////////////////////////////////////// #if defined(_MSC_VER) && !defined(__MWERKS__) #pragma warning ( disable : 4786 ) // Truncated to 255 characters warning #pragma warning ( disable : 4284 ) // nevamind what this is #pragma warning ( disable : 4100 ) // unreferenced formal parameter #pragma warning ( disable : 4512 ) // unable to generate default operator= #pragma warning ( disable : 4130 ) // logical operation on address of string constant #pragma warning ( disable : 4127 ) // conditional expression is constant #endif //////////////////////////////////////////////////////////////////////////////////////// // Includes //////////////////////////////////////////////////////////////////////////////////////// #if !defined(ASSERT_H_INC) #include #define ASSERT_H_INC #endif #if !defined(STRING_H_INC) #include #define STRING_H_INC #endif #include "../game/q_shared.h" //////////////////////////////////////////////////////////////////////////////////////// // Forward Dec. //////////////////////////////////////////////////////////////////////////////////////// class hfile; // I don't know why this needs to be in the global namespace, but it does class TRatlNew; inline void *operator new(size_t,TRatlNew *where) { return where; } inline void operator delete(void *, TRatlNew *) { return; } namespace ratl { #ifdef _DEBUG extern int HandleSaltValue; //this is used in debug for global uniqueness of handles extern int FoolTheOptimizer; //this is used to make sure certain things aren't optimized out #endif //////////////////////////////////////////////////////////////////////////////////////// // All Raven Template Library Internal Memory Operations // // This is mostly for future use. For now, they only provide a simple interface with // a couple extra functions (eql and clr). //////////////////////////////////////////////////////////////////////////////////////// namespace mem { //////////////////////////////////////////////////////////////////////////////////////// // The Align Struct Is The Root Memory Structure for Inheritance and Object Semantics // // In most cases, we just want a simple int. However, sometimes we need to use an // unsigned character array // //////////////////////////////////////////////////////////////////////////////////////// #if defined(_MSC_VER) && !defined(__MWERKS__) struct alignStruct { int space; }; #else struct alignStruct { unsigned char space[16]; } __attribute__ ((aligned(16))); #endif inline void* cpy( void *dest, const void *src, size_t count ) { return memcpy(dest, src, count); } inline void* set( void *dest, int c, size_t count ) { return memset(dest, c, count); } inline int cmp( const void *buf1, const void *buf2, size_t count ) { return memcmp( buf1, buf2, count ); } inline bool eql( const void *buf1, const void *buf2, size_t count ) { return (memcmp( buf1, buf2, count )==0); } inline void* zero( void *dest, size_t count ) { return memset(dest, 0, count); } template inline void cpy( T *dest, const T *src) { cpy(dest, src, sizeof(T)); } template inline void set(T *dest, int c) { set(dest, c, sizeof(T)); } template inline void swap(T *s1, T *s2) { unsigned char temp[sizeof(T)]; cpy((T *)temp,s1); cpy(s1,s2); cpy(s2,(T *)temp); } template inline int cmp( const T *buf1, const T *buf2) { return cmp( buf1, buf2, sizeof(T) ); } template inline bool eql( const T *buf1, const T *buf2) { return cmp( buf1, buf2,sizeof(T))==0; } template inline void zero( T *dest ) { return set(dest, 0, sizeof(T)); } } namespace str { inline int len(const char *src) { return strlen(src); } inline void cpy(char *dest,const char *src) { strcpy(dest,src); } inline void ncpy(char *dest,const char *src,int destBufferLen) { strncpy(dest,src,destBufferLen); } inline void cat(char *dest,const char *src) { strcat(dest,src); } inline void ncat(char *dest,const char *src,int destBufferLen) { ncpy(dest+len(dest),src,destBufferLen-len(dest)); } inline int cmp(const char *s1,const char *s2) { return strcmp(s1,s2); } inline bool eql(const char *s1,const char *s2) { return !strcmp(s1,s2); } inline int icmp(const char *s1,const char *s2) { return Q_stricmp(s1,s2); } inline int cmpi(const char *s1,const char *s2) { return Q_stricmp(s1,s2); } inline bool ieql(const char *s1,const char *s2) { return !Q_stricmp(s1,s2); } inline bool eqli(const char *s1,const char *s2) { return !Q_stricmp(s1,s2); } inline char *tok(char *s,const char *gap) { return strtok(s,gap); } void to_upper(char *dest); void to_lower(char *dest); void printf(char *dest,const char *formatS, ...); } //////////////////////////////////////////////////////////////////////////////////////// // The Raven Template Library Compile Assert // // If, during compile time the stuff under (condition) is zero, this code will not // compile. //////////////////////////////////////////////////////////////////////////////////////// template class compile_assert { #ifdef _DEBUG int junk[(1 - (2 * !condition))]; // Look At Where This Was Being Compiled public: compile_assert() { assert(condition); junk[0]=FoolTheOptimizer++; } int operator()() { assert(condition); FoolTheOptimizer++; return junk[0]; } #else public: int operator()() { return 1; } #endif; }; //////////////////////////////////////////////////////////////////////////////////////// // The Raven Template Library Base Class // // This is the base class for all the Raven Template Library container classes like // vector_vs and pool_vs. // // This class might be a good place to put memory profile code in the future. // //////////////////////////////////////////////////////////////////////////////////////// class ratl_base { public: #ifndef _XBOX void save(hfile& file); void load(hfile& file); #endif void ProfilePrint(const char * format, ...); public: static void* OutputPrint; }; //////////////////////////////////////////////////////////////////////////////////////// // this is a simplified version of bits_vs //////////////////////////////////////////////////////////////////////////////////////// template class bits_base { protected: enum { BITS_SHIFT = 5, // 5. Such A Nice Number BITS_INT_SIZE = 32, // Size Of A Single Word BITS_AND = (BITS_INT_SIZE - 1), // Used For And Operation ARRAY_SIZE = ((SZ + BITS_AND)/(BITS_INT_SIZE)), // Num Words Used BYTE_SIZE = (ARRAY_SIZE*sizeof(unsigned int)), // Num Bytes Used }; //////////////////////////////////////////////////////////////////////////////////// // Data //////////////////////////////////////////////////////////////////////////////////// unsigned int mV[ARRAY_SIZE]; public: enum { SIZE = SZ, CAPACITY = SZ, }; bits_base(bool init=true,bool initValue=false) { if (init) { if (initValue) { set(); } else { clear(); } } } void clear() { mem::zero(&mV,BYTE_SIZE); } void set() { mem::set(&mV, 0xff,BYTE_SIZE); } void set_bit(const int i) { assert(i>=0 && i < SIZE); mV[i>>BITS_SHIFT] |= (1<<(i&BITS_AND)); } void clear_bit(const int i) { assert(i>=0 && i < SIZE); mV[i>>BITS_SHIFT] &= ~(1<<(i&BITS_AND)); } void mark_bit(const int i, bool set) { assert(i>=0 && i < SIZE); if (set) { mV[i>>BITS_SHIFT] |= (1<<(i&BITS_AND)); } else { mV[i>>BITS_SHIFT] &= ~(1<<(i&BITS_AND)); } } bool operator[](const int i) const { assert(i>=0 && i < SIZE); return (mV[i>>BITS_SHIFT] & (1<<(i&BITS_AND)))!=0; } int next_bit(int start=0,bool onBit=true) const { assert(start>=0&&start<=SIZE); //we have to accept start==size for the way the loops are done if (start>=SIZE) { return SIZE; // Did Not Find } // Get The Word Which Contains The Start Bit & Mask Out Everything Before The Start Bit //-------------------------------------------------------------------------------------- unsigned int v = mV[start>>BITS_SHIFT]; if (!onBit) { v= (~v); } v >>= (start&31); // Search For The First Non Zero Word In The Array //------------------------------------------------- while(!v) { start = (start & (~(BITS_INT_SIZE-1))) + BITS_INT_SIZE; if (start>=SIZE) { return SIZE; // Did Not Find } v = mV[start>>BITS_SHIFT]; if (!onBit) { v= (~v); } } // So, We've Found A Non Zero Word, So Start Masking Against Parts To Skip Over Bits //----------------------------------------------------------------------------------- if (!(v&0xffff)) { start+=16; v>>=16; } if (!(v&0xff)) { start+=8; v>>=8; } if (!(v&0xf)) { start+=4; v>>=4; } // Time To Search Each Bit //------------------------- while(!(v&1)) { start++; v>>=1; } if (start>=SIZE) { return SIZE; } return start; } }; //////////////////////////////////////////////////////////////////////////////////////// // Raven Standard Compare Class //////////////////////////////////////////////////////////////////////////////////////// struct ratl_compare { float mCost; int mHandle; bool operator<(const ratl_compare& t) const { return (mCost struct value_semantics { enum { CAPACITY = SIZE, }; typedef T TAlign; // this is any type that has the right alignment typedef T TValue; // this is the actual thing the user uses typedef T TStorage; // this is what we make our array of typedef bits_true TConstructed; typedef TStorage TArray[SIZE]; enum { NEEDS_CONSTRUCT=0, TOTAL_SIZE=sizeof(TStorage), VALUE_SIZE=sizeof(TStorage), }; static void construct(TStorage *) { } static void construct(TStorage *me,const TValue &v) { *me=v; } static void destruct(TStorage *) { } static TRatlNew *raw(TStorage *me) { return (TRatlNew *)me; } static T * ptr(TStorage *me) { return me; } static const T * ptr(const TStorage *me) { return me; } static T & ref(TStorage *me) { return *me; } static const T & ref(const TStorage *me) { return *me; } static T *raw_array(TStorage *me) { return me; } static const T *raw_array(const TStorage *me) { return me; } static void swap(TStorage *s1,TStorage *s2) { mem::swap(ptr(s1),ptr(s2)); } static int pointer_to_index(const void *s1,const void *s2) { return ((TStorage *)s1)-((TStorage *)s2); } }; template struct object_semantics { enum { CAPACITY = SIZE, }; typedef mem::alignStruct TAlign; // this is any type that has the right alignment typedef T TValue; // this is the actual thing the user uses typedef bits_base TConstructed; struct TStorage { TAlign mMemory[((sizeof(T) + sizeof(TAlign) -1 )/sizeof(TAlign))]; }; typedef TStorage TArray[SIZE]; enum { NEEDS_CONSTRUCT=1, TOTAL_SIZE=sizeof(TStorage), VALUE_SIZE=sizeof(TStorage), }; static void construct(TStorage *me) { new(raw(me)) TValue(); } static void construct(TStorage *me,const TValue &v) { new(raw(me)) TValue(v); } static void destruct(TStorage *me) { ptr(me)->~T(); } static TRatlNew *raw(TStorage *me) { return (TRatlNew *)me; } static T * ptr(TStorage *me) { return (T *)me; } static const T * ptr(const TStorage *me) { return (const T *)me; } static T & ref(TStorage *me) { return *(T *)me; } static const T & ref(const TStorage *me) { return *(const T *)me; } static void swap(TStorage *s1,TStorage *s2) { TValue temp(ref(s1)); ref(s1)=ref(s2); ref(s2)=temp; } static int pointer_to_index(const void *s1,const void *s2) { return ((TStorage *)s1)-((TStorage *)s2); } }; template struct virtual_semantics { enum { CAPACITY = SIZE, }; typedef mem::alignStruct TAlign; // this is any type that has the right alignment typedef T TValue; // this is the actual thing the user uses typedef bits_base TConstructed; struct TStorage { TAlign mMemory[((MAX_CLASS_SIZE + sizeof(TAlign) -1 )/sizeof(TAlign))]; }; typedef TStorage TArray[SIZE]; enum { NEEDS_CONSTRUCT=1, TOTAL_SIZE=sizeof(TStorage), VALUE_SIZE=MAX_CLASS_SIZE, }; static void construct(TStorage *me) { new(raw(me)) TValue(); } static void destruct(TStorage *me) { ptr(me)->~T(); } static TRatlNew *raw(TStorage *me) { return (TRatlNew *)me; } static T * ptr(TStorage *me) { return (T *)me; } static const T * ptr(const TStorage *me) { return (const T *)me; } static T & ref(TStorage *me) { return *(T *)me; } static const T & ref(const TStorage *me) { return *(const T *)me; } // this is a bit suspicious, we are forced to do a memory swap, and for a class, that, say // stores a pointer to itself, it won't work right static void swap(TStorage *s1,TStorage *s2) { mem::swap(s1,s2); } static int pointer_to_index(const void *s1,const void *s2) { return ((TStorage *)s1)-((TStorage *)s2); } template static CAST_TO *verify_alloc(CAST_TO *p) { #ifdef _DEBUG assert(p); assert(dynamic_cast(p)); T *ptr=p; // if this doesn't compile, you are trying to alloc something that is not derived from base assert(dynamic_cast(ptr)); int i=VALUE_SIZE; int k=MAX_CLASS_SIZE; int j=sizeof(CAST_TO); compile_assert(); assert(sizeof(CAST_TO)<=MAX_CLASS_SIZE); #endif return p; } }; // The below versions are for nodes template struct value_semantics_node { enum { CAPACITY = SIZE, }; struct SNode { NODE nodeData; T value; }; typedef SNode TAlign; // this is any type that has the right alignment typedef T TValue; // this is the actual thing the user uses typedef SNode TStorage; // this is what we make our array of typedef bits_true TConstructed; typedef TStorage TArray[SIZE]; enum { NEEDS_CONSTRUCT=0, TOTAL_SIZE=sizeof(TStorage), VALUE_SIZE=sizeof(TValue), }; static void construct(TStorage *) { } static void construct(TStorage *me,const TValue &v) { me->value=v; } static void destruct(TStorage *) { } static TRatlNew *raw(TStorage *me) { return (TRatlNew *)&me->value; } static T * ptr(TStorage *me) { return &me->value; } static const T * ptr(const TStorage *me) { return &me->value; } static T & ref(TStorage *me) { return me->value; } static const T & ref(const TStorage *me) { return me->value; } // this ugly unsafe cast-hack is a backhanded way of getting the node data from the value data // this is so node support does not need to be added to the primitive containers static NODE & node(TValue &v) { return *(NODE *)((unsigned char *)(&v)+size_t(&((TStorage *)0)->nodeData)-size_t(&((TStorage *)0)->value)); } static const NODE & node(const TValue &v) { return *(const NODE *)((unsigned char *)(&v)+size_t(&((TStorage *)0)->nodeData)-size_t(&((TStorage *)0)->value)); } static void swap(TStorage *s1,TStorage *s2) { mem::swap(&s1->value,&s2->value); } // this is hideous static int pointer_to_index(const void *s1,const void *s2) { return ((TStorage *)(((unsigned char *)s1)-size_t(&((TStorage *)0)->value))) - ((TStorage *)(((unsigned char *)s2)-size_t(&((TStorage *)0)->value))); } }; template struct object_semantics_node { enum { CAPACITY = SIZE, }; typedef mem::alignStruct TAlign; // this is any type that has the right alignment typedef T TValue; // this is the actual thing the user uses typedef bits_base TConstructed; struct TValueStorage { TAlign mMemory[((sizeof(T) + sizeof(TAlign) -1 )/sizeof(TAlign))]; }; struct SNode { NODE nodeData; TValueStorage value; }; typedef SNode TStorage; // this is what we make our array of typedef TStorage TArray[SIZE]; enum { NEEDS_CONSTRUCT=0, TOTAL_SIZE=sizeof(TStorage), VALUE_SIZE=sizeof(TValueStorage), }; static void construct(TStorage *me) { new(raw(me)) TValue(); } static void construct(TStorage *me,const TValue &v) { new(raw(me)) TValue(v); } static void destruct(TStorage *me) { ptr(me)->~T(); } static TRatlNew *raw(TStorage *me) { return (TRatlNew *)&me->value; } static T * ptr(TStorage *me) { return (T *)&me->value; } static const T * ptr(const TStorage *me) { return (const T *)&me->value; } static T & ref(TStorage *me) { return *(T *)&me->value; } static const T & ref(const TStorage *me) { return *(const T *)&me->value; } static NODE & node(TStorage *me) { return me->nodeData; } static const NODE & node(const TStorage *me) { return me->nodeData; } // this ugly unsafe cast-hack is a backhanded way of getting the node data from the value data // this is so node support does not need to be added to the primitive containers static NODE & node(TValue &v) { return *(NODE *)((unsigned char *)(&v)+size_t(&((TStorage *)0)->nodeData)-size_t(&((TStorage *)0)->value)); } static const NODE & node(const TValue &v) { return *(const NODE *)((unsigned char *)(&v)+size_t(&((TStorage *)0)->nodeData)-size_t(&((TStorage *)0)->value)); } static void swap(TStorage *s1,TStorage *s2) { TValue temp(ref(s1)); ref(s1)=ref(s2); ref(s2)=temp; } // this is hideous static int pointer_to_index(const void *s1,const void *s2) { return ((TStorage *)(((unsigned char *)s1)-size_t(&((TStorage *)0)->value))) - ((TStorage *)(((unsigned char *)s2)-size_t(&((TStorage *)0)->value))); } }; template struct virtual_semantics_node { enum { CAPACITY = SIZE, }; typedef mem::alignStruct TAlign; // this is any type that has the right alignment typedef T TValue; // this is the actual thing the user uses typedef bits_base TConstructed; struct TValueStorage { TAlign mMemory[((MAX_CLASS_SIZE + sizeof(TAlign) -1 )/sizeof(TAlign))]; }; struct SNode { NODE nodeData; TValueStorage value; }; typedef SNode TStorage; // this is what we make our array of typedef TStorage TArray[SIZE]; enum { NEEDS_CONSTRUCT=1, TOTAL_SIZE=sizeof(TStorage), VALUE_SIZE=sizeof(TValueStorage), }; static void construct(TStorage *me) { new(raw(me)) TValue(); } static void destruct(TStorage *me) { ptr(me)->~T(); } static TRatlNew *raw(TStorage *me) { return (TRatlNew *)&me->value; } static T * ptr(TStorage *me) { return (T *)&me->value; } static const T * ptr(const TStorage *me) { return (const T *)&me->value; } static T & ref(TStorage *me) { return *(T *)&me->value; } static const T & ref(const TStorage *me) { return *(const T *)&me->value; } static NODE & node(TStorage *me) { return me->nodeData; } static const NODE & node(const TStorage *me) { return me->nodeData; } // this ugly unsafe cast-hack is a backhanded way of getting the node data from the value data // this is so node support does not need to be added to the primitive containers static NODE & node(TValue &v) { return *(NODE *)((unsigned char *)(&v)+size_t(&((TStorage *)0)->nodeData)-size_t(&((TStorage *)0)->value)); } static const NODE & node(const TValue &v) { return *(const NODE *)((unsigned char *)(&v)+size_t(&((TStorage *)0)->nodeData)-size_t(&((TStorage *)0)->value)); } // this is a bit suspicious, we are forced to do a memory swap, and for a class, that, say // stores a pointer to itself, it won't work right static void swap(TStorage *s1,TStorage *s2) { mem::swap(&s1->value,&s2->value); } // this is hideous static int pointer_to_index(const void *s1,const void *s2) { return ((TStorage *)(((unsigned char *)s1)-size_t(&((TStorage *)0)->value))) - ((TStorage *)(((unsigned char *)s2)-size_t(&((TStorage *)0)->value))); } template static CAST_TO *verify_alloc(CAST_TO *p) { #ifdef _DEBUG assert(p); assert(dynamic_cast(p)); T *ptr=p; // if this doesn't compile, you are trying to alloc something that is not derived from base assert(dynamic_cast(ptr)); int i=VALUE_SIZE; int k=MAX_CLASS_SIZE; int j=sizeof(CAST_TO); compile_assert(); assert(sizeof(CAST_TO)<=MAX_CLASS_SIZE); #endif return p; } }; } //////////////////////////////////////////////////////////////////////////////////////// // The Array Base Class, used for most containers //////////////////////////////////////////////////////////////////////////////////////// template class array_base : public ratl_base { public: //////////////////////////////////////////////////////////////////////////////////// // Capacity Enum //////////////////////////////////////////////////////////////////////////////////// enum { CAPACITY = T::CAPACITY, SIZE = T::CAPACITY, }; //////////////////////////////////////////////////////////////////////////////////// // Data //////////////////////////////////////////////////////////////////////////////////// typedef T TStorageTraits; typedef typename T::TArray TTArray; typedef typename T::TValue TTValue; typedef typename T::TConstructed TTConstructed; private: TTArray mArray; TTConstructed mConstructed; public: array_base() { } ~array_base() { clear(); } void clear() { if (T::NEEDS_CONSTRUCT) { int i=mConstructed.next_bit(); while (i=0 && index=0 && index=0 && i=0 && i=0 && j=0 && i=0 && i=0 && index=0 && index CAST_TO *verify_alloc(CAST_TO *p) const { return T::verify_alloc(p); } }; } #endif