/** This file is a part of rexy's general purpose library Copyright (C) 2020-2022 rexy712 This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef REXY_STRING_BASE_TPP #define REXY_STRING_BASE_TPP #include //move, etc #include //is_nothrow_invokable, is_nothrow_constructible #include "utility.hpp" //max, memcpy, strlen #include "detail/string_appender.hpp" #include "algorithm.hpp" #include "compat/to_address.hpp" #include "string_view.hpp" #include "compat/string_base.hpp" namespace rexy{ template constexpr auto string_base::search(const string_base& s)const -> const_iterator{ return two_way_search(cbegin(), cend(), s.begin(), s.end()); } template constexpr auto string_base::search(const_pointer c)const -> const_iterator{ const auto len = rexy::strlen(c); return two_way_search(cbegin(), cend(), c, c + len); } template constexpr auto string_base::search(const string_base& s) -> iterator{ return two_way_search(begin(), end(), s.begin(), s.end()); } template constexpr auto string_base::search(const_pointer c) -> iterator{ const auto len = rexy::strlen(c); return two_way_search(begin(), end(), c, c + len); } template template constexpr auto string_base::search(const string_base& s, const Searcher& searcher)const -> const_iterator{ return searcher(cbegin(), cend(), s.begin(), s.end()); } template template constexpr auto string_base::search(const_pointer c, const Searcher& searcher)const -> const_iterator{ const auto len = rexy::strlen(c); return searcher(cbegin(), cend(), c, c + len); } template template constexpr auto string_base::search(const string_base& s, const Searcher& searcher) -> iterator{ return searcher(begin(), end(), s.begin(), s.end()); } template template constexpr auto string_base::search(const_pointer c, const Searcher& searcher) -> iterator{ const auto len = rexy::strlen(c); return searcher(begin(), end(), c, c + len); } //allocate string if longer than small string capacity, copy otherwise template REXY_CPP20_CONSTEXPR void basic_string::_copy_construct_string(const_pointer data, size_type len, size_type cap) noexcept(is_nothrow_allocator_v) { if(cap > this->get_short_capacity()){ this->set_islong_flag(true); pointer raw = this->set_long_ptr(this->allocate(sizeof(value_type)*(cap+1))); if(data) rexy::memcpy(raw, data, sizeof(value_type)*len); raw[len] = 0; this->set_long_length(len); this->set_long_capacity(cap); }else{ this->set_islong_flag(false); pointer raw = this->set_short_ptr(); if(data) rexy::memcpy(raw, data, sizeof(value_type)*len); raw[len] = 0; this->set_short_length(len); this->set_short_capacity(cap); } } template constexpr basic_string::basic_string(void)noexcept{} template constexpr basic_string::basic_string(rexy::steal data)noexcept: basic_string(data.value(), data.value() ? rexy::strlen(data.value()) : 0){} template constexpr basic_string::basic_string(rexy::steal data, size_type len)noexcept: string_base(data.value(), len, len){} template constexpr basic_string::basic_string(rexy::steal data, size_type len, size_type cap)noexcept: string_base(data.value(), len, cap){} template REXY_CPP20_CONSTEXPR basic_string::basic_string(const_pointer data, size_type len, size_type cap) noexcept(is_nothrow_allocator_v) { _copy_construct_string(data, len, cap); } template REXY_CPP20_CONSTEXPR basic_string::basic_string(const_pointer data, size_type len) noexcept(is_nothrow_allocator_v): basic_string(data, len, len){} template REXY_CPP20_CONSTEXPR basic_string::basic_string(const_pointer data) noexcept(is_nothrow_allocator_v): basic_string(data, data ? rexy::strlen(data) : 0){} template REXY_CPP20_CONSTEXPR basic_string::basic_string(size_type cap) noexcept(is_nothrow_allocator_v): basic_string(size_type{0}, cap){} template REXY_CPP20_CONSTEXPR basic_string::basic_string(size_type len, size_type cap) noexcept(is_nothrow_allocator_v) { _copy_construct_string(nullptr, len, cap); } template REXY_CPP20_CONSTEXPR basic_string::basic_string(const basic_string_view& sv) noexcept(is_nothrow_allocator_v) { _copy_construct_string(sv.c_str(), sv.length(), sv.length()); } template template REXY_CPP20_CONSTEXPR basic_string::basic_string(InputIt start, InputIt fin) noexcept(is_nothrow_allocator_v): basic_string(nullptr, size_type{fin - start}) { auto raw = this->get_pointer(); size_type i = 0; for(auto it = start;it != fin;++it,++i){ raw[i] = *it; } raw[i] = 0; } //normal copy and move ctors template REXY_CPP20_CONSTEXPR basic_string::basic_string(const basic_string& b) noexcept(is_nothrow_allocator_v): detail::hasallocator(b) { _copy_construct_string(b.get(), b.length(), b.length()); } template constexpr basic_string::basic_string(basic_string&& s)noexcept: detail::hasallocator(std::move(s)), string_base(std::move(s)){} template REXY_CPP20_CONSTEXPR basic_string::basic_string(const string_base& b) noexcept(is_nothrow_allocator_v) { _copy_construct_string(b.get(), b.length(), b.length()); } //dtor template REXY_CPP20_CONSTEXPR basic_string::~basic_string(void) noexcept(is_nothrow_allocator_v) { if(this->islong()){ this->deallocate(this->get_pointer(), sizeof(value_type)*(this->get_long_capacity()+1)); } } template REXY_CPP20_CONSTEXPR basic_string& basic_string::operator=(const basic_string& s) noexcept(is_nothrow_allocator_v) { if(s.length() < this->capacity()){ rexy::memcpy(this->get_pointer(), s.get_pointer(), sizeof(value_type)*(s.length()+1)); this->set_length(s.length()); return *this; }else{ basic_string tmp(s); return (*this = std::move(tmp)); } } template constexpr basic_string& basic_string::operator=(basic_string&& s)noexcept{ string_base::operator=(std::move(s)); return *this; } template REXY_CPP20_CONSTEXPR basic_string& basic_string::operator=(const string_base& s) noexcept(is_nothrow_allocator_v) { return (*this = basic_string(s)); } //Copy from c string template REXY_CPP20_CONSTEXPR basic_string& basic_string::operator=(const basic_string_view& sv) noexcept(is_nothrow_allocator_v) { return _copy_string(sv.c_str(), sv.length()); } template REXY_CPP20_CONSTEXPR basic_string& basic_string::operator=(const_pointer c) noexcept(is_nothrow_allocator_v) { return _copy_string(c, rexy::strlen(c)); } //Replace managed pointer. Frees existing value template REXY_CPP20_CONSTEXPR void basic_string::reset(pointer val) noexcept(is_nothrow_allocator_v) { reset(val, val ? rexy::strlen(val) : 0); } template REXY_CPP20_CONSTEXPR void basic_string::reset(pointer val, size_type len) noexcept(is_nothrow_allocator_v) { if(this->islong()) this->deallocate(this->get_long_ptr(),sizeof(value_type)*(this->get_long_capacity()+1)); this->set_islong_flag(true); this->set_long_ptr(val); this->set_long_length(len); this->set_long_capacity(len); } template REXY_CPP20_CONSTEXPR bool basic_string::resize(size_type newsize) noexcept(is_nothrow_allocator_v) { if(newsize < this->capacity()) return false; if(!this->islong() && newsize < this->get_short_capacity()) return false; return (*this = basic_string(this->get_pointer(), newsize)); } template REXY_CPP20_CONSTEXPR auto basic_string::insert(size_type pos, size_type insert_count, value_type v)noexcept(is_nothrow_allocator_v) -> basic_string&{ struct insert_adapter{ size_type max; value_type val; constexpr insert_adapter& operator++(void)noexcept{ --max; return *this; } constexpr value_type operator*(void)const noexcept{ return val; } constexpr bool operator==(const insert_adapter& other)const = default; constexpr bool operator!=(const insert_adapter& other)const = default; }; return insert(pos, insert_adapter{insert_count, v}, insert_adapter{0, v}); } template REXY_CPP20_CONSTEXPR auto basic_string::insert(size_type pos, value_type v)noexcept(is_nothrow_allocator_v) -> basic_string&{ return insert(pos, size_type{1}, v); } template REXY_CPP20_CONSTEXPR auto basic_string::insert(size_type pos, const_pointer str)noexcept(is_nothrow_allocator_v) -> basic_string&{ const size_type slen = rexy::strlen(str); return insert(pos, str, str + slen); } template REXY_CPP20_CONSTEXPR auto basic_string::insert(size_type pos, const_pointer str, size_type insert_count)noexcept(is_nothrow_allocator_v) -> basic_string&{ return insert(pos, str, str + insert_count); } template REXY_CPP20_CONSTEXPR auto basic_string::insert(size_type pos, const basic_string& other)noexcept(is_nothrow_allocator_v) -> basic_string&{ return insert(pos, other.begin(), other.end()); } template REXY_CPP20_CONSTEXPR auto basic_string::insert(size_type pos, const basic_string& other, size_type index_str, size_type count)noexcept(is_nothrow_allocator_v) -> basic_string&{ return insert(pos, other.begin() + index_str, other.begin() + index_str + count); } template REXY_CPP20_CONSTEXPR auto basic_string::insert(const_iterator pos, value_type v)noexcept(is_nothrow_allocator_v) -> basic_string&{ return insert(pos, size_type{1}, v); } template REXY_CPP20_CONSTEXPR auto basic_string::insert(const_iterator pos, size_type count, value_type v)noexcept(is_nothrow_allocator_v) -> basic_string&{ return insert(pos - this->begin(), count, v); } template template REXY_CPP20_CONSTEXPR auto basic_string::insert(const_iterator pos, InIt start, InIt last)noexcept(is_nothrow_allocator_v) -> basic_string&{ return insert(pos - this->begin(), std::move(start), std::move(last)); } template REXY_CPP20_CONSTEXPR auto basic_string::insert(const_iterator pos, std::initializer_list list)noexcept(is_nothrow_allocator_v) -> basic_string&{ return insert(pos, list.begin(), list.end()); } template template REXY_CPP20_CONSTEXPR auto basic_string::insert(size_type pos, const StringView& sv)noexcept(is_nothrow_allocator_v) -> std::enable_if_t> && !std::is_convertible_v> { return insert(pos, sv.begin(), sv.end()); } template template REXY_CPP20_CONSTEXPR auto basic_string::insert(size_type pos, const StringView& sv, size_type index_str, size_type count)noexcept(is_nothrow_allocator_v) -> std::enable_if_t> && !std::is_convertible_v> { return insert(pos, sv.begin() + index_str, sv.begin() + index_str + count); } template template REXY_CPP20_CONSTEXPR auto basic_string::insert(size_type pos, InIt start, InIt last)noexcept(is_nothrow_allocator_v) -> basic_string&{ const size_type len = this->length(); size_type insert_count = 0; for(auto it = start;it != last;++it, ++insert_count){} resize(rexy::max(pos + insert_count, len + insert_count)); const size_type move_count = rexy::min(0, len - pos); const auto ptr = this->get_pointer(); for(size_type i = move_count+1;i > 0;--i){ const size_type index = i + pos; ptr[index] = ptr[index-1]; } { size_type i = 0; for(auto it = start;it != last;++it,++i){ ptr[pos+i] = *it; } } this->set_length(len + insert_count); return *this; } template REXY_CPP20_CONSTEXPR void basic_string::push_back(value_type data) noexcept(is_nothrow_allocator_v) { append(&data, 1); } template REXY_CPP20_CONSTEXPR void basic_string::append(const_pointer data, size_type len) noexcept(is_nothrow_allocator_v) { size_type mylen = this->length(); size_type mycap = this->capacity(); pointer raw = this->get_pointer(); if(mylen+len <= mycap){ rexy::memcpy(raw+mylen, data, sizeof(value_type)*len); this->set_length(mylen+len); raw[mylen+len] = 0; }else{ auto newsize = max(mylen+len, mycap*2); basic_string tmp(newsize); tmp.append(raw, mylen); tmp.append(data, len); *this = std::move(tmp); } } template REXY_CPP20_CONSTEXPR void basic_string::append(const_pointer data) noexcept(is_nothrow_allocator_v) { if(data) append(data, rexy::strlen(data)); } template template REXY_CPP20_CONSTEXPR void basic_string::append(InputIt start, InputIt fin) noexcept(is_nothrow_allocator_v) { size_type append_len = fin - start; size_type my_len = this->length(); size_type my_cap = this->capacity(); pointer raw = this->get_pointer(); if(my_len + append_len > my_cap){ *this = basic_string(raw, my_len, max(my_len+append_len, my_cap*2)); raw = this->get_pointer(); my_cap *= 2; } size_type i = 0; for(auto it = start;it != fin;++it,++i){ raw[my_len + i] = *it; } this->set_length(my_len + append_len); raw[my_len + i] = 0; } template template REXY_CPP20_CONSTEXPR auto basic_string::substring(size_type start, size_type end)const -> basic_string{ if(start > end || end > this->length()) return {}; const size_type newlen = end - start; basic_string tmp(newlen); tmp.append(this->get() + start, newlen); return tmp; } template REXY_CPP20_CONSTEXPR auto basic_string::substr(size_type start, size_type end)const -> basic_string{ return substring(start, end); } template REXY_CPP20_CONSTEXPR auto basic_string::release(void)noexcept(is_nothrow_allocator_v) -> pointer{ if(this->islong()){ pointer raw = this->get_long_ptr(); this->set_islong_flag(false); this->set_short_ptr(); this->set_short_length(0); return raw; } size_type len = this->get_short_length(); pointer raw = this->get_short_ptr(); pointer retval = this->allocate(sizeof(value_type)*len+1); rexy::memcpy(retval, raw, sizeof(value_type)*len); retval[len] = 0; raw[0] = 0; this->set_short_length(0); return retval; } template constexpr auto basic_string::create_view(void)const noexcept -> basic_string_view{ const auto ptr = this->get_pointer(); return basic_string_view(ptr, ptr + this->length()); } template constexpr auto basic_string::create_view(const_iterator start, const_iterator fin)const noexcept -> basic_string_view{ return basic_string_view(start, fin); } template REXY_CPP20_CONSTEXPR basic_string& basic_string::_copy_string(const_pointer s, size_type len) noexcept(is_nothrow_allocator_v) { if(!s || !len) return (*this = basic_string(rexy::steal(nullptr), 0, 0)); if(len <= this->length()){ this->set_length(len); pointer raw = this->get_pointer(); rexy::memcpy(raw, s, sizeof(value_type)*len); raw[len] = 0; return *this; } return (*this = basic_string(s, len)); } template constexpr auto string_cat_expr::length(void)const noexcept -> size_type{ return this->m_l.length() + this->m_r.length(); } template template REXY_CPP20_CONSTEXPR string_cat_expr::operator basic_string(void) noexcept(std::is_nothrow_constructible, typename basic_string::size_type>::value && std::is_nothrow_invocable>,decltype(*this)>::value) { size_type len = length(); basic_string ret(len); detail::string_appender> append(ret); append(*this); return ret; } } //namespace rexy #endif