LCOV - code coverage report
Current view: top level - core/core/memory - SPMemStorageMem.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 208 209 99.5 %
Date: 2024-05-12 00:16:13 Functions: 975 1146 85.1 %

          Line data    Source code
       1             : /**
       2             : Copyright (c) 2017-2022 Roman Katuntsev <sbkarr@stappler.org>
       3             : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
       4             : 
       5             : Permission is hereby granted, free of charge, to any person obtaining a copy
       6             : of this software and associated documentation files (the "Software"), to deal
       7             : in the Software without restriction, including without limitation the rights
       8             : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       9             : copies of the Software, and to permit persons to whom the Software is
      10             : furnished to do so, subject to the following conditions:
      11             : 
      12             : The above copyright notice and this permission notice shall be included in
      13             : all copies or substantial portions of the Software.
      14             : 
      15             : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      16             : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      17             : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      18             : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      19             : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      20             : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      21             : THE SOFTWARE.
      22             : **/
      23             : 
      24             : #ifndef STAPPLER_CORE_MEMORY_SPMEMSTORAGEMEM_H_
      25             : #define STAPPLER_CORE_MEMORY_SPMEMSTORAGEMEM_H_
      26             : 
      27             : #include "SPMemStorageMemImpl.h"
      28             : #include "SPMemPointerIterator.h"
      29             : 
      30             : namespace STAPPLER_VERSIONIZED stappler::memory {
      31             : 
      32             : template <typename Type>
      33             : struct mem_sso_test {
      34             :         static constexpr bool value = std::is_scalar<Type>::value;
      35             : };
      36             : 
      37             : template <typename Type, size_t Extra = 0>
      38             : class storage_mem_soo : public impl::mem_soo_iface<Type, Extra, mem_sso_test<Type>::value> {
      39             : public:
      40             :         using base = impl::mem_soo_iface<Type, Extra, mem_sso_test<Type>::value>;
      41             :         using self = storage_mem_soo<Type, Extra>;
      42             :         using pointer = Type *;
      43             :         using const_pointer = const Type *;
      44             :         using reference = Type &;
      45             :         using const_reference = const Type &;
      46             : 
      47             :         using size_type = size_t;
      48             :         using allocator = Allocator<Type>;
      49             : 
      50             :         using iterator = pointer_iterator<Type, pointer, reference>;
      51             :         using const_iterator = pointer_iterator<Type, const_pointer, const_reference>;
      52             : 
      53             :         using reverse_iterator = std::reverse_iterator<iterator>;
      54             :         using const_reverse_iterator = std::reverse_iterator<const_iterator>;
      55             : 
      56             :         using base::get_soo_size;
      57             : 
      58             :         // default init with current context allocator or specified allocator
      59    28518031 :         storage_mem_soo(const allocator &alloc = allocator()) noexcept : base(alloc) { }
      60             : 
      61             :         storage_mem_soo(pointer p, size_type s, const allocator &alloc) noexcept : storage_mem_soo(alloc) {
      62             :                 assign(p, s);
      63             :         }
      64             : 
      65     4514900 :         storage_mem_soo(const_pointer p, size_type s, const allocator &alloc = allocator()) noexcept : storage_mem_soo(alloc) {
      66     4514898 :                 assign(p, s);
      67     4514901 :         }
      68             : 
      69         125 :         storage_mem_soo(const self &other, size_type pos, size_type len, const allocator &alloc = allocator()) noexcept
      70         125 :         : storage_mem_soo(alloc) {
      71         125 :                 if (pos < other.size()) {
      72         100 :                         assign(other.data() + pos, min(len, other.size() - pos));
      73             :                 }
      74         125 :         }
      75             : 
      76             :         // copy-construct
      77     9840300 :         storage_mem_soo(const self &other, const allocator &alloc = allocator()) noexcept
      78     9840300 :         : storage_mem_soo(alloc) {
      79     9840298 :                 assign(other);
      80     9840297 :         }
      81             : 
      82             :         // move
      83             :         // we steal memory block from other, it lifetime is same, or make copy
      84     8320757 :         storage_mem_soo(self &&other, const allocator &alloc = allocator()) noexcept
      85     8320757 :         : storage_mem_soo(alloc) {
      86     8320759 :                 if (other._allocator == _allocator) {
      87             :                         // lifetime is same, steal allocated memory
      88     8320284 :                         perform_move(std::move(other));
      89             :                 } else {
      90         475 :                         assign(other);
      91             :                 }
      92     8320754 :                 other.clear_dealloc(_allocator);
      93     8320752 :         }
      94             : 
      95        5492 :         storage_mem_soo & operator = (const self &other) noexcept {
      96        5492 :                 assign(other);
      97        5492 :                 return *this;
      98             :         }
      99             : 
     100       44852 :         storage_mem_soo & operator = (self &&other) noexcept {
     101       44852 :                 if (other._allocator == _allocator) {
     102             :                         // clear and deallocate our memory, self-move-assignment is UB
     103       44427 :                         clear_dealloc(_allocator);
     104       44427 :                         perform_move(std::move(other));
     105             :                 } else {
     106         425 :                         assign(other);
     107             :                 }
     108       44852 :                 other.clear_dealloc(_allocator);
     109       44852 :                 return *this;
     110             :         }
     111             : 
     112             :         using base::assign;
     113             :         using base::assign_weak;
     114             :         using base::assign_mem;
     115             :         using base::is_weak;
     116             : 
     117     9848543 :         void assign(const self &other) {
     118     9848543 :                 assign(other.data(), other.size());
     119     9848542 :         }
     120             : 
     121          25 :         void assign(const self &other, size_type pos, size_type len) {
     122          25 :                 assign(other.data() + pos, min(len, other.size() - pos));
     123          25 :         }
     124             : 
     125             :         template <typename ...Args>
     126    47290830 :         reference emplace_back(Args &&  ...args) {
     127    47290830 :                 reserve(size() + 1, true); // reserve should switch mode if required
     128    47230205 :                 return emplace_back_unsafe(std::forward<Args>(args)...);
     129             :         }
     130             : 
     131     3718583 :         void pop_back() {
     132     3718583 :                 if (size() > 0) {
     133     3718585 :                         const auto size = modify_size(-1);
     134     3718586 :                         auto ptr = data() + size;
     135     3718587 :                         _allocator.destroy(ptr);
     136     3718585 :                         memset((void *)ptr, 0, sizeof(Type));
     137             :                 }
     138     3718585 :         }
     139             : 
     140             :         template <typename ...Args>
     141   546415224 :         reference emplace_back_unsafe(Args &&  ...args) {
     142   546415224 :                 const auto s = modify_size(1);
     143   546420256 :                 auto ptr = data() + s - 1;
     144   546428012 :                 _allocator.construct(data() + s - 1, std::forward<Args>(args)...);
     145   546463646 :                 return *ptr;
     146             :         }
     147             : 
     148             :         template <typename... Args>
     149      118251 :         iterator emplace( const_iterator it, Args&&... args ) {
     150      118251 :                 const auto _size = size();
     151      118251 :                 auto _ptr = data();
     152      118251 :                 size_type pos = it - _ptr;
     153      118251 :                 if (_size == 0 || pos == _size) {
     154        5240 :                         emplace_back(std::forward<Args>(args)...);
     155        5240 :                         return iterator(data() + size() - 1);
     156             :                 } else {
     157      113011 :                         _ptr = reserve(_size + 1, true);
     158      113011 :                         _allocator.move(_ptr + pos + 1, _ptr + pos, _size - pos);
     159      113011 :                         _allocator.construct(_ptr + pos, std::forward<Args>(args)...);
     160      113011 :                         modify_size(1);
     161      113011 :                         return iterator(_ptr + pos);
     162             :                 }
     163             :         }
     164             : 
     165             :         template <typename... Args>
     166       10984 :         iterator emplace_safe( const_iterator it, Args&&... args ) {
     167       10984 :                 const auto _used = size();
     168       10984 :                 auto _ptr = data();
     169       10984 :                 size_type pos = it - _ptr;
     170       10984 :                 if (_used == 0 || pos == _used) {
     171        6060 :                         emplace_back(std::forward<Args>(args)...);
     172        6060 :                         return iterator(data() + size() - 1);
     173             :                 } else {
     174        4924 :                         _ptr = reserve(_used + 2, true);
     175        4924 :                         _allocator.construct(_ptr + _used + 1, std::forward<Args>(args)...);
     176        4924 :                         _allocator.move(_ptr + pos + 1, _ptr + pos, _used - pos);
     177        4924 :                         _allocator.move(_ptr + pos, _ptr + _used + 1, 1);
     178        4924 :                         modify_size(1);
     179        4924 :                         return iterator(_ptr + pos);
     180             :                 }
     181             :         }
     182             : 
     183   494137350 :         void insert_back(const_pointer ptr, size_type s) {
     184   494137350 :                 const auto _used = size();
     185   494137350 :                 auto _ptr = reserve(_used + s, true);
     186   494137349 :                 _allocator.copy(_ptr + _used, ptr, s);
     187   494137349 :                 modify_size(s);
     188   494137350 :         }
     189             : 
     190       19675 :         void insert_back(const self &other) {
     191       19675 :                 insert_back(other.data(), other.size());
     192       19675 :         }
     193             : 
     194          25 :         void insert_back(const self &other, size_type pos, size_type len) {
     195          25 :                 insert_back(other.data() + pos, std::min(other.size() - pos, len));
     196          25 :         }
     197             : 
     198         200 :         void insert(size_type pos, const_pointer ptr, size_type s) {
     199         200 :                 const auto _used = size();
     200         200 :                 auto _ptr = reserve(_used + s, true);
     201         200 :                 _allocator.move(_ptr + pos + s, _ptr + pos, _used - pos);
     202         200 :                 _allocator.copy(_ptr + pos, ptr, s);
     203         200 :                 modify_size(s);
     204         200 :         }
     205             : 
     206          25 :         void insert(size_type pos, const self &other) {
     207          25 :                 insert(pos, other.data(), other.size());
     208          25 :         }
     209             : 
     210          25 :         void insert(size_type spos, const self &other, size_type pos, size_type len) {
     211          25 :                 insert(spos, other.data() + pos, min(other.size() - pos, len));
     212          25 :         }
     213             : 
     214             :         template< class... Args >
     215          75 :         void insert(size_type pos, size_type s, Args && ... args) {
     216          75 :                 const auto _used = size();
     217          75 :                 auto _ptr = reserve(_used + s, true);
     218          75 :                 _allocator.move(_ptr + pos + s, _ptr + pos, _used - pos);
     219         175 :                 for (size_type i = pos; i < pos + s; i++) {
     220         100 :                         _allocator.construct(_ptr + i, std::forward<Args>(args)...);
     221             :                 }
     222          75 :                 modify_size(s);
     223          75 :         }
     224             : 
     225             :         template< class... Args >
     226          50 :         iterator insert(const_iterator it, size_type len, Args && ... args) {
     227          50 :                 size_type pos = it - data();
     228          50 :                 insert(pos, len, std::forward<Args>(args)...);
     229          50 :                 return iterator(data() + pos);
     230             :         }
     231             : 
     232             :         template< class InputIt >
     233       11150 :         iterator insert( const_iterator it, InputIt first, InputIt last ) {
     234       11150 :                 auto _ptr = data();
     235       11150 :                 const auto _used = size();
     236       11150 :                 auto pos = it - _ptr;
     237       11150 :                 auto size = std::distance(first, last);
     238       11150 :                 _ptr = reserve(_used + size, true);
     239       11150 :                 if (pos - _used > 0) {
     240           0 :                         _allocator.move(_ptr + pos + size, _ptr + pos, _used - pos);
     241             :                 }
     242       11150 :                 auto i = pos;
     243       78050 :                 for (auto it = first; it != last; ++ it, ++ i) {
     244       66900 :                         _allocator.construct(_ptr + i, *it);
     245             :                 }
     246       11150 :                 modify_size(size);
     247       11150 :                 return iterator(_ptr + pos);
     248             :         }
     249             : 
     250          50 :         void erase(size_type pos, size_type len) {
     251          50 :                 auto _ptr = data();
     252          50 :                 const auto _used = size();
     253          50 :                 len = min(len, _used - pos);
     254          50 :                 _allocator.destroy(_ptr + pos, len); // удаляем указанный блок
     255          50 :                 if (pos + len < _used) { // смещаем остаток
     256          25 :                         _allocator.move(_ptr + pos, _ptr + pos + len, _used - pos - len);
     257             :                 }
     258          50 :                 auto s = modify_size(-len);
     259          50 :                 memset((void *)(_ptr + s), 0, len * sizeof(Type));
     260          50 :         }
     261             : 
     262       34094 :         iterator erase(const_iterator it) {
     263       34094 :                 auto _ptr = data();
     264       34095 :                 const auto _used = size();
     265       34095 :                 auto pos = it - _ptr;
     266       34095 :                 _allocator.destroy(const_cast<pointer>( & (*it) ));
     267       34095 :                 if (pos < _used - 1) {
     268         350 :                         _allocator.move(_ptr + pos, _ptr + pos + 1, _used - pos - 1);
     269             :                 }
     270       34095 :                 auto s = modify_size(-1);
     271       34095 :                 memset((void *)(_ptr + s), 0, sizeof(Type));
     272       34095 :                 return iterator(_ptr + pos);
     273             :         }
     274             : 
     275             :         iterator erase(const_iterator first, const_iterator last) {
     276             :                 auto _ptr = data();
     277             :                 auto pos = first - _ptr;
     278             :                 auto len = last - first;
     279             :                 erase(pos, len);
     280             :                 return iterator(_ptr + pos);
     281             :         }
     282             : 
     283          50 :         pointer prepare_replace(size_type pos, size_type len, size_type nlen) {
     284          50 :                 const auto _used = size();
     285          50 :                 auto _ptr = reserve(_used - len + nlen, true);
     286          50 :                 _allocator.destroy(_ptr + pos, len);
     287          50 :                 if (pos + len < _used) {
     288          50 :                         _allocator.move(_ptr + pos + nlen, _ptr + pos + len, _used - pos - len); // смещаем данные
     289             :                 }
     290          50 :                 return _ptr + pos;
     291             :         }
     292             : 
     293          25 :         void replace(size_type pos, size_type len, const_pointer ptr, size_type nlen) {
     294          25 :                 const auto _used = size();
     295          25 :                 len = min(len, _used - pos);
     296          25 :                 _allocator.copy(prepare_replace(pos, len, nlen), ptr, nlen);
     297             : 
     298          25 :                 const auto s = modify_size(nlen - len);
     299             : 
     300          25 :                 if (nlen < len) {
     301          25 :                         memset((void *)(data() + s), 0, (len - nlen) * sizeof(Type));
     302             :                 }
     303          25 :         }
     304             : 
     305             :         void replace(size_type pos, size_type len, const self &other) {
     306             :                 replace(pos, len, other.data(), other.size());
     307             :         }
     308             :         void replace(size_type pos, size_type len, const self &other, size_type npos, size_type nlen) {
     309             :                 replace(pos, len, other.data() + npos, MIN(other.size() - npos, nlen));
     310             :         }
     311             : 
     312          25 :         void replace(size_type pos, size_type len, size_type nlen, Type t) {
     313          25 :                 const auto _used = size();
     314          25 :                 len = min(len, _used - pos);
     315          25 :                 prepare_replace(pos, len, nlen);
     316          25 :                 auto _ptr = data();
     317          50 :                 for (size_type i = pos; i < pos + nlen; i++) {
     318          25 :                         _allocator.construct(_ptr + i, t);
     319             :                 }
     320             : 
     321          25 :                 const auto s = modify_size(nlen - len);
     322             : 
     323          25 :                 if (nlen < len) {
     324          25 :                         memset((void *)(data() + s), 0, (len - nlen) * sizeof(Type));
     325             :                 }
     326          25 :         }
     327             : 
     328             :         template< class InputIt >
     329             :         iterator replace( const_iterator first, const_iterator last, InputIt first2, InputIt last2 ) {
     330             :                 auto pos = size_t(first - data());
     331             :                 auto len = size_t(last - first);
     332             :                 auto nlen = std::distance(first2, last2);
     333             : 
     334             :                 prepare_replace(pos, len, nlen);
     335             :                 auto i = pos;
     336             :                 auto _ptr = data();
     337             :                 for (auto it = first2; it != last2; it ++, i++) {
     338             :                         _allocator.construct(_ptr + i, *it);
     339             :                 }
     340             : 
     341             :                 const auto s = modify_size(nlen - len);
     342             : 
     343             :                 if (nlen < len) {
     344             :                         memset((void *)(data() + s), 0, (len - nlen) * sizeof(Type));
     345             :                 }
     346             :                 return iterator(pos);
     347             :         }
     348             : 
     349             :         template <typename ...Args>
     350          75 :         void fill(size_type s, Args && ... args) {
     351          75 :                 clear();
     352          75 :                 auto _ptr = reserve(s, true);
     353         350 :                 for (size_type i = 0; i < s; i++) {
     354         275 :                         _allocator.construct(_ptr + i, std::forward<Args>(args)...);
     355             :                 }
     356             : 
     357          75 :                 set_size(s);
     358          75 :         }
     359             : 
     360             :         template <typename ...Args>
     361     8181617 :         void resize(size_type n, Args && ... args) {
     362     8181617 :                 auto _ptr = reserve(n, true);
     363             : 
     364     8181612 :                 const auto _used = size();
     365     8181615 :                 if (n < _used) {
     366        3729 :                         if (_ptr) {
     367        3729 :                                 _allocator.destroy(_ptr + n, _used - n);
     368             :                         }
     369     8177886 :                 } else if (n > _used) {
     370  1170520576 :                         for (size_type i = _used; i < n; i++) {
     371  1162665191 :                                 _allocator.construct(_ptr + i, std::forward<Args>(args)...);
     372             :                         }
     373             :                 }
     374             : 
     375     8181598 :                 set_size(n);
     376     8181620 :         }
     377             : 
     378             :         using base::reserve;
     379             :         using base::clear;
     380             :         using base::extract;
     381             : 
     382             :         using base::empty;
     383             :         using base::data;
     384             :         using base::size;
     385             :         using base::capacity;
     386             : 
     387   221125139 :         reference at(size_type s) noexcept {
     388   221125139 :                 return data()[s];
     389             :         }
     390             : 
     391      781741 :         const_reference at(size_type s) const noexcept {
     392      781741 :                 return data()[s];
     393             :         }
     394             : 
     395     3358780 :         reference back() noexcept { return *(data() + (size() - 1)); }
     396     1061736 :         const_reference back() const noexcept { return *(data() + (size() - 1)); }
     397             : 
     398      179119 :         reference front() noexcept { return *data(); }
     399      703089 :         const_reference front() const noexcept { return *data(); }
     400             : 
     401    51266157 :         iterator begin() noexcept { return iterator(data()); }
     402    55691442 :         iterator end() noexcept { return iterator(data() + size()); }
     403             : 
     404    12685751 :         const_iterator begin() const noexcept { return const_iterator(data()); }
     405    12956678 :         const_iterator end() const noexcept { return const_iterator(data() + size()); }
     406             : 
     407         200 :         const_iterator cbegin() const noexcept { return const_iterator(data()); }
     408          75 :         const_iterator cend() const noexcept { return const_iterator(data() + size()); }
     409             : 
     410             :     reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
     411             :     reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
     412             : 
     413             :     const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); }
     414             :     const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); }
     415             : 
     416             :     const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(cend()); }
     417             :     const_reverse_iterator crend() const noexcept { return const_reverse_iterator(cbegin()); }
     418             : 
     419          25 :         void shrink_to_fit() noexcept {
     420          25 :                 if (size() == 0) {
     421          25 :                         clear_dealloc(_allocator);
     422             :                 }
     423          25 :         }
     424             : 
     425        4991 :         const allocator & get_allocator() const noexcept { return _allocator; }
     426             : 
     427             : private:
     428             :         using base::perform_move;
     429             :         using base::clear_dealloc;
     430             :         using base::modify_size;
     431             :         using base::set_size;
     432             : 
     433             :         using base::_allocator;
     434             : };
     435             : 
     436             : template <typename Type, size_t Extra = 0>
     437             : using storage_mem = storage_mem_soo<Type, Extra>;
     438             : 
     439             : }
     440             : 
     441             : #endif /* STAPPLER_CORE_MEMORY_SPMEMSTORAGEMEM_H_ */

Generated by: LCOV version 1.14