2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
21 #include <type_traits>
22 #include <initializer_list>
24 #include "hphp/util/assertions.h"
25 #include "hphp/util/safe-cast.h"
28 ///////////////////////////////////////////////////////////////////////////////
31 * During its lifetime, an instance of CompactVector can transition
34 * This is the initial state for a newly constructed CompactVector.
35 * There are no elements and no allocated block of memory.
37 * In this state, m_data points to a malloced block of memory. The
38 * number of elements, the capacity of the block, and the values of
39 * all the elements reside in the allocated block of memory.
41 template <typename T
, typename Alloc
= std::allocator
<char>>
42 struct CompactVector
: private Alloc::template rebind
<char>::other
{
43 using size_type
= std::size_t;
46 using const_iterator
= const T
*;
47 using Allocator
= typename
Alloc::template rebind
<char>::other
;
49 friend iterator
begin(CompactVector
& v
) { return v
.begin(); }
50 friend iterator
end(CompactVector
& v
) { return v
.end(); }
51 friend const_iterator
begin(const CompactVector
& v
) { return v
.begin(); }
52 friend const_iterator
end(const CompactVector
& v
) { return v
.end(); }
55 explicit CompactVector(size_type n
);
56 CompactVector(size_type n
, const T
&);
57 CompactVector(CompactVector
&& other
) noexcept
;
58 CompactVector(const CompactVector
& other
);
59 CompactVector(std::initializer_list
<T
> init
);
60 CompactVector
& operator=(CompactVector
&&);
61 CompactVector
& operator=(const CompactVector
&);
64 void swap(CompactVector
& other
) noexcept
;
66 bool operator==(const CompactVector
& other
) const;
68 bool operator!=(const CompactVector
& other
) const {
69 return !(*this == other
);
72 iterator
begin() { return m_data
? elems() : nullptr; }
73 iterator
end() { return m_data
? elems() + size() : nullptr; }
74 const_iterator
begin() const { return m_data
? elems() : nullptr; }
75 const_iterator
end() const { return m_data
? elems() + size() : nullptr; }
76 T
* data() { return m_data
? elems() : nullptr; }
77 const T
* data() const { return m_data
? elems() : nullptr; }
80 size_type
size() const;
81 size_type
capacity() const;
83 void push_back(const T
& val
);
84 void push_back(T
&& val
);
85 template <class... Args
>
86 void emplace_back(Args
&&... args
);
89 void erase(iterator
, iterator
);
90 iterator
insert(iterator p
, const T
& v
) { return insert_impl(p
, 1, v
); }
91 iterator
insert(iterator p
, T
&& v
) { return insert_impl(p
, 1, std::move(v
)); };
92 iterator
insert(iterator p
, size_t num
, const T
& v
) {
93 return insert_impl(p
, num
, v
);
96 iterator
insert(iterator p
, U i1
, U i2
);
97 void resize(size_type sz
);
98 void resize(size_type sz
, const value_type
& value
);
101 T
& operator[](size_type index
) { return *get(index
); }
102 const T
& operator[](size_type index
) const { return *get(index
); }
103 T
& front() { return *get(0); }
104 const T
& front() const { return *get(0); }
105 T
& back() { return *get(m_data
->m_len
- 1); }
106 const T
& back() const { return *get(m_data
->m_len
- 1); }
108 void reserve(size_type sz
);
110 using Allocator::allocate
;
111 using Allocator::deallocate
;
113 struct CompactVectorData
{
118 iterator
insert_elems(iterator
, size_t num
);
120 iterator
insert_impl(iterator
, size_t num
, U
&&);
121 void assign(const CompactVector
& other
);
123 T
* get(size_type index
) const;
125 static size_t required_mem(size_type n
);
126 void reserve_impl(size_type sz
);
127 bool resize_helper(size_type sz
);
129 CompactVectorData
* m_data
;
131 static constexpr size_type initial_capacity
= 4;
132 /* We mainly want this so pretty.py can figure out the alignment */
133 static constexpr size_type elems_offset
=
134 alignof(T
) >= sizeof(CompactVectorData
) ?
135 alignof(T
) : sizeof(CompactVectorData
);
136 /* And we need this to prevent gcc from throwing away elems_offset */
137 using elems_offset_type
= char[elems_offset
];
140 template <typename T
, typename A
>
141 CompactVector
<T
, A
>::CompactVector() {
145 template <typename T
, typename A
>
146 CompactVector
<T
, A
>::CompactVector(size_type n
) {
151 template <typename T
, typename A
>
152 CompactVector
<T
, A
>::CompactVector(size_type n
, const T
& val
) {
157 template <typename T
, typename A
>
158 CompactVector
<T
, A
>::CompactVector(CompactVector
&& other
) noexcept
159 : m_data(other
.m_data
) {
160 other
.m_data
= nullptr;
163 template <typename T
, typename A
>
164 CompactVector
<T
, A
>::CompactVector(const CompactVector
& other
)
169 template <typename T
, typename A
>
171 CompactVector
<T
, A
>::operator=(const CompactVector
& other
) {
172 if (this == &other
) return *this;
178 template <typename T
, typename A
>
179 CompactVector
<T
, A
>::CompactVector(std::initializer_list
<T
> init
) :
181 reserve_impl(init
.size());
182 for (auto const& e
: init
) {
187 template <typename T
, typename A
>
188 void CompactVector
<T
, A
>::assign(const CompactVector
& other
) {
190 if (!other
.size()) return;
191 reserve_impl(other
.m_data
->m_len
);
192 auto const sz
= other
.m_data
->m_len
;
193 for (size_type i
= 0; i
< sz
; ++i
) {
198 template <typename T
, typename A
>
199 CompactVector
<T
, A
>& CompactVector
<T
, A
>::operator=(CompactVector
&& other
) {
200 std::swap(m_data
, other
.m_data
);
204 template <typename T
, typename A
>
205 void CompactVector
<T
, A
>::swap(CompactVector
& other
) noexcept
{
206 std::swap(m_data
, other
.m_data
);
209 template <typename T
, typename A
>
210 bool CompactVector
<T
, A
>::operator==(const CompactVector
& other
) const {
211 auto const sz
= size();
212 if (sz
!= other
.size()) return false;
213 for (size_type i
= 0; i
< sz
; ++i
) {
214 if (!(*get(i
) == other
[i
])) return false;
219 template <typename T
, typename A
>
220 CompactVector
<T
, A
>::~CompactVector() {
224 template <typename T
, typename A
>
225 T
* CompactVector
<T
, A
>::elems() const {
227 return (T
*)((char*)m_data
+ elems_offset
);
230 template <typename T
, typename A
>
231 size_t CompactVector
<T
, A
>::required_mem(size_type n
) {
232 return elems_offset
+ sizeof(T
) * n
;
235 template <typename T
, typename A
>
236 T
* CompactVector
<T
, A
>::get(size_type index
) const {
237 // Index into the allocated block of memory
239 assert(index
< m_data
->m_len
);
243 template <typename T
, typename A
>
244 bool CompactVector
<T
, A
>::empty() const {
248 template <typename T
, typename A
>
249 typename CompactVector
<T
, A
>::size_type CompactVector
<T
, A
>::size() const {
250 return m_data
? m_data
->m_len
: 0;
253 template <typename T
, typename A
>
254 typename CompactVector
<T
, A
>::size_type CompactVector
<T
, A
>::capacity() const {
255 return m_data
? m_data
->m_capacity
: 0;
258 template <typename T
, typename A
>
259 void CompactVector
<T
, A
>::erase(iterator elm
) {
260 assert(elm
- elems() < size());
261 auto const e
= end();
263 elm
[-1] = std::move(*elm
);
269 template <typename T
, typename A
>
270 void CompactVector
<T
, A
>::erase(iterator elm1
, iterator elm2
) {
271 if (elm1
== elm2
) return;
272 assert(elems() <= elm1
&& elm1
<= elm2
&& elm2
<= end());
273 auto const e
= end();
275 *elm1
++ = std::move(*elm2
++);
277 m_data
->m_len
-= elm2
- elm1
;
283 template <typename T
, typename A
>
284 bool CompactVector
<T
, A
>::resize_helper(size_type sz
) {
285 auto const old_size
= size();
286 if (sz
== old_size
) return true;
295 } while (++sz
< old_size
);
299 template <typename T
, typename A
>
300 void CompactVector
<T
, A
>::resize(size_type sz
, const value_type
& v
) {
301 if (resize_helper(sz
)) return;
302 while (m_data
->m_len
< sz
) {
307 template <typename T
, typename A
>
308 void CompactVector
<T
, A
>::resize(size_type sz
) {
309 if (resize_helper(sz
)) return;
310 while (m_data
->m_len
< sz
) {
315 template <typename T
, typename A
>
316 void CompactVector
<T
, A
>::shrink_to_fit() {
317 if (!m_data
|| m_data
->m_capacity
== m_data
->m_len
) return;
318 if (!m_data
->m_len
) {
322 reserve_impl(m_data
->m_len
);
325 template <typename T
, typename A
>
326 void copy(CompactVector
<T
, A
>& dest
, const std::vector
<T
>& src
) {
328 dest
.reserve(src
.size());
329 for (auto const& v
: src
) dest
.push_back(v
);
332 template <typename T
, typename A
>
333 void CompactVector
<T
, A
>::clear() {
335 if (!std::is_trivially_destructible
<T
>::value
) {
336 if (auto sz
= size()) {
338 do { elm
++->~T(); } while (--sz
);
341 deallocate(reinterpret_cast<char*>(m_data
),
342 required_mem(m_data
->m_capacity
));
346 template <typename T
, typename A
>
347 void CompactVector
<T
, A
>::grow() {
348 reserve_impl(m_data
? m_data
->m_capacity
* 2LL : initial_capacity
);
351 template <typename T
, typename A
>
352 void CompactVector
<T
, A
>::reserve_impl(size_type new_capacity
) {
353 auto new_data
= (CompactVectorData
*)allocate(required_mem(new_capacity
));
354 if (!new_data
) throw std::bad_alloc
{};
357 auto len
= m_data
->m_len
;
358 auto old_data
= m_data
;
359 auto const old_capacity
= old_data
->m_capacity
;
360 auto old_elems
= elems();
362 auto new_elems
= elems();
364 m_data
->m_capacity
= safe_cast
<uint32_t>(new_capacity
);
366 new (new_elems
++) T(std::move(*old_elems
));
369 deallocate(reinterpret_cast<char*>(old_data
), required_mem(old_capacity
));
371 // If there are currently no elements, all we have to do is allocate a
372 // block of memory and initialize m_len and m_capacity.
375 m_data
->m_capacity
= new_capacity
;
379 template <typename T
, typename A
>
380 void CompactVector
<T
, A
>::reserve(size_type new_capacity
) {
381 if (new_capacity
> capacity()) reserve_impl(new_capacity
);
384 template <typename T
, typename A
>
385 typename CompactVector
<T
, A
>::iterator
386 CompactVector
<T
, A
>::insert_elems(iterator before
, size_t num
) {
387 if (!num
) return before
;
388 auto const sz
= size();
389 assert(sz
<= capacity());
390 auto cap
= capacity();
391 if (sz
+ num
> cap
) {
392 auto const pos
= sz
? before
- elems() : 0;
395 if (sz
+ num
> cap
) {
397 if (cap
< initial_capacity
) cap
= initial_capacity
;
400 before
= elems() + pos
;
404 m_data
->m_len
+= num
;
405 while (e
!= before
) {
407 new (e
+ num
) T(std::move(*e
));
414 template <typename T
, typename A
>
415 template <typename U
>
416 typename CompactVector
<T
, A
>::iterator
417 CompactVector
<T
, A
>::insert_impl(iterator before
, size_t num
, U
&& val
) {
418 auto e
= insert_elems(before
, num
);
420 new (e
+ num
) T(std::forward
<U
>(val
));
425 template <typename T
, typename A
>
426 template <typename U
>
427 typename CompactVector
<T
, A
>::iterator
428 CompactVector
<T
, A
>::insert(iterator before
, U i1
, U i2
) {
429 auto e
= insert_elems(before
, i2
- i1
);
437 template <typename T
, typename A
>
438 void CompactVector
<T
, A
>::push_back(const T
& val
) {
439 auto const sz
= size();
440 assert(sz
<= capacity());
441 if (sz
== capacity()) grow();
443 new (get(sz
)) T(val
);
446 template <typename T
, typename A
>
447 void CompactVector
<T
, A
>::push_back(T
&& val
) {
448 auto const sz
= size();
449 assert(sz
<= capacity());
450 if (sz
== capacity()) grow();
452 new (get(sz
)) T(std::move(val
));
455 template <typename T
, typename A
>
456 template <class... Args
>
457 void CompactVector
<T
, A
>::emplace_back(Args
&&... args
) {
458 auto const sz
= size();
459 assert(sz
<= capacity());
460 if (sz
== capacity()) grow();
462 new (get(sz
)) T(std::forward
<Args
>(args
)...);
465 template <typename T
, typename A
>
466 void CompactVector
<T
, A
>::pop_back() {
467 if (m_data
&& m_data
->m_len
> 0) {
473 ///////////////////////////////////////////////////////////////////////////////