source: mainline/uspace/lib/cpp/include/impl/deque.hpp@ 3a06cc6

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 3a06cc6 was 3a06cc6, checked in by Dzejrou <dzejrou@…>, 7 years ago

cpp: added a basic deque implementation, currently push/pop/clear/indexed access

  • Property mode set to 100644
File size: 18.5 KB
Line 
1/*
2 * Copyright (c) 2018 Jaroslav Jindrak
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT 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 OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#ifndef LIBCPP_DEQUE
30#define LIBCPP_DEQUE
31
32#include <initializer_list>
33#include <iterator>
34#include <memory>
35
36namespace std
37{
38 template<class T, class Allocator = allocator<T>>
39 class deque;
40
41 namespace aux
42 {
43 template<class T, class Allocator>
44 class deque_iterator
45 {
46 using size_type = typename std::deque<T, Allocator>::size_type;
47 using value_type = typename std::deque<T, Allocator>::value_type;
48 using difference_type = size_type;
49
50 public:
51 deque_iterator(deque<T, Allocator>* deq, size_type idx)
52 : deq_{deq}, idx_{idx}
53 { /* DUMMY BODY */ }
54
55 private:
56 deque<T, Allocator>* deq_;
57 size_type idx_;
58 };
59
60 template<class T, class Allocator>
61 class deque_const_iterator
62 {
63 // TODO: implement
64 };
65 }
66
67 /**
68 * 23.3.3 deque:
69 */
70
71 template<class T, class Allocator>
72 class deque
73 {
74 public:
75 using allocator_type = Allocator;
76 using value_type = T;
77 using reference = value_type&;
78 using const_reference = const value_type&;
79
80 using iterator = aux::deque_iterator<T, Allocator>;
81 using const_iterator = aux::deque_const_iterator<T, Allocator>;
82 using reverse_iterator = std::reverse_iterator<iterator>;
83 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
84
85 using size_type = typename allocator_traits<allocator_type>::size_type;
86 using difference_type = typename allocator_traits<allocator_type>::difference_type;
87 using pointer = typename allocator_traits<allocator_type>::pointer;
88 using const_pointer = typename allocator_traits<allocator_type>::const_pointer;
89
90 /**
91 * 23.3.3.2, construct/copy/destroy:
92 */
93
94 deque()
95 : deque{allocator_type{}}
96 { /* DUMMY BODY */ }
97
98 explicit deque(const allocator_type& alloc)
99 : allocator_{alloc}, front_bucket_idx_{bucket_size_},
100 back_bucket_idx_{0}, front_bucket_{default_front_},
101 back_bucket_{default_back_}, bucket_count_{default_bucket_count_},
102 bucket_capacity_{default_bucket_capacity_}, size_{}, data_{}
103 {
104 init_();
105 }
106
107 explicit deque(size_type n, const allocator_type& alloc = allocator_type{})
108 {
109 // TODO: implement
110 }
111
112 deque(size_type n, const value_type& value, const allocator_type& alloc = allocator_type{})
113 {
114 // TODO: implement
115 }
116
117 template<class InputIterator>
118 deque(InputIterator first, InputIterator last, const allocator_type& alloc = allocator_type{})
119 {
120 // TODO: implement
121 }
122
123 deque(const deque& other)
124 {
125 // TODO: implement
126 }
127
128 deque(deque&& other)
129 {
130 // TODO: implement
131 }
132
133 deque(const deque& other, const allocator_type& alloc)
134 {
135 // TODO: implement
136 }
137
138 deque(deque&& other, const allocator_type& alloc)
139 {
140 // TODO: implement
141 }
142
143 deque(initializer_list<T> init, const allocator_type& alloc = allocator_type{})
144 {
145 // TODO: implement
146 }
147
148 ~deque()
149 {
150 fini_();
151 }
152
153 deque& operator=(const deque& other)
154 {
155 // TODO: implement
156 }
157
158 deque& operator=(deque&& other)
159 noexcept(allocator_traits<allocator_type>::is_always_equal::value)
160 {
161 // TODO: implement
162 }
163
164 deque& operator=(initializer_list<T> init)
165 {
166 // TODO: implement
167 }
168
169 template<class InputIterator>
170 void assign(InputIterator first, InputIterator last)
171 {
172 // TODO: implement
173 }
174
175 void assign(size_type n, const T& value)
176 {
177 // TODO: implement
178 }
179
180 void assign(initializer_list<T> init)
181 {
182 // TODO: implement
183 }
184
185 allocator_type get_allocator() const noexcept
186 {
187 return allocator_;
188 }
189
190 iterator begin() noexcept
191 {
192 // TODO: implement
193 }
194
195 const_iterator begin() const noexcept
196 {
197 // TODO: implement
198 }
199
200 iterator end() noexcept
201 {
202 // TODO: implement
203 }
204
205 const_iterator end() const noexcept
206 {
207 // TODO: implement
208 }
209
210 reverse_iterator rbegin() noexcept
211 {
212 // TODO: implement
213 }
214
215 const_reverse_iterator rbegin() const noexcept
216 {
217 // TODO: implement
218 }
219
220 reverse_iterator rend() noexcept
221 {
222 // TODO: implement
223 }
224
225 const_reverse_iterator rend() const noexcept
226 {
227 // TODO: implement
228 }
229
230 const_iterator cbegin() const noexcept
231 {
232 // TODO: implement
233 }
234
235 const_iterator cend() const noexcept
236 {
237 // TODO: implement
238 }
239
240 const_reverse_iterator crbegin() const noexcept
241 {
242 // TODO: implement
243 }
244
245 const_reverse_iterator crend() const noexcept
246 {
247 // TODO: implement
248 }
249
250 /**
251 * 23.3.3.3, capacity:
252 */
253
254 size_type size() const noexcept
255 {
256 return size_;
257 }
258
259 size_type max_size() const noexcept
260 {
261 // TODO: implement
262 }
263
264 void resize(size_type sz)
265 {
266 // TODO: implement
267 }
268
269 void resize(size_type sz, const value_type& value)
270 {
271 // TODO: implement
272 }
273
274 void shrink_to_fit()
275 {
276 // TODO: implement
277 }
278
279 bool empty() const noexcept
280 {
281 return size_ == size_type{};
282 }
283
284 reference operator[](size_type idx)
285 {
286 return data_[get_bucket_index_(idx)][get_element_index_(idx)];
287 }
288
289 const_reference operator[](size_type idx) const
290 {
291 return data_[get_bucket_index_(idx)][get_element_index_(idx)];
292 }
293
294 reference at(size_type idx)
295 {
296 // TODO: implement
297 }
298
299 const_reference at(size_type idx) const
300 {
301 // TODO: implement
302 }
303
304 reference front()
305 {
306 // TODO: implement
307 }
308
309 const_reference front() const
310 {
311 // TODO: implement
312 }
313
314 reference back()
315 {
316 // TODO: implement
317 }
318
319 const_reference back() const
320 {
321 // TODO: implement
322 }
323
324 /**
325 * 23.3.3.4, modifiers:
326 */
327
328 template<class... Args>
329 void emplace_front(Args&&... args)
330 {
331 // TODO: implement
332 }
333
334 template<class... Args>
335 void emplace_back(Args&&... args)
336 {
337 // TODO: implement
338 }
339
340 template<class... Args>
341 iterator emplace(const_iterator position, Args&&... args)
342 {
343 // TODO: implement
344 }
345
346 void push_front(const value_type& value)
347 {
348 if (front_bucket_idx_ == 0)
349 add_new_bucket_front_();
350
351 data_[front_bucket_][--front_bucket_idx_] = value;
352 ++size_;
353 }
354
355 void push_front(value_type&& value)
356 {
357 if (front_bucket_idx_ == 0)
358 add_new_bucket_front_();
359
360 data_[front_bucket_][--front_bucket_idx_] = forward<value_type>(value);
361 ++size_;
362 }
363
364 void push_back(const value_type& value)
365 {
366 data_[back_bucket_][back_bucket_idx_++] = value;
367 ++size_;
368
369 if (back_bucket_idx_ >= bucket_size_)
370 add_new_bucket_back_();
371 }
372
373 void push_back(value_type&& value)
374 {
375 data_[back_bucket_][back_bucket_idx_++] = forward<value_type>(value);
376 ++size_;
377
378 if (back_bucket_idx_ >= bucket_size_)
379 add_new_bucket_back_();
380 }
381
382 iterator insert(const_iterator position, const value_type& value)
383 {
384 // TODO: implement
385 }
386
387 iterator insert(const_iterator position, value_type&& value)
388 {
389 // TODO: implement
390 }
391
392 iterator insert(const_iterator position, size_type n, const value_type& value)
393 {
394 // TODO: implement
395 }
396
397 template<class InputIterator>
398 iterator insert(const_iterator position, InputIterator first, InputIterator last)
399 {
400 // TODO: implement
401 }
402
403 iterator insert(const_iterator position, initializer_list<value_type> init)
404 {
405 // TODO: implement
406 }
407
408 void pop_back()
409 {
410 if (empty())
411 return;
412
413 if (back_bucket_idx_ == 0)
414 { // Means we gotta pop data_[front_bucket_][bucket_size_ - 1]!
415 if (data_[back_bucket_])
416 allocator_.deallocate(data_[back_bucket_], bucket_size_);
417
418 --back_bucket_;
419 back_bucket_idx_ = bucket_size_ - 1;
420 }
421 else
422 --back_bucket_idx_;
423
424 allocator_.destroy(&data_[back_bucket_][back_bucket_idx_]);
425 --size_;
426 }
427
428 void pop_front()
429 {
430 if (empty())
431 return;
432
433 if (front_bucket_idx_ >= bucket_size_)
434 { // Means we gotta pop data_[front_bucket_][0]!
435 if (data_[front_bucket_])
436 allocator_.deallocate(data_[front_bucket_], bucket_size_);
437
438 ++front_bucket_;
439 front_bucket_idx_ = 1;
440
441 allocator_.destroy(&data_[front_bucket_][0]);
442 }
443 else
444 {
445 allocator_.destroy(&data_[front_bucket_][front_bucket_idx_]);
446
447 ++front_bucket_idx_;
448 }
449
450 --size_;
451 }
452
453 iterator erase(const_iterator position)
454 {
455 // TODO: implement
456 }
457
458 iterator erase(const_iterator first, const_iterator last)
459 {
460 // TODO: implement
461 }
462
463 void swap(deque& other)
464 noexcept(allocator_traits<allocator_type>::is_always_equal::value)
465 {
466 // TODO: implement
467 }
468
469 void clear() noexcept
470 {
471 fini_();
472
473 front_bucket_ = default_front_;
474 back_bucket_ = default_back_;
475 bucket_count_ = default_bucket_count_;
476 bucket_capacity_ = default_bucket_capacity_;
477 size_ = size_type{};
478
479 init_();
480 }
481
482 /* private: */
483 allocator_type allocator_;
484
485 /**
486 * Note: In our implementation, front_bucket_idx_
487 * points at the first element and back_bucket_idx_
488 * points at the one past last element. Because of this,
489 * some operations may be done in inverse order
490 * depending on the side they are applied to.
491 */
492 size_type front_bucket_idx_;
493 size_type back_bucket_idx_;
494 size_type front_bucket_;
495 size_type back_bucket_;
496
497 static constexpr size_type bucket_size_{16};
498 static constexpr size_type default_bucket_count_{2};
499 static constexpr size_type default_bucket_capacity_{4};
500 static constexpr size_type default_front_{1};
501 static constexpr size_type default_back_{2};
502
503 size_type bucket_count_;
504 size_type bucket_capacity_;
505 size_type size_{};
506
507 value_type** data_;
508
509 void init_()
510 {
511 data_ = new value_type*[bucket_capacity_];
512
513 for (size_type i = front_bucket_; i <= back_bucket_; ++i)
514 data_[i] = allocator_.allocate(bucket_size_);
515 }
516
517 void fini_()
518 {
519 for (size_type i = front_bucket_; i <= back_bucket_; ++i)
520 allocator_.deallocate(data_[i], bucket_size_);
521
522 delete[] data_;
523 data_ = nullptr;
524 }
525
526 bool has_bucket_space_back_() const
527 {
528 return back_bucket_ < bucket_capacity_ - 1;
529 }
530
531 bool has_bucket_space_front_() const
532 {
533 return front_bucket_ > 0;
534 }
535
536 void add_new_bucket_back_()
537 {
538 if (!has_bucket_space_back_())
539 expand_();
540
541 ++back_bucket_;
542 data_[back_bucket_] = allocator_.allocate(bucket_size_);
543 back_bucket_idx_ = size_type{};
544 }
545
546 void add_new_bucket_front_()
547 {
548 if (!has_bucket_space_front_())
549 expand_();
550
551 --front_bucket_;
552 data_[front_bucket_] = allocator_.allocate(bucket_size_);
553 front_bucket_idx_ = bucket_size_;
554 }
555
556 void expand_()
557 {
558 bucket_capacity_ *= 2;
559 value_type** new_data = new value_type*[bucket_capacity_];
560
561 size_type new_front = bucket_capacity_ / 4;
562 size_type new_back = bucket_capacity_ - bucket_capacity_ / 4 - 1;
563
564 for (size_type i = new_front, j = front_bucket_; i <= new_back; ++i, ++j)
565 new_data[i] = move(data_[j]);
566 std::swap(data_, new_data);
567
568 delete[] new_data;
569 front_bucket_ = new_front;
570 back_bucket_ = new_back;
571 }
572
573 size_type get_bucket_index_(size_type idx) const
574 {
575 if (idx < elements_in_front_bucket_())
576 return front_bucket_;
577
578 idx -= elements_in_front_bucket_();
579 return idx / bucket_size_ + front_bucket_ + 1;
580 }
581
582 size_type get_element_index_(size_type idx) const
583 {
584 if (idx < elements_in_front_bucket_())
585 return bucket_size_ - elements_in_front_bucket_() + idx;
586
587 idx -= elements_in_front_bucket_();
588 return idx % bucket_size_;
589 }
590
591 size_type elements_in_front_bucket_() const
592 {
593 return bucket_size_ - front_bucket_idx_;
594 }
595 };
596
597 template<class T, class Allocator>
598 bool operator==(const deque<T, Allocator>& lhs, const deque<T, Allocator>& rhs)
599 {
600 // TODO: implement
601 return false;
602 }
603
604 template<class T, class Allocator>
605 bool operator<(const deque<T, Allocator>& lhs, const deque<T, Allocator>& rhs)
606 {
607 // TODO: implement
608 return false;
609 }
610
611 template<class T, class Allocator>
612 bool operator!=(const deque<T, Allocator>& lhs, const deque<T, Allocator>& rhs)
613 {
614 // TODO: implement
615 return false;
616 }
617
618 template<class T, class Allocator>
619 bool operator>(const deque<T, Allocator>& lhs, const deque<T, Allocator>& rhs)
620 {
621 // TODO: implement
622 return false;
623 }
624
625 template<class T, class Allocator>
626 bool operator<=(const deque<T, Allocator>& lhs, const deque<T, Allocator>& rhs)
627 {
628 // TODO: implement
629 return false;
630 }
631
632 template<class T, class Allocator>
633 bool operator>=(const deque<T, Allocator>& lhs, const deque<T, Allocator>& rhs)
634 {
635 // TODO: implement
636 return false;
637 }
638
639 /**
640 * 23.3.3.5, deque specialized algorithms:
641 */
642
643 template<class T, class Allocator>
644 void swap(deque<T, Allocator>& lhs, deque<T, Allocator>& rhs)
645 noexcept(noexcept(lhs.swap(rhs)))
646 {
647 lhs.swap(rhs);
648 }
649}
650
651#endif
Note: See TracBrowser for help on using the repository browser.