/** This file is a part of rexy's general purpose library Copyright (C) 2020 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" #define STOP_STRICT_ALIAS_WARNING(x) (x) 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 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 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 basic_string::basic_string(const_pointer data, size_type len) noexcept(noexcept(this->allocate(0))): basic_string(data, len, len){} template basic_string::basic_string(const_pointer data) noexcept(noexcept(this->allocate(0))): basic_string(data, data ? strlen(data) : 0){} template basic_string::basic_string(size_type cap) noexcept(noexcept(this->allocate(0))): basic_string(size_type{0}, cap){} template basic_string::basic_string(size_type len, size_type cap) noexcept(noexcept(this->allocate(0))) { _copy_construct_string(nullptr, len, cap); } //normal copy and move ctors template 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 basic_string::basic_string(const string_base& b) noexcept(noexcept(this->allocate(0))) { _copy_construct_string(b.get(), b.length(), b.capacity()); } //dtor template 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 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 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 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 void basic_string::reset(pointer val) noexcept(noexcept(this->deallocate(nullptr,0))) { reset(val, val ? strlen(val) : 0); } template 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 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 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 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 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 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 basic_string& basic_string::_copy_string(const_pointer s, size_type len) noexcept(noexcept(this->allocate(0)) && noexcept(this->deallocate(nullptr,0))) { if(!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 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; } template constexpr static_string::static_string(void)noexcept: static_string(nullptr, 0){} template constexpr static_string::static_string(const_pointer str, size_type len)noexcept{ if(!str) this->set_long_ptr(nullptr); else this->set_long_ptr(const_cast(str)); this->set_long_length(len); this->set_long_capacity(len); } template constexpr static_string::static_string(const static_string& s)noexcept: static_string(s.get_long_ptr(), s.get_long_length()){} template constexpr static_string::static_string(static_string&& s)noexcept: static_string(s.get_long_ptr(), s.get_long_length()){} template constexpr static_string& static_string::operator=(const static_string& s)noexcept{ this->set_long_ptr(const_cast(s.get_long_ptr())); this->set_long_length(s.get_long_length()); this->set_long_capacity(s.get_long_capacity()); return *this; } template constexpr static_string::static_string(const_pointer c)noexcept: static_string(c, strlen(c)){} template constexpr static_string& static_string::operator=(const_pointer c)noexcept{ size_type len = strlen(c); this->set_long_ptr(const_cast(c)); this->set_long_length(len); this->set_long_capacity(len); return *this; } template constexpr static_string& static_string::operator=(static_string&& s)noexcept{ this->set_long_ptr(s.get_long_ptr()); this->set_long_length(s.get_long_length()); this->set_long_capacity(s.get_long_capacity()); return *this; } extern template class static_string; extern template class static_string; extern template class static_string; extern template class static_string; } //namespace rexy #undef STOP_STRICT_ALIAS_WARNING #endif