3 * Copyright 2014 Google Inc.
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
9 #include "GrGLNameAllocator.h"
12 * This is the abstract base class for a nonempty AVL tree that tracks allocated
13 * names within the half-open range [fFirst, fEnd). The inner nodes can be
14 * sparse (meaning not every name within the range is necessarily allocated),
15 * but the bounds are tight, so fFirst *is* guaranteed to be allocated, and so
18 class GrGLNameAllocator::SparseNameRange : public SkRefCnt {
20 virtual ~SparseNameRange() {}
23 * Return the beginning of the range. first() is guaranteed to be allocated.
25 * @return The first name in the range.
27 GrGLuint first() const { return fFirst; }
30 * Return the end of the range. end() - 1 is guaranteed to be allocated.
32 * @return One plus the final name in the range.
34 GrGLuint end() const { return fEnd; }
37 * Return the height of the tree. This can only be nonzero at an inner node.
39 * @return 0 if the implementation is a leaf node,
40 * The nonzero height of the tree otherwise.
42 GrGLuint height() const { return fHeight; }
45 * Allocate a name from strictly inside this range. The call will fail if
46 * there is not a free name within.
48 * @param outName A pointer that receives the allocated name. outName will
49 * be set to zero if there were no free names within the
50 * range [fFirst, fEnd).
51 * @return The resulting SparseNameRange after the allocation. Note that
52 * this call is destructive, so the original SparseNameRange will no
53 * longer be valid afterward. The caller must always update its
54 * pointer with the new SparseNameRange.
56 virtual SparseNameRange* SK_WARN_UNUSED_RESULT internalAllocate(GrGLuint* outName) = 0;
59 * Remove the leftmost leaf node from this range (or the entire thing if it
60 * *is* a leaf node). This is an internal helper method that is used after
61 * an allocation if one contiguous range became adjacent to another. (The
62 * range gets removed so the one immediately before can be extended,
63 * collapsing the two into one.)
65 * @param removedCount A pointer that receives the size of the contiguous
66 range that was removed.
67 * @return The resulting SparseNameRange after the removal (or NULL if it
68 * became empty). Note that this call is destructive, so the
69 * original SparseNameRange will no longer be valid afterward. The
70 * caller must always update its pointer with the new
73 virtual SparseNameRange* SK_WARN_UNUSED_RESULT removeLeftmostContiguousRange(GrGLuint* removedCount) = 0;
76 * Append adjacent allocated names to the end of this range. This operation
77 * does not affect the structure of the tree. The caller is responsible for
78 * ensuring the new names won't overlap sibling ranges, if any.
80 * @param count The number of adjacent names to append.
81 * @return The first name appended.
83 virtual GrGLuint appendNames(GrGLuint count) = 0;
86 * Prepend adjacent allocated names behind the beginning of this range. This
87 * operation does not affect the structure of the tree. The caller is
88 * responsible for ensuring the new names won't overlap sibling ranges, if
91 * @param count The number of adjacent names to prepend.
92 * @return The final name prepended (the one with the lowest value).
94 virtual GrGLuint prependNames(GrGLuint count) = 0;
97 * Free a name so it is no longer tracked as allocated. If the name is at
98 * the very beginning or very end of the range, the boundaries [fFirst, fEnd)
101 * @param name The name to free. Not-allocated names are silently ignored
102 * the same way they are in the OpenGL spec.
103 * @return The resulting SparseNameRange after the free (or NULL if it
104 * became empty). Note that this call is destructive, so the
105 * original SparseNameRange will no longer be valid afterward. The
106 * caller must always update its pointer with the new
109 virtual SparseNameRange* SK_WARN_UNUSED_RESULT free(GrGLuint name) = 0;
112 SparseNameRange* takeRef() {
123 * This class is the SparseNameRange implementation for an inner node. It is an
124 * AVL tree with non-null, non-adjacent left and right children.
126 class GrGLNameAllocator::SparseNameTree : public SparseNameRange {
128 SparseNameTree(SparseNameRange* left, SparseNameRange* right)
131 SkASSERT(fLeft.get());
132 SkASSERT(fRight.get());
136 SparseNameRange* SK_WARN_UNUSED_RESULT internalAllocate(GrGLuint* outName) SK_OVERRIDE {
137 // Try allocating the range inside fLeft's internal gaps.
138 fLeft.reset(fLeft->internalAllocate(outName));
141 return this->rebalance();
144 if (fLeft->end() + 1 == fRight->first()) {
145 // It closed the gap between fLeft and fRight; merge.
146 GrGLuint removedCount;
147 fRight.reset(fRight->removeLeftmostContiguousRange(&removedCount));
148 *outName = fLeft->appendNames(1 + removedCount);
149 if (NULL == fRight.get()) {
150 return fLeft.detach();
153 return this->rebalance();
156 // There is guaranteed to be a gap between fLeft and fRight, and the
157 // "size 1" case has already been covered.
158 SkASSERT(fLeft->end() + 1 < fRight->first());
159 *outName = fLeft->appendNames(1);
160 return this->takeRef();
163 SparseNameRange* SK_WARN_UNUSED_RESULT removeLeftmostContiguousRange(GrGLuint* removedCount) SK_OVERRIDE {
164 fLeft.reset(fLeft->removeLeftmostContiguousRange(removedCount));
166 return fRight.detach();
169 return this->rebalance();
172 GrGLuint appendNames(GrGLuint count) SK_OVERRIDE {
173 SkASSERT(fEnd + count > fEnd); // Check for integer wrap.
174 GrGLuint name = fRight->appendNames(count);
175 SkASSERT(fRight->end() == fEnd + count);
180 GrGLuint prependNames(GrGLuint count) SK_OVERRIDE {
181 SkASSERT(fFirst > count); // We can't allocate at or below 0.
182 GrGLuint name = fLeft->prependNames(count);
183 SkASSERT(fLeft->first() == fFirst - count);
188 SparseNameRange* SK_WARN_UNUSED_RESULT free(GrGLuint name) SK_OVERRIDE {
189 if (name < fLeft->end()) {
190 fLeft.reset(fLeft->free(name));
192 // fLeft became empty after the free.
193 return fRight.detach();
196 return this->rebalance();
198 fRight.reset(fRight->free(name));
199 if (NULL == fRight) {
200 // fRight became empty after the free.
201 return fLeft.detach();
204 return this->rebalance();
209 typedef SkAutoTUnref<SparseNameRange> SparseNameTree::* ChildRange;
211 SparseNameRange* SK_WARN_UNUSED_RESULT rebalance() {
212 if (fLeft->height() > fRight->height() + 1) {
213 return this->rebalanceImpl<&SparseNameTree::fLeft, &SparseNameTree::fRight>();
215 if (fRight->height() > fLeft->height() + 1) {
216 return this->rebalanceImpl<&SparseNameTree::fRight, &SparseNameTree::fLeft>();
218 return this->takeRef();
222 * Rebalance the tree using rotations, as described in the AVL algorithm:
223 * http://en.wikipedia.org/wiki/AVL_tree#Insertion
225 template<ChildRange Tall, ChildRange Short>
226 SparseNameRange* SK_WARN_UNUSED_RESULT rebalanceImpl() {
227 // We should be calling rebalance() enough that the tree never gets more
228 // than one rotation off balance.
229 SkASSERT(2 == (this->*Tall)->height() - (this->*Short)->height());
231 // Ensure we are in the 'Left Left' or 'Right Right' case:
232 // http://en.wikipedia.org/wiki/AVL_tree#Insertion
233 SparseNameTree* tallChild = static_cast<SparseNameTree*>((this->*Tall).get());
234 if ((tallChild->*Tall)->height() < (tallChild->*Short)->height()) {
235 (this->*Tall).reset(tallChild->rotate<Short, Tall>());
238 // Perform a rotation to balance the tree.
239 return this->rotate<Tall, Short>();
243 * Perform a node rotation, as described in the AVL algorithm:
244 * http://en.wikipedia.org/wiki/AVL_tree#Insertion
246 template<ChildRange Tall, ChildRange Short>
247 SparseNameRange* SK_WARN_UNUSED_RESULT rotate() {
248 SparseNameTree* newRoot = static_cast<SparseNameTree*>((this->*Tall).detach());
250 (this->*Tall).reset((newRoot->*Short).detach());
253 (newRoot->*Short).reset(this->takeRef());
254 newRoot->updateStats();
260 SkASSERT(fLeft->end() < fRight->first()); // There must be a gap between left and right.
261 fFirst = fLeft->first();
262 fEnd = fRight->end();
263 fHeight = 1 + SkMax32(fLeft->height(), fRight->height());
266 SkAutoTUnref<SparseNameRange> fLeft;
267 SkAutoTUnref<SparseNameRange> fRight;
271 * This class is the SparseNameRange implementation for a leaf node. It just a
272 * contiguous range of allocated names.
274 class GrGLNameAllocator::ContiguousNameRange : public SparseNameRange {
276 ContiguousNameRange(GrGLuint first, GrGLuint end) {
277 SkASSERT(first < end);
283 SparseNameRange* SK_WARN_UNUSED_RESULT internalAllocate(GrGLuint* outName) SK_OVERRIDE {
284 *outName = 0; // No internal gaps, we are contiguous.
285 return this->takeRef();
288 SparseNameRange* SK_WARN_UNUSED_RESULT removeLeftmostContiguousRange(GrGLuint* removedCount) SK_OVERRIDE {
289 *removedCount = fEnd - fFirst;
293 GrGLuint appendNames(GrGLuint count) SK_OVERRIDE {
294 SkASSERT(fEnd + count > fEnd); // Check for integer wrap.
295 GrGLuint name = fEnd;
300 GrGLuint prependNames(GrGLuint count) SK_OVERRIDE {
301 SkASSERT(fFirst > count); // We can't allocate at or below 0.
306 SparseNameRange* SK_WARN_UNUSED_RESULT free(GrGLuint name) SK_OVERRIDE {
307 if (name < fFirst || name >= fEnd) {
308 // Not-allocated names are silently ignored.
309 return this->takeRef();
312 if (fFirst == name) {
314 return (fEnd == fFirst) ? NULL : this->takeRef();
317 if (fEnd == name + 1) {
319 return this->takeRef();
322 SparseNameRange* left = SkNEW_ARGS(ContiguousNameRange, (fFirst, name));
323 SparseNameRange* right = this->takeRef();
325 return SkNEW_ARGS(SparseNameTree, (left, right));
329 GrGLNameAllocator::GrGLNameAllocator(GrGLuint firstName, GrGLuint endName)
330 : fFirstName(firstName),
332 SkASSERT(firstName > 0);
333 SkASSERT(endName > firstName);
336 GrGLNameAllocator::~GrGLNameAllocator() {
339 GrGLuint GrGLNameAllocator::allocateName() {
340 if (NULL == fAllocatedNames.get()) {
341 fAllocatedNames.reset(SkNEW_ARGS(ContiguousNameRange, (fFirstName, fFirstName + 1)));
345 if (fAllocatedNames->first() > fFirstName) {
346 return fAllocatedNames->prependNames(1);
350 fAllocatedNames.reset(fAllocatedNames->internalAllocate(&name));
355 if (fAllocatedNames->end() < fEndName) {
356 return fAllocatedNames->appendNames(1);
363 void GrGLNameAllocator::free(GrGLuint name) {
364 if (!fAllocatedNames.get()) {
365 // Not-allocated names are silently ignored.
369 fAllocatedNames.reset(fAllocatedNames->free(name));