Blender V2.61 - r43446
|
00001 00004 /* 00005 * Cache.cpp 00006 * 00007 * Created on: Feb 24, 2009 00008 * Author: benoit bolsee 00009 */ 00010 #include <string.h> 00011 #include <assert.h> 00012 #include <math.h> 00013 #include <stdlib.h> 00014 #include "Cache.hpp" 00015 00016 namespace iTaSC { 00017 00018 CacheEntry::~CacheEntry() 00019 { 00020 for (unsigned int id=0; id < m_count; id++) 00021 m_channelArray[id].clear(); 00022 if (m_channelArray) 00023 free(m_channelArray); 00024 } 00025 00026 CacheItem *CacheChannel::_findBlock(CacheBuffer *buffer, unsigned short timeOffset, unsigned int *retBlock) 00027 { 00028 // the timestamp is necessarily in this buffer 00029 unsigned int lowBlock, highBlock, midBlock; 00030 if (timeOffset <= buffer->lookup[0].m_timeOffset) { 00031 // special case: the item is in the first block, search from start 00032 *retBlock = 0; 00033 return &buffer->m_firstItem; 00034 } 00035 // general case, the item is in the middle of the buffer 00036 // before doing a dycotomic search, we will assume that timestamp 00037 // are regularly spaced so that we can try to locate the block directly 00038 highBlock = buffer->m_lastItemPositionW>>m_positionToBlockShiftW; 00039 lowBlock = midBlock = (timeOffset*highBlock)/(buffer->m_lastTimestamp-buffer->m_firstTimestamp); 00040 // give some space for security 00041 if (lowBlock > 0) 00042 lowBlock--; 00043 if (timeOffset <= buffer->lookup[lowBlock].m_timeOffset) { 00044 // bad guess, but we know this block is a good high block, just use it 00045 highBlock = lowBlock; 00046 lowBlock = 0; 00047 } else { 00048 // ok, good guess, now check the high block, give some space 00049 if (midBlock < highBlock) 00050 midBlock++; 00051 if (timeOffset <= buffer->lookup[midBlock].m_timeOffset) { 00052 // good guess, keep that block as the high block 00053 highBlock = midBlock; 00054 } 00055 } 00056 // the item is in a different block, do a dycotomic search 00057 // the timestamp is alway > lowBlock and <= highBlock 00058 while (1) { 00059 midBlock = (lowBlock+highBlock)/2; 00060 if (midBlock == lowBlock) { 00061 // low block and high block are contigous, we can start search from the low block 00062 break; 00063 } else if (timeOffset <= buffer->lookup[midBlock].m_timeOffset) { 00064 highBlock = midBlock; 00065 } else { 00066 lowBlock = midBlock; 00067 } 00068 } 00069 assert (lowBlock != highBlock); 00070 *retBlock = highBlock; 00071 return CACHE_BLOCK_ITEM_ADDR(this,buffer,lowBlock); 00072 } 00073 00074 void CacheChannel::clear() 00075 { 00076 CacheBuffer *buffer, *next; 00077 for (buffer=m_firstBuffer; buffer != 0; buffer = next) { 00078 next = buffer->m_next; 00079 free(buffer); 00080 } 00081 m_firstBuffer = NULL; 00082 m_lastBuffer = NULL; 00083 if (initItem) { 00084 free(initItem); 00085 initItem = NULL; 00086 } 00087 } 00088 00089 CacheBuffer* CacheChannel::allocBuffer() 00090 { 00091 CacheBuffer* buffer; 00092 if (!m_busy) 00093 return NULL; 00094 buffer = (CacheBuffer*)malloc(CACHE_BUFFER_HEADER_SIZE+(m_bufferSizeW<<2)); 00095 if (buffer) { 00096 memset(buffer, 0, CACHE_BUFFER_HEADER_SIZE); 00097 } 00098 return buffer; 00099 } 00100 00101 CacheItem* CacheChannel::findItemOrLater(unsigned int timestamp, CacheBuffer **rBuffer) 00102 { 00103 CacheBuffer* buffer; 00104 CacheItem *item, *limit; 00105 if (!m_busy) 00106 return NULL; 00107 if (timestamp == 0 && initItem) { 00108 *rBuffer = NULL; 00109 return initItem; 00110 } 00111 for (buffer=m_firstBuffer; buffer; buffer = buffer->m_next) { 00112 if (buffer->m_firstFreePositionW == 0) 00113 // buffer is empty, this must be the last and we didn't find the timestamp 00114 return NULL; 00115 if (timestamp < buffer->m_firstTimestamp) { 00116 *rBuffer = buffer; 00117 return &buffer->m_firstItem; 00118 } 00119 if (timestamp <= buffer->m_lastTimestamp) { 00120 // the timestamp is necessarily in this buffer 00121 unsigned short timeOffset = (unsigned short)(timestamp-buffer->m_firstTimestamp); 00122 unsigned int highBlock; 00123 item = _findBlock(buffer, timeOffset, &highBlock); 00124 // now we do a linear search until we find a timestamp that is equal or higher 00125 // we should normally always find an item but let's put a limit just in case 00126 limit = CACHE_BLOCK_ITEM_ADDR(this,buffer,highBlock); 00127 while (item<=limit && item->m_timeOffset < timeOffset ) 00128 item = CACHE_NEXT_ITEM(item); 00129 assert(item<=limit); 00130 *rBuffer = buffer; 00131 return item; 00132 } 00133 // search in next buffer 00134 } 00135 return NULL; 00136 } 00137 00138 CacheItem* CacheChannel::findItemEarlier(unsigned int timestamp, CacheBuffer **rBuffer) 00139 { 00140 CacheBuffer *buffer, *prevBuffer; 00141 CacheItem *item, *limit, *prevItem; 00142 if (!m_busy) 00143 return NULL; 00144 if (timestamp == 0) 00145 return NULL; 00146 for (prevBuffer=NULL, buffer=m_firstBuffer; buffer; prevBuffer = buffer, buffer = buffer->m_next) { 00147 if (buffer->m_firstFreePositionW == 0) 00148 // buffer is empty, this must be the last and we didn't find the timestamp 00149 return NULL; 00150 if (timestamp <= buffer->m_firstTimestamp) { 00151 if (prevBuffer == NULL) { 00152 // no item before, except the initial item 00153 *rBuffer = NULL; 00154 return initItem; 00155 } 00156 // the item is necessarily the last one of previous buffer 00157 *rBuffer = prevBuffer; 00158 return CACHE_ITEM_ADDR(prevBuffer,prevBuffer->m_lastItemPositionW); 00159 } 00160 if (timestamp <= buffer->m_lastTimestamp) { 00161 // the timestamp is necessarily in this buffer 00162 unsigned short timeOffset = (unsigned short)(timestamp-buffer->m_firstTimestamp); 00163 unsigned int highBlock; 00164 item = _findBlock(buffer, timeOffset, &highBlock); 00165 // now we do a linear search until we find a timestamp that is equal or higher 00166 // we should normally always find an item but let's put a limit just in case 00167 limit = CACHE_BLOCK_ITEM_ADDR(this,buffer,highBlock); 00168 prevItem = NULL; 00169 while (item<=limit && item->m_timeOffset < timeOffset) { 00170 prevItem = item; 00171 item = CACHE_NEXT_ITEM(item); 00172 } 00173 assert(item<=limit && prevItem!=NULL); 00174 *rBuffer = buffer; 00175 return prevItem; 00176 } 00177 // search in next buffer 00178 } 00179 // pass all buffer, the last item is the last item of the last buffer 00180 if (prevBuffer == NULL) { 00181 // no item before, except the initial item 00182 *rBuffer = NULL; 00183 return initItem; 00184 } 00185 // the item is necessarily the last one of previous buffer 00186 *rBuffer = prevBuffer; 00187 return CACHE_ITEM_ADDR(prevBuffer,prevBuffer->m_lastItemPositionW); 00188 } 00189 00190 00191 Cache::Cache() 00192 { 00193 } 00194 00195 Cache::~Cache() 00196 { 00197 CacheMap::iterator it; 00198 for (it=m_cache.begin(); it!=m_cache.end(); it=m_cache.begin()) { 00199 deleteDevice(it->first); 00200 } 00201 } 00202 00203 int Cache::addChannel(const void *device, const char *name, unsigned int maxItemSize) 00204 { 00205 CacheMap::iterator it = m_cache.find(device); 00206 CacheEntry *entry; 00207 CacheChannel *channel; 00208 unsigned int id; 00209 00210 if (maxItemSize > 0x3FFF0) 00211 return -1; 00212 00213 if (it == m_cache.end()) { 00214 // device does not exist yet, create a new entry 00215 entry = new CacheEntry(); 00216 if (entry == NULL) 00217 return -1; 00218 if (!m_cache.insert(CacheMap::value_type(device,entry)).second) 00219 return -1; 00220 } else { 00221 entry = it->second; 00222 } 00223 // locate a channel with the same name and reuse 00224 for (channel=entry->m_channelArray, id=0; id<entry->m_count; id++, channel++) { 00225 if (channel->m_busy && !strcmp(name, channel->m_name)) { 00226 // make this channel free again 00227 deleteChannel(device, id); 00228 // there can only be one channel with the same name 00229 break; 00230 } 00231 } 00232 for (channel=entry->m_channelArray, id=0; id<entry->m_count; id++, channel++) { 00233 // locate a free channel 00234 if (!channel->m_busy) 00235 break; 00236 } 00237 if (id == entry->m_count) { 00238 // no channel free, create new channels 00239 int newcount = entry->m_count + CACHE_CHANNEL_EXTEND_SIZE; 00240 channel = (CacheChannel*)realloc(entry->m_channelArray, newcount*sizeof(CacheChannel)); 00241 if (channel == NULL) 00242 return -1; 00243 entry->m_channelArray = channel; 00244 memset(&entry->m_channelArray[entry->m_count], 0, CACHE_CHANNEL_EXTEND_SIZE*sizeof(CacheChannel)); 00245 entry->m_count = newcount; 00246 channel = &entry->m_channelArray[id]; 00247 } 00248 // compute the optimal buffer size 00249 // The buffer size must be selected so that 00250 // - it does not contain more than 1630 items (=1s of cache assuming 25 items per second) 00251 // - it contains at least one item 00252 // - it's not bigger than 256kb and preferably around 32kb 00253 // - it a multiple of 4 00254 unsigned int bufSize = 1630*(maxItemSize+4); 00255 if (bufSize >= CACHE_DEFAULT_BUFFER_SIZE) 00256 bufSize = CACHE_DEFAULT_BUFFER_SIZE; 00257 if (bufSize < maxItemSize+16) 00258 bufSize = maxItemSize+16; 00259 bufSize = (bufSize + 3) & ~0x3; 00260 // compute block size and offset bit mask 00261 // the block size is computed so that 00262 // - it is a power of 2 00263 // - there is at least one item per block 00264 // - there is no more than CACHE_LOOKUP_TABLE_SIZE blocks per buffer 00265 unsigned int blockSize = bufSize/CACHE_LOOKUP_TABLE_SIZE; 00266 if (blockSize < maxItemSize+12) 00267 blockSize = maxItemSize+12; 00268 // find the power of 2 that is immediately larger than blockSize 00269 unsigned int m; 00270 unsigned int pwr2Size = blockSize; 00271 while ((m = (pwr2Size & (pwr2Size-1))) != 0) 00272 pwr2Size = m; 00273 blockSize = (pwr2Size < blockSize) ? pwr2Size<<1 : pwr2Size; 00274 // convert byte size to word size because all positions and size are expressed in 32 bit words 00275 blockSize >>= 2; 00276 channel->m_blockSizeW = blockSize; 00277 channel->m_bufferSizeW = bufSize>>2; 00278 channel->m_firstBuffer = NULL; 00279 channel->m_lastBuffer = NULL; 00280 channel->m_busy = 1; 00281 channel->initItem = NULL; 00282 channel->m_maxItemSizeB = maxItemSize; 00283 strncpy(channel->m_name, name, sizeof(channel->m_name)); 00284 channel->m_name[sizeof(channel->m_name)-1] = 0; 00285 channel->m_positionToOffsetMaskW = (blockSize-1); 00286 for (m=0; blockSize!=1; m++, blockSize>>=1); 00287 channel->m_positionToBlockShiftW = m; 00288 return (int)id; 00289 } 00290 00291 int Cache::deleteChannel(const void *device, int id) 00292 { 00293 CacheMap::iterator it = m_cache.find(device); 00294 CacheEntry *entry; 00295 00296 if (it == m_cache.end()) { 00297 // device does not exist 00298 return -1; 00299 } 00300 entry = it->second; 00301 if (id < 0 || id >= (int)entry->m_count || !entry->m_channelArray[id].m_busy) 00302 return -1; 00303 entry->m_channelArray[id].clear(); 00304 entry->m_channelArray[id].m_busy = 0; 00305 return 0; 00306 } 00307 00308 int Cache::deleteDevice(const void *device) 00309 { 00310 CacheMap::iterator it = m_cache.find(device); 00311 CacheEntry *entry; 00312 00313 if (it == m_cache.end()) { 00314 // device does not exist 00315 return -1; 00316 } 00317 entry = it->second; 00318 delete entry; 00319 m_cache.erase(it); 00320 return 0; 00321 } 00322 00323 void Cache::clearCacheFrom(const void *device, CacheTS timestamp) 00324 { 00325 CacheMap::iterator it = (device) ? m_cache.find(device) : m_cache.begin(); 00326 CacheEntry *entry; 00327 CacheChannel *channel; 00328 CacheBuffer *buffer, *nextBuffer, *prevBuffer; 00329 CacheItem *item, *prevItem, *nextItem; 00330 unsigned int positionW, block; 00331 00332 while (it != m_cache.end()) { 00333 entry = it->second; 00334 for (unsigned int ch=0; ch<entry->m_count; ch++) { 00335 channel = &entry->m_channelArray[ch]; 00336 if (channel->m_busy) { 00337 item = channel->findItemOrLater(timestamp, &buffer); 00338 if (item ) { 00339 if (!buffer) { 00340 // this is possible if we return the special timestamp=0 item, delete all buffers 00341 channel->clear(); 00342 } else { 00343 // this item and all later items will be removed, clear any later buffer 00344 while ((nextBuffer = buffer->m_next) != NULL) { 00345 buffer->m_next = nextBuffer->m_next; 00346 free(nextBuffer); 00347 } 00348 positionW = CACHE_ITEM_POSITIONW(buffer,item); 00349 if (positionW == 0) { 00350 // this item is the first one of the buffer, remove the buffer completely 00351 // first find the buffer just before it 00352 nextBuffer = channel->m_firstBuffer; 00353 prevBuffer = NULL; 00354 while (nextBuffer != buffer) { 00355 prevBuffer = nextBuffer; 00356 nextBuffer = nextBuffer->m_next; 00357 // we must quit this loop before reaching the end of the list 00358 assert(nextBuffer); 00359 } 00360 free(buffer); 00361 buffer = prevBuffer; 00362 if (buffer == NULL) 00363 // this was also the first buffer 00364 channel->m_firstBuffer = NULL; 00365 } else { 00366 // removing this item means finding the previous item to make it the last one 00367 block = positionW>>channel->m_positionToBlockShiftW; 00368 if (block == 0) { 00369 // start from first item, we know it is not our item because positionW > 0 00370 prevItem = &buffer->m_firstItem; 00371 } else { 00372 // no need to check the current block, it will point to our item or a later one 00373 // but the previous block will be a good start for sure. 00374 block--; 00375 prevItem = CACHE_BLOCK_ITEM_ADDR(channel,buffer,block); 00376 } 00377 while ((nextItem = CACHE_NEXT_ITEM(prevItem)) < item) 00378 prevItem = nextItem; 00379 // we must have found our item 00380 assert(nextItem==item); 00381 // now set the buffer 00382 buffer->m_lastItemPositionW = CACHE_ITEM_POSITIONW(buffer,prevItem); 00383 buffer->m_firstFreePositionW = positionW; 00384 buffer->m_lastTimestamp = buffer->m_firstTimestamp + prevItem->m_timeOffset; 00385 block = buffer->m_lastItemPositionW>>channel->m_positionToBlockShiftW; 00386 buffer->lookup[block].m_offsetW = buffer->m_lastItemPositionW&channel->m_positionToOffsetMaskW; 00387 buffer->lookup[block].m_timeOffset = prevItem->m_timeOffset; 00388 } 00389 // set the channel 00390 channel->m_lastBuffer = buffer; 00391 if (buffer) { 00392 channel->m_lastTimestamp = buffer->m_lastTimestamp; 00393 channel->m_lastItemPositionW = buffer->m_lastItemPositionW; 00394 } 00395 } 00396 } 00397 } 00398 } 00399 if (device) 00400 break; 00401 ++it; 00402 } 00403 } 00404 00405 void *Cache::addCacheItem(const void *device, int id, unsigned int timestamp, void *data, unsigned int length) 00406 { 00407 CacheMap::iterator it = m_cache.find(device); 00408 CacheEntry *entry; 00409 CacheChannel *channel; 00410 CacheBuffer *buffer, *next; 00411 CacheItem *item; 00412 unsigned int positionW, sizeW, block; 00413 00414 if (it == m_cache.end()) { 00415 // device does not exist 00416 return NULL; 00417 } 00418 entry = it->second; 00419 if (id < 0 || id >= (int) entry->m_count || !entry->m_channelArray[id].m_busy) 00420 return NULL; 00421 channel = &entry->m_channelArray[id]; 00422 if (length > channel->m_maxItemSizeB) 00423 return NULL; 00424 if (timestamp == 0) { 00425 // initial item, delete all buffers 00426 channel->clear(); 00427 // and create initial item 00428 item = NULL; 00429 // we will allocate the memory, which is always pointer aligned => compute size 00430 // with NULL will give same result. 00431 sizeW = CACHE_ITEM_SIZEW(item,length); 00432 item = (CacheItem*)calloc(sizeW, 4); 00433 item->m_sizeW = sizeW; 00434 channel->initItem = item; 00435 } else { 00436 if (!channel->m_lastBuffer) { 00437 // no item in buffer, insert item at first position of first buffer 00438 positionW = 0; 00439 if ((buffer = channel->m_firstBuffer) == NULL) { 00440 buffer = channel->allocBuffer(); 00441 channel->m_firstBuffer = buffer; 00442 } 00443 } else if (timestamp > channel->m_lastTimestamp) { 00444 // this is the normal case: we are writing past lastest timestamp 00445 buffer = channel->m_lastBuffer; 00446 positionW = buffer->m_firstFreePositionW; 00447 } else if (timestamp == channel->m_lastTimestamp) { 00448 // common case, rewriting the last timestamp, just reuse the last position 00449 buffer = channel->m_lastBuffer; 00450 positionW = channel->m_lastItemPositionW; 00451 } else { 00452 // general case, write in the middle of the buffer, locate the timestamp 00453 // (or the timestamp just after), clear this item and all future items, 00454 // and write at that position 00455 item = channel->findItemOrLater(timestamp, &buffer); 00456 if (item == NULL) { 00457 // this should not happen 00458 return NULL; 00459 } 00460 // this item will become the last one of this channel, clear any later buffer 00461 while ((next = buffer->m_next) != NULL) { 00462 buffer->m_next = next->m_next; 00463 free(next); 00464 } 00465 // no need to update the buffer, this will be done when the item is written 00466 positionW = CACHE_ITEM_POSITIONW(buffer,item); 00467 } 00468 item = CACHE_ITEM_ADDR(buffer,positionW); 00469 sizeW = CACHE_ITEM_SIZEW(item,length); 00470 // we have positionW pointing where we can put the item 00471 // before we do that we have to check if we can: 00472 // - enough room 00473 // - timestamp not too late 00474 if ((positionW+sizeW > channel->m_bufferSizeW) || 00475 (positionW > 0 && timestamp >= buffer->m_firstTimestamp+0x10000)) { 00476 // we must allocate a new buffer to store this item 00477 // but before we must make sure that the current buffer is consistent 00478 if (positionW != buffer->m_firstFreePositionW) { 00479 // This means that we were trying to write in the middle of the buffer. 00480 // We must set the buffer right with positionW being the last position 00481 // and find the item before positionW to make it the last. 00482 block = positionW>>channel->m_positionToBlockShiftW; 00483 CacheItem *previousItem, *nextItem; 00484 if (block == 0) { 00485 // start from first item, we know it is not our item because positionW > 0 00486 previousItem = &buffer->m_firstItem; 00487 } else { 00488 // no need to check the current block, it will point to our item or a later one 00489 // but the previous block will be a good start for sure. 00490 block--; 00491 previousItem = CACHE_BLOCK_ITEM_ADDR(channel,buffer,block); 00492 } 00493 while ((nextItem = CACHE_NEXT_ITEM(previousItem)) < item) 00494 previousItem = nextItem; 00495 // we must have found our item 00496 assert(nextItem==item); 00497 // now set the buffer 00498 buffer->m_lastItemPositionW = CACHE_ITEM_POSITIONW(buffer,previousItem); 00499 buffer->m_firstFreePositionW = positionW; 00500 buffer->m_lastTimestamp = buffer->m_firstTimestamp + previousItem->m_timeOffset; 00501 block = buffer->m_lastItemPositionW>>channel->m_positionToBlockShiftW; 00502 buffer->lookup[block].m_offsetW = buffer->m_lastItemPositionW&channel->m_positionToOffsetMaskW; 00503 buffer->lookup[block].m_timeOffset = previousItem->m_timeOffset; 00504 // and also the channel, just in case 00505 channel->m_lastBuffer = buffer; 00506 channel->m_lastTimestamp = buffer->m_lastTimestamp; 00507 channel->m_lastItemPositionW = buffer->m_lastItemPositionW; 00508 } 00509 // now allocate a new buffer 00510 buffer->m_next = channel->allocBuffer(); 00511 if (buffer->m_next == NULL) 00512 return NULL; 00513 buffer = buffer->m_next; 00514 positionW = 0; 00515 item = &buffer->m_firstItem; 00516 sizeW = CACHE_ITEM_SIZEW(item,length); 00517 } 00518 // all check passed, ready to write the item 00519 item->m_sizeW = sizeW; 00520 if (positionW == 0) { 00521 item->m_timeOffset = 0; 00522 buffer->m_firstTimestamp = timestamp; 00523 } else { 00524 item->m_timeOffset = (unsigned short)(timestamp-buffer->m_firstTimestamp); 00525 } 00526 buffer->m_lastItemPositionW = positionW; 00527 buffer->m_firstFreePositionW = positionW+sizeW; 00528 buffer->m_lastTimestamp = timestamp; 00529 block = positionW>>channel->m_positionToBlockShiftW; 00530 buffer->lookup[block].m_offsetW = positionW&channel->m_positionToOffsetMaskW; 00531 buffer->lookup[block].m_timeOffset = item->m_timeOffset; 00532 buffer->m_lastItemPositionW = CACHE_ITEM_POSITIONW(buffer,item); 00533 buffer->m_firstFreePositionW = buffer->m_lastItemPositionW+item->m_sizeW; 00534 channel->m_lastBuffer = buffer; 00535 channel->m_lastItemPositionW = positionW; 00536 channel->m_lastTimestamp = timestamp; 00537 } 00538 // now copy the item 00539 void *itemData = CACHE_ITEM_DATA_POINTER(item); 00540 if (data) 00541 memcpy(itemData, data, length); 00542 return itemData; 00543 } 00544 00545 const void *Cache::getPreviousCacheItem(const void *device, int id, unsigned int *timestamp) 00546 { 00547 CacheMap::iterator it; 00548 CacheEntry *entry; 00549 CacheChannel *channel; 00550 CacheBuffer *buffer; 00551 CacheItem *item; 00552 00553 if (device) { 00554 it = m_cache.find(device); 00555 } else { 00556 it = m_cache.begin(); 00557 } 00558 if (it == m_cache.end()) { 00559 // device does not exist 00560 return NULL; 00561 } 00562 entry = it->second; 00563 if (id < 0 || id >= (int) entry->m_count || !entry->m_channelArray[id].m_busy) 00564 return NULL; 00565 channel = &entry->m_channelArray[id]; 00566 if ((item = channel->findItemEarlier(*timestamp,&buffer)) == NULL) 00567 return NULL; 00568 *timestamp = (buffer) ? buffer->m_firstTimestamp+item->m_timeOffset : 0; 00569 return CACHE_ITEM_DATA_POINTER(item); 00570 } 00571 00572 const CacheItem *Cache::getCurrentCacheItemInternal(const void *device, int id, CacheTS timestamp) 00573 { 00574 CacheMap::iterator it = m_cache.find(device); 00575 CacheEntry *entry; 00576 CacheChannel *channel; 00577 CacheBuffer *buffer; 00578 CacheItem *item; 00579 00580 if (it == m_cache.end()) { 00581 // device does not exist 00582 return NULL; 00583 } 00584 entry = it->second; 00585 if (id < 0 || id >= (int) entry->m_count || !entry->m_channelArray[id].m_busy) 00586 return NULL; 00587 channel = &entry->m_channelArray[id]; 00588 if ((item = channel->findItemOrLater(timestamp,&buffer)) == NULL) 00589 return NULL; 00590 if (buffer && buffer->m_firstTimestamp+item->m_timeOffset != timestamp) 00591 return NULL; 00592 return item; 00593 } 00594 00595 const void *Cache::getCurrentCacheItem(const void *device, int channel, unsigned int timestamp) 00596 { 00597 const CacheItem *item = getCurrentCacheItemInternal(device, channel, timestamp); 00598 return (item) ? CACHE_ITEM_DATA_POINTER(item) : NULL; 00599 } 00600 00601 double *Cache::addCacheVectorIfDifferent(const void *device, int channel, CacheTS timestamp, double *newdata, unsigned int length, double threshold) 00602 { 00603 const CacheItem *item = getCurrentCacheItemInternal(device, channel, timestamp); 00604 unsigned int sizeW = CACHE_ITEM_SIZEW(item,length*sizeof(double)); 00605 if (!item || item->m_sizeW != sizeW) 00606 return (double*)addCacheItem(device, channel, timestamp, newdata, length*sizeof(double)); 00607 double *olddata = (double*)CACHE_ITEM_DATA_POINTER(item); 00608 if (!length) 00609 return olddata; 00610 double *ref = olddata; 00611 double *v = newdata; 00612 unsigned int i; 00613 for (i=length; i>0; --i) { 00614 if (fabs(*v-*ref) > threshold) 00615 break; 00616 *ref++ = *v++; 00617 } 00618 if (i) 00619 olddata = (double*)addCacheItem(device, channel, timestamp, newdata, length*sizeof(double)); 00620 return olddata; 00621 } 00622 00623 }