Changeset 681fdcca in mainline


Ignore:
Timestamp:
2018-07-05T21:41:18Z (6 years ago)
Author:
Dzejrou <dzejrou@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
b0b46d59
Parents:
7b1906e
git-author:
Jaroslav Jindrak <dzejrou@…> (2017-10-26 20:56:50)
git-committer:
Dzejrou <dzejrou@…> (2018-07-05 21:41:18)
Message:

cpp: implemented a boatload of string functions

File:
1 edited

Legend:

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

    r7b1906e r681fdcca  
    8181        static size_t length(const char_type* s)
    8282        {
    83             return std::str_size(s);
     83            return std::str_size(s) + 1;
    8484        }
    8585
     
    184184        static size_t length(const char_type* s)
    185185        {
    186             return std::wstr_size(s);
     186            return std::wstr_size(s) + 1;
    187187        }
    188188
     
    277277            { /* DUMMY BODY */ }
    278278
    279             explicit basic_string(const allocator_type& alloc);
    280 
    281             basic_string(const basic_string& other);
    282 
    283             basic_string(basic_string&& other);
     279            explicit basic_string(const allocator_type& alloc)
     280                : data_{}, size_{}, capacity_{}, allocator_{alloc}
     281            {
     282                /**
     283                 * Postconditions:
     284                 *  data() = non-null copyable value that can have 0 added to it.
     285                 *  size() = 0
     286                 *  capacity() = unspecified
     287                 */
     288                data_ = allocator_.allocate(initial_capacity_);
     289                capacity_ = initial_capacity_;
     290            }
     291
     292            basic_string(const basic_string& other)
     293                : data_{}, size_{other.size_}, capacity_{other.capacity_},
     294                  allocator_{other.allocator_}
     295            {
     296                init_(other.data(), size_);
     297            }
     298
     299            basic_string(basic_string&& other)
     300                : data_{other.data_}, size_{other.size_},
     301                  capacity_{other.capacity_}, allocator_{move(other.allocator_)}
     302            {
     303                other.data_ = nullptr;
     304                other.size_ = 0;
     305                other.capacity_ = 0;
     306            }
    284307
    285308            basic_string(const basic_string& other, size_type pos, size_type n = npos,
    286                          const allocator_type& alloc = allocator_type{});
    287 
    288             basic_string(const value_type*, size_type n, const allocator_type& alloc = allocator{});
    289 
    290             basic_string(const value_type*, const allocator_type& alloc = allocator{});
    291 
    292             basic_string(size_type n, value_type c, const allocator_type& alloc = allocator{});
     309                         const allocator_type& alloc = allocator_type{})
     310                : data_{}, size_{}, capacity_{}, allocator_{alloc}
     311            {
     312                // TODO: if pos < other.size() throw out_of_range.
     313                auto len = min(n, other.size() - pos);
     314                init_(other.data() + pos, len);
     315            }
     316
     317            basic_string(const value_type* str, size_type n, const allocator_type& alloc = allocator{})
     318                : data_{}, size_{n}, capacity_{n}, allocator_{alloc}
     319            {
     320                init_(str, size_);
     321            }
     322
     323            basic_string(const value_type* str, const allocator_type& alloc = allocator{})
     324                : data_{}, size_{}, capacity_{}, allocator_{alloc}
     325            {
     326                init_(str, traits_type::length(str));
     327            }
     328
     329            basic_string(size_type n, value_type c, const allocator_type& alloc = allocator{})
     330                : data_{}, size_{n}, capacity_{n}, allocator_{alloc}
     331            {
     332                data_ = allocator_.allocate(capacity_);
     333                for (size_type i = 0; i < size_; ++i)
     334                    traits_type::asign(data_[i], c);
     335                ensure_null_terminator_();
     336            }
    293337
    294338            template<class InputIterator>
    295339            basic_string(InputIterator first, InputIterator last,
    296                          const allocator_type& alloc = allocator{});
    297 
    298             basic_string(initializer_list<value_type> init, const allocator_type& alloc = allocator{});
    299 
    300             basic_string(const basic_string& other, const allocator_type& alloc);
    301 
    302             basic_string(basic_string&& other, const allocator_type& alloc);
    303 
    304             ~basic_string();
    305 
    306             basic_string& operator=(const basic_string& other);
     340                         const allocator_type& alloc = allocator{})
     341                : data_{}, size_{}, capacity_{}, allocator_{alloc}
     342            {
     343                if constexpr (is_integral_t<InputIterator>)
     344                { // Required by the standard.
     345                    size_ = static_cast<size_type>(first);
     346                    capacity_ = size_;
     347                    data_ = allocator_.allocate(capacity_);
     348
     349                    for (size_type i = 0; i < size_; ++i)
     350                        traits_type::assign(data_[i], static_cast<value_type>(last));
     351                    ensure_null_terminator_();
     352                }
     353                else
     354                {
     355                    auto len = static_cast<size_type>(last - first);
     356                    init_(static_cast<value_type*>(first), len);
     357                }
     358            }
     359
     360            basic_string(initializer_list<value_type> init, const allocator_type& alloc = allocator{})
     361                : basic_string{init.begin(), init.size(), alloc}
     362            { /* DUMMY BODY */ }
     363
     364            basic_string(const basic_string& other, const allocator_type& alloc)
     365                : data_{}, size_{other.size_}, capacity_{other.capacity_}, allocator_{alloc}
     366            {
     367                init_(other.data(), size_);
     368            }
     369
     370            basic_string(basic_string&& other, const allocator_type& alloc)
     371                : data_{other.data_}, size_{other.size_}, capacity_{other.capacity_}, allocator_{alloc}
     372            {
     373                other.data_ = nullptr;
     374                other.size_ = 0;
     375                other.capacity_ = 0;
     376            }
     377
     378            ~basic_string()
     379            {
     380                allocator_.deallocate(data_, capacity_);
     381            }
     382
     383            basic_string& operator=(const basic_string& other)
     384            {
     385                if (this != &other)
     386                {
     387                    basic_string tmp{other};
     388                    swap(tmp);
     389                }
     390            }
    307391
    308392            basic_string& operator=(basic_string&& other)
    309393                noexcept(allocator_traits<allocator_type>::propagate_on_container_move_assignment::value ||
    310                          allocator_traits<allocator_type>::is_always_equal::value);
    311 
    312             basic_string& operator=(const value_type* other);
    313 
    314             basic_string& operator=(value_type c);
    315 
    316             basic_string& operator=(initializer_list<value_type>);
     394                         allocator_traits<allocator_type>::is_always_equal::value)
     395            {
     396                if (this != &other)
     397                    swap(other);
     398            }
     399
     400            basic_string& operator=(const value_type* other)
     401            {
     402                *this = basic_string{other};
     403
     404                return *this;
     405            }
     406
     407            basic_string& operator=(value_type c)
     408            {
     409                *this = basic_string{1, c};
     410
     411                return *this;
     412            }
     413
     414            basic_string& operator=(initializer_list<value_type> init)
     415            {
     416                *this = basic_string{init};
     417
     418                return *this;
     419            }
    317420
    318421            /**
     
    399502            }
    400503
    401             void resize(size_type n, value_type c);
    402 
    403             void resize(size_type n);
     504            void resize(size_type new_size, value_type c)
     505            {
     506                // TODO: if new_size > max_size() throw length_error.
     507                if (new_size > size_)
     508                {
     509                    ensure_free_space_(new_size - size_ + 1);
     510                    for (size_type i = size_; i < new_size; ++i)
     511                        traits_type::assign(data_[i], i);
     512                }
     513
     514                size_ = new_size;
     515                ensure_null_terminator_();
     516            }
     517
     518            void resize(size_type new_size)
     519            {
     520                resize(new_size, value_type{});
     521            }
    404522
    405523            size_type capacity() const noexcept
     
    408526            }
    409527
    410             void reserve(size_type res_arg = 0);
    411 
    412             void shrink_to_fit();
    413 
    414             void clear() noexcept;
     528            void reserve(size_type new_capacity = 0)
     529            {
     530                // TODO: if new_capacity > max_size() throw
     531                //       length_error (this function shall have no
     532                //       effect in such case)
     533                if (new_capacity > capacity_)
     534                    resize_with_copy_(size_, new_capacity);
     535                else if (new_capacity < capacity)
     536                    shrink_to_fit(); // Non-binding request, but why not.
     537            }
     538
     539            void shrink_to_fit()
     540            {
     541                if (size_ != capacity_)
     542                    resize_with_copy_(size_);
     543            }
     544
     545            void clear() noexcept
     546            {
     547                size_ = 0;
     548            }
    415549
    416550            bool empty() const noexcept
     
    469603             */
    470604
    471             basic_string& operator+=(const basic_string& str);
    472 
    473             basic_string& operator+=(const value_type* str);
    474 
    475             basic_string& operator+=(value_type c);
    476 
    477             basic_string& operator+=(initializer_list<value_type> init);
    478 
    479             basic_string& append(const basic_string& str);
     605            basic_string& operator+=(const basic_string& str)
     606            {
     607                return append(str);
     608            }
     609
     610            basic_string& operator+=(const value_type* str)
     611            {
     612                return append(str);
     613            }
     614
     615            basic_string& operator+=(value_type c)
     616            {
     617                push_back(c);
     618                return *this;
     619            }
     620
     621            basic_string& operator+=(initializer_list<value_type> init)
     622            {
     623                return append(init.begin(), init.size());
     624            }
     625
     626            basic_string& append(const basic_string& str)
     627            {
     628                return append(str.data(), str.size());
     629            }
    480630
    481631            basic_string& append(const basic_string& str, size_type pos
    482                                  size_type n = npos);
    483 
    484             basic_string& append(const value_type* str, size_type n);
    485 
    486             basic_string& append(const value_type* str);
    487 
    488             basic_string& append(size_type n, value_type c);
     632                                 size_type n = npos)
     633            {
     634                if (pos < str.size())
     635                {
     636                    auto len = min(n, str.size() - pos);
     637                    ensure_free_space_(len);
     638
     639                    return append(str.data() + pos, len);
     640                }
     641                // TODO: Else throw out_of_range.
     642            }
     643
     644            basic_string& append(const value_type* str, size_type n)
     645            {
     646                // TODO: if (size_ + n > max_size()) throw length_error
     647                ensure_free_space_(n);
     648                traits_type::copy(data_ + size_, str, n);
     649                size_ += n;
     650                ensure_null_terminator_();
     651
     652                return *this;
     653            }
     654
     655            basic_string& append(const value_type* str)
     656            {
     657                return append(str, traits_type::length(str));
     658            }
     659
     660            basic_string& append(size_type n, value_type c)
     661            {
     662                return append(basic_string(n, c));
     663            }
    489664
    490665            template<class InputIterator>
    491             basic_string& append(InputIterator first, InputIterator last);
    492 
    493             basic_string& append(initializer_list<value_type> init);
    494 
    495             void push_back(value_type c);
    496 
    497             basic_string& assign(const basic_string& str);
    498 
    499             basic_string& assign(basic_string&& str);
     666            basic_string& append(InputIterator first, InputIterator last)
     667            {
     668                return append(basic_string(frist, last));
     669            }
     670
     671            basic_string& append(initializer_list<value_type> init)
     672            {
     673                return append(init.begin(), init.size());
     674            }
     675
     676            void push_back(value_type c)
     677            {
     678                ensure_free_space_(1);
     679                traits_type::assign(data_[size_++], c);
     680                ensure_null_terminator_();
     681            }
     682
     683            basic_string& assign(const basic_string& str)
     684            {
     685                return assign(str, 0, npos);
     686            }
     687
     688            basic_string& assign(basic_string&& str)
     689            {
     690                swap(str);
     691
     692                return *this;
     693            }
    500694
    501695            basic_string& assign(const basic_string& str, size_type pos,
    502                                  size_type n = npos);
    503 
    504             basic_string& assign(const value_type* str, size_type n);
    505 
    506             basic_string& assign(const value_type* str);
    507 
    508             basic_string& assign(size_type n, value_type c);
     696                                 size_type n = npos)
     697            {
     698                if (pos < str.size())
     699                {
     700                    auto len = min(n, str.size() - pos);
     701                    ensure_free_space_(len);
     702
     703                    return assign(str.data() + pos, len);
     704                }
     705                // TODO: Else throw out_of_range.
     706            }
     707
     708            basic_string& assign(const value_type* str, size_type n)
     709            {
     710                // TODO: if (n > max_size()) throw length_error.
     711                resize_without_copy_(n);
     712                traits_type::copy(begin(), str, n);
     713
     714                return *this;
     715            }
     716
     717            basic_string& assign(const value_type* str)
     718            {
     719                return assign(str, traits_type::length(str));
     720            }
     721
     722            basic_string& assign(size_type n, value_type c)
     723            {
     724                return assign(basic_string(n, c));
     725            }
    509726
    510727            template<class InputIterator>
    511             basic_string& assign(InputIterator first, InputIterator last);
    512 
    513             basic_string& assign(initializer_list<value_type> init);
    514 
    515             basic_string& insert(size_type pos, const basic_string& str);
     728            basic_string& assign(InputIterator first, InputIterator last)
     729            {
     730                return assign(basic_string(first, last));
     731            }
     732
     733            basic_string& assign(initializer_list<value_type> init)
     734            {
     735                return assign(init.begin(), init.size());
     736            }
     737
     738            basic_string& insert(size_type pos, const basic_string& str)
     739            {
     740                // TODO: if (pos > str.size()) throw out_of_range.
     741                return insert(pos, str.data(), str.size());
     742            }
    516743
    517744            basic_string& insert(size_type pos1, const basic_string& str,
    518                                  size_type pos2, size_type n = npos);
    519 
    520             basic_string& insert(size_type pos, const value_type* str, size_type n);
    521 
    522             basic_string& insert(size_type pos, const value_type* str);
    523 
    524             basic_string& insert(size_type pos, size_type n, value_type c);
    525 
    526             iterator insert(const_iterator pos, value_type c);
    527 
    528             iterator insert(const_iterator pos, size_type n, value_type c);
     745                                 size_type pos2, size_type n = npos)
     746            {
     747                // TODO: if (pos1 > size() or pos2 > str.size()) throw
     748                //       out_of_range.
     749                auto len = min(n, str.size() - pos2);
     750
     751                return insert(pos1, str.data() + pos2, len);
     752            }
     753
     754            basic_string& insert(size_type pos, const value_type* str, size_type n)
     755            {
     756                ensure_free_space_(size_ + n);
     757                copy_backward_(begin() + pos, end(), end() + n);
     758                copy_(begin() + pos, begin() + pos + n, str);
     759
     760                return *this;
     761            }
     762
     763            basic_string& insert(size_type pos, const value_type* str)
     764            {
     765                return insert(pos, str, traits_type::length(str));
     766            }
     767
     768            basic_string& insert(size_type pos, size_type n, value_type c)
     769            {
     770                return insert(pos, basic_string(n, c));
     771            }
     772
     773            iterator insert(const_iterator pos, value_type c)
     774            {
     775                auto idx = static_cast<size_type>(pos - begin());
     776
     777                ensure_free_space_(1);
     778                copy_backward_(begin() + pos, end(), end() + 1);
     779                ensure_null_terminator_();
     780
     781                return begin() + idx;
     782            }
     783
     784            iterator insert(const_iterator pos, size_type n, value_type c)
     785            {
     786                if (n == 0)
     787                    return const_cast<iterator>(pos);
     788
     789                auto idx = static_cast<size_type>(pos - begin());
     790
     791                ensure_free_space_(n);
     792                copy_backward_(begin() + pos, end(), end() + n);
     793
     794                auto it = position;
     795                for (size_type i = 0; i < n; ++i)
     796                    type_traits::assign(*it++, c);
     797                ensure_null_terminator_();
     798
     799                return begin() + idx;
     800            }
    529801
    530802            template<class InputIterator>
    531803            iterator insert(const_iterator pos, InputIterator first,
    532                             InputIterator last);
    533 
    534             iterator insert(const_iterator pos, initializer_list<value_type>);
    535 
    536             basic_string& erase(size_type pos = 0; size_type n = npos);
     804                            InputIterator last)
     805            {
     806                return insert(pos - begin(), basic_string(first, last));
     807            }
     808
     809            iterator insert(const_iterator pos, initializer_list<value_type> init)
     810            {
     811                return insert(pos, init.begin(), init.end());
     812            }
     813
     814            basic_string& erase(size_type pos = 0; size_type n = npos)
     815            {
     816                auto len = min(n, size_ - pos);
     817                copy_(begin() + pos + n, end(), begin() + pos);
     818                size_ -= len;
     819                ensure_null_terminator_();
     820            }
    537821
    538822            iterator erase(const_iterator pos);
     
    540824            iterator erase(const_iterator pos, const_iterator last);
    541825
    542             void pop_back();
     826            void pop_back()
     827            {
     828                --size_;
     829                ensure_null_terminator_();
     830            }
    543831
    544832            basic_string& replace(size_type pos, size_type n, const basic_string& str);
     
    673961            size_type capacity_;
    674962            allocator_type allocator_;
     963
     964            /**
     965             * Arbitrary value, standard just requires
     966             * data() to have some capacity.
     967             * (Well, we could've done data_ = &data_ and
     968             * set capacity to 0, but that would be too cryptic.)
     969             */
     970            static constexpr size_type default_capacity_{4}
     971
     972            void init_(const value_type* str, size_type size)
     973            {
     974                if (data_)
     975                    allocator_.deallocate(data_, capacity_);
     976
     977                size_ = size;
     978                capacity_ = size;
     979
     980                data_ = allocator_.allocate(capacity_);
     981                traits_type::copy(data_, str, size);
     982                ensure_null_terminator_();
     983            }
     984
     985            size_type next_capacity_(size_type hint = 0) const noexcept
     986            {
     987                if (hint != 0)
     988                    return max(capacity_ * 2, hint);
     989                else
     990                    return max(capacity_ * 2, 2ul);
     991            }
     992
     993            void ensure_free_space_(size_type n)
     994            {
     995                /**
     996                 * Note: We cannot use reserve like we
     997                 *       did in vector, because in string
     998                 *       reserve can cause shrinking.
     999                 */
     1000                if (size_ + 1 + n > capacity)
     1001                    resize_with_copy_(size_, max(size_ + 1 + n, next_capacity_()));
     1002            }
     1003
     1004            void resize_without_copy_(size_type capacity)
     1005            {
     1006                if (data_)
     1007                    allocator_.deallocate(data_, capacity_);
     1008
     1009                data_ = allocator_.allocate(capacity);
     1010                size_ = 0;
     1011                capacity_ = capacity;
     1012                ensure_null_terminator_();
     1013            }
     1014
     1015            void resize_with_copy_(size_type size, size_type capacity)
     1016            {
     1017                if(capacity_ == 0 || capacity_ < capacity)
     1018                {
     1019                    auto new_data = allocator_.allocate(capacity);
     1020
     1021                    auto to_copy = min(size, size_);
     1022                    traits_type::move(new_data, data_, to_copy);
     1023
     1024                    std::swap(data_, new_data);
     1025
     1026                    allocator_.deallocate(new_data, capacity_);
     1027                }
     1028
     1029                capacity_ = capacity;
     1030                size_ = size;
     1031                ensure_null_terminator_();
     1032            }
     1033
     1034            iterator copy_(const_iterator first, const_iterator last,
     1035                           iterator result)
     1036            {
     1037                while (first != last)
     1038                    traits_type::assign(*result++, *first++);
     1039
     1040                ensure_null_terminator_();
     1041                return result;
     1042            }
     1043
     1044            iterator copy_backward_(const_iterator first, const_iterator last,
     1045                                    iterator result)
     1046            {
     1047                while (last-- != first)
     1048                    traits_type::assign(*result--, *last);
     1049
     1050                ensure_null_terminator_();
     1051                return result;
     1052            }
     1053
     1054            void ensure_null_terminator_()
     1055            {
     1056                traits_type::assign(data_[size_], value_type{});
     1057            }
    6751058    };
    6761059}
Note: See TracChangeset for help on using the changeset viewer.