/** 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 Affero 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 Affero General Public License for more details. You should have received a copy of the GNU Affero 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 "cx/utility.hpp" //max #include "detail/string_appender.hpp" #define STOP_STRICT_ALIAS_WARNING(x) (x) namespace rexy{ template constexpr basic_string::basic_string(void)noexcept{} template constexpr basic_string::basic_string(rexy::steal data)noexcept: string_base(data.value() ? cx::strlen(data.value()) : 0) { m_data = data.value(); m_length = m_cap; } 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) noexcept(noexcept(this->allocate(0))): string_base(len ? this->allocate(sizeof(Char)*(len+1)) : nullptr, len, len) { if(len){ memcpy(m_data, data, len*sizeof(Char)); m_data[len] = 0; } } template basic_string::basic_string(const_pointer data) noexcept(noexcept(this->allocate(0))): string_base(data ? cx::strlen(data) : 0) { if(m_cap){ m_data = this->allocate(sizeof(Char)*(m_cap+1)); memcpy(m_data, data, sizeof(Char)*m_cap); m_length = m_cap; } } template basic_string::basic_string(size_type len) noexcept(noexcept(this->allocate(0))): string_base(len ? this->allocate(sizeof(Char)*(len+1)) : nullptr, len) { if(len) m_data[len] = 0; } template basic_string::basic_string(size_type len, size_type cap) noexcept(noexcept(this->allocate(0))): string_base(len ? this->allocate(sizeof(Char)*(len+1)) : nullptr, len, cap) { if(len) m_data[len] = 0; } //normal copy and move ctors template basic_string::basic_string(const basic_string& b) noexcept(noexcept(this->allocate(0))): string_base(b.m_length ? this->allocate(sizeof(Char)*(b.m_length+1)) : nullptr, b.m_length, b.m_length) { if(b.m_length) memcpy(m_data, b.m_data, sizeof(Char)*(b.m_length+1)); } template constexpr basic_string::basic_string(basic_string&& s) noexcept(noexcept(cx::exchange(s.m_data, nullptr))): string_base(cx::exchange(s.m_data, nullptr), s.m_length, s.m_cap){} template template basic_string::basic_string(const string_base& b) noexcept(noexcept(this->allocate(0))): string_base(b.length() ? this->allocate(sizeof(Char)*(b.length()+1)) : nullptr, b.length(), b.length()) { if(b.length()) memcpy(m_data, b.get(), sizeof(Char)*(b.length()+1)); } //dtor template basic_string::~basic_string(void) noexcept(noexcept(this->deallocate(nullptr, 0))) { this->deallocate(m_data, sizeof(Char)*(m_cap+1)); } template basic_string& basic_string::operator=(const basic_string& s) noexcept(noexcept(this->allocate(0)) && noexcept(this->deallocate(nullptr, 0))) { if(s.m_length < m_cap){ memcpy(m_data, s.m_data, sizeof(Char)*(s.m_length+1)); m_length = s.m_length; return *this; } basic_string tmp(s); return (*this = std::move(tmp)); } template constexpr basic_string& basic_string::operator=(basic_string&& s)noexcept{ cx::swap(m_data, s.m_data); m_length = s.m_length; m_cap = s.m_cap; return *this; } //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, cx::strlen(c)); } //Copy from other string_base template template basic_string& basic_string::operator=(const string_base& s) noexcept(noexcept(this->allocate(0)) && noexcept(this->deallocate(nullptr,0))) { return _copy_string(s.get(), s.length()); } //Replace managed pointer. Frees existing value template void basic_string::reset(pointer val) noexcept(noexcept(this->deallocate(nullptr,0))) { this->deallocate(m_data,sizeof(Char)*(m_cap+1)); m_data = val; m_length = val ? cx::strlen(val) : 0; m_cap = m_length; } template void basic_string::reset(pointer val, size_type len) noexcept(noexcept(this->deallocate(nullptr,0))) { this->deallocate(m_data,sizeof(Char)*(m_cap+1)); m_data = val; m_length = len; m_cap = len; } template bool basic_string::resize(size_type newsize) noexcept(noexcept(this->allocate(0)) && noexcept(this->deallocate(nullptr,0))) { if(newsize < m_cap) return false; return (*this = basic_string(m_data, newsize)); } template void basic_string::append(const_pointer data, size_type len) noexcept(noexcept(this->allocate(0)) && noexcept(this->deallocate(nullptr,0))) { if(len+m_length <= m_cap){ memcpy(m_data+m_length, data, sizeof(Char)*len); m_length += len; m_data[m_length] = 0; }else if(!m_data){ *this = basic_string(len, len); memcpy(m_data, data, sizeof(Char)*len); m_data[len] = 0; }else{ auto newsize = cx::max(m_length+len, m_cap*2); basic_string tmp(newsize); tmp.append(m_data, m_length); 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, cx::strlen(data)); } template template void basic_string::append(const string_base& s) noexcept(noexcept(this->allocate(0)) && noexcept(this->deallocate(nullptr,0))) { append(s.get(), s.length()); } 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 <= m_length){ m_length = len; memcpy(m_data, s, sizeof(Char)*len); m_data[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(const_pointer str, size_type len)noexcept: string_base(const_cast(str), len, len){} template constexpr static_string::static_string(const static_string& s)noexcept: string_base(s.m_data, s.m_length, s.m_length){} template constexpr static_string::static_string(static_string&& s)noexcept: string_base(s.m_data, s.m_length, s.m_length){} template constexpr static_string& static_string::operator=(const static_string& s)noexcept{ m_data = s.m_data; m_length = s.m_length; m_cap = s.m_cap; return *this; } template constexpr static_string::static_string(const_pointer c)noexcept: static_string(c, cx::strlen(c)){} template constexpr static_string& static_string::operator=(const_pointer c)noexcept{ m_data = const_cast(c); m_length = cx::strlen(c); m_cap = m_length; return *this; } template constexpr static_string& static_string::operator=(static_string&& s)noexcept{ m_data = s.m_data; m_length = s.m_length; m_cap = s.m_cap; 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