| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // This file contains the implementation of IdAllocator. | 5 // This file contains the implementation of IdAllocator. |
| 6 | 6 |
| 7 #include "gpu/command_buffer/common/id_allocator.h" | 7 #include "gpu/command_buffer/common/id_allocator.h" |
| 8 | 8 |
| 9 #include <limits> |
| 9 #include "base/logging.h" | 10 #include "base/logging.h" |
| 10 | 11 |
| 11 namespace gpu { | 12 namespace gpu { |
| 12 | 13 |
| 13 IdAllocator::IdAllocator() {} | 14 IdAllocator::IdAllocator() { |
| 15 COMPILE_ASSERT(kInvalidResource == 0u, invalid_resource_is_not_zero); |
| 16 // Simplify the code by making sure that lower_bound(id) never |
| 17 // returns the beginning of the map, if id is valid (eg != |
| 18 // kInvalidResource). |
| 19 used_ids_.insert(std::make_pair(0u, 0u)); |
| 20 } |
| 14 | 21 |
| 15 IdAllocator::~IdAllocator() {} | 22 IdAllocator::~IdAllocator() {} |
| 16 | 23 |
| 17 ResourceId IdAllocator::AllocateID() { | 24 ResourceId IdAllocator::AllocateID() { |
| 18 ResourceId id; | 25 return AllocateIDRange(1u); |
| 19 ResourceIdSet::iterator iter = free_ids_.begin(); | 26 } |
| 20 if (iter != free_ids_.end()) { | 27 |
| 21 id = *iter; | 28 ResourceId IdAllocator::AllocateIDAtOrAbove(ResourceId desired_id) { |
| 29 if (desired_id == 0u || desired_id == 1u) { |
| 30 return AllocateIDRange(1u); |
| 31 } |
| 32 |
| 33 ResourceIdRangeMap::iterator current = used_ids_.lower_bound(desired_id); |
| 34 ResourceIdRangeMap::iterator next = current; |
| 35 if (current == used_ids_.end() || current->first > desired_id) { |
| 36 current--; |
| 22 } else { | 37 } else { |
| 23 id = LastUsedId() + 1; | 38 next++; |
| 24 if (!id) { | 39 } |
| 25 // We wrapped around to 0. | 40 |
| 26 id = FindFirstUnusedId(); | 41 ResourceId first_id = current->first; |
| 27 } | 42 ResourceId last_id = current->second; |
| 28 } | 43 |
| 29 MarkAsUsed(id); | 44 DCHECK(desired_id >= first_id); |
| 30 return id; | 45 |
| 31 } | 46 if (desired_id - 1u <= last_id) { |
| 32 | 47 // Append to current range. |
| 33 ResourceId IdAllocator::AllocateIDAtOrAbove(ResourceId desired_id) { | 48 last_id++; |
| 34 ResourceId id; | 49 if (last_id == 0) { |
| 35 ResourceIdSet::iterator iter = free_ids_.lower_bound(desired_id); | 50 // The increment overflowed. |
| 36 if (iter != free_ids_.end()) { | 51 return AllocateIDRange(1u); |
| 37 id = *iter; | 52 } |
| 38 } else if (LastUsedId() < desired_id) { | 53 |
| 39 id = desired_id; | 54 current->second = last_id; |
| 40 } else { | 55 |
| 41 id = LastUsedId() + 1; | 56 if (next != used_ids_.end() && next->first - 1u == last_id) { |
| 42 if (!id) { | 57 // Merge with next range. |
| 43 // We wrapped around to 0. | 58 current->second = next->second; |
| 44 id = FindFirstUnusedId(); | 59 used_ids_.erase(next); |
| 45 } | 60 } |
| 46 } | 61 return last_id; |
| 47 MarkAsUsed(id); | 62 } else if (next != used_ids_.end() && next->first - 1u == desired_id) { |
| 48 return id; | 63 // Prepend to next range. |
| 64 ResourceId last_existing_id = next->second; |
| 65 used_ids_.erase(next); |
| 66 used_ids_.insert(std::make_pair(desired_id, last_existing_id)); |
| 67 return desired_id; |
| 68 } |
| 69 used_ids_.insert(std::make_pair(desired_id, desired_id)); |
| 70 return desired_id; |
| 71 } |
| 72 |
| 73 ResourceId IdAllocator::AllocateIDRange(uint32_t range) { |
| 74 DCHECK(range > 0u); |
| 75 |
| 76 ResourceIdRangeMap::iterator current = used_ids_.begin(); |
| 77 ResourceIdRangeMap::iterator next = current; |
| 78 |
| 79 while (++next != used_ids_.end()) { |
| 80 if (next->first - current->second > range) { |
| 81 break; |
| 82 } |
| 83 current = next; |
| 84 } |
| 85 |
| 86 ResourceId first_id = current->second + 1u; |
| 87 ResourceId last_id = first_id + range - 1u; |
| 88 |
| 89 if (first_id == 0u || last_id < first_id) { |
| 90 return kInvalidResource; |
| 91 } |
| 92 |
| 93 current->second = last_id; |
| 94 |
| 95 if (next != used_ids_.end() && next->first - 1u == last_id) { |
| 96 // Merge with next range. |
| 97 current->second = next->second; |
| 98 used_ids_.erase(next); |
| 99 } |
| 100 |
| 101 return first_id; |
| 49 } | 102 } |
| 50 | 103 |
| 51 bool IdAllocator::MarkAsUsed(ResourceId id) { | 104 bool IdAllocator::MarkAsUsed(ResourceId id) { |
| 52 DCHECK(id); | 105 DCHECK(id); |
| 53 free_ids_.erase(id); | 106 ResourceIdRangeMap::iterator current = used_ids_.lower_bound(id); |
| 54 std::pair<ResourceIdSet::iterator, bool> result = used_ids_.insert(id); | 107 if (current != used_ids_.end() && current->first == id) { |
| 55 return result.second; | 108 return false; |
| 109 } |
| 110 |
| 111 ResourceIdRangeMap::iterator next = current; |
| 112 --current; |
| 113 |
| 114 if (current->second >= id) { |
| 115 return false; |
| 116 } |
| 117 |
| 118 DCHECK(current->first < id && current->second < id); |
| 119 |
| 120 if (current->second + 1u == id) { |
| 121 // Append to current range. |
| 122 current->second = id; |
| 123 if (next != used_ids_.end() && next->first - 1u == id) { |
| 124 // Merge with next range. |
| 125 current->second = next->second; |
| 126 used_ids_.erase(next); |
| 127 } |
| 128 return true; |
| 129 } else if (next != used_ids_.end() && next->first - 1u == id) { |
| 130 // Prepend to next range. |
| 131 ResourceId last_existing_id = next->second; |
| 132 used_ids_.erase(next); |
| 133 used_ids_.insert(std::make_pair(id, last_existing_id)); |
| 134 return true; |
| 135 } |
| 136 |
| 137 used_ids_.insert(std::make_pair(id, id)); |
| 138 return true; |
| 56 } | 139 } |
| 57 | 140 |
| 58 void IdAllocator::FreeID(ResourceId id) { | 141 void IdAllocator::FreeID(ResourceId id) { |
| 59 if (id) { | 142 FreeIDRange(id, 1u); |
| 60 used_ids_.erase(id); | 143 } |
| 61 free_ids_.insert(id); | 144 |
| 145 void IdAllocator::FreeIDRange(ResourceId first_id, uint32 range) { |
| 146 COMPILE_ASSERT(kInvalidResource == 0u, invalid_resource_is_not_zero); |
| 147 |
| 148 if (range == 0u || (first_id == 0u && range == 1u)) { |
| 149 return; |
| 150 } |
| 151 |
| 152 if (first_id == 0u) { |
| 153 first_id++; |
| 154 range--; |
| 155 } |
| 156 |
| 157 ResourceId last_id = first_id + range - 1u; |
| 158 if (last_id < first_id) { |
| 159 last_id = std::numeric_limits<ResourceId>::max(); |
| 160 } |
| 161 |
| 162 while (true) { |
| 163 ResourceIdRangeMap::iterator current = used_ids_.lower_bound(last_id); |
| 164 if (current == used_ids_.end() || current->first > last_id) { |
| 165 --current; |
| 166 } |
| 167 |
| 168 if (current->second < first_id) { |
| 169 return; |
| 170 } |
| 171 |
| 172 if (current->first >= first_id) { |
| 173 ResourceId last_existing_id = current->second; |
| 174 used_ids_.erase(current); |
| 175 if (last_id < last_existing_id) { |
| 176 used_ids_.insert(std::make_pair(last_id + 1u, last_existing_id)); |
| 177 } |
| 178 } else if (current->second <= last_id) { |
| 179 current->second = first_id - 1u; |
| 180 } else { |
| 181 DCHECK(current->first < first_id && current->second > last_id); |
| 182 ResourceId last_existing_id = current->second; |
| 183 current->second = first_id - 1u; |
| 184 used_ids_.insert(std::make_pair(last_id + 1u, last_existing_id)); |
| 185 } |
| 62 } | 186 } |
| 63 } | 187 } |
| 64 | 188 |
| 65 bool IdAllocator::InUse(ResourceId id) const { | 189 bool IdAllocator::InUse(ResourceId id) const { |
| 66 return id == kInvalidResource || used_ids_.find(id) != used_ids_.end(); | 190 if (id == kInvalidResource) { |
| 67 } | 191 return false; |
| 68 | 192 } |
| 69 ResourceId IdAllocator::LastUsedId() const { | 193 |
| 70 if (used_ids_.empty()) { | 194 ResourceIdRangeMap::const_iterator current = used_ids_.lower_bound(id); |
| 71 return 0u; | 195 if (current != used_ids_.end()) { |
| 72 } else { | 196 if (current->first == id) { |
| 73 return *used_ids_.rbegin(); | 197 return true; |
| 74 } | 198 } |
| 75 } | 199 } |
| 76 | 200 |
| 77 ResourceId IdAllocator::FindFirstUnusedId() const { | 201 --current; |
| 78 ResourceId id = 1; | 202 return current->second >= id; |
| 79 for (ResourceIdSet::const_iterator it = used_ids_.begin(); | |
| 80 it != used_ids_.end(); ++it) { | |
| 81 if ((*it) != id) { | |
| 82 return id; | |
| 83 } | |
| 84 ++id; | |
| 85 } | |
| 86 return id; | |
| 87 } | 203 } |
| 88 | 204 |
| 89 } // namespace gpu | 205 } // namespace gpu |
| OLD | NEW |