/** 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 #define STOP_STRICT_ALIAS_WARNING(x) (x) namespace rexy{ template constexpr string_intermediary::string_intermediary(void)noexcept{} template constexpr string_intermediary::string_intermediary(rexy::steal data)noexcept: string_base(data.value() ? cx::strlen(data.value()) : 0) { m_data = data.value(); m_length = m_cap; } template constexpr string_intermediary::string_intermediary(rexy::steal data, size_t len)noexcept: string_base(data.value(), len){} template constexpr string_intermediary::string_intermediary(rexy::steal data, size_t len, size_t cap)noexcept: string_base(data.value(), len, cap){} template /*deprecated*/ constexpr string_intermediary::string_intermediary(char* data, size_t len)noexcept: string_base(data, len){} template /*deprecated*/ constexpr string_intermediary::string_intermediary(char* data, size_t len, size_t cap)noexcept: string_base(data, len, cap){} template string_intermediary::string_intermediary(const char* data, size_t len) noexcept(noexcept(Allocator::copy(data,len))): string_base(reinterpret_cast(len ? Allocator::copy(data, len+1) : nullptr), len) { m_data[len] = 0; } template string_intermediary::string_intermediary(const char* data) noexcept(noexcept(strlen(data)) && noexcept(Allocator::copy(data, m_cap))): string_base(data ? strlen(data) : 0) { if(m_cap){ m_data = reinterpret_cast(Allocator::copy(data, m_cap+1)); m_length = m_cap; } } template string_intermediary::string_intermediary(size_t len) noexcept(noexcept(Allocator::allocate(len))): string_base(reinterpret_cast(len ? Allocator::allocate(len+1) : nullptr), len) { m_data[len] = 0; } template string_intermediary::string_intermediary(size_t len, size_t cap) noexcept(noexcept(Allocator::allocate(len))): string_base(reinterpret_cast(len ? Allocator::allocate(len+1) : nullptr), len, cap) { m_data[len] = 0; } //normal copy and move ctors template string_intermediary::string_intermediary(const string_intermediary& b) noexcept(noexcept(Allocator::copy(b.m_data, b.m_length))): string_base(reinterpret_cast(b.m_length ? Allocator::copy(b.m_data, b.m_length+1) : nullptr), b.m_length, b.m_cap){} template constexpr string_intermediary::string_intermediary(string_intermediary&& s) noexcept(noexcept(cx::exchange(s.m_data, nullptr))): string_base(cx::exchange(s.m_data, nullptr), s.m_length, s.m_cap){} template string_intermediary::string_intermediary(const string_base& b) noexcept(noexcept(Allocator::copy(b.get(), b.length()))): string_base(reinterpret_cast(b.length() ? Allocator::copy(b.get(), b.length()+1) : nullptr), b.length(), b.capacity()){} //dtor template string_intermediary::~string_intermediary(void) noexcept(noexcept(Allocator::free(m_data))) { Allocator::free(m_data); } template string_intermediary& string_intermediary::operator=(const string_intermediary& s) noexcept(std::is_nothrow_copy_constructible>::value && std::is_nothrow_move_assignable>::value) { if(s.m_length < m_length){ memcpy(m_data, s.m_data, s.m_length+1); m_length = s.m_length; return *this; } string_intermediary tmp(s); return (*this = std::move(tmp)); } template constexpr string_intermediary& string_intermediary::operator=(string_intermediary&& s) noexcept(noexcept(cx::swap(m_data, s.m_data))) { cx::swap(m_data, s.m_data); m_length = s.m_length; m_cap = s.m_cap; return *this; } //Copy from c string template string_intermediary& string_intermediary::operator=(const char* c) noexcept(noexcept(_copy_string(c, 0))) { return _copy_string(c, strlen(c)); } //Copy from other string_base template string_intermediary& string_intermediary::operator=(const string_base& s) noexcept(noexcept(_copy_string(s.get(), 0))) { return _copy_string(s.get(), s.length()); } //Replace managed pointer. Frees existing value template void string_intermediary::reset(char* val) noexcept(noexcept(Allocator::free(m_data))) { Allocator::free(m_data); m_data = val; m_length = val ? strlen(val) : 0; m_cap = m_length; } template void string_intermediary::reset(char* val, size_t len) noexcept(noexcept(Allocator::free(m_data))) { Allocator::free(m_data); m_data = val; m_length = len; m_cap = len; } template bool string_intermediary::resize(size_t newsize) noexcept(std::is_nothrow_copy_constructible>::value && std::is_nothrow_move_assignable>::value) { if(newsize < m_cap) return false; string_intermediary tmp(newsize); if(m_data){ memcpy(tmp.get(), m_data, m_length); tmp[m_length] = 0; } *this = std::move(tmp); return true; } template void string_intermediary::append(const char* data, size_t len) noexcept(std::is_nothrow_constructible,decltype(m_length)>::value) { if(len+m_length <= m_cap){ memcpy(m_data+m_length, data, len); m_length += len; m_data[m_length] = 0; }else{ string_intermediary tmp(cx::max(m_length + len, m_cap*2)); if(m_data) memcpy(STOP_STRICT_ALIAS_WARNING(tmp).m_data, m_data, m_length); memcpy(STOP_STRICT_ALIAS_WARNING(tmp).m_data+m_length, data, len); STOP_STRICT_ALIAS_WARNING(tmp).m_length = len+m_length; tmp[m_length+len] = 0; *this = std::move(tmp); } } template void string_intermediary::append(const char* data) noexcept(std::is_nothrow_constructible,decltype(m_length)>::value) { if(data) append(data, strlen(data)); } template void string_intermediary::append(const string_base& s) noexcept(std::is_nothrow_constructible,decltype(m_length)>::value) { append(s.get(), s.length()); } template string_intermediary& string_intermediary::_copy_string(const char* s, size_t len) noexcept(noexcept(Allocator::free(m_data)) && noexcept(Allocator::copy(s, len))) { if(!len){ Allocator::free(m_data); m_length = 0; m_cap = 0; return *this; } if(len <= m_length){ strcpy(m_data, s); }else{ Allocator::free(m_data); m_cap = cx::max(len, m_cap*2); m_data = reinterpret_cast(Allocator::copy(s, m_cap+1)); if(!m_data){ m_length = 0; m_cap = 0; return *this; } } m_length = len; return *this; } template template constexpr string_cat_expr::string_cat_expr(T&& l, U&& r) noexcept(std::is_nothrow_constructible::value && std::is_nothrow_constructible::value): m_l(std::forward(l)), m_r(std::forward(r)){} template constexpr string_cat_expr::string_cat_expr(string_cat_expr&& s) noexcept(std::is_nothrow_constructible::value && std::is_nothrow_constructible::value): m_l(std::forward(s.m_l)), m_r(std::forward(s.m_r)){} template constexpr size_t string_cat_expr::length(void)const noexcept(noexcept(m_l.length()) && noexcept(m_r.length())) { return m_l.length() + m_r.length(); } template template string_cat_expr::operator string_intermediary(void) noexcept(std::is_nothrow_constructible, size_t>::value && std::is_nothrow_invocable>,decltype(*this)>::value) { size_t len = length(); string_intermediary ret(len); detail::string_appender> append(ret); append(*this); return ret; } template constexpr const Left& string_cat_expr::left(void)const noexcept{ return m_l; } template constexpr const Right& string_cat_expr::right(void)const noexcept{ return m_r; } constexpr static_string::static_string(const char* str, size_t len)noexcept: string_base(const_cast(str), len, len){} constexpr static_string::static_string(const static_string& s)noexcept: string_base(s.m_data, s.m_length, s.m_length){} constexpr static_string::static_string(static_string&& s)noexcept: string_base(s.m_data, s.m_length, s.m_length){} constexpr static_string& static_string::operator=(const static_string& s)noexcept{ m_data = s.m_data; m_length = s.m_length; return *this; } constexpr static_string::static_string(const char* c)noexcept: static_string(const_cast(c), cx::strlen(c)){} constexpr static_string& static_string::operator=(const char* c)noexcept{ m_data = const_cast(c); m_length = cx::strlen(c); return *this; } constexpr static_string& static_string::operator=(static_string&& s)noexcept{ m_data = s.m_data; m_length = s.m_length; return *this; } namespace detail{ template constexpr string_appender::string_appender(Targ& t)noexcept: m_targ(t){} template template constexpr void string_appender::operator()(const string_cat_expr& str) noexcept(noexcept((*this)(str.left())) && noexcept((*this)(str.right()))) { (*this)(str.left()); (*this)(str.right()); } template template::value,int>> constexpr void string_appender::operator()(Str&& str) noexcept(noexcept(m_targ.append(str.get(), str.length()))) { m_targ.append(str.get(), str.length()); } } } //namespace rexy #undef STOP_STRICT_ALIAS_WARNING #endif