/** 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 //forward, move, swap, etc #include //memcpy #include //strlen, strcpy #include "utility.hpp" //max #include "detail/string_appender.hpp" #include "algorithm.hpp" #include "compat/to_address.hpp" #include "string_view.hpp" #ifdef __cpp_concepts #include "compat/cpp20/string_base.hpp" #else #include "compat/cpp17/string_base.hpp" #endif 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 = 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 = 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 = 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 = 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(noexcept(this->allocate(0))) { 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) 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) 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() ? 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(noexcept(this->allocate(0))) { _copy_construct_string(data, len, cap); } template REXY_CPP20_CONSTEXPR basic_string::basic_string(const_pointer data, size_type len) noexcept(noexcept(this->allocate(0))): basic_string(data, len, len){} template REXY_CPP20_CONSTEXPR basic_string::basic_string(const_pointer data) noexcept(noexcept(this->allocate(0))): basic_string(data, data ? strlen(data) : 0){} template REXY_CPP20_CONSTEXPR basic_string::basic_string(size_type cap) noexcept(noexcept(this->allocate(0))): basic_string(size_type{0}, cap){} template REXY_CPP20_CONSTEXPR basic_string::basic_string(size_type len, size_type cap) noexcept(noexcept(this->allocate(0))) { _copy_construct_string(nullptr, len, cap); } template REXY_CPP20_CONSTEXPR basic_string::basic_string(const basic_string_view& sv) noexcept(noexcept(this->allocate(0))) { _copy_construct_string(sv.c_str(), sv.length(), sv.length()); } template template REXY_CPP20_CONSTEXPR basic_string::basic_string(InputIt start, InputIt fin) noexcept(noexcept(this->allocate(0))): 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(noexcept(this->allocate(0))): detail::hasallocator(b) { _copy_construct_string(b.get(), b.length(), b.capacity()); } 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(noexcept(this->allocate(0))) { _copy_construct_string(b.get(), b.length(), b.capacity()); } //dtor template REXY_CPP20_CONSTEXPR basic_string::~basic_string(void) noexcept(noexcept(this->deallocate(nullptr, 0))) { 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(noexcept(this->allocate(0)) && noexcept(this->deallocate(nullptr, 0))) { if(s.length() < this->capacity()){ memcpy(this->get_pointer(), s.get_pointer(), sizeof(value_type)*(s.length()+1)); this->set_length(s.length()); return *this; } 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(noexcept(this->allocate(0)) && noexcept(this->deallocate(nullptr,0))) { return (*this = basic_string(s)); } //Copy from c string template REXY_CPP20_CONSTEXPR basic_string& basic_string::operator=(const basic_string_view& sv) noexcept(noexcept(this->allocate(0)) && noexcept(this->deallocate(nullptr,0))) { return _copy_string(sv.c_str(), sv.length()); } template REXY_CPP20_CONSTEXPR basic_string& basic_string::operator=(const_pointer c) noexcept(noexcept(this->allocate(0)) && noexcept(this->deallocate(nullptr,0))) { return _copy_string(c, strlen(c)); } //Replace managed pointer. Frees existing value template REXY_CPP20_CONSTEXPR void basic_string::reset(pointer val) noexcept(noexcept(this->deallocate(nullptr,0))) { reset(val, val ? strlen(val) : 0); } template REXY_CPP20_CONSTEXPR void basic_string::reset(pointer val, size_type len) noexcept(noexcept(this->deallocate(nullptr,0))) { 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(noexcept(this->allocate(0)) && noexcept(this->deallocate(nullptr,0))) { 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 void basic_string::append(const_pointer data, size_type len) noexcept(noexcept(this->allocate(0)) && noexcept(this->deallocate(nullptr,0))) { size_type mylen = this->length(); size_type mycap = this->capacity(); pointer raw = this->get_pointer(); if(mylen+len <= mycap){ 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(noexcept(this->allocate(0)) && noexcept(this->deallocate(nullptr,0))) { if(data) append(data, strlen(data)); } template template REXY_CPP20_CONSTEXPR void basic_string::append(InputIt start, InputIt fin) noexcept(noexcept(this->allocate(0)) && noexcept(this->deallocate(nullptr,0))) { 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::release(void)noexcept(noexcept(this->allocate(0))) -> 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); 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(noexcept(this->allocate(0)) && noexcept(this->deallocate(nullptr,0))) { 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(); 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