blob: 295a06f26afc50bc39f81a21f777f3e1b922b4de [file] [log] [blame]
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001// Copyright 2011 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#ifndef V8_SMALL_POINTER_LIST_H_
29#define V8_SMALL_POINTER_LIST_H_
30
31#include "checks.h"
32#include "v8globals.h"
33#include "zone.h"
34
35namespace v8 {
36namespace internal {
37
38// SmallPointerList is a list optimized for storing no or just a
39// single value. When more values are given it falls back to ZoneList.
40//
41// The interface tries to be as close to List from list.h as possible.
42template <typename T>
43class SmallPointerList {
44 public:
45 SmallPointerList() : data_(kEmptyTag) {}
46
mmassi@chromium.org7028c052012-06-13 11:51:58 +000047 SmallPointerList(int capacity, Zone* zone) : data_(kEmptyTag) {
48 Reserve(capacity, zone);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000049 }
50
mmassi@chromium.org7028c052012-06-13 11:51:58 +000051 void Reserve(int capacity, Zone* zone) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000052 if (capacity < 2) return;
53 if ((data_ & kTagMask) == kListTag) {
54 if (list()->capacity() >= capacity) return;
55 int old_length = list()->length();
mmassi@chromium.org7028c052012-06-13 11:51:58 +000056 list()->AddBlock(NULL, capacity - list()->capacity(), zone);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000057 list()->Rewind(old_length);
58 return;
59 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +000060 PointerList* list = new(zone) PointerList(capacity, zone);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000061 if ((data_ & kTagMask) == kSingletonTag) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +000062 list->Add(single_value(), zone);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000063 }
64 ASSERT(IsAligned(reinterpret_cast<intptr_t>(list), kPointerAlignment));
65 data_ = reinterpret_cast<intptr_t>(list) | kListTag;
66 }
67
68 void Clear() {
69 data_ = kEmptyTag;
70 }
71
jkummerow@chromium.org1456e702012-03-30 08:38:13 +000072 void Sort() {
73 if ((data_ & kTagMask) == kListTag) {
74 list()->Sort(compare_value);
75 }
76 }
77
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000078 bool is_empty() const { return length() == 0; }
79
80 int length() const {
81 if ((data_ & kTagMask) == kEmptyTag) return 0;
82 if ((data_ & kTagMask) == kSingletonTag) return 1;
83 return list()->length();
84 }
85
mmassi@chromium.org7028c052012-06-13 11:51:58 +000086 void Add(T* pointer, Zone* zone) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000087 ASSERT(IsAligned(reinterpret_cast<intptr_t>(pointer), kPointerAlignment));
88 if ((data_ & kTagMask) == kEmptyTag) {
89 data_ = reinterpret_cast<intptr_t>(pointer) | kSingletonTag;
90 return;
91 }
92 if ((data_ & kTagMask) == kSingletonTag) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +000093 PointerList* list = new(zone) PointerList(2, zone);
94 list->Add(single_value(), zone);
95 list->Add(pointer, zone);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000096 ASSERT(IsAligned(reinterpret_cast<intptr_t>(list), kPointerAlignment));
97 data_ = reinterpret_cast<intptr_t>(list) | kListTag;
98 return;
99 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000100 list()->Add(pointer, zone);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000101 }
102
103 // Note: returns T* and not T*& (unlike List from list.h).
104 // This makes the implementation simpler and more const correct.
105 T* at(int i) const {
106 ASSERT((data_ & kTagMask) != kEmptyTag);
107 if ((data_ & kTagMask) == kSingletonTag) {
108 ASSERT(i == 0);
109 return single_value();
110 }
111 return list()->at(i);
112 }
113
114 // See the note above.
115 T* operator[](int i) const { return at(i); }
116
117 // Remove the given element from the list (if present).
118 void RemoveElement(T* pointer) {
119 if ((data_ & kTagMask) == kEmptyTag) return;
120 if ((data_ & kTagMask) == kSingletonTag) {
121 if (pointer == single_value()) {
122 data_ = kEmptyTag;
123 }
124 return;
125 }
126 list()->RemoveElement(pointer);
127 }
128
129 T* RemoveLast() {
130 ASSERT((data_ & kTagMask) != kEmptyTag);
131 if ((data_ & kTagMask) == kSingletonTag) {
132 T* result = single_value();
133 data_ = kEmptyTag;
134 return result;
135 }
136 return list()->RemoveLast();
137 }
138
139 void Rewind(int pos) {
140 if ((data_ & kTagMask) == kEmptyTag) {
141 ASSERT(pos == 0);
142 return;
143 }
144 if ((data_ & kTagMask) == kSingletonTag) {
145 ASSERT(pos == 0 || pos == 1);
146 if (pos == 0) {
147 data_ = kEmptyTag;
148 }
149 return;
150 }
151 list()->Rewind(pos);
152 }
153
154 int CountOccurrences(T* pointer, int start, int end) const {
155 if ((data_ & kTagMask) == kEmptyTag) return 0;
156 if ((data_ & kTagMask) == kSingletonTag) {
157 if (start == 0 && end >= 0) {
158 return (single_value() == pointer) ? 1 : 0;
159 }
160 return 0;
161 }
162 return list()->CountOccurrences(pointer, start, end);
163 }
164
165 private:
166 typedef ZoneList<T*> PointerList;
167
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000168 static int compare_value(T* const* a, T* const* b) {
169 return Compare<T>(**a, **b);
170 }
171
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000172 static const intptr_t kEmptyTag = 1;
173 static const intptr_t kSingletonTag = 0;
174 static const intptr_t kListTag = 2;
175 static const intptr_t kTagMask = 3;
176 static const intptr_t kValueMask = ~kTagMask;
177
178 STATIC_ASSERT(kTagMask + 1 <= kPointerAlignment);
179
180 T* single_value() const {
181 ASSERT((data_ & kTagMask) == kSingletonTag);
182 STATIC_ASSERT(kSingletonTag == 0);
183 return reinterpret_cast<T*>(data_);
184 }
185
186 PointerList* list() const {
187 ASSERT((data_ & kTagMask) == kListTag);
188 return reinterpret_cast<PointerList*>(data_ & kValueMask);
189 }
190
191 intptr_t data_;
192
193 DISALLOW_COPY_AND_ASSIGN(SmallPointerList);
194};
195
196} } // namespace v8::internal
197
198#endif // V8_SMALL_POINTER_LIST_H_