template struct modelcacheentry { typedef modelcacheentry entry; T *prev, *next, *nextalloc; size_t size; bool locked; modelcacheentry(T *prev = NULL, T *next = NULL) : prev(prev), next(next), nextalloc(NULL), size(0), locked(false) {} bool empty() const { return prev==next; } void linkbefore(T *pos) { next = pos; prev = pos->entry::prev; prev->entry::next = (T *)this; next->entry::prev = (T *)this; } void linkafter(T *pos) { next = pos->entry::next; prev = pos; prev->entry::next = (T *)this; next->entry::prev = (T *)this; } void unlink() { prev->entry::next = next; next->entry::prev = prev; prev = next = (T *)this; } void *getdata() { return (T *)this + 1; } }; template struct modelcachelist : modelcacheentry { typedef modelcacheentry entry; modelcachelist() : entry((T *)this, (T *)this) {} T *start() { return entry::next; } T *end() { return (T *)this; } void addfirst(entry *e) { e->linkafter((T *)this); } void addlast(entry *e) { e->linkbefore((T *)this); } void removefirst() { if(!entry::empty()) entry::next->unlink(); } void removelast() { if(!entry::empty()) entry::prev->unlink(); } }; struct modelcache { struct entry : modelcacheentry {}; uchar *buf; size_t size; entry *curalloc; modelcache(size_t size = 0) : buf(size ? new uchar[size] : NULL), size(size), curalloc(NULL) {} ~modelcache() { DELETEA(buf); } void resize(size_t nsize) { if(curalloc) { for(curalloc = (entry *)buf; curalloc; curalloc = curalloc->nextalloc) curalloc->unlink(); } DELETEA(buf); buf = nsize ? new uchar[nsize] : 0; size = nsize; } template T *allocate(size_t reqsize) { reqsize += sizeof(T); if(reqsize > size) return NULL; if(!curalloc) { curalloc = (entry *)buf; curalloc->size = reqsize; curalloc->locked = false; curalloc->nextalloc = NULL; return (T *)curalloc; } if(curalloc) for(bool failed = false;;) { uchar *nextfree = curalloc ? (uchar *)curalloc + curalloc->size : (uchar *)buf; entry *nextused = curalloc ? curalloc->nextalloc : (entry *)buf; for(;;) { if(!nextused) { if(size_t(&buf[size] - nextfree) >= reqsize) goto success; break; } else if(size_t((uchar *)nextused - nextfree) >= reqsize) goto success; else if(nextused->locked) break; nextused->unlink(); nextused = nextused->nextalloc; } if(curalloc) curalloc->nextalloc = nextused; else if(failed) { curalloc = nextused; break; } else failed = true; curalloc = nextused; continue; success: entry *result = (entry *)nextfree; result->size = reqsize; result->locked = false; result->nextalloc = nextused; if(curalloc) curalloc->nextalloc = result; curalloc = result; return (T *)curalloc; } curalloc = (entry *)buf; return NULL; } template void release(modelcacheentry *e) { e->unlink(); } };