void StreamBuffer::pop(UInt32 n) { // discard all chunks if n is greater than or equal to m_size if (n >= m_size) { m_size = 0; m_headUsed = 0; m_chunks.clear(); return; } // update size m_size -= n; // discard chunks until more than n bytes would've been discarded ChunkList::iterator scan = m_chunks.begin(); assert(scan != m_chunks.end()); while (scan->size() - m_headUsed <= n) { n -= (UInt32)scan->size() - m_headUsed; m_headUsed = 0; scan = m_chunks.erase(scan); assert(scan != m_chunks.end()); } // remove left over bytes from the head chunk if (n > 0) { m_headUsed += n; } }
const void* StreamBuffer::peek(UInt32 n) { assert(n <= m_size); // if requesting no data then return NULL so we don't try to access // an empty list. if (n == 0) { return NULL; } // reserve space in first chunk ChunkList::iterator head = m_chunks.begin(); head->reserve(n + m_headUsed); // consolidate chunks into the first chunk until it has n bytes ChunkList::iterator scan = head; ++scan; while (head->size() - m_headUsed < n && scan != m_chunks.end()) { head->insert(head->end(), scan->begin(), scan->end()); scan = m_chunks.erase(scan); } return reinterpret_cast<const void*>(&(head->begin()[m_headUsed])); }
void StreamBuffer::write(const void* vdata, UInt32 n) { assert(vdata != NULL); // ignore if no data, otherwise update size if (n == 0) { return; } m_size += n; // cast data to bytes const UInt8* data = reinterpret_cast<const UInt8*>(vdata); // point to last chunk if it has space, otherwise append an empty chunk ChunkList::iterator scan = m_chunks.end(); if (scan != m_chunks.begin()) { --scan; if (scan->size() >= kChunkSize) { ++scan; } } if (scan == m_chunks.end()) { scan = m_chunks.insert(scan, Chunk()); } // append data in chunks while (n > 0) { // choose number of bytes for next chunk assert(scan->size() <= kChunkSize); UInt32 count = kChunkSize - (UInt32)scan->size(); if (count > n) count = n; // transfer data scan->insert(scan->end(), data, data + count); n -= count; data += count; // append another empty chunk if we're not done yet if (n > 0) { ++scan; scan = m_chunks.insert(scan, Chunk()); } } }
bool Heap::deallocate(void *ptr, size_t sz) { if (ptr < mHeap || ptr >= end()) { return false; } mUsedSize -= sz; Chunk chunk = {ptr, sz}; ChunkList::iterator it = std::lower_bound(mChunks.begin(), mChunks.end(), chunk); if (it != mChunks.begin()) { // have a previous chunk ChunkList::iterator pit = it; --pit; if (it == mChunks.end()) { // no next chunk if (pit->end() == ptr) { PrintDebug("Merge with prev free chunk"); pit->size += sz; } else { PrintDebug("Add new free chunk"); mChunks.insert(it, chunk); } } else { // also have next chunk if (pit->end() == ptr) { PrintDebug("Merge with prev free chunk"); pit->size += sz; if (pit->end() == it->start) { PrintDebug("Merge with next free chunk"); pit->size += it->size; mChunks.erase(it); } } else { if (offset(ptr, sz) == it->start) { PrintDebug("Merge with next free chunk"); it->start = ptr; it->size += sz; } else { PrintDebug("Add new free chunk"); mChunks.insert(it, chunk); } } } } else { // no previous chunk if (it == mChunks.end()) { // no next chunk PrintDebug("Add new free chunk"); mChunks.insert(it, chunk); } else { // have next chunk if (offset(ptr, sz) == it->start) { PrintDebug("Merge with next free chunk"); it->start = ptr; it->size += sz; } else { PrintDebug("Add new free chunk"); mChunks.insert(it, chunk); } } } /* ChunkList::iterator it = std::lower_bound(mChunks.begin(), mChunks.end(), chunk); if (it != mChunks.begin()) { // have a previous chunk ChunkList::iterator pit = it; --pit; if (it == mChunks.end()) { // no next chunk } else { // also have next chunk } } else { // no previous chunk if (it == mChunks.end()) { // no next chunk } else { // have next chunk } } if (it != mChunks.end()) { // it points to next available chunk if (offset(ptr, sz) < it->start) { if (it != mChunks.begin()) { // theres also a previous chunck ChunkList::iterator pit = it; --pit; if (ptr > pit->end()) { #ifdef _DEBUG std::cerr << "### Add new free chunk" << std::endl; #endif mChunks.insert(it, chunk); } else { #ifdef _DEBUG std::cerr << "### Merge with previous free chunk" << std::endl; #endif // merge with prev pit->size += sz; } } else { mChunks.insert(it, chunk); } } else { // merge with next #ifdef _DEBUG std::cerr << "### Merge with next free chunk" << std::endl; #endif it->start = ptr; it->size += sz; } } else { ChunkList::iterator pit = it; --pit; if (ptr > pit->end()) { #ifdef _DEBUG std::cerr << "### Add new free chunk" << std::endl; #endif mChunks.insert(it, chunk); } else { // merge with prev #ifdef _DEBUG std::cerr << "### Merge with previous free chunk" << std::endl; #endif pit->size += sz; } } */ return true; }