OLD | NEW |
---|---|
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // PagedArray implements an array stored using many fixed-size pages. | 5 // PagedArray implements an array stored using many fixed-size pages. |
6 // | 6 // |
7 // PagedArray is a work-around to allow large arrays to be allocated when there | 7 // PagedArray is a work-around to allow large arrays to be allocated when there |
8 // is too much address space fragmentation for allocating the large arrays as | 8 // is too much address space fragmentation for allocating the large arrays as |
9 // contiguous arrays. | 9 // contiguous arrays. |
10 | 10 |
11 #ifndef COURGETTE_THIRD_PARTY_BSDIFF_PAGED_ARRAY_H_ | 11 #ifndef COURGETTE_THIRD_PARTY_BSDIFF_PAGED_ARRAY_H_ |
12 #define COURGETTE_THIRD_PARTY_BSDIFF_PAGED_ARRAY_H_ | 12 #define COURGETTE_THIRD_PARTY_BSDIFF_PAGED_ARRAY_H_ |
13 | 13 |
14 #include <stddef.h> | 14 #include <stddef.h> |
15 | 15 |
16 #include <iterator> | |
17 | |
18 #include "base/logging.h" | |
16 #include "base/macros.h" | 19 #include "base/macros.h" |
17 #include "base/process/memory.h" | 20 #include "base/process/memory.h" |
18 | 21 |
19 namespace courgette { | 22 namespace courgette { |
20 | 23 |
24 // Page size of 2^18 * sizeof(T) is 1MB for T = int32_t. | |
25 constexpr int kPagedArrayDefaultPageLogSize = 18; | |
26 | |
27 template <typename T, int LOG_PAGE_SIZE = kPagedArrayDefaultPageLogSize> | |
28 class PagedArray; | |
29 | |
30 template <typename T, int LOG_PAGE_SIZE = kPagedArrayDefaultPageLogSize> | |
31 class PagedArray_const_iterator; | |
32 | |
33 template <typename T, int LOG_PAGE_SIZE = kPagedArrayDefaultPageLogSize> | |
34 class PagedArray_iterator; | |
35 | |
36 } // courgette | |
37 | |
38 namespace std { | |
39 | |
40 template <typename T, int LOG_PAGE_SIZE> | |
41 struct iterator_traits<class courgette::PagedArray_iterator<T, LOG_PAGE_SIZE>> { | |
etiennep
2016/05/25 14:19:02
We can declare these typedefs directly in the iter
huangs
2016/05/25 19:36:42
Went with directly declaring, using "using".
| |
42 typedef ptrdiff_t difference_type; | |
43 typedef T value_type; | |
44 typedef T& reference; | |
45 typedef T* pointer; | |
46 typedef random_access_iterator_tag iterator_category; | |
47 }; | |
48 | |
49 template <typename T, int LOG_PAGE_SIZE> | |
50 struct iterator_traits< | |
51 class courgette::PagedArray_const_iterator<T, LOG_PAGE_SIZE>> { | |
52 typedef ptrdiff_t difference_type; | |
53 typedef T value_type; | |
54 typedef const T& reference; | |
55 typedef const T* pointer; | |
56 typedef random_access_iterator_tag iterator_category; | |
57 }; | |
58 | |
59 } // namespace std | |
60 | |
61 namespace courgette { | |
62 | |
63 template <typename T, int LOG_PAGE_SIZE> | |
64 class PagedArray_const_iterator { | |
etiennep
2016/05/25 14:19:01
This does a lot of duplicate code. I don't think w
huangs
2016/05/25 19:36:42
For this revision, went with the standard way of d
| |
65 public: | |
66 using ContainerType = PagedArray<T, LOG_PAGE_SIZE>; | |
67 using ConstItType = PagedArray_const_iterator<T, LOG_PAGE_SIZE>; | |
68 | |
69 PagedArray_const_iterator() : array_(nullptr), index_(0U) { } | |
70 | |
71 PagedArray_const_iterator(const ContainerType* array, size_t index) | |
72 : array_(array), index_(index) { } | |
73 | |
74 PagedArray_const_iterator(const PagedArray_const_iterator&) = default; | |
75 | |
76 PagedArray_const_iterator(void*) | |
77 : array_(nullptr), index_(0) { } | |
78 | |
79 ~PagedArray_const_iterator() { } | |
80 | |
81 const T& operator*() const { return (*array_)[index_]; } | |
82 | |
83 const T& operator[](size_t idx) const { return (*array_)[index_ + idx]; } | |
84 | |
85 ConstItType& operator++() { | |
86 ++index_; | |
87 return *this; | |
88 } | |
89 | |
90 ConstItType& operator--() { | |
91 --index_; | |
92 return *this; | |
93 } | |
94 | |
95 ConstItType operator++(int) { return ConstItType(array_, index_++); } | |
96 ConstItType operator--(int) { return ConstItType(array_, index_--); } | |
97 | |
98 ConstItType operator+=(size_t delta) { | |
etiennep
2016/05/25 14:19:01
NIT: the iterator concept requires delta to be dif
huangs
2016/05/25 19:36:42
Done.
| |
99 return ConstItType(array_, index_ += delta); | |
100 } | |
101 ConstItType operator-=(size_t delta) { | |
102 return ConstItType(array_, index_ -= delta); | |
103 } | |
104 | |
105 ConstItType operator+(size_t offset) { | |
106 return ConstItType(array_, index_ + offset); | |
107 } | |
108 ConstItType operator-(size_t offset) { | |
109 return ConstItType(array_, index_ - offset); | |
110 } | |
111 | |
112 bool operator==(const ConstItType& it) const { | |
113 return index_ == it.index_ && array_ == it.array_; | |
114 } | |
115 bool operator!=(const ConstItType& it) const { | |
etiennep
2016/05/25 14:19:02
The implementation could be {return !(*this == it)
huangs
2016/05/25 19:36:42
Done.
| |
116 return index_ != it.index_ || array_ != it.array_; | |
117 } | |
118 | |
119 bool operator<(const ConstItType& it) const { | |
120 // Not bothering to check array_, for performance. | |
121 return index_ < it.index_; | |
122 } | |
123 bool operator<=(const ConstItType& it) const { | |
124 // Not bothering to check array_, for performance. | |
125 return index_ <= it.index_; | |
126 } | |
127 | |
128 ptrdiff_t operator-(const ConstItType& it) const { | |
129 return index_ - it.index_; | |
130 } | |
131 | |
132 private: | |
133 friend PagedArray_iterator<T, LOG_PAGE_SIZE>; | |
134 | |
135 const ContainerType* array_; | |
136 size_t index_; | |
137 }; | |
138 | |
139 // RandomAccessIterator for PagedArray<T> to enable std::sort(). | |
140 template <typename T, int LOG_PAGE_SIZE> | |
141 class PagedArray_iterator { | |
142 public: | |
143 using ContainerType = PagedArray<T, LOG_PAGE_SIZE>; | |
144 using ItType = PagedArray_iterator<T, LOG_PAGE_SIZE>; | |
145 using ConstItType = PagedArray_const_iterator<T, LOG_PAGE_SIZE>; | |
etiennep
2016/05/25 14:19:01
If you were to merge both iterator, we can get Con
huangs
2016/05/25 19:36:42
May try this next. So conversion operator will se
| |
146 | |
147 PagedArray_iterator() : array_(nullptr), index_(0U) { } | |
148 | |
149 PagedArray_iterator(ContainerType* array, size_t index) | |
150 : array_(array), index_(index) { } | |
151 | |
152 PagedArray_iterator(const PagedArray_iterator&) = default; | |
153 | |
154 ~PagedArray_iterator() { } | |
etiennep
2016/05/25 14:19:02
Would be more consistent = default
huangs
2016/05/25 19:36:42
Done.
| |
155 | |
156 operator ConstItType() { return ConstItType(array_, index_); } | |
157 | |
158 const T& operator*() const { return (*array_)[index_]; } | |
159 T& operator*() { return (*array_)[index_]; } | |
160 | |
etiennep
2016/05/25 14:19:01
We could put operator-> as it is a requirement for
huangs
2016/05/25 19:36:42
Added, with tests.
| |
161 const T& operator[](size_t idx) const { return (*array_)[index_ + idx]; } | |
etiennep
2016/05/25 14:19:01
Not very useful. A const-qualified iterator (could
huangs
2016/05/25 19:36:42
Good point; removed!
Also removing const T& opera
| |
162 T& operator[](size_t idx) { return (*array_)[index_ + idx]; } | |
163 | |
164 ItType& operator++() { | |
165 ++index_; | |
166 return *this; | |
167 } | |
168 | |
169 ItType& operator--() { | |
170 --index_; | |
171 return *this; | |
172 } | |
173 | |
174 ItType operator++(int) { return ItType(array_, index_++); } | |
175 ItType operator--(int) { return ItType(array_, index_--); } | |
176 | |
177 ItType operator+=(size_t delta) { return ItType(array_, index_ += delta); } | |
178 ItType operator-=(size_t delta) { return ItType(array_, index_ -= delta); } | |
179 | |
180 ItType operator+(size_t offset) { return ItType(array_, index_ + offset); } | |
181 ItType operator-(size_t offset) { return ItType(array_, index_ - offset); } | |
182 | |
183 // Only useful for assigning nullptr. | |
184 ItType& operator=(void*) { | |
etiennep
2016/05/25 14:19:01
The arguments should be std::nullptr_t instead.
huangs
2016/05/25 19:36:42
Done.
| |
185 array_ = nullptr; | |
186 index_ = 0; | |
187 return *this; | |
188 } | |
189 | |
190 bool operator==(const ItType& it) const { | |
191 return index_ == it.index_ && array_ == it.array_; | |
192 } | |
193 | |
194 // Only intended for comparing against nullptr. | |
195 bool operator==(const void* p) const { | |
etiennep
2016/05/25 14:19:02
std::nullptr_t again. There would be non need to c
huangs
2016/05/25 19:36:42
Done.
| |
196 DCHECK_EQ(nullptr, p); | |
197 return index_ == 0 && array_ == p; | |
198 } | |
199 | |
200 bool operator!=(const ItType& it) const { | |
201 return index_ != it.index_ || array_ != it.array_; | |
202 } | |
203 | |
204 bool operator<(const ItType& it) const { | |
205 // Not bothering to check array_, for performance. | |
206 return index_ < it.index_; | |
207 } | |
208 bool operator<=(const ItType& it) const { | |
209 // Not bothering to check array_, for performance. | |
210 return index_ <= it.index_; | |
211 } | |
212 | |
213 ptrdiff_t operator-(const ItType& it) const { | |
214 return index_ - it.index_; | |
215 } | |
216 | |
217 ptrdiff_t operator-(const ConstItType& it) const { | |
218 return index_ - it.index_; | |
219 } | |
220 | |
221 private: | |
222 ContainerType* array_; | |
223 size_t index_; | |
224 }; | |
225 | |
21 // PagedArray implements an array stored using many fixed-size pages. | 226 // PagedArray implements an array stored using many fixed-size pages. |
22 template <typename T> | 227 template <typename T, int LOG_PAGE_SIZE> |
23 class PagedArray { | 228 class PagedArray { |
24 enum { | 229 enum { |
25 // Page size in elements. Page size of 2^18 * sizeof(T) is 1MB for T = int. | 230 // Page size in elements. |
26 kLogPageSize = 18, | 231 kLogPageSize = LOG_PAGE_SIZE, |
27 kPageSize = 1 << kLogPageSize | 232 kPageSize = 1 << LOG_PAGE_SIZE |
28 }; | 233 }; |
29 | 234 |
30 public: | 235 public: |
31 PagedArray() : pages_(NULL), page_count_(0) {} | 236 typedef PagedArray_const_iterator<T, LOG_PAGE_SIZE> const_iterator; |
32 | 237 typedef PagedArray_iterator<T, LOG_PAGE_SIZE> iterator; |
238 | |
239 PagedArray() { } | |
33 ~PagedArray() { clear(); } | 240 ~PagedArray() { clear(); } |
34 | 241 |
242 iterator begin() { return iterator(this, 0); } | |
243 iterator end() { return iterator(this, size_); } | |
244 const_iterator begin() const { return const_iterator(this, 0); } | |
245 const_iterator end() const { return const_iterator(this, size_); } | |
246 | |
35 T& operator[](size_t i) { | 247 T& operator[](size_t i) { |
36 size_t page = i >> kLogPageSize; | 248 size_t page = i >> kLogPageSize; |
37 size_t offset = i & (kPageSize - 1); | 249 size_t offset = i & (kPageSize - 1); |
38 // It is tempting to add a DCHECK(page < page_count_), but that makes | 250 // It is tempting to add a DCHECK(page < page_count_), but that makes |
39 // bsdiff_create run 2x slower (even when compiled optimized.) | 251 // bsdiff_create run 2x slower (even when compiled optimized.) |
40 return pages_[page][offset]; | 252 return pages_[page][offset]; |
41 } | 253 } |
42 | 254 |
255 const T& operator[](size_t i) const { | |
etiennep
2016/05/25 14:19:01
This is me asking : If PagedArray is meant to supp
huangs
2016/05/25 19:36:42
PagedArray is meant to solve memory fragmentation
| |
256 size_t page = i >> kLogPageSize; | |
257 size_t offset = i & (kPageSize - 1); | |
258 // It is tempting to add a DCHECK(page < page_count_), but that makes | |
259 // bsdiff_create run 2x slower (even when compiled optimized.) | |
260 return pages_[page][offset]; | |
261 } | |
262 | |
43 // Allocates storage for |size| elements. Returns true on success and false if | 263 // Allocates storage for |size| elements. Returns true on success and false if |
44 // allocation fails. | 264 // allocation fails. |
45 bool Allocate(size_t size) { | 265 bool Allocate(size_t size) { |
46 clear(); | 266 clear(); |
47 size_t pages_needed = (size + kPageSize - 1) >> kLogPageSize; | 267 size_ = size; |
268 size_t pages_needed = (size_ + kPageSize - 1) >> kLogPageSize; | |
48 if (!base::UncheckedMalloc(sizeof(T*) * pages_needed, | 269 if (!base::UncheckedMalloc(sizeof(T*) * pages_needed, |
49 reinterpret_cast<void**>(&pages_))) { | 270 reinterpret_cast<void**>(&pages_))) { |
50 return false; | 271 return false; |
51 } | 272 } |
52 | 273 |
53 for (page_count_ = 0; page_count_ < pages_needed; ++page_count_) { | 274 for (page_count_ = 0; page_count_ < pages_needed; ++page_count_) { |
54 T* block = nullptr; | 275 T* block = nullptr; |
55 if (!base::UncheckedMalloc(sizeof(T) * kPageSize, | 276 if (!base::UncheckedMalloc(sizeof(T) * kPageSize, |
56 reinterpret_cast<void**>(&block))) { | 277 reinterpret_cast<void**>(&block))) { |
57 clear(); | 278 clear(); |
58 return false; | 279 return false; |
59 } | 280 } |
60 pages_[page_count_] = block; | 281 pages_[page_count_] = block; |
61 } | 282 } |
62 return true; | 283 return true; |
63 } | 284 } |
64 | 285 |
65 // Releases all storage. May be called more than once. | 286 // Releases all storage. May be called more than once. |
66 void clear() { | 287 void clear() { |
67 if (pages_ != NULL) { | 288 if (pages_ != nullptr) { |
68 while (page_count_ != 0) { | 289 while (page_count_ != 0) { |
69 --page_count_; | 290 --page_count_; |
70 free(pages_[page_count_]); | 291 free(pages_[page_count_]); |
71 } | 292 } |
72 free(pages_); | 293 free(pages_); |
73 pages_ = NULL; | 294 pages_ = nullptr; |
74 } | 295 } |
75 } | 296 } |
76 | 297 |
77 private: | 298 private: |
78 T** pages_; | 299 T** pages_ = nullptr; |
79 size_t page_count_; | 300 size_t size_ = 0U; |
301 size_t page_count_ = 0U; | |
80 | 302 |
81 DISALLOW_COPY_AND_ASSIGN(PagedArray); | 303 DISALLOW_COPY_AND_ASSIGN(PagedArray); |
82 }; | 304 }; |
83 | 305 |
84 } // namespace courgette | 306 } // namespace courgette |
307 | |
85 #endif // COURGETTE_THIRD_PARTY_BSDIFF_PAGED_ARRAY_H_ | 308 #endif // COURGETTE_THIRD_PARTY_BSDIFF_PAGED_ARRAY_H_ |
OLD | NEW |