/** This file is a part of rexy's general purpose library Copyright (C) 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_COMPAT_CPP17_STRING_BASE_HPP #define REXY_COMPAT_CPP17_STRING_BASE_HPP #include "../../string_base.hpp" #include //forward #include //{false,true}_type, declval, enable_if, remove_reference, decay #include //lexicographically_compare #include "../../utility.hpp" //strlen, strncmp #include "../../traits.hpp" namespace rexy{ template class string_cat_expr; template class basic_string; template class basic_string_view; #define REXY_HAS_MEMFUN_WITH_RET(type, ret, fun, ...) \ template \ struct has_##fun##_f{ \ static std::false_type check(...); \ template \ static auto check(type* u) -> std::enable_if_t().fun(__VA_ARGS__)),ret>,std::true_type>; \ \ static constexpr bool value = decltype(check(std::declval*>()))::value; \ }; \ template \ static constexpr bool has_##fun##_f_v = has_##fun##_f::value #define REXY_HAS_MEMOP_WITH_RET(type, ret, opname, op, ...) \ template \ struct has_##opname##_f{ \ static std::false_type check(...); \ template \ static auto check(type* u) -> std::enable_if_t().operator op(__VA_ARGS__)),ret>,std::true_type>; \ \ static constexpr bool value = decltype(check(std::declval*>()))::value; \ }; \ template \ static constexpr bool has_##opname##_f_v = has_##opname##_f::value REXY_HAS_MEMFUN_WITH_RET(U, typename U::size_type, length); REXY_HAS_MEMFUN_WITH_RET(U, typename U::const_pointer, c_str); REXY_HAS_MEMOP_WITH_RET(U, typename U::const_reference, indexop, [], 0); REXY_HAS_MEMFUN_WITH_RET(U, typename U::const_iterator, begin); REXY_HAS_MEMFUN_WITH_RET(U, typename U::const_iterator, end); #undef REXY_HAS_MEMFUN_WITH_RET #undef REXY_HAS_MEMOP_WITH_RET template struct is_basic_string{ template static std::true_type check(const basic_string*); static std::false_type check(...); static constexpr bool value = decltype(check(std::declval*>()))::value; }; template struct is_basic_string_view{ template static std::true_type check(const basic_string_view*); static std::false_type check(...); static constexpr bool value = decltype(check(std::declval*>()))::value; }; template struct is_basic_string_expr{ template static std::true_type check(const string_cat_expr*); static std::false_type check(...); static constexpr bool value = decltype(check(std::declval*>()))::value; }; template struct is_string{ static constexpr bool value = (is_basic_string::value || is_basic_string_view::value) && (has_length_f_v && has_c_str_f_v && has_indexop_f_v && has_begin_f_v && has_end_f_v); }; template static constexpr bool is_string_v = is_string::value; template struct are_strings{ static constexpr bool value = (is_string::value && ...); }; template static constexpr bool are_strings_v = are_strings::value; template struct is_string_expr{ static constexpr bool value = is_basic_string_expr::value; }; template static constexpr bool is_string_expr_v = is_string_expr::value; template struct are_string_expr{ static constexpr bool value = (is_string_expr::value && ...); }; template static constexpr bool are_string_expr_v = are_string_expr::value; //Compare template::value,int> = 0> constexpr bool operator==(const Str1& left, const Str2& right){ if(left.length() != right.length()){ return false; } return !rexy::strncmp(left.c_str(), right.c_str(), left.length()+1); } template::value,int> = 0> constexpr bool operator==(const Str1& left, typename std::decay_t::const_pointer right){ if(right == nullptr){ return false; } const rexy::basic_string_view rstr(right); if(rstr.length() != left.length()){ return false; } return !rexy::strncmp(left.c_str(), rstr.c_str(), left.length()); } template::value,int> = 0> constexpr bool operator==(typename std::decay_t::const_pointer left, const Str1& right){ if(left == nullptr){ return false; } const rexy::basic_string_view lstr(left); if(lstr.length() != right.length()){ return false; } return !rexy::strncmp(lstr.c_str(), right.c_str(), right.length()); } template::value,int> = 0> constexpr bool operator!=(const Str1& left, const Str2& right)noexcept{ return !(left == right); } template::value,int> = 0> constexpr bool operator!=(const Str1& left, typename std::decay_t::const_pointer right)noexcept{ return !(left == right); } template::value,int> = 0> constexpr bool operator!=(typename std::decay_t::const_pointer left, const Str1& right)noexcept{ return !(left == right); } template::value,int> = 0> constexpr bool operator<(const Str1& left, const Str2& right)noexcept{ return std::lexicographical_compare(left.begin(), left.end(), right.begin(), right.end()); } template::value,int> = 0> constexpr bool operator<=(const Str1& left, const Str2& right)noexcept{ return !(right < left); } template::value,int> = 0> constexpr bool operator>(const Str1& left, const Str2& right)noexcept{ return (right < left); } template::value,int> = 0> constexpr bool operator>=(const Str1& left, const Str2& right)noexcept{ return !(left < right); } //String + string concat template::value,int> = 0> constexpr auto operator+(Left&& l, Right&& r) //uses deduction guide whereas std::is_nothrow_constructible couldn't noexcept(noexcept(::new (nullptr) string_cat_expr(std::forward(l), std::forward(r)))) { return string_cat_expr(std::forward(l), std::forward(r)); } //String + char pointer template::value,int> = 0> constexpr auto operator+(typename std::decay_t::const_pointer left, Right&& right) noexcept(noexcept(::new (nullptr) string_cat_expr(rexy::basic_string_view(left), std::forward(right)))) { return string_cat_expr(rexy::basic_string_view(left), std::forward(right)); } //Char pointer + string template::value,int> = 0> constexpr auto operator+(Left&& left, typename std::decay_t::const_pointer right) noexcept(noexcept(::new (nullptr) string_cat_expr(std::forward(left), rexy::basic_string_view(right)))) { return rexy::string_cat_expr(std::forward(left), rexy::basic_string_view(right)); } //String + expr concat template::value && is_string_expr::value,int> = 0> constexpr auto operator+(Left&& left, Right&& right){ return string_cat_expr(std::forward(left), std::forward(right)); } //Expr + string template::value && is_string::value,int> = 0> constexpr auto operator+(Left&& left, Right&& right){ return string_cat_expr(std::forward(left), std::forward(right)); } //Expr + expr template::value,int> = 0> constexpr auto operator+(Left&& left, Right&& right){ return string_cat_expr(std::forward(left), std::forward(right)); } //Expr + char pointer template::value,int> = 0> constexpr auto operator+(Left&& left, typename std::decay_t::const_pointer right){ return string_cat_expr(std::forward(left), rexy::basic_string_view(right)); } //char pointer + Expr template::value,int> = 0> constexpr auto operator+(typename std::decay_t::const_pointer left, Right&& right){ return string_cat_expr(rexy::basic_string_view(left), std::forward(right)); } //String concat assignment template::value,int> = 0> decltype(auto) operator+=(Left& l, Right&& r) noexcept(noexcept(l + std::forward(r)) && std::is_nothrow_assignable(r))>::value) { return l = (l + std::forward(r)); } template::value && is_string_expr::value,int> = 0> decltype(auto) operator+=(Left& l, Right&& r) noexcept(noexcept(l + std::forward(r)) && std::is_nothrow_assignable(r))>::value) { return l = (l + std::forward(r)); } template::value, int> = 0> decltype(auto) operator+=(Left& l, typename std::decay_t::const_pointer r) noexcept(noexcept(l + r) && std::is_nothrow_assignable::value) { return l = (l + r); } template::value, int> = 0> constexpr std::size_t find_first_of(T&& t, const Char* c, std::size_t start, std::size_t size)noexcept{ if(start > t.length()){ return rexy::npos; } for(auto it = t.cbegin() + start;it != t.cend();++it){ for(std::size_t i = 0;i < size;++i){ if(*it == c[i]){ return it - t.cbegin(); } } } return rexy::npos; } template::value, int> = 0> constexpr std::size_t find_first_not_of(T&& t, const Char* c, std::size_t start, std::size_t size)noexcept{ if(start > t.length()){ return rexy::npos; } for(auto it = t.cbegin() + start;it != t.cend();++it){ bool found = false; for(std::size_t i = 0;i < size;++i){ if(*it == c[i]){ found = true; break; } } if(!found){ return it - t.cbegin(); } } return rexy::npos; } template::value, int> = 0> constexpr std::size_t find_last_of(T&& t, const Char* c, std::size_t start, std::size_t size)noexcept{ if(start > t.length()){ return rexy::npos; } const auto b = t.cend() - 1; const auto e = t.cbegin() - 1 - start; for(auto it = b;it != e;--it){ for(std::size_t i = 0;i < size;++i){ if(*it == c[i]){ return it - t.cbegin(); } } } return rexy::npos; } template::value, int> = 0> constexpr std::size_t find_last_not_of(T&& t, const Char* c, std::size_t start, std::size_t size)noexcept{ if(start > t.length()){ return rexy::npos; } const auto b = t.cend() - 1; const auto e = t.cbegin() - 1 - start; for(auto it = b;it != e;--it){ bool found = false; for(std::size_t i = 0;i < size;++i){ if(*it == c[i]){ found = true; break; } } if(!found){ return it - t.cbegin(); } } return rexy::npos; } } #endif