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 <cstddef> | |
etiennep
2016/05/26 14:03:29
Redundant with stddef.h
huangs
2016/05/26 17:54:27
Done.
| |
17 #include <iterator> | |
18 #include <type_traits> | |
19 | |
20 #include "base/logging.h" | |
16 #include "base/macros.h" | 21 #include "base/macros.h" |
17 #include "base/process/memory.h" | 22 #include "base/process/memory.h" |
18 | 23 |
19 namespace courgette { | 24 namespace courgette { |
20 | 25 |
26 // Page size of 2^18 * sizeof(T) is 1MB for T = int32_t. | |
27 constexpr int kPagedArrayDefaultPageLogSize = 18; | |
28 | |
29 template <typename T, int LOG_PAGE_SIZE = kPagedArrayDefaultPageLogSize> | |
30 class PagedArray; | |
31 | |
32 template <typename ContainerType, typename T> | |
33 class PagedArray_iterator { | |
34 public: | |
35 using ThisType = PagedArray_iterator<ContainerType, T>; | |
36 using difference_type = ptrdiff_t; | |
37 using value_type = typename std::remove_const<T>::type; | |
38 using reference = T&; | |
39 using pointer = T*; | |
40 using iterator_category = std::random_access_iterator_tag; | |
41 | |
42 PagedArray_iterator() : array_(nullptr), index_(0U) { } | |
43 PagedArray_iterator(ContainerType* array, size_t index) | |
44 : array_(array), index_(index) { } | |
45 | |
46 template <typename ContainerType2, typename T2> | |
47 PagedArray_iterator(const PagedArray_iterator<ContainerType2, T2>& it) | |
48 : array_(it.array_), index_(it.index_) { } | |
49 | |
50 PagedArray_iterator(std::nullptr_t) | |
51 : array_(nullptr), index_(0) { } | |
52 | |
53 virtual ~PagedArray_iterator() = default; | |
etiennep
2016/05/26 14:03:30
I don't think virtual is necessary anymore.
huangs
2016/05/26 17:54:27
Done.
| |
54 | |
55 reference operator*() const { return (*array_)[index_]; } | |
56 reference operator[](size_t idx) const { return (*array_)[index_ + idx]; } | |
57 pointer operator->() const { return &(*array_)[index_]; } | |
58 | |
59 ThisType& operator=(std::nullptr_t) { | |
60 array_ = nullptr; | |
61 index_ = 0; | |
62 return *this; | |
63 } | |
64 | |
65 ThisType& operator++() { | |
66 ++index_; | |
67 return *this; | |
68 } | |
69 ThisType& operator--() { | |
70 --index_; | |
71 return *this; | |
72 } | |
73 | |
74 ThisType operator++(int) { return ThisType(array_, index_++); } | |
75 ThisType operator--(int) { return ThisType(array_, index_--); } | |
76 | |
77 ThisType& operator+=(difference_type delta) { | |
78 index_ += delta; | |
79 return *this; | |
80 } | |
81 ThisType& operator-=(difference_type delta) { | |
82 index_ -= delta; | |
83 return *this; | |
84 } | |
85 | |
86 ThisType operator+(difference_type offset) const { | |
87 return ThisType(array_, index_ + offset); | |
88 } | |
89 ThisType operator-(difference_type offset) const { | |
90 return ThisType(array_, index_ - offset); | |
91 } | |
92 | |
93 template <typename ContainerType2, typename T2> | |
94 bool operator==(const PagedArray_iterator<ContainerType2, T2>& it) const { | |
95 return index_ == it.index_ && array_ == it.array_; | |
96 } | |
97 bool operator==(std::nullptr_t) const { | |
98 return index_ == 0 && array_ == nullptr; | |
99 } | |
100 template <typename ContainerType2, typename T2> | |
101 bool operator!=(const PagedArray_iterator<ContainerType2, T2>& it) const { | |
102 return !(*this == it); | |
103 } | |
104 | |
105 template <typename ContainerType2, typename T2> | |
106 bool operator<(const PagedArray_iterator<ContainerType2, T2>& it) const { | |
107 // Not bothering to check array_, for performance. | |
108 return index_ < it.index_; | |
109 } | |
110 template <typename ContainerType2, typename T2> | |
111 bool operator<=(const PagedArray_iterator<ContainerType2, T2>& it) const { | |
112 // Not bothering to check array_, for performance. | |
113 return index_ <= it.index_; | |
114 } | |
115 | |
116 template <typename ContainerType2, typename T2> | |
117 difference_type operator-(const PagedArray_iterator<ContainerType2, T2>& it) c onst { | |
etiennep
2016/05/26 14:03:29
Line too long?
huangs
2016/05/26 17:54:27
Done.
| |
118 return index_ - it.index_; | |
119 } | |
120 | |
121 private: | |
122 template <typename, typename> | |
123 friend class PagedArray_iterator; | |
124 | |
125 ContainerType* array_; | |
126 size_t index_; | |
127 }; | |
128 | |
21 // PagedArray implements an array stored using many fixed-size pages. | 129 // PagedArray implements an array stored using many fixed-size pages. |
22 template <typename T> | 130 template <typename T, int LOG_PAGE_SIZE> |
23 class PagedArray { | 131 class PagedArray { |
24 enum { | 132 enum { |
25 // Page size in elements. Page size of 2^18 * sizeof(T) is 1MB for T = int. | 133 // Page size in elements. |
26 kLogPageSize = 18, | 134 kLogPageSize = LOG_PAGE_SIZE, |
27 kPageSize = 1 << kLogPageSize | 135 kPageSize = 1 << LOG_PAGE_SIZE |
28 }; | 136 }; |
29 | 137 |
30 public: | 138 public: |
31 PagedArray() : pages_(NULL), page_count_(0) {} | 139 using ThisType = PagedArray<T, LOG_PAGE_SIZE>; |
140 using const_iterator = PagedArray_iterator<const ThisType, const T>; | |
141 using iterator = PagedArray_iterator<ThisType, T>; | |
32 | 142 |
143 PagedArray() { } | |
etiennep
2016/05/26 14:03:29
= default
huangs
2016/05/26 17:54:27
Done.
| |
33 ~PagedArray() { clear(); } | 144 ~PagedArray() { clear(); } |
34 | 145 |
146 iterator begin() { return iterator(this, 0); } | |
147 iterator end() { return iterator(this, size_); } | |
148 const_iterator begin() const { return const_iterator(this, 0); } | |
149 const_iterator end() const { return const_iterator(this, size_); } | |
150 | |
35 T& operator[](size_t i) { | 151 T& operator[](size_t i) { |
36 size_t page = i >> kLogPageSize; | 152 size_t page = i >> kLogPageSize; |
37 size_t offset = i & (kPageSize - 1); | 153 size_t offset = i & (kPageSize - 1); |
38 // It is tempting to add a DCHECK(page < page_count_), but that makes | 154 // It is tempting to add a DCHECK(page < page_count_), but that makes |
39 // bsdiff_create run 2x slower (even when compiled optimized.) | 155 // bsdiff_create run 2x slower (even when compiled optimized.) |
40 return pages_[page][offset]; | 156 return pages_[page][offset]; |
41 } | 157 } |
42 | 158 |
159 const T& operator[](size_t i) const { | |
etiennep
2016/05/26 14:03:29
Optionally, implement this one using the other one
huangs
2016/05/26 17:54:27
I'd rather avoid unneeded use of const_cast<>. Ad
| |
160 size_t page = i >> kLogPageSize; | |
161 size_t offset = i & (kPageSize - 1); | |
162 // It is tempting to add a DCHECK(page < page_count_), but that makes | |
163 // bsdiff_create run 2x slower (even when compiled optimized.) | |
164 return pages_[page][offset]; | |
165 } | |
166 | |
43 // Allocates storage for |size| elements. Returns true on success and false if | 167 // Allocates storage for |size| elements. Returns true on success and false if |
44 // allocation fails. | 168 // allocation fails. |
45 bool Allocate(size_t size) { | 169 bool Allocate(size_t size) { |
46 clear(); | 170 clear(); |
47 size_t pages_needed = (size + kPageSize - 1) >> kLogPageSize; | 171 size_ = size; |
172 size_t pages_needed = (size_ + kPageSize - 1) >> kLogPageSize; | |
48 if (!base::UncheckedMalloc(sizeof(T*) * pages_needed, | 173 if (!base::UncheckedMalloc(sizeof(T*) * pages_needed, |
49 reinterpret_cast<void**>(&pages_))) { | 174 reinterpret_cast<void**>(&pages_))) { |
50 return false; | 175 return false; |
51 } | 176 } |
52 | 177 |
53 for (page_count_ = 0; page_count_ < pages_needed; ++page_count_) { | 178 for (page_count_ = 0; page_count_ < pages_needed; ++page_count_) { |
54 T* block = nullptr; | 179 T* block = nullptr; |
55 if (!base::UncheckedMalloc(sizeof(T) * kPageSize, | 180 if (!base::UncheckedMalloc(sizeof(T) * kPageSize, |
56 reinterpret_cast<void**>(&block))) { | 181 reinterpret_cast<void**>(&block))) { |
57 clear(); | 182 clear(); |
58 return false; | 183 return false; |
59 } | 184 } |
60 pages_[page_count_] = block; | 185 pages_[page_count_] = block; |
61 } | 186 } |
62 return true; | 187 return true; |
63 } | 188 } |
64 | 189 |
65 // Releases all storage. May be called more than once. | 190 // Releases all storage. May be called more than once. |
66 void clear() { | 191 void clear() { |
67 if (pages_ != NULL) { | 192 if (pages_ != nullptr) { |
68 while (page_count_ != 0) { | 193 while (page_count_ != 0) { |
69 --page_count_; | 194 --page_count_; |
70 free(pages_[page_count_]); | 195 free(pages_[page_count_]); |
71 } | 196 } |
72 free(pages_); | 197 free(pages_); |
73 pages_ = NULL; | 198 pages_ = nullptr; |
74 } | 199 } |
75 } | 200 } |
76 | 201 |
77 private: | 202 private: |
78 T** pages_; | 203 T** pages_ = nullptr; |
79 size_t page_count_; | 204 size_t size_ = 0U; |
205 size_t page_count_ = 0U; | |
etiennep
2016/05/26 14:03:29
If we have size_, we don't really need page_count_
huangs
2016/05/26 17:54:27
True. However, note that page_count_ is used in t
| |
80 | 206 |
81 DISALLOW_COPY_AND_ASSIGN(PagedArray); | 207 DISALLOW_COPY_AND_ASSIGN(PagedArray); |
82 }; | 208 }; |
83 | 209 |
84 } // namespace courgette | 210 } // namespace courgette |
211 | |
85 #endif // COURGETTE_THIRD_PARTY_BSDIFF_PAGED_ARRAY_H_ | 212 #endif // COURGETTE_THIRD_PARTY_BSDIFF_PAGED_ARRAY_H_ |
OLD | NEW |