// Copyright 2011 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following // disclaimer in the documentation and/or other materials provided // with the distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived // from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef V8_SMALL_POINTER_LIST_H_ #define V8_SMALL_POINTER_LIST_H_ #include "checks.h" #include "v8globals.h" #include "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); } ASSERT(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) { ASSERT(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); ASSERT(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 { ASSERT((data_ & kTagMask) != kEmptyTag); if ((data_ & kTagMask) == kSingletonTag) { ASSERT(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() { ASSERT((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) { ASSERT(pos == 0); return; } if ((data_ & kTagMask) == kSingletonTag) { ASSERT(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 { ASSERT((data_ & kTagMask) == kSingletonTag); STATIC_ASSERT(kSingletonTag == 0); return reinterpret_cast<T*>(data_); } PointerList* list() const { ASSERT((data_ & kTagMask) == kListTag); return reinterpret_cast<PointerList*>(data_ & kValueMask); } intptr_t data_; DISALLOW_COPY_AND_ASSIGN(SmallPointerList); }; } } // namespace v8::internal #endif // V8_SMALL_POINTER_LIST_H_