Fix missing string comparisons
This commit is contained in:
parent
1ece6dccca
commit
d9f44cfeda
@ -441,15 +441,41 @@ namespace rexy{
|
|||||||
template<class Left, class Right>
|
template<class Left, class Right>
|
||||||
string_cat_expr(Left&&,Right&&) -> string_cat_expr<Left&&,Right&&>;
|
string_cat_expr(Left&&,Right&&) -> string_cat_expr<Left&&,Right&&>;
|
||||||
|
|
||||||
|
|
||||||
|
namespace detail{
|
||||||
|
template<class Left, class Right>
|
||||||
|
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<class Str>
|
||||||
|
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
|
#if __cplusplus >= 202002L
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
concept BasicString = requires(T a){
|
concept BasicString = requires(const T& a){
|
||||||
{a.length()} -> std::same_as<typename std::decay_t<T>::size_type>;
|
{std::as_const(a).length()} -> std::convertible_to<typename std::decay_t<T>::size_type>;
|
||||||
{a.c_str()} -> std::same_as<typename std::decay_t<T>::const_pointer>;
|
{std::as_const(a).c_str()} -> std::convertible_to<typename std::decay_t<T>::const_pointer>;
|
||||||
{a[0]} -> std::same_as<typename std::decay_t<T>::const_reference>;
|
{std::as_const(a)[0]} -> std::convertible_to<typename std::decay_t<T>::const_reference>;
|
||||||
{a.begin()} -> std::same_as<typename std::decay_t<T>::const_iterator>;
|
{std::as_const(a).begin()} -> std::convertible_to<typename std::decay_t<T>::const_iterator>;
|
||||||
{a.end()} -> std::same_as<typename std::decay_t<T>::const_iterator>;
|
{std::as_const(a).end()} -> std::convertible_to<typename std::decay_t<T>::const_iterator>;
|
||||||
};
|
};
|
||||||
template<class T>
|
template<class T>
|
||||||
concept StringExpr = rexy::is_template_type<T,string_cat_expr>::value;
|
concept StringExpr = rexy::is_template_type<T,string_cat_expr>::value;
|
||||||
@ -484,12 +510,47 @@ namespace rexy{
|
|||||||
//Compare
|
//Compare
|
||||||
template<BasicString Str1, BasicString Str2>
|
template<BasicString Str1, BasicString Str2>
|
||||||
constexpr bool operator==(Str1&& left, Str2&& right){
|
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<Str1>(left), std::forward<Str2>(right), left.length());
|
||||||
|
}
|
||||||
|
template<BasicString Str1>
|
||||||
|
constexpr bool operator==(Str1&& left, typename std::decay_t<Str1>::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<BasicString Str1>
|
||||||
|
constexpr bool operator==(typename std::decay_t<Str1>::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<BasicString Str1, BasicString Str2>
|
template<BasicString Str1, BasicString Str2>
|
||||||
constexpr bool operator!=(Str1&& left, Str2&& right){
|
constexpr bool operator!=(Str1&& left, Str2&& right){
|
||||||
return !(std::forward<Str1>(left) == std::forward<Str2>(right));
|
return !(std::forward<Str1>(left) == std::forward<Str2>(right));
|
||||||
}
|
}
|
||||||
|
template<BasicString Str1>
|
||||||
|
constexpr bool operator!=(Str1&& left, typename std::decay_t<Str1>::const_pointer right){
|
||||||
|
return !(std::forward<Str1>(left) == right);
|
||||||
|
}
|
||||||
|
template<BasicString Str1>
|
||||||
|
constexpr bool operator!=(typename std::decay_t<Str1>::const_pointer left, Str1&& right){
|
||||||
|
return !(left == std::forward<Str1>(right));
|
||||||
|
}
|
||||||
|
|
||||||
//String + string concat
|
//String + string concat
|
||||||
template<String Left, String Right>
|
template<String Left, String Right>
|
||||||
@ -533,7 +594,7 @@ namespace rexy{
|
|||||||
struct has_##fun##_f{ \
|
struct has_##fun##_f{ \
|
||||||
std::false_type check(...); \
|
std::false_type check(...); \
|
||||||
template<class type> \
|
template<class type> \
|
||||||
auto check(type* u) -> std::enable_if<std::is_same_v<std::declval<type>().fun(__VA_ARGS__),ret>,std::true_type>; \
|
auto check(type* u) -> std::enable_if<std::is_convertible_v<std::declval<type>().fun(__VA_ARGS__),ret>,std::true_type>; \
|
||||||
\
|
\
|
||||||
static constexpr bool value = decltype(check(std::declval<T*>()))::value; \
|
static constexpr bool value = decltype(check(std::declval<T*>()))::value; \
|
||||||
}; \
|
}; \
|
||||||
@ -545,7 +606,7 @@ namespace rexy{
|
|||||||
struct has_##opname##_f{ \
|
struct has_##opname##_f{ \
|
||||||
std::false_type check(...); \
|
std::false_type check(...); \
|
||||||
template<class type> \
|
template<class type> \
|
||||||
auto check(type* u) -> std::enable_if<std::is_same_v<std::declval<type>().operator op(__VA_ARGS__),ret>,std::true_type>; \
|
auto check(type* u) -> std::enable_if<std::is_convertible_v<std::declval<type>().operator op(__VA_ARGS__),ret>,std::true_type>; \
|
||||||
\
|
\
|
||||||
static constexpr bool value = decltype(check(std::declval<T*>()))::value; \
|
static constexpr bool value = decltype(check(std::declval<T*>()))::value; \
|
||||||
}; \
|
}; \
|
||||||
@ -590,12 +651,47 @@ namespace rexy{
|
|||||||
//Compare
|
//Compare
|
||||||
template<class Str1, class Str2, std::enable_if_t<are_strings<Str1, Str2>::value,int> = 0>
|
template<class Str1, class Str2, std::enable_if_t<are_strings<Str1, Str2>::value,int> = 0>
|
||||||
constexpr bool operator==(Str1&& left, Str2&& right){
|
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<Str1>(left), std::forward<Str2>(right), left.length());
|
||||||
|
}
|
||||||
|
template<class Str1, std::enable_if_t<are_strings<Str1>::value,int> = 0>
|
||||||
|
constexpr bool operator==(Str1&& left, typename std::decay_t<Str1>::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<class Str1, std::enable_if_t<are_strings<Str1>::value,int> = 0>
|
||||||
|
constexpr bool operator==(typename std::decay_t<Str1>::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<class Str1, class Str2, std::enable_if_t<are_strings<Str1, Str2>::value,int> = 0>
|
template<class Str1, class Str2, std::enable_if_t<are_strings<Str1, Str2>::value,int> = 0>
|
||||||
constexpr bool operator!=(Str1&& left, Str2&& right)noexcept{
|
constexpr bool operator!=(Str1&& left, Str2&& right)noexcept{
|
||||||
return !(std::forward<Str1>(left) == std::forward<Str2>(right));
|
return !(std::forward<Str1>(left) == std::forward<Str2>(right));
|
||||||
}
|
}
|
||||||
|
template<class Str1, std::enable_if_t<are_strings<Str1>::value,int> = 0>
|
||||||
|
constexpr bool operator!=(Str1&& left, typename std::decay_t<Str1>::const_pointer right)noexcept{
|
||||||
|
return !(std::forward<Str1>(left) == right);
|
||||||
|
}
|
||||||
|
template<class Str1, std::enable_if_t<are_strings<Str1>::value,int> = 0>
|
||||||
|
constexpr bool operator!=(typename std::decay_t<Str1>::const_pointer left, Str1&& right)noexcept{
|
||||||
|
return !(left == std::forward<Str1>(right));
|
||||||
|
}
|
||||||
|
|
||||||
//String + string concat
|
//String + string concat
|
||||||
template<class Left, class Right, std::enable_if_t<are_strings<Left, Right>::value,int> = 0>
|
template<class Left, class Right, std::enable_if_t<are_strings<Left, Right>::value,int> = 0>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user