#include "normSegment.h"
NormSegmentPool::NormSegmentPool()
: seg_size(0), seg_count(0), seg_total(0), seg_list(NULL), seg_pool(NULL),
peak_usage(0), overruns(0), overrun_flag(false)
{
}
NormSegmentPool::~NormSegmentPool()
{
Destroy();
}
bool NormSegmentPool::Init(unsigned int count, unsigned int size)
{
if (seg_pool) Destroy();
peak_usage = 0;
overruns = 0;
#ifdef SIMULATE
size = MIN(size, SIM_PAYLOAD_MAX);
#endif unsigned int allocSize = size / sizeof(char*);
if ((allocSize*sizeof(char*)) < size) allocSize++;
seg_size = allocSize * sizeof(char*);
seg_pool = new char*[allocSize * count];
if (seg_pool)
{
char** ptr = seg_pool;
for (unsigned int i = 0; i < count; i++)
{
*ptr = seg_list;
seg_list = (char*)ptr;
ptr += allocSize;
}
}
else
{
PLOG(PL_FATAL, "NormSegmentPool::Init() memory allocation error: %s\n",
GetErrorString());
Destroy();
return false;
}
seg_total = seg_count = count;
return true;
}
void NormSegmentPool::Destroy()
{
ASSERT(seg_count == seg_total);
if (NULL != seg_pool)
delete[] seg_pool;
seg_pool = NULL;
seg_list = NULL;
seg_count = 0;
seg_total = 0;
seg_size = 0;
}
char* NormSegmentPool::Get()
{
char* ptr = seg_list;
if (ptr)
{
seg_list = *((char**)((void*)ptr));
seg_count--;
overrun_flag = false;
unsigned int usage = seg_total - seg_count;
if (usage > peak_usage) peak_usage = usage;
}
else
{
if (!overrun_flag)
{
PLOG(PL_WARN, "NormSegmentPool::Get() warning: operating with constrained buffering resources\n");
overruns++;
overrun_flag = true;
}
}
return ptr;
}
NormBlock::NormBlock()
: size(0), segment_table(NULL), erasure_count(0), parity_count(0), next(NULL)
{
}
NormBlock::~NormBlock()
{
Destroy();
}
bool NormBlock::Init(UINT16 totalSize)
{
if (segment_table) Destroy();
if (!(segment_table = new char*[totalSize]))
{
PLOG(PL_FATAL, "NormBlock::Init() segment_table allocation error: %s\n", GetErrorString());
return false;
}
memset(segment_table, 0, totalSize*sizeof(char*));
if (!pending_mask.Init(totalSize))
{
PLOG(PL_FATAL, "NormBlock::Init() pending_mask allocation error: %s\n", GetErrorString());
Destroy();
return false;
}
if (!repair_mask.Init(totalSize))
{
PLOG(PL_FATAL, "NormBlock::Init() repair_mask allocation error: %s\n", GetErrorString());
Destroy();
return false;
}
size = totalSize;
erasure_count = 0;
parity_count = 0;
parity_offset = 0;
seg_size_max = 0;
return true;
}
void NormBlock::Destroy()
{
repair_mask.Destroy();
pending_mask.Destroy();
if (segment_table)
{
for (unsigned int i = 0; i < size; i++)
{
ASSERT(!segment_table[i]);
if (segment_table[i]) delete []segment_table[i];
}
delete []segment_table;
segment_table = (char**)NULL;
}
erasure_count = parity_count = size = 0;
}
void NormBlock::EmptyToPool(NormSegmentPool& segmentPool)
{
ASSERT(NULL != segment_table);
for (unsigned int i = 0; i < size; i++)
{
if (NULL != segment_table[i])
{
segmentPool.Put(segment_table[i]);
segment_table[i] = (char*)NULL;
}
}
}
bool NormBlock::IsRepairPending(UINT16 numData, UINT16 numParity)
{
if (erasure_count > numParity)
{
if (numParity)
{
UINT16 i = numParity;
NormSegmentId nextId = 0;
GetFirstPending(nextId);
while (i--)
{
repair_mask.Set(nextId); nextId++;
GetNextPending(nextId);
}
}
else if (size > numData)
{
repair_mask.SetBits(numData, size-numData);
}
}
else
{
repair_mask.SetBits(0, numData);
repair_mask.SetBits(numData+erasure_count, numParity-erasure_count);
}
repair_mask.XCopy(pending_mask);
return (repair_mask.IsSet());
}
bool NormBlock::TxReset(UINT16 numData,
UINT16 numParity,
UINT16 autoParity,
UINT16 segmentSize)
{
bool increasedRepair = false;
repair_mask.SetBits(0, numData+autoParity);
repair_mask.UnsetBits(numData+autoParity, numParity-autoParity);
repair_mask.Xor(pending_mask);
if (repair_mask.IsSet())
{
increasedRepair = true;
repair_mask.Clear();
pending_mask.SetBits(0, numData+autoParity);
pending_mask.UnsetBits(numData+autoParity, numParity-autoParity);
parity_offset = autoParity; parity_count = numParity; SetFlag(IN_REPAIR);
if (!ParityReady(numData)) {
char** ptr = segment_table+numData;
while (numParity--)
{
if (*ptr)
{
UINT16 payloadMax = segmentSize +
NormDataMsg::GetStreamPayloadHeaderLength();
#ifdef SIMULATE
payloadMax = MIN(payloadMax, SIM_PAYLOAD_MAX);
#endif memset(*ptr, 0, payloadMax);
}
ptr++;
}
erasure_count = 0;
seg_size_max = 0;
}
}
return increasedRepair;
}
bool NormBlock::ActivateRepairs(UINT16 numParity)
{
if (repair_mask.IsSet())
{
pending_mask.Add(repair_mask);
ASSERT(pending_mask.IsSet());
repair_mask.Clear();
SetFlag(IN_REPAIR);
return true;
}
else
{
return false;
}
}
bool NormBlock::TxUpdate(NormSegmentId nextId, NormSegmentId lastId,
UINT16 numData, UINT16 numParity, UINT16 erasureCount)
{
bool increasedRepair = false;
if (nextId < numData)
{
parity_offset = parity_count = numParity;
while (nextId <= lastId)
{
if (!pending_mask.Test(nextId))
{
pending_mask.Set(nextId);
increasedRepair = true;
}
nextId++;
}
}
else
{
UINT16 parityAvailable = numParity - parity_offset;
if (erasureCount <= parityAvailable)
{
if (erasureCount > parity_count)
{
pending_mask.SetBits(numData+parity_offset+parity_count,
erasureCount - parity_count);
parity_count = erasureCount;
increasedRepair = true;
}
}
else
{
if (parity_count < parityAvailable)
{
UINT16 count = parityAvailable - parity_count;
pending_mask.SetBits(numData+parity_offset+parity_count, count);
parity_count = parityAvailable;
nextId += parityAvailable;
increasedRepair = true;
}
while (nextId <= lastId)
{
if (!pending_mask.Test(nextId))
{
pending_mask.Set(nextId);
increasedRepair = true;
}
nextId++;
}
}
}
return increasedRepair;
}
bool NormBlock::HandleSegmentRequest(NormSegmentId nextId, NormSegmentId lastId,
UINT16 numData, UINT16 numParity, UINT16 erasureCount)
{
PLOG(PL_TRACE, "NormBlock::HandleSegmentRequest() blk>%lu seg>%hu:%hu erasures:%hu\n",
(unsigned long)blk_id.GetValue(), (UINT16)nextId, (UINT16)lastId, erasureCount);
bool increasedRepair = false;
if (nextId < numData)
{
parity_count = parity_offset = numParity;
while (nextId <= lastId)
{
if (!repair_mask.Test(nextId))
{
repair_mask.Set(nextId);
increasedRepair = true;
}
nextId++;
}
}
else
{
UINT16 parityAvailable = numParity - parity_offset;
if (erasureCount <= parityAvailable)
{
if (erasureCount > parity_count)
{
repair_mask.SetBits(numData+parity_offset+parity_count,
erasureCount - parity_count);
parity_count = erasureCount;
increasedRepair = true;
}
}
else
{
if (parity_count < parityAvailable)
{
UINT16 count = parityAvailable - parity_count;
repair_mask.SetBits(numData+parity_offset+parity_count, count);
parity_count = parityAvailable;
nextId += parityAvailable;
increasedRepair = true;
}
while (nextId <= lastId)
{
if (!repair_mask.Test(nextId))
{
repair_mask.Set(nextId);
increasedRepair = true;
}
nextId++;
}
}
}
return increasedRepair;
}
bool NormBlock::AppendRepairAdv(NormCmdRepairAdvMsg& cmd,
NormObjectId objectId,
bool repairInfo,
UINT8 fecId,
UINT8 fecM,
UINT16 numData,
UINT16 payloadMax)
{
bool requestAppended = false;
NormRepairRequest req;
req.SetFlag(NormRepairRequest::SEGMENT);
if (repairInfo) req.SetFlag(NormRepairRequest::INFO);
NormSymbolId nextId = 0;
if (GetFirstRepair(nextId))
{
UINT16 totalSize = size;
NormRepairRequest::Form prevForm = NormRepairRequest::INVALID;
UINT16 segmentCount = 0;
UINT16 firstId = 0;
while (nextId < totalSize)
{
UINT16 currentId = nextId;
if (!GetNextRepair(++nextId)) nextId = totalSize;
if (!segmentCount) firstId = currentId;
segmentCount++;
if (((nextId - currentId) > 1) || (nextId >= totalSize))
{
NormRepairRequest::Form form;
switch (segmentCount)
{
case 0:
form = NormRepairRequest::INVALID;
break;
case 1:
case 2:
form = NormRepairRequest::ITEMS;
break;
default:
form = NormRepairRequest::RANGES;
break;
}
if (form != prevForm)
{
if (NormRepairRequest::INVALID != prevForm)
{
if (0 == cmd.PackRepairRequest(req))
{
prevForm = NormRepairRequest::INVALID;
PLOG(PL_WARN, "NormBlock::AppendRepairAdv() warning: full msg\n");
break;
}
requestAppended = true;
}
req.SetForm(form);
cmd.AttachRepairRequest(req, payloadMax); prevForm = form;
}
switch(form)
{
case NormRepairRequest::INVALID:
ASSERT(0); break;
case NormRepairRequest::ITEMS:
req.AppendRepairItem(fecId, fecM, objectId, blk_id, numData, firstId);
if (2 == segmentCount)
req.AppendRepairItem(fecId, fecM, objectId, blk_id, numData, currentId);
break;
case NormRepairRequest::RANGES:
req.AppendRepairRange(fecId, fecM, objectId, blk_id, numData, firstId,
objectId, blk_id, numData, currentId);
break;
case NormRepairRequest::ERASURES:
break;
}
segmentCount = 0;
}
} if (NormRepairRequest::INVALID != prevForm)
{
if (0 == cmd.PackRepairRequest(req))
PLOG(PL_WARN, "NormBlock::AppendRepairAdv() warning: full msg\n");
else
requestAppended = true;
}
}
return requestAppended;
}
NormObjectSize NormBlock::GetBytesPending(UINT16 numData,
UINT16 segmentSize,
NormBlockId finalBlockId,
UINT16 finalSegmentSize) const
{
NormObjectSize pendingBytes(0);
NormSegmentId nextId;
if (GetFirstPending(nextId))
{
do
{
if (nextId < numData)
pendingBytes += NormObjectSize(segmentSize);
else
break;
nextId++;
} while (GetNextPending(nextId));
}
if ((blk_id == finalBlockId) && IsPending(numData - 1))
{
pendingBytes -= NormObjectSize(segmentSize);
pendingBytes += NormObjectSize(finalSegmentSize);
}
return pendingBytes;
}
bool NormBlock::AppendRepairRequest(NormNackMsg& nack,
UINT8 fecId,
UINT8 fecM,
UINT16 numData,
UINT16 numParity,
NormObjectId objectId,
bool pendingInfo,
UINT16 payloadMax)
{
bool requestAppended = false;
NormSegmentId nextId = 0;
NormSegmentId endId;
if (erasure_count > numParity)
{
GetFirstPending(nextId);
UINT16 i = numParity;
while (i--)
{
nextId++;
GetNextPending(nextId);
}
endId = numData + numParity;
}
else
{
nextId = numData;
GetNextPending(nextId);
endId = numData + erasure_count;
}
NormRepairRequest req;
req.SetFlag(NormRepairRequest::SEGMENT);
if (pendingInfo) req.SetFlag(NormRepairRequest::INFO);
NormRepairRequest::Form prevForm = NormRepairRequest::INVALID;
UINT16 segmentCount = 0;
UINT16 firstId = 0;
while (nextId < endId)
{
UINT16 currentId = nextId;
if (!GetNextPending(++nextId)) nextId = endId;
if (0 == segmentCount) firstId = currentId;
segmentCount++;
if (((nextId - currentId) > 1) || (nextId >= endId))
{
NormRepairRequest::Form form;
switch (segmentCount)
{
case 0:
form = NormRepairRequest::INVALID;
break;
case 1:
case 2:
form = NormRepairRequest::ITEMS;
break;
default:
form = NormRepairRequest::RANGES;
break;
}
if (form != prevForm)
{
if (NormRepairRequest::INVALID != prevForm)
{
if (0 == nack.PackRepairRequest(req))
{
prevForm = NormRepairRequest::INVALID; PLOG(PL_WARN, "NormBlock::AppendRepairRequest() warning: full NACK msg\n");
break;
}
requestAppended = true;
}
nack.AttachRepairRequest(req, payloadMax); req.SetForm(form);
prevForm = form;
}
switch (form)
{
case NormRepairRequest::INVALID:
ASSERT(0);
break;
case NormRepairRequest::ITEMS:
req.AppendRepairItem(fecId, fecM, objectId, blk_id, numData, firstId); if (2 == segmentCount)
req.AppendRepairItem(fecId, fecM, objectId, blk_id, numData, currentId); break;
case NormRepairRequest::RANGES:
req.AppendRepairRange(fecId, fecM,
objectId, blk_id, numData, firstId, objectId, blk_id, numData, currentId); break;
case NormRepairRequest::ERASURES:
break;
} segmentCount = 0;
}
} if (NormRepairRequest::INVALID != prevForm)
{
if (0 == nack.PackRepairRequest(req))
PLOG(PL_WARN, "NormBlock::AppendRepairRequest() warning: full NACK msg\n");
else
requestAppended = true;
}
return requestAppended;
}
NormBlockPool::NormBlockPool()
: head((NormBlock*)NULL), blk_total(0), blk_count(0), overruns(0), overrun_flag(false)
{
}
NormBlockPool::~NormBlockPool()
{
Destroy();
}
bool NormBlockPool::Init(UINT32 numBlocks, UINT16 segsPerBlock)
{
if (head) Destroy();
for (UINT32 i = 0; i < numBlocks; i++)
{
NormBlock* b = new NormBlock();
if (b)
{
if (!b->Init(segsPerBlock))
{
PLOG(PL_FATAL, "NormBlockPool::Init() block init error\n");
delete b;
Destroy();
return false;
}
b->next = head;
head = b;
blk_count++;
blk_total++;
}
else
{
PLOG(PL_FATAL, "NormBlockPool::Init() new block error\n");
Destroy();
return false;
}
}
return true;
}
void NormBlockPool::Destroy()
{
ASSERT(blk_total == blk_count);
NormBlock* next;
while ((next = head))
{
head = next->next;
delete next;
}
blk_count = blk_total = 0;
}
NormBlockBuffer::NormBlockBuffer()
#ifdef USE_PROTO_TREE
:
#else
: table((NormBlock**)NULL),
#endif range_max(0), range(0), fec_block_mask(0)
{
}
NormBlockBuffer::~NormBlockBuffer()
{
Destroy();
}
bool NormBlockBuffer::Init(unsigned long rangeMax, unsigned long tableSize, UINT32 fecBlockMask)
{
Destroy();
if (0 == tableSize)
{
PLOG(PL_FATAL, "NormBlockBuffer::Init() bad range(%lu) or tableSize(%lu)\n",
rangeMax, tableSize);
return false;
}
#ifndef USE_PROTO_TREE
if (0 != (tableSize & 0x07)) tableSize = (tableSize >> 3) + 1;
if (!(table = new NormBlock*[tableSize]))
{
PLOG(PL_FATAL, "NormBlockBuffer::Init() buffer allocation error: %s\n", GetErrorString());
return false;
}
memset(table, 0, tableSize*sizeof(char*));
hash_mask = tableSize - 1;
#endif range_max = rangeMax;
range = 0;
fec_block_mask = fecBlockMask;
return true;
}
#ifdef USE_PROTO_TREE
void NormBlockBuffer::Destroy()
{
NormBlock* block;
while((block = Find(range_lo)))
{
PLOG(PL_ERROR, "NormBlockBuffer::Destroy() buffer not empty!?\n");
Remove(block);
delete block;
}
range_max = range = 0;
}
NormBlock* NormBlockBuffer::Find(const NormBlockId& blockId) const
{
if ((0 == range) || (Compare(blockId, range_lo) < 0) || (Compare(blockId, range_hi) > 0))
return NULL;
else
return tree.Find(blockId.GetValuePtr(), 8*sizeof(UINT32));
}
#else
void NormBlockBuffer::Destroy()
{
if (table)
{
NormBlock* block;
while((block = Find(range_lo)))
{
PLOG(PL_ERROR, "NormBlockBuffer::Destroy() buffer not empty!?\n");
Remove(block);
delete block;
}
delete []table;
table = (NormBlock**)NULL;
}
range_max = range = 0;
}
NormBlock* NormBlockBuffer::Find(const NormBlockId& blockId) const
{
if (range)
{
if ((Compare(blockId, range_lo) < 0) || (Compare(blockId, range_hi) > 0))
return (NormBlock*)NULL;
NormBlock* theBlock = table[(blockId.GetValue()) & hash_mask];
while ((NULL != theBlock) && (blockId != theBlock->GetId()))
theBlock = theBlock->next;
return theBlock;
}
else
{
return (NormBlock*)NULL;
}
}
#endif
NormBlockId NormBlockBuffer::RangeMin() const
{
if (range_max > 1)
{
NormBlockId rangeMin = range_hi;
Decrement(rangeMin, (UINT32)range_max - 1);
return rangeMin;
}
else
{
return range_lo;
}
}
bool NormBlockBuffer::CanInsert(NormBlockId blockId) const
{
if (0 != range)
{
if (Compare(blockId, range_lo) < 0)
{
if (((UINT32)Difference(range_lo, blockId) + range) > range_max)
return false;
else
return true;
}
else if (Compare(blockId, range_hi) > 0)
{
if (((UINT32)Difference(blockId, range_hi) + range) > range_max)
return false;
else
return true;
}
else
{
return true;
}
}
else
{
return true;
}
}
bool NormBlockBuffer::Insert(NormBlock* theBlock)
{
const NormBlockId& blockId = theBlock->GetId();
if (0 == range)
{
range_lo = range_hi = blockId;
range = 1;
}
else if (Compare(blockId, range_lo) < 0)
{
UINT32 newRange = (UINT32)Difference(range_lo, blockId) + (UINT32)range;
if (newRange > range_max) return false;
range_lo = blockId;
range = newRange;
}
else if (Compare(blockId, range_hi) > 0)
{
UINT32 newRange = (UINT32)Difference(blockId, range_hi) + (UINT32)range;
if (newRange > range_max) return false;
range_hi = blockId;
range = newRange;
}
ASSERT(Compare(range_hi, range_lo) >= 0);
#ifdef USE_PROTO_TREE
ASSERT(NULL == Find(theBlock->GetId()));
tree.Insert(*theBlock);
#else
UINT32 index = blockId.GetValue() & hash_mask;
NormBlock* prev = NULL;
NormBlock* entry = table[index];
while ((NULL != entry) && (Compare(entry->GetId(), blockId) < 0))
{
prev = entry;
entry = entry->next;
}
if (prev)
prev->next = theBlock;
else
table[index] = theBlock;
ASSERT((entry ? (blockId != entry->GetId()) : true));
theBlock->next = entry;
#endif return true;
}
#ifdef USE_PROTO_TREE
bool NormBlockBuffer::Remove(NormBlock* theBlock)
{
ASSERT(NULL != theBlock);
const NormBlockId& blockId = theBlock->GetId();
switch (range)
{
case 0:
return false; case 1:
if (blockId != range_lo)
return false; range = 0;
break;
default:
if ((Compare(blockId, range_lo) < 0) || (Compare(blockId, range_hi) > 0))
return false; if (blockId == range_lo)
{
const NormBlock* next = static_cast<const NormBlock*>(theBlock->GetNext());
if (NULL == next) next = static_cast<const NormBlock*>(tree.GetHead());
ASSERT(NULL != next);
range_lo = next->GetId();
range = Difference(range_hi, range_lo) + 1;
}
else if (blockId == range_hi)
{
const NormBlock* prev = static_cast<const NormBlock*>(theBlock->GetPrev());
if (NULL == prev) prev = static_cast<const NormBlock*>(tree.GetTail());
ASSERT(NULL != prev);
range_hi = prev->GetId();
range = Difference(range_hi, range_lo) + 1;
}
break;
}
ASSERT(NULL != tree.Find(theBlock->GetId().GetValuePtr(), 8*sizeof(UINT32)));
tree.Remove(*theBlock);
return true;
}
#else
bool NormBlockBuffer::Remove(NormBlock* theBlock)
{
ASSERT(NULL != theBlock);
if (range)
{
const NormBlockId& blockId = theBlock->GetId();
if ((Compare(blockId, range_lo) < 0) || (Compare(blockId, range_hi) > 0))
return false;
UINT32 index = blockId.GetValue() & hash_mask;
NormBlock* prev = NULL;
NormBlock* entry = table[index];
while (entry && (entry->GetId() != blockId))
{
prev = entry;
entry = entry->next;
}
if (NULL == entry) return false;
if (NULL != prev)
prev->next = entry->next;
else
table[index] = entry->next;
if (range > 1)
{
if (blockId == range_lo)
{
UINT32 i = index;
UINT32 endex;
if (range <= hash_mask)
endex = (index + range - 1) & hash_mask;
else
endex = index;
entry = NULL;
UINT32 offset = 0;
NormBlockId nextId = range_hi;
do
{
++i &= hash_mask;
offset++;
if (NULL != (entry = table[i]))
{
NormBlockId id = blockId;
Increment(id, offset);
while(entry && (entry->GetId() != id))
{
if ((Compare(entry->GetId(), blockId) > 0) &&
(Compare(entry->GetId(), nextId) < 0))
{
nextId = entry->GetId();
}
entry = entry->next;
}
if (NULL != entry) break;
}
} while (i != endex);
if (NULL != entry)
range_lo = entry->GetId();
else
range_lo = nextId;
range = (UINT32)Difference(range_hi, range_lo) + 1;
}
else if (blockId == range_hi)
{
UINT32 i = index;
UINT32 endex;
if (range <= hash_mask)
endex = (index - range + 1) & hash_mask;
else
endex = index;
entry = NULL;
UINT32 offset = 0;
NormBlockId prevId = range_lo;
do
{
--i &= hash_mask;
offset++;
if ((entry = table[i]))
{
NormBlockId id = blockId;
Decrement(id, offset);
while(entry && (entry->GetId() != id))
{
if ((Compare(entry->GetId(), blockId) < 0) &&
(Compare(entry->GetId(), prevId) > 0))
{
prevId = entry->GetId();
}
entry = entry->next;
}
if (NULL != entry) break;
}
} while (i != endex);
if (NULL != entry)
range_hi = entry->GetId();
else
range_hi = prevId;
range = (UINT32)Difference(range_hi, range_lo) + 1;
}
}
else
{
range = 0;
}
return true;
}
else
{
return false;
}
}
#endif
#ifdef USE_PROTO_TREE
NormBlockBuffer::Iterator::Iterator(NormBlockBuffer& blockBuffer)
: buffer(blockBuffer), iterator(blockBuffer.tree, false, blockBuffer.range_lo.GetValuePtr(), 8*sizeof(UINT32))
{
next_block = iterator.GetNextItem();
ASSERT((NULL == next_block) || (blockBuffer.range_lo == next_block->GetId()))
}
void NormBlockBuffer::Iterator::Reset()
{
iterator.Reset(false, buffer.range_lo.GetValuePtr(), 8*sizeof(UINT32));
next_block = iterator.GetNextItem();
ASSERT(buffer.IsEmpty() || (NULL != next_block));
ASSERT((NULL == next_block) || (buffer.range_lo == next_block->GetId()))
}
NormBlock* NormBlockBuffer::Iterator::GetNextBlock()
{
NormBlock* nextBlock = next_block;
if (NULL != nextBlock)
{
next_block = iterator.GetNextItem();
if (NULL == next_block)
{
iterator.Reset();
next_block = iterator.GetNextItem();
if (buffer.Compare(next_block->GetId(), nextBlock->GetId()) <= 0)
next_block = NULL;
}
else if (buffer.Compare(next_block->GetId(), nextBlock->GetId()) <= 0)
{
next_block = NULL;
}
}
return nextBlock;
}
#else
NormBlockBuffer::Iterator::Iterator(const NormBlockBuffer& blockBuffer)
: buffer(blockBuffer), reset(true)
{
}
NormBlock* NormBlockBuffer::Iterator::GetNextBlock()
{
if (reset)
{
if (buffer.range)
{
reset = false;
index = buffer.range_lo;
return buffer.Find(index);
}
else
{
return (NormBlock*)NULL;
}
}
else
{
if ((0 != buffer.range) &&
(buffer.Compare(index, buffer.range_hi) < 0) &&
(buffer.Compare(index, buffer.range_lo) >= 0))
{
UINT32 i = index.GetValue();;
UINT32 endex;
if ((UINT32)buffer.Difference(buffer.range_hi, index) <= buffer.hash_mask)
endex = buffer.range_hi.GetValue() & buffer.hash_mask;
else
endex = index.GetValue();
UINT32 offset = 0;
NormBlockId nextId = buffer.range_hi;
do
{
++i &= buffer.hash_mask;
offset++;
NormBlockId id = index;
buffer.Increment(id, offset);
ASSERT(i < 256);
NormBlock* entry = buffer.table[i];
while ((NULL != entry ) && (entry->GetId() != id))
{
if ((buffer.Compare(entry->GetId(), index) > 0) &&
(buffer.Compare(entry->GetId(), nextId) < 0))
{
nextId = entry->GetId();
}
entry = NormBlockBuffer::Next(entry);
}
if (entry)
{
index = entry->GetId();
return entry;
}
} while (i != endex);
index = nextId;
return buffer.Find(nextId);
}
else
{
return (NormBlock*)NULL;
}
}
}
#endif