/** Create a new hash table and return it. * @param[in] _u32NbKey Number of keys that will be inserted. * @param[in] _u32Flags Flags used by the hash table * @param[in] _eMemType Memory type to use * @return Returns the hashtable pointer or orxNULL if failed. */ orxHASHTABLE *orxFASTCALL orxHashTable_Create(orxU32 _u32NbKey, orxU32 _u32Flags, orxMEMORY_TYPE _eMemType) { orxHASHTABLE *pstHashTable; orxU32 u32Size; orxU32 u32Flags; /* Checks */ orxASSERT(_eMemType < orxMEMORY_TYPE_NUMBER); orxASSERT(_u32NbKey > 0); /* Gets Power of Two size */ u32Size = orxMath_GetNextPowerOfTwo(_u32NbKey); /* Allocate memory for a hash table */ pstHashTable = (orxHASHTABLE *)orxMemory_Allocate(sizeof(orxHASHTABLE) + (u32Size * sizeof(orxHASHTABLE_CELL *)), _eMemType); /* Enough memory ? */ if(pstHashTable != orxNULL) { /* Set flags */ if(_u32Flags == orxHASHTABLE_KU32_FLAG_NOT_EXPANDABLE) { u32Flags = orxBANK_KU32_FLAG_NOT_EXPANDABLE; } else { u32Flags = orxBANK_KU32_FLAG_NONE; } /* Clean values */ orxMemory_Zero(pstHashTable, sizeof(orxHASHTABLE) + (u32Size * sizeof(orxHASHTABLE_CELL *))); /* Allocate bank for cells */ pstHashTable->pstBank = orxBank_Create((orxU16)u32Size, sizeof(orxHASHTABLE_CELL), u32Flags, _eMemType); /* Correct bank allocation ? */ if(pstHashTable->pstBank != orxNULL) { /* Stores its size */ pstHashTable->u32Size = u32Size; } else { /* Allocation problem, returns orxNULL */ orxMemory_Free(pstHashTable); pstHashTable = orxNULL; } } return pstHashTable; }
/** Create a new bank in memory and returns a pointer on it * @param[in] _u16NbElem Number of elements per segments * @param[in] _u32Size Size of an element * @param[in] _u32Flags Flags set for this bank * @param[in] _eMemType Memory type where the Data will be allocated * @return returns a pointer on the memory bank */ orxBANK *orxFASTCALL orxBank_Create(orxU16 _u16NbElem, orxU32 _u32Size, orxU32 _u32Flags, orxMEMORY_TYPE _eMemType) { orxBANK *pstBank; /* Module initialized ? */ orxASSERT((sstBank.u32Flags & orxBANK_KU32_STATIC_FLAG_READY) == orxBANK_KU32_STATIC_FLAG_READY); /* Correct parameters ? */ orxASSERT(_eMemType < orxMEMORY_TYPE_NUMBER); orxASSERT(_u16NbElem > 0); orxASSERT(_u32Size > 0); /* Allocate the bank */ pstBank = (orxBANK *)orxMemory_Allocate(sizeof(orxBANK), _eMemType); /* Memory allocated ? */ if(pstBank != orxNULL) { /* Set initial values */ orxMemory_Zero(pstBank, sizeof(orxBANK)); pstBank->u32Counter = 0; pstBank->u32ElemSize = (_u32Size > sstBank.u32CacheLineSize) ? (orxU32)orxALIGN(_u32Size, sstBank.u32CacheLineSize) : (orxMath_IsPowerOfTwo(_u32Size) == orxFALSE) ? orxMath_GetNextPowerOfTwo(_u32Size) : _u32Size; pstBank->u32Flags = _u32Flags; pstBank->u16NbCellPerSegments = _u16NbElem; pstBank->eMemType = _eMemType; /* Compute the necessary number of 32 bits packs */ pstBank->u16SizeSegmentBitField = orxALIGN32(_u16NbElem) >> 5; /* Allocate the first segment, and select it as current */ pstBank->pstFirstSegment = orxBank_CreateSegment(pstBank); /* Success? */ if(pstBank->pstFirstSegment != orxNULL) { /* Add it to the list */ orxLinkList_AddEnd(&(sstBank.stBankList), &(pstBank->stNode)); } else { /* Can't allocate segment, cancel bank allocation */ orxMemory_Free(pstBank); pstBank = orxNULL; } }
/** Delete a hash table. * @param[in] _pstHashTable Hash table to delete. * @return orxSTATUS_SUCCESS / orxSTATUS_FAILURE */ orxSTATUS orxFASTCALL orxHashTable_Delete(orxHASHTABLE *_pstHashTable) { /* Checks */ orxASSERT(_pstHashTable != orxNULL); /* Clear hash table (unallocate cells) */ orxHashTable_Clear(_pstHashTable); /* Free bank */ orxBank_Delete(_pstHashTable->pstBank); /* Unallocate memory */ orxMemory_Free(_pstHashTable); /* Done ! */ return orxSTATUS_SUCCESS; }
/** Removes a track */ static orxINLINE void orxTimeLine_DeleteTrack(orxTIMELINE_TRACK *_pstTrack) { /* Decreases counter */ _pstTrack->u32RefCounter--; /* Not referenced? */ if(_pstTrack->u32RefCounter == 0) { /* Has an ID? */ if((_pstTrack->zReference != orxNULL) && (_pstTrack->zReference != orxSTRING_EMPTY)) { /* Removes it from the table */ orxHashTable_Remove(sstTimeLine.pstTrackTable, _pstTrack->u32ID); } /* Deletes it */ orxMemory_Free(_pstTrack); } /* Done! */ return; }
static orxINLINE orxU32 orxMemory_CacheLineSize() { SYSTEM_LOGICAL_PROCESSOR_INFORMATION *astProcessorInfoList; orxU32 u32InfoListSize = 0, u32Result = orxMEMORY_KU32_DEFAULT_CACHE_LINE_SIZE, i, u32Number; /* Requests total size of processors info */ GetLogicalProcessorInformation(0, (PDWORD)&u32InfoListSize); /* Allocates info list */ astProcessorInfoList = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION *)orxMemory_Allocate(u32InfoListSize, orxMEMORY_TYPE_TEMP); /* Gets processors info */ GetLogicalProcessorInformation(astProcessorInfoList, (PDWORD)&u32InfoListSize); /* For all processor info */ for(i = 0, u32Number = u32InfoListSize / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); i < u32Number; i++) { /* Found first level cache info? */ if((astProcessorInfoList[i].Relationship == RelationCache) && (astProcessorInfoList[i].Cache.Level == 1)) { /* Updates result */ u32Result = astProcessorInfoList[i].Cache.LineSize; break; } } /* Frees info list */ orxMemory_Free(astProcessorInfoList); /* Done! */ return u32Result; }
/** Event handler */ static orxSTATUS orxFASTCALL orxTimeLine_EventHandler(const orxEVENT *_pstEvent) { orxSTATUS eResult = orxSTATUS_SUCCESS; /* Add or update? */ if((_pstEvent->eID == orxRESOURCE_EVENT_ADD) || (_pstEvent->eID == orxRESOURCE_EVENT_UPDATE)) { orxRESOURCE_EVENT_PAYLOAD *pstPayload; /* Gets payload */ pstPayload = (orxRESOURCE_EVENT_PAYLOAD *)_pstEvent->pstPayload; /* Is config group? */ if(pstPayload->u32GroupID == orxString_ToCRC(orxCONFIG_KZ_RESOURCE_GROUP)) { orxHANDLE hIterator; orxU64 u64Key; orxTIMELINE_TRACK *pstTrack; /* For all tracks */ for(hIterator = orxHashTable_GetNext(sstTimeLine.pstTrackTable, orxHANDLE_UNDEFINED, &u64Key, (void **)&pstTrack); hIterator != orxHANDLE_UNDEFINED; hIterator = orxHashTable_GetNext(sstTimeLine.pstTrackTable, hIterator, &u64Key, (void **)&pstTrack)) { /* Match origin? */ if(orxConfig_GetOriginID(pstTrack->zReference) == pstPayload->u32NameID) { orxTIMELINE *pstTimeLine; orxTIMELINE_TRACK *pstNewTrack; orxU32 u32Counter, u32ID, u32Flags; const orxSTRING zReference; /* Backups counter, ID, flags & reference */ u32Counter = pstTrack->u32RefCounter; u32ID = pstTrack->u32ID; u32Flags = orxFLAG_GET(pstTrack->u32Flags, orxTIMELINE_TRACK_KU32_MASK_BACKUP); zReference = pstTrack->zReference; /* Deletes it (but keeps it reference in the hashtable to prevent infinite loop upon table changes) */ orxMemory_Free(pstTrack); /* Creates new track */ pstNewTrack = orxTimeLine_CreateTrack(zReference); /* Success? */ if(pstNewTrack != orxNULL) { /* Restores its counter */ pstNewTrack->u32RefCounter = u32Counter; /* Restores its flags */ orxFLAG_SET(pstNewTrack->u32Flags, u32Flags, orxTIMELINE_TRACK_KU32_MASK_BACKUP); } else { /* Removes old reference from the table */ orxHashTable_Remove(sstTimeLine.pstTrackTable, u32ID); } /* For all timelines */ for(pstTimeLine = orxTIMELINE(orxStructure_GetFirst(orxSTRUCTURE_ID_TIMELINE)); pstTimeLine != orxNULL; pstTimeLine = orxTIMELINE(orxStructure_GetNext(pstTimeLine))) { orxU32 u32Index; /* For all its track */ for(u32Index = 0; u32Index < orxTIMELINE_KU32_TRACK_NUMBER; u32Index++) { /* Matches? */ if(pstTimeLine->astTrackList[u32Index].pstTrack == pstTrack) { /* Updates its data */ pstTimeLine->astTrackList[u32Index].pstTrack = pstNewTrack; } } } } } } } /* Done! */ return eResult; }
/** Adds a track */ static orxINLINE orxTIMELINE_TRACK *orxTimeLine_CreateTrack(const orxSTRING _zTrackID) { orxTIMELINE_TRACK *pstResult = orxNULL; /* Pushes section */ if((orxConfig_HasSection(_zTrackID) != orxFALSE) && (orxConfig_PushSection(_zTrackID) != orxSTATUS_FAILURE)) { orxU32 u32KeyCounter; /* Gets number of keys */ u32KeyCounter = orxConfig_GetKeyCounter(); /* Valid? */ if(u32KeyCounter > 0) { orxU32 u32EventCounter = 0, i; #ifdef __orxMSVC__ orxFLOAT *afTimeList = (orxFLOAT *)alloca(u32KeyCounter * sizeof(orxFLOAT)); #else /* __orxMSVC__ */ orxFLOAT afTimeList[u32KeyCounter]; #endif /* __orxMSVC__ */ /* For all time entries */ for(i = 0; i < u32KeyCounter; i++) { /* Inits it */ afTimeList[i] = orxFLOAT_MAX; } /* For all config keys */ for(i = 0; i < u32KeyCounter; i++) { const orxSTRING zKey; orxFLOAT fTime; /* Gets it */ zKey = orxConfig_GetKey(i); /* Is a valid time stamp? */ if((orxString_ToFloat(zKey, &fTime, orxNULL) != orxSTATUS_FAILURE) && (fTime >= orxFLOAT_0)) { /* Stores it */ afTimeList[i] = fTime; /* Updates event counter */ u32EventCounter += orxConfig_GetListCounter(zKey); } else { /* Not keep in cache, immediate nor loop? */ if((orxString_Compare(orxTIMELINE_KZ_CONFIG_KEEP_IN_CACHE, zKey) != 0) && (orxString_Compare(orxTIMELINE_KZ_CONFIG_IMMEDIATE, zKey) != 0) && (orxString_Compare(orxTIMELINE_KZ_CONFIG_LOOP, zKey) != 0)) { /* Logs message */ orxDEBUG_PRINT(orxDEBUG_LEVEL_OBJECT, "TimeLine track [%s]: ignoring invalid key (%s).", _zTrackID, zKey); } } } /* Allocates track */ pstResult = (orxTIMELINE_TRACK *)orxMemory_Allocate(sizeof(orxTIMELINE_TRACK) + (u32EventCounter * sizeof(orxTIMELINE_TRACK_EVENT)), orxMEMORY_TYPE_MAIN); /* Valid? */ if(pstResult != orxNULL) { /* Stores its ID */ pstResult->u32ID = orxString_GetID(orxConfig_GetCurrentSection()); /* Adds it to reference table */ if(orxHashTable_Set(sstTimeLine.pstTrackTable, pstResult->u32ID, pstResult) != orxSTATUS_FAILURE) { orxU32 u32EventIndex, u32Flags = orxTIMELINE_TRACK_KU32_FLAG_NONE; /* For all events */ for(u32EventIndex = 0; u32EventIndex < u32EventCounter;) { const orxSTRING zKey; orxFLOAT fTime; orxU32 u32KeyIndex, u32ListCounter; /* Finds time to add next */ for(fTime = orxFLOAT_MAX, u32KeyIndex = orxU32_UNDEFINED, i = 0; i < u32KeyCounter; i++) { /* Is sooner? */ if(afTimeList[i] < fTime) { /* Stores it */ fTime = afTimeList[i]; u32KeyIndex = i; } } /* Checks */ orxASSERT(u32KeyIndex != orxU32_UNDEFINED); /* Gets corresponding key */ zKey = orxConfig_GetKey(u32KeyIndex); /* For all events */ for(i = 0, u32ListCounter = orxConfig_GetListCounter(zKey); i < u32ListCounter; i++, u32EventIndex++) { /* Checks */ orxASSERT(u32EventIndex < u32EventCounter); /* Stores event */ pstResult->astEventList[u32EventIndex].fTimeStamp = fTime; pstResult->astEventList[u32EventIndex].zEventText = orxString_Store(orxConfig_GetListString(zKey, i)); } /* Clears time entry */ afTimeList[u32KeyIndex] = orxFLOAT_MAX; } /* Stores its reference */ pstResult->zReference = orxString_GetFromID(pstResult->u32ID); /* Updates track counters */ pstResult->u32RefCounter = 1; pstResult->u32EventCounter = u32EventCounter; /* Should keep in cache? */ if(orxConfig_GetBool(orxTIMELINE_KZ_CONFIG_KEEP_IN_CACHE) != orxFALSE) { /* Increases its reference counter to keep it in cache table */ pstResult->u32RefCounter++; /* Updates flags */ u32Flags |= orxTIMELINE_TRACK_KU32_FLAG_CACHED; } /* Should loop? */ if(orxConfig_GetBool(orxTIMELINE_KZ_CONFIG_LOOP) != orxFALSE) { /* Updates flags */ u32Flags |= orxTIMELINE_TRACK_KU32_FLAG_LOOP; } /* Is immediate? */ if(orxConfig_GetBool(orxTIMELINE_KZ_CONFIG_IMMEDIATE) != orxFALSE) { /* Updates flags */ u32Flags |= orxTIMELINE_TRACK_KU32_FLAG_IMMEDIATE; } /* Stores flags */ pstResult->u32Flags = u32Flags; } else { /* Logs message */ orxDEBUG_PRINT(orxDEBUG_LEVEL_OBJECT, "Failed to add track to hashtable."); /* Deletes it */ orxMemory_Free(pstResult); /* Updates result */ pstResult = orxNULL; } } else { /* Logs message */ orxDEBUG_PRINT(orxDEBUG_LEVEL_OBJECT, "Couldn't create TimeLine track [%s]: memory allocation failure.", _zTrackID); } } else { /* Logs message */ orxDEBUG_PRINT(orxDEBUG_LEVEL_OBJECT, "Couldn't create TimeLine track [%s]: config section is empty.", _zTrackID); } /* Pops previous section */ orxConfig_PopSection(); } else { /* Logs message */ orxDEBUG_PRINT(orxDEBUG_LEVEL_OBJECT, "Couldn't create TimeLine track [%s]: config section not found.", _zTrackID); } /* Done! */ return pstResult; }
/** Optimizes a hashtable for read accesses (minimizes number of cache misses upon collisions) * @param[in] _pstHashTable HashTable to optimize * @return orxSTATUS_SUCESS / orxSTATUS_FAILURE */ orxSTATUS orxFASTCALL orxHashTable_Optimize(orxHASHTABLE *_pstHashTable) { orxSTATUS eResult = orxSTATUS_SUCCESS; /* Checks */ orxASSERT(_pstHashTable != orxNULL); /* Has elements? */ if(_pstHashTable->u32Counter > 0) { orxHASHTABLE_CELL *astWorkBuffer; /* Allocates work buffer */ astWorkBuffer = (orxHASHTABLE_CELL *)orxMemory_Allocate(_pstHashTable->u32Counter * sizeof(orxHASHTABLE_CELL), orxMEMORY_TYPE_TEMP); /* Valid? */ if(astWorkBuffer != orxNULL) { orxU64 u64KeyIndex; orxU32 u32BufferIndex, i; orxHASHTABLE_CELL *pstCell; /* For all cells */ for(i = 0, u64KeyIndex = 0, u32BufferIndex = 0, pstCell = orxNULL; i < _pstHashTable->u32Counter; i++, u32BufferIndex++) { /* Linked cell? */ if((pstCell != orxNULL) && (pstCell->pstNext != orxNULL)) { /* Gets next in line */ pstCell = pstCell->pstNext; } else { /* Finds next head cell */ do{pstCell = _pstHashTable->apstCell[u64KeyIndex++];} while(pstCell == orxNULL); } /* Stores it */ orxMemory_Copy(&astWorkBuffer[u32BufferIndex], pstCell, sizeof(orxHASHTABLE_CELL)); } /* Clears bank */ orxBank_Clear(_pstHashTable->pstBank); /* For all ordered cells */ for(i = 0, pstCell = orxNULL; i < _pstHashTable->u32Counter; i++) { orxHASHTABLE_CELL *pstPreviousCell; /* Allocates new cell */ pstPreviousCell = pstCell; pstCell = (orxHASHTABLE_CELL *)orxBank_Allocate(_pstHashTable->pstBank); /* Checks */ orxASSERT(pstCell != orxNULL); /* Stores its data */ orxMemory_Copy(pstCell, &astWorkBuffer[i], sizeof(orxHASHTABLE_CELL)); /* Chained? */ if((pstPreviousCell != orxNULL) && (pstPreviousCell->pstNext != orxNULL)) { /* Updates chaining */ pstPreviousCell->pstNext = pstCell; } else { /* Updates head pointer */ _pstHashTable->apstCell[orxHashTable_FindIndex(_pstHashTable, pstCell->u64Key)] = pstCell; } } /* Clears work buffer */ orxMemory_Free(astWorkBuffer); } else { /* Updates result */ eResult = orxSTATUS_FAILURE; } } /* Done! */ return eResult; }