OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright 2013 Google Inc. |
| 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. |
| 6 */ |
| 7 |
| 8 #ifndef SkTDStackNester_DEFINED |
| 9 #define SkTDStackNester_DEFINED |
| 10 |
| 11 #include "SkTypes.h" |
| 12 |
| 13 // Adobe limits it to 28, so 256 should be more than enough |
| 14 #define MAX_NESTING 256 |
| 15 |
| 16 /** \class SkTDStackNester |
| 17 * |
| 18 * The difference between SkTDStackNester and SkTDStack is that: |
| 19 * - SkTDStackNester uses new/delete to manage initializations |
| 20 * - Supports nest/unnest which simulates a stack of stack. unnest will pop al
l the |
| 21 * objects pushed since the last nest |
| 22 */ |
| 23 |
| 24 template <typename T> class SkTDStackNester : SkNoncopyable { |
| 25 public: |
| 26 SkTDStackNester() : fCount(0), fTotalCount(0), fLocalCount(0) { |
| 27 fInitialRec.fNext = NULL; |
| 28 fRec = &fInitialRec; |
| 29 |
| 30 // fCount = kSlotCount; |
| 31 } |
| 32 |
| 33 ~SkTDStackNester() { |
| 34 Rec* rec = fRec; |
| 35 while (rec != &fInitialRec) { |
| 36 Rec* next = rec->fNext; |
| 37 delete rec; |
| 38 rec = next; |
| 39 } |
| 40 } |
| 41 |
| 42 int count() const { return fLocalCount; } |
| 43 bool empty() const { return fLocalCount == 0; } |
| 44 |
| 45 int nests() { |
| 46 return fNestingLevel; |
| 47 } |
| 48 |
| 49 void nest() { |
| 50 // We are are past max nesting levels, we will still continue to work, b
ut we might fail |
| 51 // to properly ignore errors. Ideally it should only mean poor rendering
in exceptional |
| 52 // cases |
| 53 if (fNestingLevel >= 0 && fNestingLevel < MAX_NESTING) { |
| 54 fNestings[fNestingLevel] = fLocalCount; |
| 55 fLocalCount = 0; |
| 56 } |
| 57 fNestingLevel++; |
| 58 } |
| 59 |
| 60 void unnest() { |
| 61 SkASSERT(fNestingLevel > 0); |
| 62 fNestingLevel--; |
| 63 if (fNestingLevel >= 0 && fNestingLevel < MAX_NESTING) { |
| 64 // TODO(edisonn): warn if fLocal > 0 |
| 65 while (fLocalCount > 0) { |
| 66 pop(); |
| 67 } |
| 68 fLocalCount = fNestings[fNestingLevel]; |
| 69 } |
| 70 } |
| 71 |
| 72 T* push() { |
| 73 SkASSERT(fCount <= kSlotCount); |
| 74 if (fCount == kSlotCount) { |
| 75 Rec* rec = new Rec(); |
| 76 rec->fNext = fRec; |
| 77 fRec = rec; |
| 78 fCount = 0; |
| 79 } |
| 80 ++fTotalCount; |
| 81 ++fLocalCount; |
| 82 return &fRec->fSlots[fCount++]; |
| 83 } |
| 84 |
| 85 void push(const T& elem) { *this->push() = elem; } |
| 86 |
| 87 const T& index(int idx) const { |
| 88 SkASSERT(fRec && fCount > idx); |
| 89 return fRec->fSlots[fCount - idx - 1]; |
| 90 } |
| 91 |
| 92 T& index(int idx) { |
| 93 SkASSERT(fRec && fCount > idx); |
| 94 return fRec->fSlots[fCount - idx - 1]; |
| 95 } |
| 96 |
| 97 const T& top() const { |
| 98 SkASSERT(fRec && fCount > 0); |
| 99 return fRec->fSlots[fCount - 1]; |
| 100 } |
| 101 |
| 102 T& top() { |
| 103 SkASSERT(fRec && fCount > 0); |
| 104 return fRec->fSlots[fCount - 1]; |
| 105 } |
| 106 |
| 107 void pop(T* elem) { |
| 108 if (elem) { |
| 109 *elem = fRec->fSlots[fCount - 1]; |
| 110 } |
| 111 this->pop(); |
| 112 } |
| 113 |
| 114 void pop() { |
| 115 SkASSERT(fCount > 0 && fRec); |
| 116 --fLocalCount; |
| 117 --fTotalCount; |
| 118 if (--fCount == 0) { |
| 119 if (fRec != &fInitialRec) { |
| 120 Rec* rec = fRec->fNext; |
| 121 delete fRec; |
| 122 fCount = kSlotCount; |
| 123 fRec = rec; |
| 124 } else { |
| 125 SkASSERT(fTotalCount == 0); |
| 126 } |
| 127 } |
| 128 } |
| 129 |
| 130 private: |
| 131 enum { |
| 132 kSlotCount = 64 |
| 133 }; |
| 134 |
| 135 struct Rec; |
| 136 friend struct Rec; |
| 137 |
| 138 struct Rec { |
| 139 Rec* fNext; |
| 140 T fSlots[kSlotCount]; |
| 141 }; |
| 142 Rec fInitialRec; |
| 143 Rec* fRec; |
| 144 int fCount, fTotalCount, fLocalCount; |
| 145 int fNestings[MAX_NESTING]; |
| 146 int fNestingLevel; |
| 147 }; |
| 148 #endif // SkTDStackNester_DEFINED |
OLD | NEW |