| // Copyright 2011 the V8 project authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #ifndef V8_SMALL_POINTER_LIST_H_ | |
| #define V8_SMALL_POINTER_LIST_H_ | |
| #include "src/base/logging.h" | |
| #include "src/globals.h" | |
| #include "src/zone/zone.h" | |
| namespace v8 { | |
| namespace internal { | |
| // SmallPointerList is a list optimized for storing no or just a | |
| // single value. When more values are given it falls back to ZoneList. | |
| // | |
| // The interface tries to be as close to List from list.h as possible. | |
| template <typename T> | |
| class SmallPointerList { | |
| public: | |
| SmallPointerList() : data_(kEmptyTag) {} | |
| SmallPointerList(int capacity, Zone* zone) : data_(kEmptyTag) { | |
| Reserve(capacity, zone); | |
| } | |
| void Reserve(int capacity, Zone* zone) { | |
| if (capacity < 2) return; | |
| if ((data_ & kTagMask) == kListTag) { | |
| if (list()->capacity() >= capacity) return; | |
| int old_length = list()->length(); | |
| list()->AddBlock(NULL, capacity - list()->capacity(), zone); | |
| list()->Rewind(old_length); | |
| return; | |
| } | |
| PointerList* list = new(zone) PointerList(capacity, zone); | |
| if ((data_ & kTagMask) == kSingletonTag) { | |
| list->Add(single_value(), zone); | |
| } | |
| DCHECK(IsAligned(reinterpret_cast<intptr_t>(list), kPointerAlignment)); | |
| data_ = reinterpret_cast<intptr_t>(list) | kListTag; | |
| } | |
| void Clear() { | |
| data_ = kEmptyTag; | |
| } | |
| void Sort() { | |
| if ((data_ & kTagMask) == kListTag) { | |
| list()->Sort(compare_value); | |
| } | |
| } | |
| bool is_empty() const { return length() == 0; } | |
| int length() const { | |
| if ((data_ & kTagMask) == kEmptyTag) return 0; | |
| if ((data_ & kTagMask) == kSingletonTag) return 1; | |
| return list()->length(); | |
| } | |
| void Add(T* pointer, Zone* zone) { | |
| DCHECK(IsAligned(reinterpret_cast<intptr_t>(pointer), kPointerAlignment)); | |
| if ((data_ & kTagMask) == kEmptyTag) { | |
| data_ = reinterpret_cast<intptr_t>(pointer) | kSingletonTag; | |
| return; | |
| } | |
| if ((data_ & kTagMask) == kSingletonTag) { | |
| PointerList* list = new(zone) PointerList(2, zone); | |
| list->Add(single_value(), zone); | |
| list->Add(pointer, zone); | |
| DCHECK(IsAligned(reinterpret_cast<intptr_t>(list), kPointerAlignment)); | |
| data_ = reinterpret_cast<intptr_t>(list) | kListTag; | |
| return; | |
| } | |
| list()->Add(pointer, zone); | |
| } | |
| // Note: returns T* and not T*& (unlike List from list.h). | |
| // This makes the implementation simpler and more const correct. | |
| T* at(int i) const { | |
| DCHECK((data_ & kTagMask) != kEmptyTag); | |
| if ((data_ & kTagMask) == kSingletonTag) { | |
| DCHECK(i == 0); | |
| return single_value(); | |
| } | |
| return list()->at(i); | |
| } | |
| // See the note above. | |
| T* operator[](int i) const { return at(i); } | |
| // Remove the given element from the list (if present). | |
| void RemoveElement(T* pointer) { | |
| if ((data_ & kTagMask) == kEmptyTag) return; | |
| if ((data_ & kTagMask) == kSingletonTag) { | |
| if (pointer == single_value()) { | |
| data_ = kEmptyTag; | |
| } | |
| return; | |
| } | |
| list()->RemoveElement(pointer); | |
| } | |
| T* RemoveLast() { | |
| DCHECK((data_ & kTagMask) != kEmptyTag); | |
| if ((data_ & kTagMask) == kSingletonTag) { | |
| T* result = single_value(); | |
| data_ = kEmptyTag; | |
| return result; | |
| } | |
| return list()->RemoveLast(); | |
| } | |
| void Rewind(int pos) { | |
| if ((data_ & kTagMask) == kEmptyTag) { | |
| DCHECK(pos == 0); | |
| return; | |
| } | |
| if ((data_ & kTagMask) == kSingletonTag) { | |
| DCHECK(pos == 0 || pos == 1); | |
| if (pos == 0) { | |
| data_ = kEmptyTag; | |
| } | |
| return; | |
| } | |
| list()->Rewind(pos); | |
| } | |
| int CountOccurrences(T* pointer, int start, int end) const { | |
| if ((data_ & kTagMask) == kEmptyTag) return 0; | |
| if ((data_ & kTagMask) == kSingletonTag) { | |
| if (start == 0 && end >= 0) { | |
| return (single_value() == pointer) ? 1 : 0; | |
| } | |
| return 0; | |
| } | |
| return list()->CountOccurrences(pointer, start, end); | |
| } | |
| private: | |
| typedef ZoneList<T*> PointerList; | |
| static int compare_value(T* const* a, T* const* b) { | |
| return Compare<T>(**a, **b); | |
| } | |
| static const intptr_t kEmptyTag = 1; | |
| static const intptr_t kSingletonTag = 0; | |
| static const intptr_t kListTag = 2; | |
| static const intptr_t kTagMask = 3; | |
| static const intptr_t kValueMask = ~kTagMask; | |
| STATIC_ASSERT(kTagMask + 1 <= kPointerAlignment); | |
| T* single_value() const { | |
| DCHECK((data_ & kTagMask) == kSingletonTag); | |
| STATIC_ASSERT(kSingletonTag == 0); | |
| return reinterpret_cast<T*>(data_); | |
| } | |
| PointerList* list() const { | |
| DCHECK((data_ & kTagMask) == kListTag); | |
| return reinterpret_cast<PointerList*>(data_ & kValueMask); | |
| } | |
| intptr_t data_; | |
| DISALLOW_COPY_AND_ASSIGN(SmallPointerList); | |
| }; | |
| } // namespace internal | |
| } // namespace v8 | |
| #endif // V8_SMALL_POINTER_LIST_H_ |