From d9f44cfeda099dc35aa841d23225b2ffb8164e4d Mon Sep 17 00:00:00 2001 From: rexy712 Date: Sat, 21 May 2022 22:42:21 -0700 Subject: [PATCH] Fix missing string comparisons --- include/rexy/string_base.hpp | 116 ++++++++++++++++++++++++++++++++--- 1 file changed, 106 insertions(+), 10 deletions(-) diff --git a/include/rexy/string_base.hpp b/include/rexy/string_base.hpp index 54feaf7..ba4f028 100644 --- a/include/rexy/string_base.hpp +++ b/include/rexy/string_base.hpp @@ -441,15 +441,41 @@ namespace rexy{ template string_cat_expr(Left&&,Right&&) -> string_cat_expr; + + namespace detail{ + template + constexpr int string_compare(Left&& left, Right&& right, size_t maxlen){ + for(size_t i = 0;i < maxlen;++i){ + const auto diff = left[i] - right[i]; + if(diff != 0){ + return diff; + } + if(left[i] == 0 || right[i] == 0){ + return diff; + } + } + return 0; + } + template + constexpr size_t string_len(const Str* str){ + if(!str){ + return 0; + } + size_t i; + for(i = 0;str[i] != 0;++i); + return i; + } + } + #if __cplusplus >= 202002L template - concept BasicString = requires(T a){ - {a.length()} -> std::same_as::size_type>; - {a.c_str()} -> std::same_as::const_pointer>; - {a[0]} -> std::same_as::const_reference>; - {a.begin()} -> std::same_as::const_iterator>; - {a.end()} -> std::same_as::const_iterator>; + concept BasicString = requires(const T& a){ + {std::as_const(a).length()} -> std::convertible_to::size_type>; + {std::as_const(a).c_str()} -> std::convertible_to::const_pointer>; + {std::as_const(a)[0]} -> std::convertible_to::const_reference>; + {std::as_const(a).begin()} -> std::convertible_to::const_iterator>; + {std::as_const(a).end()} -> std::convertible_to::const_iterator>; }; template concept StringExpr = rexy::is_template_type::value; @@ -484,12 +510,47 @@ namespace rexy{ //Compare template constexpr bool operator==(Str1&& left, Str2&& right){ - return left.length() == right.length() && !strcmp(left.c_str(), right.c_str()); + if(left.length() != right.length()){ + return false; + } + return !detail::string_compare(std::forward(left), std::forward(right), left.length()); + } + template + constexpr bool operator==(Str1&& left, typename std::decay_t::const_pointer right){ + if(right == nullptr){ + return false; + } + const auto rlen = detail::string_len(right); + if(rlen != left.length()){ + return false; + } + const auto minlen = min(left.length(), rlen); + return !detail::string_compare(left.c_str(), right, minlen+1); + } + template + constexpr bool operator==(typename std::decay_t::const_pointer left, Str1&& right){ + if(left == nullptr){ + return false; + } + const auto llen = detail::string_len(left); + if(llen != right.length()){ + return false; + } + const auto minlen = min(right.length(), llen); + return !detail::string_compare(right.c_str(), left, minlen+1); } template constexpr bool operator!=(Str1&& left, Str2&& right){ return !(std::forward(left) == std::forward(right)); } + template + constexpr bool operator!=(Str1&& left, typename std::decay_t::const_pointer right){ + return !(std::forward(left) == right); + } + template + constexpr bool operator!=(typename std::decay_t::const_pointer left, Str1&& right){ + return !(left == std::forward(right)); + } //String + string concat template @@ -533,7 +594,7 @@ namespace rexy{ struct has_##fun##_f{ \ std::false_type check(...); \ template \ - auto check(type* u) -> std::enable_if().fun(__VA_ARGS__),ret>,std::true_type>; \ + auto check(type* u) -> std::enable_if().fun(__VA_ARGS__),ret>,std::true_type>; \ \ static constexpr bool value = decltype(check(std::declval()))::value; \ }; \ @@ -545,7 +606,7 @@ namespace rexy{ struct has_##opname##_f{ \ std::false_type check(...); \ template \ - auto check(type* u) -> std::enable_if().operator op(__VA_ARGS__),ret>,std::true_type>; \ + auto check(type* u) -> std::enable_if().operator op(__VA_ARGS__),ret>,std::true_type>; \ \ static constexpr bool value = decltype(check(std::declval()))::value; \ }; \ @@ -590,12 +651,47 @@ namespace rexy{ //Compare template::value,int> = 0> constexpr bool operator==(Str1&& left, Str2&& right){ - return left.length() == right.length() && !strcmp(left.c_str(), right.c_str()); + if(left.length() != right.length()){ + return false; + } + return !detail::string_compare(std::forward(left), std::forward(right), left.length()); + } + template::value,int> = 0> + constexpr bool operator==(Str1&& left, typename std::decay_t::const_pointer right){ + if(right == nullptr){ + return false; + } + const auto rlen = detail::string_len(right); + if(rlen != left.length()){ + return false; + } + const auto minlen = min(left.length(), rlen); + return !detail::string_compare(left.c_str(), right, minlen+1); + } + template::value,int> = 0> + constexpr bool operator==(typename std::decay_t::const_pointer left, Str1&& right){ + if(left == nullptr){ + return false; + } + const auto llen = detail::string_len(left); + if(llen != right.length()){ + return false; + } + const auto minlen = min(right.length(), llen); + return !detail::string_compare(right.c_str(), left, minlen+1); } template::value,int> = 0> constexpr bool operator!=(Str1&& left, Str2&& right)noexcept{ return !(std::forward(left) == std::forward(right)); } + template::value,int> = 0> + constexpr bool operator!=(Str1&& left, typename std::decay_t::const_pointer right)noexcept{ + return !(std::forward(left) == right); + } + template::value,int> = 0> + constexpr bool operator!=(typename std::decay_t::const_pointer left, Str1&& right)noexcept{ + return !(left == std::forward(right)); + } //String + string concat template::value,int> = 0>