Listing 1: Definition of Slot<> and Index<> classes
// Listing 1: Definition of Slot<> and Index<> classes
template <typename C, size_t CCH>
struct Slot
{
Slot(Slot *next)
: next(next)
{}
~Slot()
{
delete next;
}
// Use the process heap because:
//
// 1. Don't want to worry about thread-specificity, since
// deallocation will occur in a different thread to allocation
// 2. Don't want to worry about linkage to any specific CRT or
// other library
// 3. Doesn't matter how fast it is
// 4. Want it to be *highly* unlikely that allocation will fail,
// which is indeed pretty unheard of when using the Win32
// process heap.
// 5. Want a C++-exception free solution, so use the Win32-system
// out-of-memory exception, and not have to worry about any
// linkage pains.
void *operator new(size_t cb)
{
return ::HeapAlloc(::GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, cb);
}
void operator delete(void *pv)
{
::HeapFree(::GetProcessHeap(), 0, pv);
}
C buff[CCH];
Slot *next;
};
template <typename C, size_t CCH>
struct Index
{
typedef Slot<C, CCH> Slot;
Index()
: m_index(::TlsAlloc())
{
// Use Win32 exception because:
//
// 1. Process cannot recover from this error in any
// meaningful way
// 2. Do not want to couple to C++ exception-handling
// and there is no graceful way to allow this to be
// parameterisable. (May allow a pp-discriminated
// mechanism in next version.)
if(TLS_OUT_OF_INDEXES == m_index)
{
::RaiseException(STATUS_NO_MEMORY, EXCEPTION_NONCONTINUABLE, 0, 0);
}
}
~Index()
{
// Walk the slot list and free. This can be as slow as
// you like, since performance is not important here
delete m_top;
// Now release the index
::TlsFree(m_index);
}
Slot *GetSlot()
{
// NOTE: This does not need to be thread-safe
return reinterpret_cast<Slot*>(::TlsGetValue(m_index));
}
Slot *AllocSlot()
{
Slot *next;
{ // Protect linked-list manipulation
lock_scope<thread_mutex> lock(m_mx);
m_top = next = new Slot(m_top);
}
::TlsSetValue(m_index, next);
return next;
}
private:
ws_dword_t const m_index;
Slot *m_top;
thread_mutex m_mx;
};