blob: 9ece249064488f3dbce43af57363dcb24a67c469 [file] [log] [blame]
Steve Block44f0eee2011-05-26 01:26:41 +01001// Copyright 2011 the V8 project authors. All rights reserved.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
Steve Block44f0eee2011-05-26 01:26:41 +01004
5#ifndef V8_SMALL_POINTER_LIST_H_
6#define V8_SMALL_POINTER_LIST_H_
7
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008#include "src/base/logging.h"
9#include "src/globals.h"
10#include "src/zone.h"
Steve Block44f0eee2011-05-26 01:26:41 +010011
12namespace v8 {
13namespace internal {
14
15// SmallPointerList is a list optimized for storing no or just a
16// single value. When more values are given it falls back to ZoneList.
17//
18// The interface tries to be as close to List from list.h as possible.
19template <typename T>
20class SmallPointerList {
21 public:
22 SmallPointerList() : data_(kEmptyTag) {}
23
Ben Murdochb8a8cc12014-11-26 15:28:44 +000024 SmallPointerList(int capacity, Zone* zone) : data_(kEmptyTag) {
25 Reserve(capacity, zone);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000026 }
27
Ben Murdochb8a8cc12014-11-26 15:28:44 +000028 void Reserve(int capacity, Zone* zone) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000029 if (capacity < 2) return;
30 if ((data_ & kTagMask) == kListTag) {
31 if (list()->capacity() >= capacity) return;
32 int old_length = list()->length();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000033 list()->AddBlock(NULL, capacity - list()->capacity(), zone);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000034 list()->Rewind(old_length);
35 return;
36 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000037 PointerList* list = new(zone) PointerList(capacity, zone);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000038 if ((data_ & kTagMask) == kSingletonTag) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000039 list->Add(single_value(), zone);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000040 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000041 DCHECK(IsAligned(reinterpret_cast<intptr_t>(list), kPointerAlignment));
Ben Murdoch69a99ed2011-11-30 16:03:39 +000042 data_ = reinterpret_cast<intptr_t>(list) | kListTag;
43 }
44
45 void Clear() {
46 data_ = kEmptyTag;
47 }
48
Ben Murdochb8a8cc12014-11-26 15:28:44 +000049 void Sort() {
50 if ((data_ & kTagMask) == kListTag) {
51 list()->Sort(compare_value);
52 }
53 }
54
Steve Block44f0eee2011-05-26 01:26:41 +010055 bool is_empty() const { return length() == 0; }
56
57 int length() const {
58 if ((data_ & kTagMask) == kEmptyTag) return 0;
59 if ((data_ & kTagMask) == kSingletonTag) return 1;
60 return list()->length();
61 }
62
Ben Murdochb8a8cc12014-11-26 15:28:44 +000063 void Add(T* pointer, Zone* zone) {
64 DCHECK(IsAligned(reinterpret_cast<intptr_t>(pointer), kPointerAlignment));
Steve Block44f0eee2011-05-26 01:26:41 +010065 if ((data_ & kTagMask) == kEmptyTag) {
66 data_ = reinterpret_cast<intptr_t>(pointer) | kSingletonTag;
67 return;
68 }
69 if ((data_ & kTagMask) == kSingletonTag) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000070 PointerList* list = new(zone) PointerList(2, zone);
71 list->Add(single_value(), zone);
72 list->Add(pointer, zone);
73 DCHECK(IsAligned(reinterpret_cast<intptr_t>(list), kPointerAlignment));
Steve Block44f0eee2011-05-26 01:26:41 +010074 data_ = reinterpret_cast<intptr_t>(list) | kListTag;
75 return;
76 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000077 list()->Add(pointer, zone);
Steve Block44f0eee2011-05-26 01:26:41 +010078 }
79
80 // Note: returns T* and not T*& (unlike List from list.h).
81 // This makes the implementation simpler and more const correct.
82 T* at(int i) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000083 DCHECK((data_ & kTagMask) != kEmptyTag);
Steve Block44f0eee2011-05-26 01:26:41 +010084 if ((data_ & kTagMask) == kSingletonTag) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000085 DCHECK(i == 0);
Steve Block44f0eee2011-05-26 01:26:41 +010086 return single_value();
87 }
88 return list()->at(i);
89 }
90
91 // See the note above.
92 T* operator[](int i) const { return at(i); }
93
94 // Remove the given element from the list (if present).
95 void RemoveElement(T* pointer) {
96 if ((data_ & kTagMask) == kEmptyTag) return;
97 if ((data_ & kTagMask) == kSingletonTag) {
98 if (pointer == single_value()) {
99 data_ = kEmptyTag;
100 }
101 return;
102 }
103 list()->RemoveElement(pointer);
104 }
105
106 T* RemoveLast() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000107 DCHECK((data_ & kTagMask) != kEmptyTag);
Steve Block44f0eee2011-05-26 01:26:41 +0100108 if ((data_ & kTagMask) == kSingletonTag) {
109 T* result = single_value();
110 data_ = kEmptyTag;
111 return result;
112 }
113 return list()->RemoveLast();
114 }
115
116 void Rewind(int pos) {
117 if ((data_ & kTagMask) == kEmptyTag) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000118 DCHECK(pos == 0);
Steve Block44f0eee2011-05-26 01:26:41 +0100119 return;
120 }
121 if ((data_ & kTagMask) == kSingletonTag) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000122 DCHECK(pos == 0 || pos == 1);
Steve Block44f0eee2011-05-26 01:26:41 +0100123 if (pos == 0) {
124 data_ = kEmptyTag;
125 }
126 return;
127 }
128 list()->Rewind(pos);
129 }
130
131 int CountOccurrences(T* pointer, int start, int end) const {
132 if ((data_ & kTagMask) == kEmptyTag) return 0;
133 if ((data_ & kTagMask) == kSingletonTag) {
134 if (start == 0 && end >= 0) {
135 return (single_value() == pointer) ? 1 : 0;
136 }
137 return 0;
138 }
139 return list()->CountOccurrences(pointer, start, end);
140 }
141
142 private:
143 typedef ZoneList<T*> PointerList;
144
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000145 static int compare_value(T* const* a, T* const* b) {
146 return Compare<T>(**a, **b);
147 }
148
Steve Block44f0eee2011-05-26 01:26:41 +0100149 static const intptr_t kEmptyTag = 1;
150 static const intptr_t kSingletonTag = 0;
151 static const intptr_t kListTag = 2;
152 static const intptr_t kTagMask = 3;
153 static const intptr_t kValueMask = ~kTagMask;
154
155 STATIC_ASSERT(kTagMask + 1 <= kPointerAlignment);
156
157 T* single_value() const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000158 DCHECK((data_ & kTagMask) == kSingletonTag);
Steve Block44f0eee2011-05-26 01:26:41 +0100159 STATIC_ASSERT(kSingletonTag == 0);
160 return reinterpret_cast<T*>(data_);
161 }
162
163 PointerList* list() const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000164 DCHECK((data_ & kTagMask) == kListTag);
Steve Block44f0eee2011-05-26 01:26:41 +0100165 return reinterpret_cast<PointerList*>(data_ & kValueMask);
166 }
167
168 intptr_t data_;
169
170 DISALLOW_COPY_AND_ASSIGN(SmallPointerList);
171};
172
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000173} // namespace internal
174} // namespace v8
Steve Block44f0eee2011-05-26 01:26:41 +0100175
176#endif // V8_SMALL_POINTER_LIST_H_