Changeset 35584b19 in mainline


Ignore:
Timestamp:
2018-07-05T21:41:17Z (6 years ago)
Author:
Dzejrou <dzejrou@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
b6d68a3
Parents:
de89870
git-author:
Jaroslav Jindrak <dzejrou@…> (2017-10-22 17:02:19)
git-committer:
Dzejrou <dzejrou@…> (2018-07-05 21:41:17)
Message:

cpp: added mostly functioning version of std::vector, but inserts currently reallocate everytime

Location:
uspace/lib/cpp/include/impl
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/cpp/include/impl/memory.hpp

    rde89870 r35584b19  
    3939     */
    4040
    41     template<class T>
     41    template<class Ptr>
    4242    struct pointer_traits
    4343    {
    44         // TODO:
     44        using pointer = Ptr;
     45        // TODO: element type, difference type
     46
     47        // TODO: this is conditional, see standard
     48        template<class U>
     49        using rebind = typename Ptr::template rebind<U>;
    4550    };
    4651
     
    180185        using pointer = typename aux::get_pointer<Alloc>::type;
    181186        using const_pointer = typename aux::get_const_pointer<Alloc, pointer>::type;
    182         using void_pointer = typename aux::get_void_pointer<Alloc, pointer>::type;
    183         using const_void_pointer = typename aux::get_const_void_pointer<Alloc, pointer>::type;
     187        // TODO: fix void pointer typedefs
     188        /* using void_pointer = typename aux::get_void_pointer<Alloc, pointer>::type; */
     189        /* using const_void_pointer = typename aux::get_const_void_pointer<Alloc, pointer>::type; */
     190        using void_pointer = void*;
     191        using const_void_pointer = const void*;
    184192        using difference_type = typename aux::get_difference_type<Alloc, pointer>::type;
    185193        using size_type = typename aux::get_size_type<Alloc, difference_type>::type;
     
    279287            using is_always_equal                        = true_type;
    280288
    281             allocator() noexcept;
    282 
    283             allocator(const allocator&) noexcept;
     289            allocator() noexcept = default;
     290
     291            allocator(const allocator&) noexcept = default;
    284292
    285293            template<class U>
    286             allocator(const allocator<U>&) noexcept;
     294            allocator(const allocator<U>&) noexcept
     295            {
     296                // TODO: implement
     297            }
    287298
    288299            ~allocator() = default;
     
    303314                 * Note: The usage of hint is unspecified.
    304315                 *       TODO: Check HelenOS hint allocation capabilities.
     316                 * TODO: assert that n < max_size()
    305317                 */
    306                 return ::operator new(n);
     318                return static_cast<pointer>(::operator new(n * sizeof(value_type)));
    307319            }
    308320
  • uspace/lib/cpp/include/impl/vector.hpp

    rde89870 r35584b19  
    3030#define LIBCPP_VECTOR
    3131
     32#include <algorithm>
    3233#include <initializer_list>
    3334#include <iterator>
    3435#include <memory>
     36#include <utility>
    3537
    3638namespace std
     
    6163            { /* DUMMY BODY */ }
    6264
    63             explicit vector(const Allocator&);
    64 
    65             explicit vector(size_type n, const Allocator& alloc = Allocator{});
    66 
    67             vector(size_type n, const T& val, const Allocator& alloc = Allocator{});
     65            explicit vector(const Allocator& alloc)
     66                : data_{nullptr}, size_{}, capacity_{},
     67                  allocator_{alloc}
     68            { /* DUMMY BODY */ }
     69
     70            explicit vector(size_type n, const Allocator& alloc = Allocator{})
     71                : data_{}, size_{n}, capacity_{n}, allocator_{alloc}
     72            {
     73                data_ = allocator_.allocate(capacity_);
     74
     75                for (size_type i = 0; i < size_; ++i)
     76                    allocator_traits<Allocator>::construct(allocator_, data_ + i);
     77            }
     78
     79            vector(size_type n, const T& val, const Allocator& alloc = Allocator{})
     80                : data_{}, size_{n}, capacity_{n}, allocator_{alloc}
     81            {
     82                data_ = allocator_.allocate(capacity_);
     83
     84                for (size_type i = 0; i < size_; ++i)
     85                    data_[i] = val;
     86            }
    6887
    6988            template<class InputIterator>
    7089            vector(InputIterator first, InputIterator last,
    71                    const Allocator& alloc = Allocator{});
    72 
    73             vector(const vector& other);
    74 
    75             vector(vector&& other) noexcept;
    76 
    77             vector(const vector& other, const Allocator& alloc);
    78 
    79             vector(initializer_list<T> init, const Allocator& alloc = Allocator{});
    80 
    81             ~vector();
    82 
    83             vector& operator=(const vector& other);
     90                   const Allocator& alloc = Allocator{})
     91            {
     92                // TODO: research constraints and provide multiple
     93                //       implementations via enable_if
     94            }
     95
     96            vector(const vector& other)
     97                : data_{nullptr}, size_{other.size_}, capacity_{other.capacity_},
     98                  allocator_{other.allocator_}
     99            {
     100                data_ = allocator_.allocate(capacity_);
     101
     102                for (size_type i = 0; i < size_; ++i)
     103                    data_[i] = other.data_[i];
     104            }
     105
     106            vector(vector&& other) noexcept
     107                : data_{other.data_}, size_{other.size_}, capacity_{other.capacity_},
     108                  allocator_{move(other.allocator_)}
     109            {
     110                // other is guaranteed to be empty()
     111                other.size_ = other.capacity_ = 0;
     112                other.data_ = nullptr;
     113            }
     114
     115            vector(const vector& other, const Allocator& alloc)
     116                : data_{nullptr}, size_{other.size_}, capacity_{other.capacity_},
     117                  allocator_{alloc}
     118            {
     119                data_ = allocator_.allocate(capacity_);
     120
     121                for (size_type i = 0; i < size_; ++i)
     122                    data_[i] = other.data_[i];
     123            }
     124
     125            vector(initializer_list<T> init, const Allocator& alloc = Allocator{})
     126                : data_{nullptr}, size_{init.size()}, capacity_{init.size()},
     127                  allocator_{alloc}
     128            {
     129                data_ = allocator_.allocate(capacity_);
     130
     131                auto it = init.begin();
     132                for (size_type i = 0; it != init.end(); ++i, ++it)
     133                {
     134                    data_[i] = *it;
     135                }
     136            }
     137
     138            ~vector()
     139            {
     140                allocator_.deallocate(data_, capacity_);
     141            }
     142
     143            vector& operator=(const vector& other)
     144            {
     145                vector tmp{other};
     146                swap(tmp);
     147
     148                return *this;
     149            }
    84150
    85151            vector& operator=(vector&& other)
     
    87153                         allocator_traits<Allocator>::is_always_equal::value)
    88154            {
     155                // TODO: implement
    89156                return *this;
    90157            }
    91158
    92             vector& operator=(initializer_list<T> init);
     159            vector& operator=(initializer_list<T> init)
     160            {
     161                vector tmp{init, allocator_};
     162                swap(tmp);
     163
     164                return *this;
     165            }
    93166
    94167            template<class InputIterator>
    95             void assign(InputIterator first, InputIterator last);
    96 
    97             void assign(size_type n, const T& val);
    98 
    99             void assign(initializer_list<T> init);
    100 
    101             allocator_type get_allocator() const noexcept;
     168            void assign(InputIterator first, InputIterator last)
     169            {
     170                vector tmp{first, last};
     171                swap(tmp);
     172            }
     173
     174            void assign(size_type size, const T& val)
     175            {
     176                // Parenthesies required to avoid initializer list
     177                // construction.
     178                vector tmp(size, val);
     179                swap(tmp);
     180            }
     181
     182            void assign(initializer_list<T> init)
     183            {
     184                vector tmp{init};
     185                swap(tmp);
     186            }
     187
     188            allocator_type get_allocator() const noexcept
     189            {
     190                return allocator_type{};
     191            }
     192
     193            iterator begin() noexcept
     194            {
     195                return &data_[0];
     196            }
     197
     198            const_iterator begin() const noexcept
     199            {
     200                return &data_[0];
     201            }
     202
     203            iterator end() noexcept
     204            {
     205                return begin() + size_;
     206            }
     207
     208            const_iterator end() const noexcept
     209            {
     210                return begin() + size_;
     211            }
     212
     213            reverse_iterator rbegin() noexcept
     214            {
     215                return make_reverse_iterator(begin());
     216            }
     217
     218            const_reverse_iterator rbegin() const noexcept
     219            {
     220                return make_reverse_iterator(cbegin());
     221            }
     222
     223            reverse_iterator rend() noexcept
     224            {
     225                return make_reverse_iterator(end());
     226            }
     227
     228            const_reverse_iterator rend() const noexcept
     229            {
     230                return make_reverse_iterator(cend());
     231            }
     232
     233            const_iterator cbegin() const noexcept
     234            {
     235                return &data_[0];
     236            }
     237
     238            const_iterator cend() const noexcept
     239            {
     240                return cbegin() + size_;
     241            }
     242
     243            const_reverse_iterator rcbegin() const noexcept
     244            {
     245                return rbegin();
     246            }
     247
     248            const_reverse_iterator rcend() const noexcept
     249            {
     250                return rend();
     251            }
     252
     253            size_type size() const noexcept
     254            {
     255                return size_;
     256            }
     257
     258            size_type max_size() const noexcept
     259            {
     260                return std::allocator_traits<Allocator>::max_size(allocator_);
     261            }
     262
     263            void resize(size_type sz)
     264            {
     265                resize_with_copy_(size_, capacity_);
     266            }
     267
     268            void resize(size_type sz, const value_type& val)
     269            {
     270                auto old_size = size_;
     271                resize_with_copy_(sz, capacity_);
     272
     273                for (size_type i = old_size - 1; i < size_; ++i)
     274                    data_[i] = val;
     275            }
     276
     277            size_type capacity() const noexcept
     278            {
     279                return capacity_;
     280            }
     281
     282            bool empty() const noexcept
     283            {
     284                return size_ == 0;
     285            }
     286
     287            void reserve(size_type new_capacity)
     288            {
     289                // TODO: if new_capacity > max_size() throw
     290                //       length_error (this function shall have no
     291                //       effect in such case)
     292                if (new_capacity > capacity_)
     293                    resize_with_copy_(size_, new_capacity);
     294            }
     295
     296            void shrink_to_fit()
     297            {
     298                resize_with_copy_(size_, size_);
     299            }
     300
     301            reference operator[](size_type idx)
     302            {
     303                return data_[idx];
     304            }
     305
     306            const_reference operator[](size_type idx) const
     307            {
     308                return data_[idx];
     309            }
     310
     311            reference at(size_type idx)
     312            {
     313                // TODO: bounds checking
     314                return data_[idx];
     315            }
     316
     317            const_reference at(size_type idx) const
     318            {
     319                // TODO: bounds checking
     320                return data_[idx];
     321            }
     322
     323            reference front()
     324            {
     325                /**
     326                 * Note: Calling front/back on an empty container
     327                 *       is undefined, we opted for at-like
     328                 *       behavior to provide our users with means
     329                 *       to protect their programs from accidental
     330                 *       accesses to an empty vector.
     331                 */
     332                return at(0);
     333            }
     334
     335            const_reference front() const
     336            {
     337                return at(0);
     338            }
     339
     340            reference back()
     341            {
     342                return at(size_ - 1);
     343            }
     344
     345            const_reference back() const
     346            {
     347                return at(size - 1);
     348            }
     349
     350            T* data() noexcept
     351            {
     352                return data_;
     353            }
     354
     355            const T* data() const noexcept
     356            {
     357                return data_;
     358            }
     359
     360            template<class... Args>
     361            reference emplace_back(Args&&... args)
     362            {
     363                if (size_ >= capacity_)
     364                    resize_with_copy_(size_, next_capacity_());
     365
     366                allocator_traits<Allocator>::construct(begin() + size_, forward<Args>(args)...);
     367
     368                return back();
     369            }
     370
     371            // TODO: assert CopyInstertable etc with enable_if!
     372            void push_back(const T& x)
     373            {
     374                if (size_ >= capacity_)
     375                    resize_with_copy_(size_, next_capacity_());
     376                data_[size_++] = x;
     377            }
     378
     379            void push_back(T&& x)
     380            {
     381                if (size_ >= capacity_)
     382                    resize_with_copy_(size_, next_capacity_());
     383                data_[size_++] = forward<T>(x);
     384            }
     385
     386            void pop_back()
     387            {
     388                destroy_from_end_until_(end() - 1);
     389            }
     390
     391            template<class... Args>
     392            iterator emplace(const_iterator position, Args&&... args)
     393            {
     394                auto idx = shift_right_(position, 1);
     395                allocator_.construct(data_ + idx, std::forward<Args>(args)...);
     396
     397                return begin() + idx;
     398            }
     399
     400            iterator insert(const_iterator position, const value_type& x)
     401            {
     402                /**
     403                 * Note: The reason that all insert functions are done in this weird
     404                 *       way with an auxiliary vector instead of just shifting
     405                 *       the elements is that we need to provide strong exception
     406                 *       guarantee - in the case of exception our vector needs to
     407                 *       stay in its pre-instert state and this swap method guarantees
     408                 *       that.
     409                 * TODO: Avoid reallocation if it still fits!
     410                 */
     411                size_type idx = static_cast<size_type>(position - cbegin());
     412
     413                vector tmp{};
     414                tmp.resize_without_copy_(max(size_ + 1, capacity_));
     415
     416                // Copy before insertion index.
     417                tmp.copy_(0, begin(), begin() + idx);
     418
     419                // Insertion.
     420                tmp.data_[idx] = x;
     421
     422                // Copy after insertion index.
     423                tmp.copy_(idx + 1, begin() + idx + 1, end());
     424                tmp.size_ = size_ + 1;
     425                swap(tmp);
     426
     427                return begin() + idx;
     428            }
     429
     430            iterator insert(const_iterator position, value_type&& x)
     431            {
     432                size_type idx = static_cast<size_type>(position - cbegin());
     433
     434                vector tmp{};
     435                tmp.resize_without_copy_(max(size_ + 1, capacity_));
     436
     437                // Copy before insertion index.
     438                tmp.copy_(0, begin(), begin() + idx);
     439
     440                // Insertion.
     441                tmp.data_[idx] = std::forward<value_type>(x);
     442
     443                // Copy after insertion index.
     444                tmp.copy_(idx + 1, begin() + idx + 1, end());
     445                tmp.size_ = size_ + 1;
     446                swap(tmp);
     447
     448                return begin() + idx;
     449            }
     450
     451            iterator insert(const_iterator position, size_type count, const value_type& x)
     452            {
     453                size_type idx = static_cast<size_type>(position - cbegin());
     454
     455                vector tmp{};
     456                tmp.resize_without_copy_(max(size_ + 1, capacity_));
     457
     458                // Copy before insertion index.
     459                tmp.copy_(0, begin(), begin() + idx);
     460
     461                // Insertion.
     462                auto tmp_idx = idx;
     463                for (size_type i = 0; i < count; ++i, ++tmp_idx)
     464                    tmp.data_[tmp_idx] = x;
     465
     466                // Copy after insertion index.
     467                tmp.copy_(tmp_idx, begin() + idx, end());
     468                tmp.size_ = size_ + count;
     469                swap(tmp);
     470
     471                return begin() + idx;
     472            }
     473
     474            template<class InputIterator>
     475            iterator insert(const_iterator position, InputIterator first,
     476                            InputIterator last)
     477            {
     478                size_type idx = static_cast<size_type>(position - cbegin());
     479                size_type count = static_cast<size_type>(last - first);
     480
     481                return insert_(idx, count, first, last);
     482            }
     483
     484            iterator insert(const_iterator position, initializer_list<T> init)
     485            {
     486                size_type idx = static_cast<size_type>(position - cbegin());
     487                size_type count = init.size();
     488
     489                return insert_(idx, count, init.begin(), init.end());
     490            }
     491
     492            iterator erase(const_iterator position)
     493            {
     494                iterator pos = const_cast<iterator>(position);
     495                copy(position + 1, cend(), pos);
     496                --size_;
     497
     498                return pos;
     499            }
     500
     501            iterator erase(const_iterator first, const_iterator last)
     502            {
     503                iterator pos = const_cast<iterator>(first);
     504                copy(last, cend(), pos);
     505                size_ -= static_cast<size_type>(last - first);
     506
     507                return pos;
     508            }
     509
     510            void swap(vector& other)
     511                noexcept(allocator_traits<Allocator>::propagate_on_container_swap::value ||
     512                         allocator_traits<Allocator>::is_always_equal::value)
     513            {
     514                std::swap(data_, other.data_);
     515                std::swap(size_, other.size_);
     516                std::swap(capacity_, other.capacity_);
     517            }
     518
     519            void clear() noexcept
     520            {
     521                // Note: Capacity remains unchanged.
     522                destroy_from_end_until_(begin());
     523                size_ = 0;
     524            }
     525
     526        private:
     527            value_type* data_;
     528            size_type size_;
     529            size_type capacity_;
     530            Allocator allocator_;
     531
     532            void resize_without_copy_(size_type capacity)
     533            {
     534                if (data_)
     535                    allocator_.deallocate(data_, capacity_);
     536
     537                data_ = allocator_.allocate(capacity);
     538                size_ = 0;
     539                capacity_ = capacity;
     540            }
     541
     542            void resize_with_copy_(size_type size, size_type capacity)
     543            {
     544                if (size < size_)
     545                    destroy_from_end_until_(begin() + size);
     546
     547                if(capacity_ == 0 || capacity_ < capacity)
     548                {
     549                    auto new_data = allocator_.allocate(capacity);
     550
     551                    auto to_copy = min(size, size_);
     552                    for (size_type i = 0; i < to_copy; ++i)
     553                        new_data[i] = move(data_[i]);
     554
     555                    std::swap(data_, new_data);
     556
     557                    allocator_.deallocate(new_data, capacity_);
     558                }
     559
     560                capacity_ = capacity;
     561                size_ = size;
     562            }
     563
     564            void destroy_from_end_until_(iterator target)
     565            {
     566                if (!empty())
     567                {
     568                    auto last = end();
     569                    while(last != target)
     570                        allocator_traits<Allocator>::destroy(allocator_, --last);
     571                }
     572            }
     573
     574            size_type next_capacity_(size_type hint = 0) const noexcept
     575            {
     576                if (hint != 0)
     577                    return max(capacity_ * 2, hint);
     578                else
     579                    return max(capacity_ * 2, 2ul);
     580            }
     581
     582            template<class Iterator>
     583            void copy_(size_type idx, Iterator first, Iterator last)
     584            {
     585                for (size_type i = idx; first != last; ++i, ++first)
     586                    data_[i] = *first;
     587            }
     588
     589            template<class Iterator>
     590            iterator insert_(size_type idx, size_type count, Iterator first, Iterator last)
     591            {
     592                vector tmp{};
     593                tmp.resize_without_copy_(max(size_ + count, capacity_));
     594
     595                // Copy before insertion index.
     596                tmp.copy_(0, begin(), begin() + idx);
     597
     598                // Insertion.
     599                tmp.copy_(idx, first, last);
     600
     601                // Copy after insertion index.
     602                tmp.copy_(idx + count, begin() + idx, end());
     603                tmp.size_ = size_ + count;
     604                swap(tmp);
     605
     606                return begin() + idx;
     607            }
    102608    };
     609
     610    template<class T, class Alloc>
     611    bool operator==(const vector<T, Alloc>& lhs, const vector<T, Alloc>& rhs)
     612    {
     613        // TODO: implement
     614        return false;
     615    }
     616
     617    template<class T, class Alloc>
     618    bool operator<(const vector<T, Alloc>& lhs, const vector<T, Alloc>& rhs)
     619    {
     620        // TODO: implement
     621        return false;
     622    }
     623
     624    template<class T, class Alloc>
     625    bool operator!=(const vector<T, Alloc>& lhs, const vector<T, Alloc>& rhs)
     626    {
     627        return !(lhs == rhs);
     628    }
     629
     630    template<class T, class Alloc>
     631    bool operator>(const vector<T, Alloc>& lhs, const vector<T, Alloc>& rhs)
     632    {
     633        // TODO: implement
     634        return false;
     635    }
     636
     637    template<class T, class Alloc>
     638    bool operator>=(const vector<T, Alloc>& lhs, const vector<T, Alloc>& rhs)
     639    {
     640        // TODO: implement
     641        return false;
     642    }
     643
     644    template<class T, class Alloc>
     645    bool operator<=(const vector<T, Alloc>& lhs, const vector<T, Alloc>& rhs)
     646    {
     647        // TODO: implement
     648        return false;
     649    }
     650
     651    /**
     652     * 23.3.6.6, specialized algorithms:
     653     */
     654    template<class T, class Alloc>
     655    void swap(vector<T, Alloc>& lhs, vector<T, Alloc>& rhs)
     656        noexcept(noexcept(lhs.swap(rhs)))
     657    {
     658        lhs.swap(rhs);
     659    }
    103660}
    104661
Note: See TracChangeset for help on using the changeset viewer.