1 //
2 // Copyright 2016 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 // HandleRangeAllocator.cpp : Implementation for HandleRangeAllocator.h
8
9 #include "libANGLE/HandleRangeAllocator.h"
10
11 #include <algorithm>
12 #include <limits>
13 #include <utility>
14
15 #include "common/angleutils.h"
16 #include "common/debug.h"
17
18 namespace gl
19 {
20
21 const GLuint HandleRangeAllocator::kInvalidHandle = 0;
22
HandleRangeAllocator()23 HandleRangeAllocator::HandleRangeAllocator()
24 {
25 // Simplify the code by making sure that lower_bound(id) never
26 // returns the beginning of the map, if id is valid (eg != kInvalidHandle).
27 mUsed.insert(std::make_pair(0u, 0u));
28 }
29
~HandleRangeAllocator()30 HandleRangeAllocator::~HandleRangeAllocator() {}
31
allocate()32 GLuint HandleRangeAllocator::allocate()
33 {
34 return allocateRange(1u);
35 }
36
allocateAtOrAbove(GLuint wanted)37 GLuint HandleRangeAllocator::allocateAtOrAbove(GLuint wanted)
38 {
39 if (wanted == 0u || wanted == 1u)
40 return allocateRange(1u);
41
42 auto current = mUsed.lower_bound(wanted);
43 auto next = current;
44 if (current == mUsed.end() || current->first > wanted)
45 {
46 current--;
47 }
48 else
49 {
50 next++;
51 }
52
53 GLuint firstId = current->first;
54 GLuint lastId = current->second;
55 ASSERT(wanted >= firstId);
56
57 if (wanted - 1u <= lastId)
58 {
59 // Append to current range.
60 lastId++;
61 if (lastId == 0)
62 {
63 // The increment overflowed.
64 return allocateRange(1u);
65 }
66
67 current->second = lastId;
68
69 if (next != mUsed.end() && next->first - 1u == lastId)
70 {
71 // Merge with next range.
72 current->second = next->second;
73 mUsed.erase(next);
74 }
75 return lastId;
76 }
77 else if (next != mUsed.end() && next->first - 1u == wanted)
78 {
79 // Prepend to next range.
80 GLuint lastExisting = next->second;
81 mUsed.erase(next);
82 mUsed.insert(std::make_pair(wanted, lastExisting));
83 return wanted;
84 }
85 mUsed.insert(std::make_pair(wanted, wanted));
86 return wanted;
87 }
88
allocateRange(GLuint range)89 GLuint HandleRangeAllocator::allocateRange(GLuint range)
90 {
91 ASSERT(range != 0);
92
93 auto current = mUsed.begin();
94 auto next = current;
95
96 while (++next != mUsed.end())
97 {
98 if (next->first - current->second > range)
99 break;
100 current = next;
101 }
102 const GLuint firstId = current->second + 1u;
103 const GLuint lastId = firstId + range - 1u;
104
105 // deal with wraparound
106 if (firstId == 0u || lastId < firstId)
107 return kInvalidHandle;
108
109 current->second = lastId;
110
111 if (next != mUsed.end() && next->first - 1u == lastId)
112 {
113 // merge with next range
114 current->second = next->second;
115 mUsed.erase(next);
116 }
117 return firstId;
118 }
119
markAsUsed(GLuint handle)120 bool HandleRangeAllocator::markAsUsed(GLuint handle)
121 {
122 ASSERT(handle);
123 auto current = mUsed.lower_bound(handle);
124 if (current != mUsed.end() && current->first == handle)
125 return false;
126
127 auto next = current;
128 --current;
129
130 if (current->second >= handle)
131 return false;
132
133 ASSERT(current->first < handle && current->second < handle);
134
135 if (current->second + 1u == handle)
136 {
137 // Append to current range.
138 current->second = handle;
139 if (next != mUsed.end() && next->first - 1u == handle)
140 {
141 // Merge with next range.
142 current->second = next->second;
143 mUsed.erase(next);
144 }
145 return true;
146 }
147 else if (next != mUsed.end() && next->first - 1u == handle)
148 {
149 // Prepend to next range.
150 GLuint lastExisting = next->second;
151 mUsed.erase(next);
152 mUsed.insert(std::make_pair(handle, lastExisting));
153 return true;
154 }
155
156 mUsed.insert(std::make_pair(handle, handle));
157 return true;
158 }
159
release(GLuint handle)160 void HandleRangeAllocator::release(GLuint handle)
161 {
162 releaseRange(handle, 1u);
163 }
164
releaseRange(GLuint first,GLuint range)165 void HandleRangeAllocator::releaseRange(GLuint first, GLuint range)
166 {
167 if (range == 0u || (first == 0u && range == 1u))
168 return;
169
170 if (first == 0u)
171 {
172 first++;
173 range--;
174 }
175
176 GLuint last = first + range - 1u;
177 if (last < first)
178 last = std::numeric_limits<GLuint>::max();
179
180 while (true)
181 {
182 auto current = mUsed.lower_bound(last);
183 if (current == mUsed.end() || current->first > last)
184 --current;
185
186 if (current->second < first)
187 return;
188
189 if (current->first >= first)
190 {
191 const GLuint lastExisting = current->second;
192 mUsed.erase(current);
193 if (last < lastExisting)
194 {
195 mUsed.insert(std::make_pair(last + 1u, lastExisting));
196 }
197 }
198 else if (current->second <= last)
199 {
200 current->second = first - 1u;
201 }
202 else
203 {
204 ASSERT(current->first < first && current->second > last);
205 const GLuint lastExisting = current->second;
206 current->second = first - 1u;
207 mUsed.insert(std::make_pair(last + 1u, lastExisting));
208 }
209 }
210 }
211
isUsed(GLuint handle) const212 bool HandleRangeAllocator::isUsed(GLuint handle) const
213 {
214 if (handle == kInvalidHandle)
215 return false;
216
217 auto current = mUsed.lower_bound(handle);
218 if (current != mUsed.end())
219 {
220 if (current->first == handle)
221 return true;
222 }
223 --current;
224 return current->second >= handle;
225 }
226
227 } // namespace gl
228