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

View File

@ -26,25 +26,51 @@
#include <rexy/detail/util.hpp> //max #include <rexy/detail/util.hpp> //max
namespace rexy{ namespace rexy{
namespace{ namespace detail{
template<class T, class U = T> namespace{
constexpr T cx_exchange(T& t, U&& u){ constexpr size_t cx_strlen(char* c){
T old = std::move(t); size_t i = 0;
t = std::forward<U>(u); for(;c[i];++i);
return old; 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> template<class Allocator>
constexpr string_intermediary<Allocator>::string_intermediary(void){} constexpr string_intermediary<Allocator>::string_intermediary(void){}
template<class Allocator> 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){} string_base(data, len){}
template<class Allocator> template<class Allocator>
constexpr string_intermediary<Allocator>::string_intermediary(rexy::steal<char*> data, size_t len): constexpr string_intermediary<Allocator>::string_intermediary(rexy::steal<char*> data, size_t len):
string_base(data.value(), len){} string_base(data.value(), len){}
template<class Allocator> 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){} string_base(data, len, cap){}
template<class Allocator> template<class Allocator>
constexpr string_intermediary<Allocator>::string_intermediary(rexy::steal<char*> data, size_t len, size_t cap): 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> template<class Allocator>
string_intermediary<Allocator>::string_intermediary(rexy::steal<char*> data): constexpr string_intermediary<Allocator>::string_intermediary(rexy::steal<char*> data):
string_base(data.value() ? strlen(data.value()) : 0) string_base(data.value() ? detail::cx_strlen(data.value()) : 0)
{ {
m_data = data.value(); m_data = data.value();
m_length = m_cap; m_length = m_cap;
@ -113,8 +139,8 @@ namespace rexy{
return (*this = std::move(tmp)); return (*this = std::move(tmp));
} }
template<class Allocator> template<class Allocator>
string_intermediary<Allocator>& string_intermediary<Allocator>::operator=(string_intermediary&& s){ constexpr string_intermediary<Allocator>& string_intermediary<Allocator>::operator=(string_intermediary&& s){
std::swap(m_data, s.m_data); cx_swap(m_data, s.m_data);
m_length = s.m_length; m_length = s.m_length;
m_cap = s.m_cap; m_cap = s.m_cap;
return *this; return *this;