#ifndef TA_MEMORY_H #define TA_MEMORY_H #if !defined( _MANAGED ) && !defined( _JAVA ) #ifndef TA_COMMON_H #include "ta_common.h" #endif #include /* Interface macros */ #define TA_Malloc(a) malloc(a) #define TA_Realloc(a,b) realloc((a),(b)) #define TA_Free(a) free(a) #define FREE_IF_NOT_NULL(x) { if((x)!=NULL) {TA_Free((void *)(x)); (x)=NULL;} } #endif /* !defined(_MANAGED) && !defined( _JAVA ) */ /* ARRAY : Macros to manipulate arrays of value type. * * Using temporary array of double and integer are often needed for the * TA functions. * * These macros allow basic operations to alloc/copy/free array of value type. * * These macros works in plain old C/C++, managed C++.and Java. * * (Use ARRAY_REF and ARRAY_INT_REF for double/integer arrays). */ #if defined( _MANAGED ) #define ARRAY_VTYPE_REF(type,name) cli::array^ name #define ARRAY_VTYPE_LOCAL(type,name,size) cli::array^ name = gcnew cli::array(size) #define ARRAY_VTYPE_ALLOC(type,name,size) name = gcnew cli::array(size) #define ARRAY_VTYPE_COPY(type,dest,src,size) cli::array::Copy( src, 0, dest, 0, size ) #define ARRAY_VTYPE_MEMMOVE(type,dest,destIdx,src,srcIdx,size) cli::array::Copy( src, srcIdx, dest, destIdx, size ) #define ARRAY_VTYPE_FREE(type,name) #define ARRAY_VTYPE_FREE_COND(type,cond,name) #elif defined( _JAVA ) #define ARRAY_VTYPE_REF(type,name) type []name #define ARRAY_VTYPE_LOCAL(type,name,size) type []name = new type[size] #define ARRAY_VTYPE_ALLOC(type,name,size) name = new type[size] #define ARRAY_VTYPE_COPY(type,dest,src,size) System.arraycopy(src,0,dest,0,size) #define ARRAY_VTYPE_MEMMOVE(type,dest,destIdx,src,srcIdx,size) System.arraycopy(src,srcIdx,dest,destIdx,size) #define ARRAY_VTYPE_FREE(type,name) #define ARRAY_VTYPE_FREE_COND(type,cond,name) #else #define ARRAY_VTYPE_REF(type,name) type *name #define ARRAY_VTYPE_LOCAL(type,name,size) type name[size] #define ARRAY_VTYPE_ALLOC(type,name,size) name = (type *)TA_Malloc( sizeof(type)*(size)) #define ARRAY_VTYPE_COPY(type,dest,src,size) memcpy(dest,src,sizeof(type)*(size)) #define ARRAY_VTYPE_MEMMOVE(type,dest,destIdx,src,srcIdx,size) memmove( &dest[destIdx], &src[srcIdx], (size)*sizeof(type) ) #define ARRAY_VTYPE_FREE(type,name) TA_Free(name) #define ARRAY_VTYPE_FREE_COND(type,cond,name) if( cond ){ TA_Free(name); } #endif /* ARRAY : Macros to manipulate arrays of double. */ #define ARRAY_REF(name) ARRAY_VTYPE_REF(double,name) #define ARRAY_LOCAL(name,size) ARRAY_VTYPE_LOCAL(double,name,size) #define ARRAY_ALLOC(name,size) ARRAY_VTYPE_ALLOC(double,name,size) #define ARRAY_COPY(dest,src,size) ARRAY_VTYPE_COPY(double,dest,src,size) #define ARRAY_MEMMOVE(dest,destIdx,src,srcIdx,size) ARRAY_VTYPE_MEMMOVE(double,dest,destIdx,src,srcIdx,size) #define ARRAY_FREE(name) ARRAY_VTYPE_FREE(double,name) #define ARRAY_FREE_COND(cond,name) ARRAY_VTYPE_FREE_COND(double,cond,name) /* ARRAY : Macros to manipulate arrays of integer. */ #define ARRAY_INT_REF(name) ARRAY_VTYPE_REF(int,name) #define ARRAY_INT_LOCAL(name,size) ARRAY_VTYPE_LOCAL(int,name,size) #define ARRAY_INT_ALLOC(name,size) ARRAY_VTYPE_ALLOC(int,name,size) #define ARRAY_INT_COPY(dest,src,size) ARRAY_VTYPE_COPY(int,dest,src,size) #define ARRAY_INT_MEMMOVE(dest,destIdx,src,srcIdx,size) ARRAY_VTYPE_MEMMOVE(int,dest,destIdx,src,srcIdx,size) #define ARRAY_INT_FREE(name) ARRAY_VTYPE_FREE(int,name) #define ARRAY_INT_FREE_COND(cond,name) ARRAY_VTYPE_FREE_COND(int,cond,name) /* Access to "Globals" * * The globals here just means that these variables are accessible from * all technical analysis functions. * * Depending of the language/platform, the globals might be in reality * a private member variable of an object... */ #if defined( _MANAGED ) #define TA_GLOBALS_UNSTABLE_PERIOD(x,y) (Globals->unstablePeriod[(int)(FuncUnstId::y)]) #define TA_GLOBALS_COMPATIBILITY (Globals->compatibility) #elif defined( _JAVA ) #define TA_GLOBALS_UNSTABLE_PERIOD(x,y) (this.unstablePeriod[FuncUnstId.y.ordinal()]) #define TA_GLOBALS_COMPATIBILITY (this.compatibility) #else #define TA_GLOBALS_UNSTABLE_PERIOD(x,y) (TA_Globals->unstablePeriod[x]) #define TA_GLOBALS_COMPATIBILITY (TA_Globals->compatibility) #endif /* CIRCBUF : Circular Buffer Macros. * * The CIRCBUF is like a FIFO buffer (First In - First Out), except * that the rate of data coming out is the same as the rate of * data coming in (for simplification and speed optimization). * In other word, when you add one new value, you must also consume * one value (if not consume, the value is lost). * * The CIRCBUF size is unlimited, so it will automatically allocate and * de-allocate memory as needed. In C/C++. when small enough, CIRCBUF will * instead use a buffer "allocated" on the stack (automatic variable). * * Multiple CIRCBUF can be used within the same function. To make that * possible the first parameter of the MACRO is an "Id" that can be * any string. * * The macros offer the advantage to work in C/C++ and managed C++. * * CIRCBUF_PROLOG(Id,Type,Size); * Will declare all the needed variables. 2 variables are * important: * 1) 'Id' will be a ptr of the specified Type. * 2) 'Id'_Idx indicates from where to consume and * to add the data. * * Important: You must consume the oldest data before * setting the new data! * * The Size must be reasonable since it might "allocate" * an array of this size on the stack (each element are 'Type'). * * CIRCBUF_CONSTRUCT(Id,Type,Size); * Must be called prior to use the remaining macros. Must be * followed by CIRCBUF_DESTROY when leaving the function. * The Size here can be large. If the static Size specified * with CIRCBUF_PROLOG is not sufficient, this MACRO will * allocate a new buffer from the Heap. * * CIRCBUF_DESTROY(Id,Size); * Must be call prior to leave the function. * * CIRCBUF_NEXT(Id); * Move forward the indexes. * * Example: * TA_RetCode MyFunc( int size ) * { * CIRCBUF_PROLOG(MyBuf,int,4); * int i, value; * ... * CIRCBUF_CONSTRUCT(MyBuf,int,size); * ... * // 1st Loop: Fill MyBuf with initial values * // (must be done). * value = 0; * for( i=0; i < size; i++ ) * { * // Set the data * MyBuf[MyBuf_Idx] = value++; * CIRCBUF_NEXT(MyBuf); * } * * // 2nd Loop: Get and Add subsequent values * // in MyBuf (optional) * for( i=0; i < 3; i++ ) * { * // Consume the data (must be done first) * printf( "%d ", MyBuf[MyBuf_Idx] ); * * // Set the new data (must be done second) * MyBuf[MyBuf_Idx] = value++; * * // Move the index forward * CIRCBUF_NEXT(MyBuf); * } * * // 3rd Loop: Empty MyBuf (optional) * for( i=0; i < size; i++ ) * { * printf( "%d ", MyBuf[MyBuf_Idx] ); * CIRCBUF_NEXT(MyBuf); * } * * CIRCBUF_DESTROY(MyBuf); * return TA_SUCCESS; * } * * * A call to MyFunc(5) will output: * 0 1 2 3 4 5 6 7 * * The value 0 to 4 are added by the 1st loop. * The value 5 to 7 are added by the 2nd loop. * * The value 0 to 2 are displayed by the 2nd loop. * The value 3 to 7 are displayed by the 3rd loop. * * Because the size 5 is greater than the * value provided in CIRCBUF_PROLOG, a buffer will * be dynamically allocated (and freed). */ #if defined( _MANAGED ) #define CIRCBUF_PROLOG(Id,Type,Size) int Id##_Idx = 0; \ cli::array^ Id; \ int maxIdx_##Id = (Size-1) /* Use this macro instead if the Type is a class or a struct. */ #define CIRCBUF_PROLOG_CLASS(Id,Type,Size) int Id##_Idx = 0; \ cli::array^ Id; \ int maxIdx_##Id = (Size-1) #define CIRCBUF_INIT(Id,Type,Size) \ { \ if( Size <= 0 ) \ return ENUM_VALUE(RetCode,TA_ALLOC_ERR,AllocErr); \ Id = gcnew cli::array(Size); \ if( !Id ) \ return ENUM_VALUE(RetCode,TA_ALLOC_ERR,AllocErr); \ maxIdx_##Id = (Size-1); \ } #define CIRCBUF_INIT_CLASS(Id,Type,Size) \ { \ if( Size <= 0 ) \ return ENUM_VALUE(RetCode,TA_ALLOC_ERR,AllocErr); \ Id = gcnew cli::array(Size); \ for( int _##Id##_index=0; _##Id##_indexLength; _##Id##_index++) \ { \ Id[_##Id##_index]=gcnew Type(); \ } \ if( !Id ) \ return ENUM_VALUE(RetCode,TA_ALLOC_ERR,AllocErr); \ maxIdx_##Id = (Size-1); \ } #define CIRCBUF_INIT_LOCAL_ONLY(Id,Type) \ { \ Id = gcnew cli::array(maxIdx_##Id+1); \ if( !Id ) \ return ENUM_VALUE(RetCode,TA_ALLOC_ERR,AllocErr); \ } #define CIRCBUF_DESTROY(Id) /* Use this macro to access the member when type is a class or a struct. */ #define CIRCBUF_REF(x) (x)-> #elif defined(_JAVA) #define CIRCBUF_PROLOG(Id,Type,Size) int Id##_Idx = 0; \ Type []Id; \ int maxIdx_##Id = (Size-1) /* Use this macro instead if the Type is a class or a struct. */ #define CIRCBUF_PROLOG_CLASS(Id,Type,Size) int Id##_Idx = 0; \ Type []Id; \ int maxIdx_##Id = (Size-1) #define CIRCBUF_INIT(Id,Type,Size) \ { \ if( Size <= 0 ) \ return ENUM_VALUE(RetCode,TA_ALLOC_ERR,AllocErr); \ Id = new Type[Size]; \ maxIdx_##Id = (Size-1); \ } #define CIRCBUF_INIT_CLASS(Id,Type,Size) \ { \ if( Size <= 0 ) \ return ENUM_VALUE(RetCode,TA_ALLOC_ERR,AllocErr); \ Id = new Type[Size]; \ for( int _##Id##_index=0; _##Id##_index (int)(sizeof(local_##Id)/sizeof(Type)) ) \ { \ Id = TA_Malloc( sizeof(Type)*Size ); \ if( !Id ) \ return TA_ALLOC_ERR; \ } \ else \ Id = &local_##Id[0]; \ maxIdx_##Id = (Size-1); \ Id##_Idx = 0; \ } #define CIRCBUF_INIT_CLASS(Id,Type,Size) CIRCBUF_INIT(Id,Type,Size) #define CIRCBUF_INIT_LOCAL_ONLY(Id,Type) \ { \ Id = &local_##Id[0]; \ maxIdx_##Id = (int)(sizeof(local_##Id)/sizeof(Type))-1; \ Id##_Idx = 0; \ } #define CIRCBUF_DESTROY(Id) \ { \ if( Id != &local_##Id[0] ) \ TA_Free( Id ); \ } /* Use this macro to access the member when Type is a class or a struct. */ #define CIRCBUF_REF(x) (x). #endif #define CIRCBUF_NEXT(Id) \ { \ Id##_Idx++; \ if( Id##_Idx > maxIdx_##Id ) \ Id##_Idx = 0; \ } #endif