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.
214 lines
4.7 KiB
214 lines
4.7 KiB
// Name table interface/implementation
|
|
|
|
#ifndef __NMTNI_INCLUDED__
|
|
#define __NMTNI_INCLUDED__
|
|
|
|
#ifndef __ARRAY_INCLUDED__
|
|
#include "array.h"
|
|
#endif
|
|
#ifndef __MAP_INCLUDED__
|
|
#include "map.h"
|
|
#endif
|
|
#ifndef __BUFFER_INCLUDED__
|
|
#include "buffer.h"
|
|
#endif
|
|
#ifndef __MISC_INCLUDED__
|
|
#include "misc.h"
|
|
#endif
|
|
|
|
class NMTNI { // name table with user-defined NIs
|
|
public:
|
|
static const Buffer* pbufCur;
|
|
// current buffer, shared amongst all NMTNIs and
|
|
// their SZOs, req'd because C++ lacks closures
|
|
struct SZO { // string offset: relative to start of pbufCur
|
|
OFF off; // offset within pbufCur
|
|
|
|
SZ sz() const { // produce a SZ for the SZO; goes invalid quick!
|
|
return (SZ)(pbufCur->Start() + off);
|
|
}
|
|
BOOL operator==(const SZO& szo) const {
|
|
return off == szo.off || strcmp(sz(), szo.sz()) == 0;
|
|
}
|
|
operator HASH() const {
|
|
return hashSz(sz());
|
|
}
|
|
};
|
|
|
|
typedef HashClass<SZO,hcCast> HcSzo;
|
|
|
|
public:
|
|
// create a name table with default name index generation (0, 1, 2, ...)
|
|
NMTNI()
|
|
{
|
|
pfnNi = niNext;
|
|
pfnNiArg = this;
|
|
niMac = niNil + 1;
|
|
}
|
|
// create a name table with client defined name index generation
|
|
NMTNI(BOOL (*pfnNi_)(void*, OUT NI*), void* pfnNiArg_ = 0)
|
|
{
|
|
pfnNi = pfnNi_;
|
|
pfnNiArg = pfnNiArg_;
|
|
niMac = 0; // will not be used
|
|
}
|
|
// append a serialization of this NMTNI to the buffer
|
|
BOOL save(Buffer* pbuf) {
|
|
// optimization: since mapNiSzo is just the reverse map of mapSzoNi,
|
|
// we store only the latter
|
|
if (!buf.save(pbuf))
|
|
return FALSE;
|
|
traceOnly(CB cb0 = pbuf->Size());
|
|
|
|
if (!mapSzoNi.save(pbuf))
|
|
return FALSE;
|
|
traceOnly(CB cbMap = pbuf->Size() - cb0);
|
|
|
|
if (!pbuf->Append((PB)&niMac, sizeof niMac))
|
|
return FALSE;
|
|
|
|
trace((trSave, "NMTNI::save() cbBuf=%d cbMap=%d\n", buf.Size(), cbMap));
|
|
return TRUE;
|
|
}
|
|
// reload a serialization of this empty NMTNI from the buffer; leave
|
|
// *ppb pointing just past the NMTNI representation
|
|
BOOL reload(PB* ppb) {
|
|
if (!buf.reload(ppb))
|
|
return FALSE;
|
|
pbufCur = &buf;
|
|
|
|
if (!mapSzoNi.reload(ppb))
|
|
return FALSE;
|
|
|
|
niMac = *(NI UNALIGNED *)*ppb;
|
|
*ppb += sizeof(niMac);
|
|
|
|
// recover mapNiSzo from mapSzoNi
|
|
mapNiSzo.reset();
|
|
EnumMap<SZO,NI,HcSzo> enumMap(mapSzoNi);
|
|
while (enumMap.next()) {
|
|
SZO szo;
|
|
NI ni;
|
|
enumMap.get(&szo, &ni);
|
|
if (!mapNiSzo.add(ni, szo))
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
// return a name index for this name
|
|
BOOL addNiForSz(SZ_CONST sz, OUT NI *pni) {
|
|
precondition(pni);
|
|
|
|
pbufCur = &buf;
|
|
|
|
// speculatively add the argument name to the name buffer
|
|
SZO szo;
|
|
if (!addSzo(sz, &szo))
|
|
return FALSE;
|
|
else if (mapSzoNi.map(szo, pni)) {
|
|
// name already in table, remove name we just added to buffer
|
|
verify(retractSzo(szo));
|
|
return TRUE;
|
|
}
|
|
else if (pfnNi(pfnNiArg, pni) &&
|
|
mapSzoNi.add(szo, *pni) &&
|
|
mapNiSzo.add(*pni, szo))
|
|
{
|
|
// successfully added the name and its new name index
|
|
return TRUE;
|
|
}
|
|
else {
|
|
// failed hard; we'd better not commit these changes!
|
|
verify(retractSzo(szo));
|
|
return FALSE;
|
|
}
|
|
}
|
|
// return the name corresponding to ni, valid until next NMTNI call
|
|
BOOL szForNi(NI ni, OUT SZ *psz) {
|
|
precondition(ni != niNil);
|
|
precondition(psz);
|
|
|
|
pbufCur = &buf;
|
|
|
|
SZO szo;
|
|
if (mapNiSzo.map(ni, &szo)) {
|
|
*psz = szo.sz();
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
void reset() {
|
|
niMac = niNil + 1;
|
|
mapSzoNi.reset();
|
|
mapNiSzo.reset();
|
|
buf.Clear();
|
|
}
|
|
|
|
private:
|
|
Map<SZO,NI,HcSzo> mapSzoNi; // map from szo to ni
|
|
Map<NI,SZO,HcNi> mapNiSzo; // map from ni to szo
|
|
Buffer buf; // store the names
|
|
// REVIEW: this buffer should be a pool!
|
|
BOOL (*pfnNi)(void*, OUT NI*);
|
|
void* pfnNiArg;
|
|
NI niMac; // last NI allocated by niNext()
|
|
|
|
// append the name to the names buffer
|
|
BOOL addSzo(SZ_CONST sz, OUT SZO* pszo) {
|
|
precondition(sz && strlen(sz) > 0);
|
|
precondition(pszo);
|
|
|
|
CB cb = strlen(sz) + 1;
|
|
PB pb;
|
|
if (buf.Append((PB)sz, cb, &pb)) {
|
|
pszo->off = pb - buf.Start();
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
// remove the name recently appended to the names buffer
|
|
BOOL retractSzo(const SZO& szo) {
|
|
return buf.Truncate(szo.off);
|
|
}
|
|
// default NI generator: returns the sequence (1, 2, ...)
|
|
static BOOL niNext(void* pv, OUT NI* pni) {
|
|
NMTNI* pnmt = (NMTNI*)pv;
|
|
precondition(pnmt);
|
|
|
|
*pni = pnmt->niMac++;
|
|
return TRUE;
|
|
}
|
|
|
|
friend class EnumNMTNI;
|
|
};
|
|
|
|
class EnumNMTNI : public EnumNameMap {
|
|
public:
|
|
EnumNMTNI(const NMTNI& nmt)
|
|
: enumMap(nmt.mapSzoNi), pnmt(&nmt)
|
|
{
|
|
}
|
|
void release() {
|
|
delete this;
|
|
}
|
|
void reset() {
|
|
enumMap.reset();
|
|
}
|
|
BOOL next() {
|
|
return enumMap.next();
|
|
}
|
|
void get(OUT SZ_CONST* psz, OUT NI* pni) {
|
|
NMTNI::SZO szo;
|
|
enumMap.get(&szo, pni);
|
|
NMTNI::pbufCur = &pnmt->buf;
|
|
*psz = szo.sz();
|
|
}
|
|
private:
|
|
EnumMap<NMTNI::SZO,NI,NMTNI::HcSzo> enumMap;
|
|
const NMTNI* pnmt;
|
|
};
|
|
|
|
#endif // !__NMTNI_INCLUDED__
|