Improve constexpr-ness of strings

This commit is contained in:
rexy712 2020-04-23 14:40:51 -07:00
parent 6c142c990d
commit de681d3cd7
2 changed files with 54 additions and 40 deletions

View File

@ -81,11 +81,11 @@ namespace rexy{
constexpr string_intermediary(void);
constexpr string_intermediary(rexy::steal<char*> data, size_t len);
constexpr string_intermediary(rexy::steal<char*> data, size_t len, size_t cap);
[[deprecated]] string_intermediary(char* data, size_t len);
[[deprecated]] constexpr string_intermediary(char* data, size_t len);
string_intermediary(const char* data, size_t len);
[[deprecated]] constexpr string_intermediary(char* data, size_t len, size_t cap);
string_intermediary(const char* data);
string_intermediary(rexy::steal<char*>);
constexpr string_intermediary(rexy::steal<char*>);
string_intermediary(size_t len);
string_intermediary(size_t len, size_t cap);
@ -99,7 +99,7 @@ namespace rexy{
~string_intermediary(void);
string_intermediary& operator=(const string_intermediary& s);
string_intermediary& operator=(string_intermediary&& s);
constexpr string_intermediary& operator=(string_intermediary&& s);
//Copy from c string
string_intermediary& operator=(const char* c);
//Copy from other string_base
@ -182,19 +182,11 @@ namespace rexy{
static constexpr bool value = std::is_same<std::true_type,decltype(is_string_base(std::declval<typename std::decay<T>::type*>()))>::value;
};
//check for member function 'length'
template<class T>
struct has_len{
template<class U, class V>
struct check;
template<class... Ts>
using enable_if_string = std::enable_if_t<(is_string<Ts>::value && ...),int>;
template<class... Ts>
using enable_if_concrete_string = std::enable_if_t<(is_concrete_string<Ts>::value && ...),int>;
template<class U>
static std::true_type test(check<U,decltype(&U::length)>*);
template<class U>
static std::false_type test(...);
static constexpr bool value = std::is_same<std::true_type,decltype(test<T>(0))>::value;
};
template<class Targ>
struct appender
{
@ -206,39 +198,35 @@ namespace rexy{
void operator()(const string_cat_expr<L,R>& str);
void operator()(const string_base& str);
};
}
template<class Str1, class Str2, std::enable_if_t<detail::is_concrete_string<Str1>::value &&
detail::is_concrete_string<Str2>::value,int> = 0>
} //namespace detail
template<class Str1, class Str2, detail::enable_if_concrete_string<Str1,Str2> = 0>
bool operator==(Str1&& left, Str2&& right){
return left.valid() && right.valid() && left.length() == right.length() && !strcmp(left.get(), right.get());
}
template<class Str1, class Str2, std::enable_if_t<detail::is_concrete_string<Str1>::value &&
detail::is_concrete_string<Str2>::value,int> = 0>
template<class Str1, class Str2, detail::enable_if_concrete_string<Str1,Str2> = 0>
bool operator!=(Str1&& left, Str2&& right){
return !(left == right);
}
template<class Left, class Right, std::enable_if_t<detail::is_string<Left>::value &&
detail::is_string<Right>::value,int> = 0>
template<class Left, class Right, detail::enable_if_string<Left,Right> = 0>
constexpr auto operator+(Left&& l, Right&& r){
return string_cat_expr(std::forward<Left>(l), std::forward<Right>(r));
}
template<class Right, std::enable_if_t<detail::is_string<Right>::value,int> = 0>
template<class Right, detail::enable_if_string<Right> = 0>
constexpr auto operator+(const char* left, Right&& right){
return string_cat_expr(rexy::static_string(left), std::forward<Right>(right));
}
template<class Left, std::enable_if_t<detail::is_string<Left>::value,int> = 0>
template<class Left, detail::enable_if_string<Left> = 0>
constexpr auto operator+(Left&& left, const char* right){
return rexy::string_cat_expr(std::forward<Left>(left), rexy::static_string(right));
}
template<class Left, class Right, std::enable_if_t<detail::is_string<Left>::value &&
detail::is_string<Right>::value,int> = 0>
template<class Left, class Right, detail::enable_if_concrete_string<Left> = 0, detail::enable_if_string<Right> = 0>
decltype(auto) operator+=(Left& l, Right&& r){
return l = (l + std::forward<Right>(r));
}
template<class Left, std::enable_if_t<detail::is_string<Left>::value,int> = 0>
template<class Left, detail::enable_if_concrete_string<Left> = 0>
decltype(auto) operator+=(Left& l, const char* r){
return l = (l + r);
}

View File

@ -26,25 +26,51 @@
#include <rexy/detail/util.hpp> //max
namespace rexy{
namespace{
template<class T, class U = T>
constexpr T cx_exchange(T& t, U&& u){
T old = std::move(t);
t = std::forward<U>(u);
return old;
namespace detail{
namespace{
constexpr size_t cx_strlen(char* c){
size_t i = 0;
for(;c[i];++i);
return i;
}
}
}
}//namespace detail
//std::swap and std::exchange aren't constexpr until c++20
#if __cplusplus > 201703L
#define cx_swap(...) std::swap(__VA_ARGS__)
#define cx_exchange(...) std::exchange(__VA_ARGS__)
#else
namespace detail{
namespace{
template<class T>
constexpr void cx_swap(T& a, T& b){
T tmp = std::move(a);
a = std::move(b);
b = std::move(tmp);
}
template<class T, class U = T>
constexpr T cx_exchange(T& t, U&& u){
T old = std::move(t);
t = std::forward<U>(u);
return old;
}
}
} //namespace detail
#define cx_swap(...) detail::cx_swap(__VA_ARGS__)
#define cx_exchange(...) detail::cx_exchange(__VA_ARGS__)
#endif
template<class Allocator>
constexpr string_intermediary<Allocator>::string_intermediary(void){}
template<class Allocator>
string_intermediary<Allocator>::string_intermediary(char* data, size_t len):
/*deprecated*/ constexpr string_intermediary<Allocator>::string_intermediary(char* data, size_t len):
string_base(data, len){}
template<class Allocator>
constexpr string_intermediary<Allocator>::string_intermediary(rexy::steal<char*> data, size_t len):
string_base(data.value(), len){}
template<class Allocator>
constexpr string_intermediary<Allocator>::string_intermediary(char* data, size_t len, size_t cap):
/*deprecated*/ constexpr string_intermediary<Allocator>::string_intermediary(char* data, size_t len, size_t cap):
string_base(data, len, cap){}
template<class Allocator>
constexpr string_intermediary<Allocator>::string_intermediary(rexy::steal<char*> data, size_t len, size_t cap):
@ -65,8 +91,8 @@ namespace rexy{
}
}
template<class Allocator>
string_intermediary<Allocator>::string_intermediary(rexy::steal<char*> data):
string_base(data.value() ? strlen(data.value()) : 0)
constexpr string_intermediary<Allocator>::string_intermediary(rexy::steal<char*> data):
string_base(data.value() ? detail::cx_strlen(data.value()) : 0)
{
m_data = data.value();
m_length = m_cap;
@ -113,8 +139,8 @@ namespace rexy{
return (*this = std::move(tmp));
}
template<class Allocator>
string_intermediary<Allocator>& string_intermediary<Allocator>::operator=(string_intermediary&& s){
std::swap(m_data, s.m_data);
constexpr string_intermediary<Allocator>& string_intermediary<Allocator>::operator=(string_intermediary&& s){
cx_swap(m_data, s.m_data);
m_length = s.m_length;
m_cap = s.m_cap;
return *this;