mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
144 lines
3.5 KiB
144 lines
3.5 KiB
//
|
|
// distarr.h
|
|
//
|
|
// implements a distributed array, a logically contiguous
|
|
// array is presented given pieces in various streams at
|
|
// various offsets.
|
|
|
|
#ifndef __DISTARRAY_INCLUDED__
|
|
#define __DISTARRAY_INCLUDED__
|
|
|
|
#include "..\include\array.h"
|
|
|
|
#define C_ITEMS_BUF 128
|
|
|
|
// maintains the stream and offset info for each
|
|
// piece of the array
|
|
struct SECT {
|
|
int iElBase;
|
|
int cEl;
|
|
Stream * pstm;
|
|
OFF offStm;
|
|
};
|
|
|
|
// this is the array
|
|
template <class T> class DistArray
|
|
{
|
|
public:
|
|
const T& operator[](int iEl);
|
|
int isectOfIel(int iEl);
|
|
BOOL addSection(Stream *pstm, OFF off, int cEl);
|
|
int iMac();
|
|
DistArray() { iTBufMin = iTBufMac = 0; }
|
|
|
|
private:
|
|
// the range of items that is currently buffered
|
|
int iTBufMin;
|
|
int iTBufMac;
|
|
int iTSection;
|
|
T rgTBuffered[C_ITEMS_BUF];
|
|
|
|
int cElMac;
|
|
Array<SECT> rgOffs;
|
|
};
|
|
|
|
|
|
// helper function for finding a lastest section
|
|
// that comes before the requested index
|
|
__inline BOOL FSectLeInt(SECT *psect, void *pvInteger)
|
|
{
|
|
return ((int)pvInteger) < psect->iElBase + psect->cEl ;
|
|
}
|
|
|
|
template <class T> inline
|
|
int DistArray<T>::isectOfIel(int iEl)
|
|
{
|
|
if (iEl >= iTBufMin && iEl < iTBufMac)
|
|
return iTSection;
|
|
|
|
return rgOffs.binarySearch(FSectLeInt, (void*)iEl);
|
|
}
|
|
|
|
|
|
// this is the meat and potoatoes of this class,
|
|
// we return the requested element directly if
|
|
// it is in the buffer area, and if not we
|
|
// read in a section of the stream that contains
|
|
// the requested element and then return it
|
|
template <class T> inline
|
|
const T& DistArray<T>::operator[](int iEl)
|
|
{
|
|
if (iEl >= iTBufMin && iEl < iTBufMac)
|
|
return rgTBuffered[iEl - iTBufMin];
|
|
|
|
assert(iEl < iMac());
|
|
|
|
int iElBase = (iEl - iEl%C_ITEMS_BUF);
|
|
int isect = rgOffs.binarySearch(FSectLeInt, (void*)iElBase);
|
|
|
|
assert(isect < (int)rgOffs.size());
|
|
assert(rgOffs[isect].iElBase <= iEl);
|
|
|
|
// look for a section that spans iEl
|
|
while (rgOffs[isect].iElBase + rgOffs[isect].cEl <= iEl) {
|
|
isect++;
|
|
iElBase = rgOffs[isect].iElBase;
|
|
assert(iElBase <= iEl);
|
|
assert(isect < (int)rgOffs.size());
|
|
}
|
|
|
|
// now that we've found a section with the element we
|
|
// need in it, we have to read it in
|
|
|
|
// find the offset of the element within the section
|
|
// and the number of elements we can read starting
|
|
// at that point
|
|
int cElSkip = iElBase - rgOffs[isect].iElBase;
|
|
int cElLeft = rgOffs[isect].cEl - cElSkip;
|
|
|
|
// we'll read in at most C_ITEMS_BUF into our buffer
|
|
int cEl = min(cElLeft, C_ITEMS_BUF);
|
|
iTBufMin = iElBase;
|
|
iTBufMac = iTBufMin + cEl;
|
|
iTSection = isect;
|
|
|
|
// compute the offset and size we need to read
|
|
CB cb = cEl*sizeof(T);
|
|
OFF off = rgOffs[isect].offStm + cElSkip*sizeof(T);
|
|
|
|
// now read in the bytes (REVIEW: error handling?)
|
|
verify(rgOffs[isect].pstm->Read(off, rgTBuffered, &cb));
|
|
assert(cb == (CB)(cEl*sizeof(T)));
|
|
|
|
// now it's in the buffer, we're ready to return.
|
|
return rgTBuffered[iEl - iTBufMin];
|
|
}
|
|
|
|
template <class T> inline
|
|
int DistArray<T>::iMac()
|
|
{
|
|
int cSect = rgOffs.size();
|
|
if (cSect == 0)
|
|
return 0;
|
|
|
|
return rgOffs[cSect-1].iElBase + rgOffs[cSect-1].cEl;
|
|
}
|
|
|
|
template <class T> inline
|
|
BOOL DistArray<T>::addSection(Stream *pstm, OFF offStm, int cEl)
|
|
{
|
|
SECT sect;
|
|
sect.pstm = pstm;
|
|
sect.offStm = offStm;
|
|
sect.cEl = cEl;
|
|
sect.iElBase = iMac();
|
|
|
|
// add the new section
|
|
if (!rgOffs.append(sect))
|
|
return FALSE;
|
|
|
|
postcondition(iMac() == sect.iElBase + sect.cEl);
|
|
return TRUE;
|
|
}
|
|
|
|
#endif
|