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 |