// // Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // HandleRangeAllocator.cpp : Implementation for HandleRangeAllocator.h #include "libANGLE/HandleRangeAllocator.h" #include #include #include #include "common/angleutils.h" #include "common/debug.h" namespace gl { const GLuint HandleRangeAllocator::kInvalidHandle = 0; HandleRangeAllocator::HandleRangeAllocator() { // Simplify the code by making sure that lower_bound(id) never // returns the beginning of the map, if id is valid (eg != kInvalidHandle). mUsed.insert(std::make_pair(0u, 0u)); } HandleRangeAllocator::~HandleRangeAllocator() {} GLuint HandleRangeAllocator::allocate() { return allocateRange(1u); } GLuint HandleRangeAllocator::allocateAtOrAbove(GLuint wanted) { if (wanted == 0u || wanted == 1u) return allocateRange(1u); auto current = mUsed.lower_bound(wanted); auto next = current; if (current == mUsed.end() || current->first > wanted) { current--; } else { next++; } GLuint firstId = current->first; GLuint lastId = current->second; ASSERT(wanted >= firstId); if (wanted - 1u <= lastId) { // Append to current range. lastId++; if (lastId == 0) { // The increment overflowed. return allocateRange(1u); } current->second = lastId; if (next != mUsed.end() && next->first - 1u == lastId) { // Merge with next range. current->second = next->second; mUsed.erase(next); } return lastId; } else if (next != mUsed.end() && next->first - 1u == wanted) { // Prepend to next range. GLuint lastExisting = next->second; mUsed.erase(next); mUsed.insert(std::make_pair(wanted, lastExisting)); return wanted; } mUsed.insert(std::make_pair(wanted, wanted)); return wanted; } GLuint HandleRangeAllocator::allocateRange(GLuint range) { ASSERT(range != 0); auto current = mUsed.begin(); auto next = current; while (++next != mUsed.end()) { if (next->first - current->second > range) break; current = next; } const GLuint firstId = current->second + 1u; const GLuint lastId = firstId + range - 1u; // deal with wraparound if (firstId == 0u || lastId < firstId) return kInvalidHandle; current->second = lastId; if (next != mUsed.end() && next->first - 1u == lastId) { // merge with next range current->second = next->second; mUsed.erase(next); } return firstId; } bool HandleRangeAllocator::markAsUsed(GLuint handle) { ASSERT(handle); auto current = mUsed.lower_bound(handle); if (current != mUsed.end() && current->first == handle) return false; auto next = current; --current; if (current->second >= handle) return false; ASSERT(current->first < handle && current->second < handle); if (current->second + 1u == handle) { // Append to current range. current->second = handle; if (next != mUsed.end() && next->first - 1u == handle) { // Merge with next range. current->second = next->second; mUsed.erase(next); } return true; } else if (next != mUsed.end() && next->first - 1u == handle) { // Prepend to next range. GLuint lastExisting = next->second; mUsed.erase(next); mUsed.insert(std::make_pair(handle, lastExisting)); return true; } mUsed.insert(std::make_pair(handle, handle)); return true; } void HandleRangeAllocator::release(GLuint handle) { releaseRange(handle, 1u); } void HandleRangeAllocator::releaseRange(GLuint first, GLuint range) { if (range == 0u || (first == 0u && range == 1u)) return; if (first == 0u) { first++; range--; } GLuint last = first + range - 1u; if (last < first) last = std::numeric_limits::max(); while (true) { auto current = mUsed.lower_bound(last); if (current == mUsed.end() || current->first > last) --current; if (current->second < first) return; if (current->first >= first) { const GLuint lastExisting = current->second; mUsed.erase(current); if (last < lastExisting) { mUsed.insert(std::make_pair(last + 1u, lastExisting)); } } else if (current->second <= last) { current->second = first - 1u; } else { ASSERT(current->first < first && current->second > last); const GLuint lastExisting = current->second; current->second = first - 1u; mUsed.insert(std::make_pair(last + 1u, lastExisting)); } } } bool HandleRangeAllocator::isUsed(GLuint handle) const { if (handle == kInvalidHandle) return false; auto current = mUsed.lower_bound(handle); if (current != mUsed.end()) { if (current->first == handle) return true; } --current; return current->second >= handle; } } // namespace gl