source: mainline/uspace/lib/cpp/include/__bits/adt/vector.hpp@ 34b2f54d

Last change on this file since 34b2f54d was b57ba05, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 3 years ago

Update headers in C++ files

  • Property mode set to 100644
File size: 18.5 KB
Line 
1/*
2 * SPDX-FileCopyrightText: 2018 Jaroslav Jindrak
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#ifndef LIBCPP_BITS_ADT_VECTOR
8#define LIBCPP_BITS_ADT_VECTOR
9
10#include <algorithm>
11#include <initializer_list>
12#include <iterator>
13#include <memory>
14#include <utility>
15
16namespace std
17{
18 /**
19 * 23.3.6, vector:
20 */
21
22 template<class T, class Allocator = allocator<T>>
23 class vector
24 {
25 public:
26 using value_type = T;
27 using reference = value_type&;
28 using const_reference = const value_type&;
29 using allocator_type = Allocator;
30 using size_type = size_t;
31 using difference_type = ptrdiff_t;
32 using pointer = typename allocator_traits<Allocator>::pointer;
33 using const_pointer = typename allocator_traits<Allocator>::pointer;
34 using iterator = pointer;
35 using const_iterator = const_pointer;
36 using reverse_iterator = std::reverse_iterator<iterator>;
37 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
38
39 vector() noexcept
40 : vector{Allocator{}}
41 { /* DUMMY BODY */ }
42
43 explicit vector(const Allocator& alloc)
44 : data_{nullptr}, size_{}, capacity_{},
45 allocator_{alloc}
46 { /* DUMMY BODY */ }
47
48 explicit vector(size_type n, const Allocator& alloc = Allocator{})
49 : data_{}, size_{n}, capacity_{n}, allocator_{alloc}
50 {
51 data_ = allocator_.allocate(capacity_);
52
53 for (size_type i = 0; i < size_; ++i)
54 allocator_traits<Allocator>::construct(allocator_, data_ + i);
55 }
56
57 vector(size_type n, const T& val, const Allocator& alloc = Allocator{})
58 : data_{}, size_{n}, capacity_{n}, allocator_{alloc}
59 {
60 data_ = allocator_.allocate(capacity_);
61
62 for (size_type i = 0; i < size_; ++i)
63 data_[i] = val;
64 }
65
66 template<class InputIterator>
67 vector(InputIterator first, InputIterator last,
68 const Allocator& alloc = Allocator{})
69 {
70 // TODO: research constraints and provide multiple
71 // implementations via enable_if
72 }
73
74 vector(const vector& other)
75 : data_{nullptr}, size_{other.size_}, capacity_{other.capacity_},
76 allocator_{other.allocator_}
77 {
78 data_ = allocator_.allocate(capacity_);
79
80 for (size_type i = 0; i < size_; ++i)
81 data_[i] = other.data_[i];
82 }
83
84 vector(vector&& other) noexcept
85 : data_{other.data_}, size_{other.size_}, capacity_{other.capacity_},
86 allocator_{move(other.allocator_)}
87 {
88 // other is guaranteed to be empty()
89 other.size_ = other.capacity_ = 0;
90 other.data_ = nullptr;
91 }
92
93 vector(const vector& other, const Allocator& alloc)
94 : data_{nullptr}, size_{other.size_}, capacity_{other.capacity_},
95 allocator_{alloc}
96 {
97 data_ = allocator_.allocate(capacity_);
98
99 for (size_type i = 0; i < size_; ++i)
100 data_[i] = other.data_[i];
101 }
102
103 vector(initializer_list<T> init, const Allocator& alloc = Allocator{})
104 : data_{nullptr}, size_{init.size()}, capacity_{init.size()},
105 allocator_{alloc}
106 {
107 data_ = allocator_.allocate(capacity_);
108
109 auto it = init.begin();
110 for (size_type i = 0; it != init.end(); ++i, ++it)
111 {
112 data_[i] = *it;
113 }
114 }
115
116 ~vector()
117 {
118 allocator_.deallocate(data_, capacity_);
119 }
120
121 vector& operator=(const vector& other)
122 {
123 vector tmp{other};
124 swap(tmp);
125
126 return *this;
127 }
128
129 vector& operator=(vector&& other)
130 noexcept(allocator_traits<Allocator>::propagate_on_container_move_assignment::value ||
131 allocator_traits<Allocator>::is_always_equal::value)
132 {
133 if (data_)
134 allocator_.deallocate(data_, capacity_);
135
136 // TODO: test this
137 data_ = other.data_;
138 size_ = other.size_;
139 capacity_ = other.capacity_;
140 allocator_ = move(other.allocator_);
141
142 other.data_ = nullptr;
143 other.size_ = size_type{};
144 other.capacity_ = size_type{};
145 other.allocator_ = allocator_type{};
146 return *this;
147 }
148
149 vector& operator=(initializer_list<T> init)
150 {
151 vector tmp{init, allocator_};
152 swap(tmp);
153
154 return *this;
155 }
156
157 template<class InputIterator>
158 void assign(InputIterator first, InputIterator last)
159 {
160 vector tmp{first, last};
161 swap(tmp);
162 }
163
164 void assign(size_type size, const T& val)
165 {
166 // Parenthesies required to avoid initializer list
167 // construction.
168 vector tmp(size, val);
169 swap(tmp);
170 }
171
172 void assign(initializer_list<T> init)
173 {
174 vector tmp{init};
175 swap(tmp);
176 }
177
178 allocator_type get_allocator() const noexcept
179 {
180 return allocator_type{allocator_};
181 }
182
183 iterator begin() noexcept
184 {
185 return &data_[0];
186 }
187
188 const_iterator begin() const noexcept
189 {
190 return &data_[0];
191 }
192
193 iterator end() noexcept
194 {
195 return begin() + size_;
196 }
197
198 const_iterator end() const noexcept
199 {
200 return begin() + size_;
201 }
202
203 reverse_iterator rbegin() noexcept
204 {
205 return make_reverse_iterator(end());
206 }
207
208 const_reverse_iterator rbegin() const noexcept
209 {
210 return make_reverse_iterator(cend());
211 }
212
213 reverse_iterator rend() noexcept
214 {
215 return make_reverse_iterator(begin());
216 }
217
218 const_reverse_iterator rend() const noexcept
219 {
220 return make_reverse_iterator(cbegin());
221 }
222
223 const_iterator cbegin() const noexcept
224 {
225 return &data_[0];
226 }
227
228 const_iterator cend() const noexcept
229 {
230 return cbegin() + size_;
231 }
232
233 const_reverse_iterator crbegin() const noexcept
234 {
235 return rbegin();
236 }
237
238 const_reverse_iterator crend() const noexcept
239 {
240 return rend();
241 }
242
243 size_type size() const noexcept
244 {
245 return size_;
246 }
247
248 size_type max_size() const noexcept
249 {
250 return std::allocator_traits<Allocator>::max_size(allocator_);
251 }
252
253 void resize(size_type sz)
254 {
255 resize_with_copy_(size_, capacity_);
256 }
257
258 void resize(size_type sz, const value_type& val)
259 {
260 auto old_size = size_;
261 resize_with_copy_(sz, capacity_);
262
263 for (size_type i = old_size - 1; i < size_; ++i)
264 data_[i] = val;
265 }
266
267 size_type capacity() const noexcept
268 {
269 return capacity_;
270 }
271
272 bool empty() const noexcept
273 {
274 return size_ == 0;
275 }
276
277 void reserve(size_type new_capacity)
278 {
279 // TODO: if new_capacity > max_size() throw
280 // length_error (this function shall have no
281 // effect in such case)
282 if (new_capacity > capacity_)
283 resize_with_copy_(size_, new_capacity);
284 }
285
286 void shrink_to_fit()
287 {
288 resize_with_copy_(size_, size_);
289 }
290
291 reference operator[](size_type idx)
292 {
293 return data_[idx];
294 }
295
296 const_reference operator[](size_type idx) const
297 {
298 return data_[idx];
299 }
300
301 reference at(size_type idx)
302 {
303 // TODO: bounds checking
304 return data_[idx];
305 }
306
307 const_reference at(size_type idx) const
308 {
309 // TODO: bounds checking
310 return data_[idx];
311 }
312
313 reference front()
314 {
315 /**
316 * Note: Calling front/back on an empty container
317 * is undefined, we opted for at-like
318 * behavior to provide our users with means
319 * to protect their programs from accidental
320 * accesses to an empty vector.
321 */
322 return at(0);
323 }
324
325 const_reference front() const
326 {
327 return at(0);
328 }
329
330 reference back()
331 {
332 return at(size_ - 1);
333 }
334
335 const_reference back() const
336 {
337 return at(size - 1);
338 }
339
340 T* data() noexcept
341 {
342 return data_;
343 }
344
345 const T* data() const noexcept
346 {
347 return data_;
348 }
349
350 template<class... Args>
351 reference emplace_back(Args&&... args)
352 {
353 if (size_ >= capacity_)
354 resize_with_copy_(size_, next_capacity_());
355
356 allocator_traits<Allocator>::construct(allocator_,
357 begin() + size_, forward<Args>(args)...);
358
359 return back();
360 }
361
362 void push_back(const T& x)
363 {
364 if (size_ >= capacity_)
365 resize_with_copy_(size_, next_capacity_());
366 data_[size_++] = x;
367 }
368
369 void push_back(T&& x)
370 {
371 if (size_ >= capacity_)
372 resize_with_copy_(size_, next_capacity_());
373 data_[size_++] = forward<T>(x);
374 }
375
376 void pop_back()
377 {
378 destroy_from_end_until_(end() - 1);
379 --size_;
380 }
381
382 template<class... Args>
383 iterator emplace(const_iterator position, Args&&... args)
384 {
385 auto pos = const_cast<iterator>(position);
386
387 pos = shift_(pos, 1);
388 allocator_.construct(pos, forward<Args>(args)...);
389
390 return pos;
391 }
392
393 iterator insert(const_iterator position, const value_type& x)
394 {
395 auto pos = const_cast<iterator>(position);
396
397 pos = shift_(pos, 1);
398 *pos = x;
399
400 return pos;
401 }
402
403 iterator insert(const_iterator position, value_type&& x)
404 {
405 auto pos = const_cast<iterator>(position);
406
407 pos = shift_(pos, 1);
408 *pos = forward<value_type>(x);
409
410 return pos;
411 }
412
413 iterator insert(const_iterator position, size_type count, const value_type& x)
414 {
415 auto pos = const_cast<iterator>(position);
416
417 pos = shift_(pos, count);
418 auto copy_target = pos;
419 for (size_type i = 0; i < count; ++i)
420 *copy_target++ = x;
421
422 return pos;
423 }
424
425 template<class InputIterator>
426 iterator insert(const_iterator position, InputIterator first,
427 InputIterator last)
428 {
429 auto pos = const_cast<iterator>(position);
430 auto count = static_cast<size_type>(last - first);
431
432 pos = shift_(pos, count);
433 copy(first, last, pos);
434
435 return pos;
436 }
437
438 iterator insert(const_iterator position, initializer_list<T> init)
439 {
440 auto pos = const_cast<iterator>(position);
441
442 pos = shift_(pos, init.size());
443 copy(init.begin(), init.end(), pos);
444
445 return pos;
446 }
447
448 iterator erase(const_iterator position)
449 {
450 iterator pos = const_cast<iterator>(position);
451 copy(position + 1, cend(), pos);
452 --size_;
453
454 return pos;
455 }
456
457 iterator erase(const_iterator first, const_iterator last)
458 {
459 iterator pos = const_cast<iterator>(first);
460 copy(last, cend(), pos);
461 size_ -= static_cast<size_type>(last - first);
462
463 return pos;
464 }
465
466 void swap(vector& other)
467 noexcept(allocator_traits<Allocator>::propagate_on_container_swap::value ||
468 allocator_traits<Allocator>::is_always_equal::value)
469 {
470 std::swap(data_, other.data_);
471 std::swap(size_, other.size_);
472 std::swap(capacity_, other.capacity_);
473 }
474
475 void clear() noexcept
476 {
477 // Note: Capacity remains unchanged.
478 destroy_from_end_until_(begin());
479 size_ = 0;
480 }
481
482 private:
483 value_type* data_;
484 size_type size_;
485 size_type capacity_;
486 allocator_type allocator_;
487
488 void resize_without_copy_(size_type capacity)
489 {
490 if (data_)
491 allocator_.deallocate(data_, capacity_);
492
493 data_ = allocator_.allocate(capacity);
494 size_ = 0;
495 capacity_ = capacity;
496 }
497
498 void resize_with_copy_(size_type size, size_type capacity)
499 {
500 if (size < size_)
501 destroy_from_end_until_(begin() + size);
502
503 if(capacity_ == 0 || capacity_ < capacity)
504 {
505 auto new_data = allocator_.allocate(capacity);
506
507 auto to_copy = min(size, size_);
508 for (size_type i = 0; i < to_copy; ++i)
509 new_data[i] = move(data_[i]);
510
511 std::swap(data_, new_data);
512
513 allocator_.deallocate(new_data, capacity_);
514 }
515
516 capacity_ = capacity;
517 size_ = size;
518 }
519
520 void destroy_from_end_until_(iterator target)
521 {
522 if (!empty())
523 {
524 auto last = end();
525 while(last != target)
526 allocator_traits<Allocator>::destroy(allocator_, --last);
527 }
528 }
529
530 size_type next_capacity_(size_type hint = 0) const noexcept
531 {
532 if (hint != 0)
533 return max(capacity_ * 2, hint);
534 else
535 return max(capacity_ * 2, size_type{2u});
536 }
537
538 iterator shift_(iterator position, size_type count)
539 {
540 if (size_ + count < capacity_)
541 {
542 copy_backward(position, end(), end() + count);
543 size_ += count;
544
545 return position;
546 }
547 else
548 {
549 auto start_idx = static_cast<size_type>(position - begin());
550 auto end_idx = start_idx + count;
551 auto new_size = size_ + count;
552
553 // Auxiliary vector for easier swap.
554 vector tmp{};
555 tmp.resize_without_copy_(max(new_size, capacity_));
556 tmp.size_ = new_size;
557
558 // Copy before insertion index.
559 copy(begin(), begin() + start_idx, tmp.begin());
560
561 // Copy after insertion index.
562 copy(begin() + start_idx, end(), tmp.begin() + end_idx);
563
564 swap(tmp);
565
566 // Position was invalidated!
567 return begin() + start_idx;
568 }
569 }
570 };
571
572 template<class T, class Alloc>
573 bool operator==(const vector<T, Alloc>& lhs, const vector<T, Alloc>& rhs)
574 {
575 if (lhs.size() != rhs.size())
576 return false;
577
578 for (decltype(lhs.size()) i = 0; i < lhs.size(); ++i)
579 {
580 if (lhs[i] != rhs[i])
581 return false;
582 }
583
584 return true;
585 }
586
587 template<class T, class Alloc>
588 bool operator<(const vector<T, Alloc>& lhs, const vector<T, Alloc>& rhs)
589 {
590 auto min_size = min(lhs.size(), rhs.size());
591 for (decltype(lhs.size()) i = 0; i < min_size; ++i)
592 {
593 if (lhs[i] >= rhs[i])
594 return false;
595 }
596
597 if (lhs.size() == rhs.size())
598 return true;
599 else
600 return lhs.size() < rhs.size();
601 }
602
603 template<class T, class Alloc>
604 bool operator!=(const vector<T, Alloc>& lhs, const vector<T, Alloc>& rhs)
605 {
606 return !(lhs == rhs);
607 }
608
609 template<class T, class Alloc>
610 bool operator>(const vector<T, Alloc>& lhs, const vector<T, Alloc>& rhs)
611 {
612 return rhs < lhs;
613 }
614
615 template<class T, class Alloc>
616 bool operator>=(const vector<T, Alloc>& lhs, const vector<T, Alloc>& rhs)
617 {
618 return !(lhs < rhs);
619 }
620
621 template<class T, class Alloc>
622 bool operator<=(const vector<T, Alloc>& lhs, const vector<T, Alloc>& rhs)
623 {
624 return !(rhs < lhs);
625 }
626
627 /**
628 * 23.3.6.6, specialized algorithms:
629 */
630 template<class T, class Alloc>
631 void swap(vector<T, Alloc>& lhs, vector<T, Alloc>& rhs)
632 noexcept(noexcept(lhs.swap(rhs)))
633 {
634 lhs.swap(rhs);
635 }
636
637 /**
638 * 23.3.7, class vector<bool>:
639 */
640
641 // TODO: implement
642}
643
644#endif
Note: See TracBrowser for help on using the repository browser.