TBSpaceAllocator::Space *TBSpaceAllocator::GetSmallestAvailableSpace(int needed_w) { assert(needed_w > 0); // Add free space covering all available space if empty. if (!m_free_space_list.HasLinks() && IsAllAvailable()) { if (Space *fs = new Space) { fs->x = 0; fs->width = m_available_space; m_free_space_list.AddLast(fs); } } // Check for the smallest space where we fit Space *best_fs = nullptr; for (Space *fs = m_free_space_list.GetFirst(); fs; fs = fs->GetNext()) { if (needed_w == fs->width) return fs; // It can't be better than a perfect match! if (needed_w < fs->width) if (!best_fs || fs->width < best_fs->width) best_fs = fs; } return best_fs; }
bool TBSpaceAllocator::HasSpace(int needed_w) const { if (needed_w > m_available_space) return false; if (IsAllAvailable()) return true; for (Space *fs = m_free_space_list.GetFirst(); fs; fs = fs->GetNext()) { if (needed_w <= fs->width) return true; } return false; }
void TBSpaceAllocator::FreeSpace(Space *space) { m_used_space_list.Remove(space); m_available_space += space->width; // Find where in m_free_space_list we should insert the space, // or which existing space we can extend. Space *preceeding = nullptr; Space *succeeding = nullptr; for (Space *fs = m_free_space_list.GetFirst(); fs; fs = fs->GetNext()) { if (fs->x < space->x) preceeding = fs; if (fs->x > space->x) { succeeding = fs; break; } } if (preceeding && preceeding->x + preceeding->width == space->x) { preceeding->width += space->width; delete space; } else if (succeeding && succeeding->x == space->x + space->width) { succeeding->x -= space->width; succeeding->width += space->width; delete space; } else { if (preceeding) m_free_space_list.AddAfter(space, preceeding); else if (succeeding) m_free_space_list.AddBefore(space, succeeding); else { assert(!m_free_space_list.HasLinks()); m_free_space_list.AddLast(space); } } // Merge free spaces Space *fs = m_free_space_list.GetFirst(); while (fs) { Space *next_fs = fs->GetNext(); if (!next_fs) break; if (fs->x + fs->width == next_fs->x) { fs->width += next_fs->width; m_free_space_list.Delete(next_fs); continue; } fs = next_fs; } #ifdef TB_RUNTIME_DEBUG_INFO // Check that free space is in order Space *tmp = m_free_space_list.GetFirst(); int x = 0; while (tmp) { assert(tmp->x >= x); x = tmp->x + tmp->width; tmp = tmp->GetNext(); } #endif // TB_RUNTIME_DEBUG_INFO }