Generalize expression templates and bring binary_data up to par with string_intermediary
This commit is contained in:
parent
ee1c180071
commit
0d33ec9444
@ -29,7 +29,7 @@ if(ENABLE_PROFILING)
|
||||
target_link_options(rexy PRIVATE -fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls)
|
||||
endif()
|
||||
|
||||
set(LIBREXY_PUBLIC_HEADERS "include/rexy/traits.hpp" "include/rexy/steal.hpp" "include/rexy/binary.hpp" "include/rexy/string_base.hpp" "include/rexy/string.hpp" "include/rexy/filerd.hpp" "include/rexy/string_base.tpp")
|
||||
set(LIBREXY_PUBLIC_HEADERS "include/rexy/traits.hpp" "include/rexy/steal.hpp" "include/rexy/binary.hpp" "include/rexy/expression.hpp" "include/rexy/binary.tpp" "include/rexy/string_base.hpp" "include/rexy/string.hpp" "include/rexy/filerd.hpp" "include/rexy/string_base.tpp")
|
||||
target_compile_options(rexy PRIVATE -Wall -Wextra -pedantic -std=c++17)
|
||||
|
||||
install(TARGETS rexy
|
||||
@ -40,8 +40,8 @@ install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/pc/librexy.pc"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig"
|
||||
)
|
||||
install(FILES ${LIBREXY_PUBLIC_HEADERS} DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/rexy/")
|
||||
install(DIRECTORY "include/rexy/detail" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/rexy")
|
||||
install(DIRECTORY "include/rexy/cx" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/rexy")
|
||||
install(DIRECTORY "include/rexy/detail" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/rexy" FILES_MATCHING PATTERN "*.hpp" PATTERN "*.tpp")
|
||||
install(DIRECTORY "include/rexy/cx" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/rexy" FILES_MATCHING PATTERN "*.hpp" PATTERN "*.tpp")
|
||||
|
||||
configure_file(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/pc/librexy.pc.cmake.in"
|
||||
|
||||
@ -26,8 +26,9 @@
|
||||
#include "cx/utility.hpp" //max
|
||||
#include "detail/default_allocator.hpp"
|
||||
#include "steal.hpp"
|
||||
|
||||
#define STOP_STRICT_ALIAS_WARNING(x) (x)
|
||||
#include "expression.hpp"
|
||||
#include "traits.hpp"
|
||||
#include "detail/string_appender.hpp"
|
||||
|
||||
namespace rexy{
|
||||
|
||||
@ -42,7 +43,7 @@ namespace rexy{
|
||||
constexpr binary_base(void)noexcept = default;
|
||||
constexpr binary_base(char* data, size_t size)noexcept;
|
||||
constexpr binary_base(char* data, size_t cap, size_t size)noexcept;
|
||||
binary_base(const binary_base& b)noexcept;
|
||||
constexpr binary_base(const binary_base& b)noexcept;
|
||||
~binary_base(void)noexcept = default;
|
||||
|
||||
public:
|
||||
@ -67,6 +68,8 @@ namespace rexy{
|
||||
constexpr binary_data(void)noexcept = default;
|
||||
binary_data(const char* data, size_t size)
|
||||
noexcept(noexcept(Allocator::copy(data, size)));
|
||||
explicit binary_data(const char* data)
|
||||
noexcept(noexcept(Allocator::copy(data, 0)));
|
||||
constexpr binary_data(rexy::steal<char*> data, size_t size)noexcept;
|
||||
constexpr binary_data(rexy::steal<char*> data, size_t cap, size_t size)noexcept;
|
||||
binary_data(const char* data, size_t cap, size_t size)
|
||||
@ -94,50 +97,106 @@ namespace rexy{
|
||||
};
|
||||
using binary = binary_data<>;
|
||||
|
||||
template<class Left, class Right>
|
||||
class binary_cat_expr : public rexy::binary_expression<Left,Right>
|
||||
{
|
||||
public:
|
||||
using binary_expression<Left,Right>::binary_expression;
|
||||
|
||||
constexpr binary_cat_expr(const binary_cat_expr&) = default;
|
||||
constexpr binary_cat_expr(binary_cat_expr&&) = default;
|
||||
|
||||
constexpr size_t size(void)const noexcept;
|
||||
|
||||
template<class Alloc>
|
||||
operator binary_data<Alloc>(void)
|
||||
noexcept(std::is_nothrow_constructible<binary_data<Alloc>, size_t>::value &&
|
||||
std::is_nothrow_invocable<detail::string_appender<binary_data<Alloc>>,decltype(*this)>::value);
|
||||
};
|
||||
|
||||
class static_binary : public binary_base
|
||||
{
|
||||
public:
|
||||
constexpr static_binary(void)noexcept = default;
|
||||
constexpr static_binary(const char* str, size_t len)noexcept;
|
||||
constexpr static_binary(const char* str)noexcept;
|
||||
constexpr static_binary(const static_binary&)noexcept;
|
||||
constexpr static_binary(static_binary&&)noexcept;
|
||||
~static_binary(void)noexcept = default;
|
||||
|
||||
constexpr static_binary& operator=(const char* str)noexcept;
|
||||
constexpr static_binary& operator=(const static_binary& str)noexcept;
|
||||
constexpr static_binary& operator=(static_binary&& str)noexcept;
|
||||
};
|
||||
|
||||
template<class Left, class Right>
|
||||
binary_cat_expr(Left&&, Right&&) -> binary_cat_expr<Left&&,Right&&>;
|
||||
|
||||
template<class T>
|
||||
struct is_binary{
|
||||
static constexpr bool value = rexy::is_type<T,binary_base>::value || rexy::is_template_type<T,binary_cat_expr>::value;
|
||||
};
|
||||
template<class T>
|
||||
struct is_concrete_binary{
|
||||
static constexpr bool value = rexy::is_type<T,binary_base>::value;
|
||||
};
|
||||
namespace detail{
|
||||
std::true_type is_binary_type_helper(binary_base);
|
||||
std::false_type is_binary_type_helper(...);
|
||||
|
||||
template<class T>
|
||||
struct is_binary_type{
|
||||
constexpr static bool value = std::is_same<decltype(is_binary_type_helper(std::declval<typename std::decay<T>::type>())),std::true_type>::value;
|
||||
};
|
||||
|
||||
template<class... Ts>
|
||||
using enable_if_binary = std::enable_if_t<(is_binary_type<Ts>::value && ...),int>;
|
||||
using enable_if_binary = std::enable_if_t<(is_binary<Ts>::value && ...),int>;
|
||||
template<class... Ts>
|
||||
using enable_if_concrete_binary = std::enable_if_t<(is_concrete_binary<Ts>::value && ...),int>;
|
||||
|
||||
}
|
||||
|
||||
template<class Left, class Right, detail::enable_if_binary<Left,Right> = 0>
|
||||
template<class Left, class Right, detail::enable_if_concrete_binary<Left,Right> = 0>
|
||||
bool operator==(Left&& l, Right&& r)noexcept{
|
||||
return l && r && l.size() == r.size() && l.capacity() == r.capacity() && !memcmp(l.get(), r.get(), l.size());
|
||||
}
|
||||
template<class Left, class Right, detail::enable_if_binary<Left,Right> = 0>
|
||||
template<class Left, class Right, detail::enable_if_concrete_binary<Left,Right> = 0>
|
||||
bool operator!=(Left&& l, Right&& r)noexcept{
|
||||
return !(std::forward<Left>(l) == std::forward<Right>(r));
|
||||
}
|
||||
template<class All, class Alr>
|
||||
auto operator+(const rexy::binary_data<All>& l, const rexy::binary_data<Alr>& r)
|
||||
noexcept(std::is_nothrow_constructible<binary_data<All>, size_t>::value)
|
||||
template<class Left, class Right, detail::enable_if_binary<Left,Right> = 0>
|
||||
auto operator+(Left&& l, Right&& r)
|
||||
noexcept(noexcept(::new (nullptr) binary_cat_expr(std::forward<Left>(l), std::forward<Right>(r))))
|
||||
{
|
||||
rexy::binary_data<All> retval(l.size() + r.size());
|
||||
memcpy(retval.get(), l.get(), l.size());
|
||||
memcpy(retval.get()+l.size(), r.get(), r.size());
|
||||
return retval;
|
||||
return binary_cat_expr(std::forward<Left>(l), std::forward<Right>(r));
|
||||
}
|
||||
template<class All, class Alr>
|
||||
decltype(auto) operator+=(rexy::binary_data<All>& l, const rexy::binary_data<Alr>& r)
|
||||
noexcept(noexcept(All::allocate(0)))
|
||||
template<class Left, detail::enable_if_binary<Left> = 0>
|
||||
auto operator+(Left&& l, const char* c)
|
||||
noexcept(noexcept(::new (nullptr) binary_cat_expr(std::forward<Left>(l), rexy::static_binary(c))))
|
||||
{
|
||||
l.resize(l.size() + r.size());
|
||||
memcpy(l.get()+l.size(), r.get(), r.size());
|
||||
return l;
|
||||
return binary_cat_expr(std::forward<Left>(l), rexy::static_binary(c));
|
||||
}
|
||||
template<class Right, detail::enable_if_binary<Right> = 0>
|
||||
auto operator+(const char* c, Right&& r)
|
||||
noexcept(noexcept(::new (nullptr) binary_cat_expr(rexy::static_binary(c), std::forward<Right>(r))))
|
||||
{
|
||||
return binary_cat_expr(rexy::static_binary(c), std::forward<Right>(r));
|
||||
}
|
||||
template<class Left, class Right, detail::enable_if_concrete_binary<Left> = 0, detail::enable_if_binary<Right> = 0>
|
||||
decltype(auto) operator+=(Left& l, Right&& r)
|
||||
noexcept(noexcept(l + std::forward<Right>(r)) && std::is_nothrow_assignable<Left,decltype(l + std::forward<Right>(r))>::value)
|
||||
{
|
||||
return l = (l + std::forward<Right>(r));
|
||||
}
|
||||
template<class Left, detail::enable_if_concrete_binary<Left> = 0>
|
||||
decltype(auto) operator+=(Left& l, const char* c)
|
||||
noexcept(noexcept(l + c) && std::is_nothrow_assignable<Left, decltype(l + c)>::value)
|
||||
{
|
||||
return l = (l + c);
|
||||
}
|
||||
} //namespace rexy
|
||||
|
||||
#undef STOP_STRICT_ALIAS_WARNING
|
||||
|
||||
#include "binary.tpp"
|
||||
|
||||
namespace{
|
||||
constexpr inline rexy::static_binary operator"" _sb(const char* str, size_t len)noexcept{
|
||||
return rexy::static_binary(str, len);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef REXY_STRING_BASE_HPP
|
||||
#include "detail/binary_string_conv.hpp"
|
||||
#endif
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
#include "cx/utility.hpp" //max
|
||||
#include "detail/default_allocator.hpp"
|
||||
#include "steal.hpp"
|
||||
#include "detail/string_appender.hpp"
|
||||
|
||||
#define STOP_STRICT_ALIAS_WARNING(x) (x)
|
||||
|
||||
@ -35,7 +36,7 @@ namespace rexy{
|
||||
m_data(data), m_cap(size){}
|
||||
constexpr binary_base::binary_base(char* data, size_t cap, size_t size)noexcept:
|
||||
m_data(data), m_size(size), m_cap(cap){}
|
||||
binary_base::binary_base(const binary_base& b)noexcept{}
|
||||
constexpr binary_base::binary_base(const binary_base&)noexcept{}
|
||||
|
||||
constexpr char* binary_base::release(void)noexcept{
|
||||
return cx::exchange(m_data, nullptr);
|
||||
@ -69,6 +70,10 @@ namespace rexy{
|
||||
noexcept(noexcept(Allocator::copy(data, size))):
|
||||
binary_base(reinterpret_cast<char*>(Allocator::copy(data, size)), size){}
|
||||
template<class Allocator>
|
||||
binary_data<Allocator>::binary_data(const char* data)
|
||||
noexcept(noexcept(Allocator::copy(data, 0))):
|
||||
binary_data(data, cx::strlen(data)){}
|
||||
template<class Allocator>
|
||||
constexpr binary_data<Allocator>::binary_data(rexy::steal<char*> data, size_t size)noexcept:
|
||||
binary_base(data.value(), size){}
|
||||
template<class Allocator>
|
||||
@ -154,6 +159,53 @@ namespace rexy{
|
||||
memcpy(m_data+m_size, data, len);
|
||||
m_size += len;
|
||||
}
|
||||
constexpr static_binary::static_binary(const char* str, size_t len)noexcept:
|
||||
binary_base(const_cast<char*>(str), len, len){}
|
||||
constexpr static_binary::static_binary(const char* str)noexcept:
|
||||
static_binary(str, cx::strlen(str)){}
|
||||
constexpr static_binary::static_binary(const static_binary& s)noexcept:
|
||||
static_binary(s.get(), s.size()){}
|
||||
constexpr static_binary::static_binary(static_binary&& s)noexcept:
|
||||
static_binary(s.get(), s.size()){}
|
||||
|
||||
constexpr static_binary& static_binary::operator=(const char* str)noexcept{
|
||||
m_data = const_cast<char*>(str);
|
||||
m_size = cx::strlen(str);
|
||||
m_cap = m_size;
|
||||
return *this;
|
||||
}
|
||||
constexpr static_binary& static_binary::operator=(const static_binary& str)noexcept{
|
||||
m_data = str.m_data;
|
||||
m_size = str.m_size;
|
||||
m_cap = str.m_cap;
|
||||
return *this;
|
||||
}
|
||||
constexpr static_binary& static_binary::operator=(static_binary&& str)noexcept{
|
||||
m_data = str.m_data;
|
||||
m_size = str.m_size;
|
||||
m_cap = str.m_cap;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class Left, class Right>
|
||||
constexpr size_t binary_cat_expr<Left,Right>::size(void)const noexcept{
|
||||
return this->m_l.size() + this->m_r.size();
|
||||
}
|
||||
|
||||
template<class Left, class Right>
|
||||
template<class Alloc>
|
||||
binary_cat_expr<Left,Right>::operator binary_data<Alloc>(void)
|
||||
noexcept(std::is_nothrow_constructible<binary_data<Alloc>, size_t>::value &&
|
||||
std::is_nothrow_invocable<detail::string_appender<binary_data<Alloc>>,decltype(*this)>::value)
|
||||
{
|
||||
auto sz = size();
|
||||
binary_data<Alloc> ret(sz);
|
||||
|
||||
detail::string_appender<binary_data<Alloc>> append(ret);
|
||||
|
||||
append(*this);
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -57,7 +57,7 @@ namespace rexy{
|
||||
l.append(r.get(), r.length()+1);
|
||||
return l;
|
||||
}
|
||||
template<class L, class R, detail::enable_if_binary<L> = 0, detail::enable_if_string<R> = 0, std::enable_if_t<!detail::is_concrete_string<R>::value,int> = 0>
|
||||
template<class L, class R, detail::enable_if_binary<L> = 0, detail::enable_if_string<R> = 0, std::enable_if_t<!is_concrete_string<R>::value,int> = 0>
|
||||
decltype(auto) operator+=(L& l, R&& r)
|
||||
noexcept(std::is_nothrow_constructible<rexy::string,R&&>::value &&
|
||||
(noexcept(std::decay_t<L>::allocator_type::allocate(0))))
|
||||
|
||||
46
include/rexy/detail/string_appender.hpp
Normal file
46
include/rexy/detail/string_appender.hpp
Normal file
@ -0,0 +1,46 @@
|
||||
#ifndef REXY_STRING_APPENDER_HPP
|
||||
#define REXY_STRING_APPENDER_HPP
|
||||
|
||||
#include "../expression.hpp"
|
||||
#include "../traits.hpp"
|
||||
#include <utility> //forward
|
||||
|
||||
namespace rexy::detail{
|
||||
|
||||
template<class Targ>
|
||||
struct string_appender
|
||||
{
|
||||
private:
|
||||
Targ& m_targ;
|
||||
public:
|
||||
constexpr string_appender(Targ& t)noexcept:
|
||||
m_targ(t){}
|
||||
template<class L, class R>
|
||||
constexpr void operator()(const binary_expression<L,R>& expr)
|
||||
noexcept(noexcept((*this)(expr.left())) && noexcept((*this)(expr.right())))
|
||||
{
|
||||
(*this)(expr.left());
|
||||
(*this)(expr.right());
|
||||
}
|
||||
template<class L>
|
||||
constexpr void operator()(const unary_expression<L>& expr)
|
||||
noexcept(noexcept((*this)(expr.left())))
|
||||
{
|
||||
(*this)(expr.left());
|
||||
}
|
||||
template<class Val, std::enable_if_t<!rexy::is_template_derived_type<Val,binary_expression>::value,int> = 0, class = decltype(std::declval<Val>().length())>
|
||||
constexpr void operator()(Val&& v)
|
||||
{
|
||||
m_targ.append(std::forward<Val>(v).get(), std::forward<Val>(v).length());
|
||||
}
|
||||
template<class Val, std::enable_if_t<!rexy::is_template_derived_type<Val,binary_expression>::value,void*> = nullptr, class = decltype(std::declval<Val>().size())>
|
||||
constexpr void operator()(Val&& v)
|
||||
{
|
||||
m_targ.append(std::forward<Val>(v).get(), std::forward<Val>(v).size());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
97
include/rexy/expression.hpp
Normal file
97
include/rexy/expression.hpp
Normal file
@ -0,0 +1,97 @@
|
||||
#ifndef REXY_EXPRESSION_HPP
|
||||
#define REXY_EXPRESSION_HPP
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility> //forward
|
||||
|
||||
namespace rexy{
|
||||
|
||||
template<class L, class R>
|
||||
class binary_expression
|
||||
{
|
||||
static_assert(!std::is_same<std::decay_t<L>,void>::value, "Left value of rexy::binary_expression cannot be void!");
|
||||
static_assert(!std::is_same<std::decay_t<R>,void>::value, "Right value of rexy::binary_expression cannot be void!");
|
||||
|
||||
public:
|
||||
using left_type = std::conditional_t<std::is_rvalue_reference<L>::value,
|
||||
std::remove_reference_t<L>,
|
||||
L>;
|
||||
using right_type = std::conditional_t<std::is_rvalue_reference<R>::value,
|
||||
std::remove_reference_t<R>,
|
||||
R>;
|
||||
|
||||
using left_reference = std::remove_reference_t<left_type>&;
|
||||
using left_const_reference = const std::remove_reference_t<left_type>&;
|
||||
using right_reference = std::remove_reference_t<right_type>&;
|
||||
using right_const_reference = const std::remove_reference_t<right_type>&;
|
||||
|
||||
protected:
|
||||
left_type m_l;
|
||||
right_type m_r;
|
||||
|
||||
public:
|
||||
template<class U, class V>
|
||||
constexpr binary_expression(U&& u, V&& v)noexcept:
|
||||
m_l(std::forward<U>(u)),
|
||||
m_r(std::forward<V>(v)){}
|
||||
constexpr binary_expression(const binary_expression&) = default;
|
||||
constexpr binary_expression(binary_expression&&) = default;
|
||||
|
||||
constexpr binary_expression& operator=(const binary_expression&) = default;
|
||||
constexpr binary_expression& operator=(binary_expression&&) = default;
|
||||
|
||||
constexpr left_reference left(void)noexcept{
|
||||
return m_l;
|
||||
}
|
||||
constexpr left_const_reference left(void)const noexcept{
|
||||
return m_l;
|
||||
}
|
||||
constexpr right_reference right(void)noexcept{
|
||||
return m_r;
|
||||
}
|
||||
constexpr right_const_reference right(void)const noexcept{
|
||||
return m_r;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<class L>
|
||||
class unary_expression
|
||||
{
|
||||
static_assert(!std::is_same<std::decay_t<L>,void>::value, "Value of rexy::unary_expression cannot be void!");
|
||||
|
||||
public:
|
||||
using left_type = std::conditional_t<std::is_rvalue_reference<L>::value,
|
||||
std::remove_reference_t<L>,
|
||||
L>;
|
||||
using left_reference = std::remove_reference_t<left_type>&;
|
||||
using left_const_reference = const std::remove_reference_t<left_type>&;
|
||||
|
||||
using value_type = left_type;
|
||||
using reference = left_reference;
|
||||
using const_reference = left_const_reference;
|
||||
|
||||
protected:
|
||||
value_type m_l;
|
||||
|
||||
public:
|
||||
template<class U>
|
||||
constexpr unary_expression(U&& u)noexcept:
|
||||
m_l(std::forward<U>(u)){}
|
||||
|
||||
constexpr unary_expression(const unary_expression&)noexcept = default;
|
||||
constexpr unary_expression(unary_expression&&)noexcept = default;
|
||||
|
||||
constexpr reference left(void)noexcept{
|
||||
return m_l;
|
||||
}
|
||||
constexpr const_reference left(void)const noexcept{
|
||||
return m_l;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -27,13 +27,13 @@
|
||||
#include "steal.hpp"
|
||||
#include "cx/utility.hpp"
|
||||
#include "traits.hpp"
|
||||
#include "expression.hpp"
|
||||
#include "detail/string_appender.hpp"
|
||||
|
||||
namespace rexy{
|
||||
|
||||
class string_expr{};
|
||||
|
||||
//Base of all RAII strings. Its use is allowing passing of rexy strings to functions without knowing the exact type
|
||||
class string_base : public string_expr
|
||||
class string_base
|
||||
{
|
||||
protected:
|
||||
size_t m_length = 0;
|
||||
@ -137,45 +137,24 @@ namespace rexy{
|
||||
|
||||
};
|
||||
|
||||
namespace detail{
|
||||
template<class T>
|
||||
struct string_appender;
|
||||
}
|
||||
|
||||
//Like an expression template but not really
|
||||
template<class Left, class Right>
|
||||
class string_cat_expr : public string_expr
|
||||
class string_cat_expr : public rexy::binary_expression<Left,Right>
|
||||
{
|
||||
private:
|
||||
Left m_l;
|
||||
Right m_r;
|
||||
|
||||
public:
|
||||
template<class T, class U>
|
||||
constexpr string_cat_expr(T&& l, U&& r)noexcept(std::is_nothrow_constructible<Left,T&&>::value &&
|
||||
std::is_nothrow_constructible<Right,U&&>::value);
|
||||
constexpr string_cat_expr(string_cat_expr&& s)noexcept(std::is_nothrow_constructible<Left,decltype(s.m_l)>::value &&
|
||||
std::is_nothrow_constructible<Right,decltype(s.m_r)>::value);
|
||||
using binary_expression<Left,Right>::binary_expression;
|
||||
|
||||
constexpr string_cat_expr(const string_cat_expr&) = default;
|
||||
constexpr string_cat_expr(string_cat_expr&&) = default;
|
||||
|
||||
constexpr size_t length(void)const noexcept;
|
||||
template<class Alloc>
|
||||
operator string_intermediary<Alloc>(void)
|
||||
noexcept(std::is_nothrow_constructible<string_intermediary<Alloc>, size_t>::value &&
|
||||
std::is_nothrow_invocable<detail::string_appender<string_intermediary<Alloc>>,decltype(*this)>::value);
|
||||
constexpr const Left& left(void)const noexcept;
|
||||
constexpr const Right& right(void)const noexcept;
|
||||
};
|
||||
template<class Left, class Right>
|
||||
string_cat_expr(Left&, Right&) -> string_cat_expr<Left&,Right&>;
|
||||
|
||||
template<class Left, class Right>
|
||||
string_cat_expr(Left&&,Right&&) -> string_cat_expr<Left,Right>;
|
||||
|
||||
template<class Left, class Right>
|
||||
string_cat_expr(Left&,Right&&) -> string_cat_expr<Left&,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&&>;
|
||||
|
||||
class static_string : public string_base
|
||||
{
|
||||
@ -193,15 +172,15 @@ namespace rexy{
|
||||
};
|
||||
|
||||
|
||||
template<class T>
|
||||
struct is_string{
|
||||
static constexpr bool value = rexy::is_type<T,string_base>::value || rexy::is_template_type<T,string_cat_expr>::value;
|
||||
};
|
||||
template<class T>
|
||||
struct is_concrete_string{
|
||||
static constexpr bool value = rexy::is_type<T,string_base>::value;
|
||||
};
|
||||
namespace detail{
|
||||
template<class T>
|
||||
struct is_string{
|
||||
static constexpr bool value = rexy::is_type<T,string_expr>::value;
|
||||
};
|
||||
template<class T>
|
||||
struct is_concrete_string{
|
||||
static constexpr bool value = rexy::is_type<T,string_base>::value;
|
||||
};
|
||||
|
||||
template<class... Ts>
|
||||
using enable_if_string = std::enable_if_t<(is_string<Ts>::value && ...),int>;
|
||||
@ -210,19 +189,6 @@ namespace rexy{
|
||||
template<class... Ts>
|
||||
using enable_if_expr_string = std::enable_if_t<(rexy::is_template_type<Ts,string_cat_expr>::value && ...),int>;
|
||||
|
||||
template<class Targ>
|
||||
struct string_appender
|
||||
{
|
||||
private:
|
||||
Targ& m_targ;
|
||||
public:
|
||||
constexpr string_appender(Targ& t)noexcept;
|
||||
template<class L, class R>
|
||||
constexpr void operator()(const string_cat_expr<L,R>& str)
|
||||
noexcept(noexcept((*this)(str.left())) && noexcept((*this)(str.right())));
|
||||
template<class Str, std::enable_if_t<!rexy::is_template_type<Str,string_cat_expr>::value,int> = 0>
|
||||
constexpr void operator()(Str&& str)noexcept(noexcept(m_targ.append(str.get(), str.length())));
|
||||
};
|
||||
} //namespace detail
|
||||
|
||||
template<class Str1, class Str2, detail::enable_if_concrete_string<Str1,Str2> = 0>
|
||||
|
||||
@ -24,6 +24,7 @@
|
||||
#include <cstring> //strlen, strcpy
|
||||
|
||||
#include "cx/utility.hpp" //max
|
||||
#include "detail/string_appender.hpp"
|
||||
|
||||
#define STOP_STRICT_ALIAS_WARNING(x) (x)
|
||||
|
||||
@ -216,23 +217,9 @@ namespace rexy{
|
||||
}
|
||||
|
||||
|
||||
template<class Left, class Right>
|
||||
template<class T, class U>
|
||||
constexpr string_cat_expr<Left,Right>::string_cat_expr(T&& l, U&& r)
|
||||
noexcept(std::is_nothrow_constructible<Left,T&&>::value &&
|
||||
std::is_nothrow_constructible<Right,U&&>::value):
|
||||
m_l(std::forward<T>(l)),
|
||||
m_r(std::forward<U>(r)){}
|
||||
template<class Left, class Right>
|
||||
constexpr string_cat_expr<Left,Right>::string_cat_expr(string_cat_expr&& s)
|
||||
noexcept(std::is_nothrow_constructible<Left,decltype(s.m_l)>::value &&
|
||||
std::is_nothrow_constructible<Right,decltype(s.m_r)>::value):
|
||||
m_l(std::forward<Left>(s.m_l)),
|
||||
m_r(std::forward<Right>(s.m_r)){}
|
||||
|
||||
template<class Left, class Right>
|
||||
constexpr size_t string_cat_expr<Left,Right>::length(void)const noexcept{
|
||||
return m_l.length() + m_r.length();
|
||||
return this->m_l.length() + this->m_r.length();
|
||||
}
|
||||
template<class Left, class Right>
|
||||
template<class Alloc>
|
||||
@ -246,14 +233,6 @@ namespace rexy{
|
||||
append(*this);
|
||||
return ret;
|
||||
}
|
||||
template<class Left, class Right>
|
||||
constexpr const Left& string_cat_expr<Left,Right>::left(void)const noexcept{
|
||||
return m_l;
|
||||
}
|
||||
template<class Left, class Right>
|
||||
constexpr const Right& string_cat_expr<Left,Right>::right(void)const noexcept{
|
||||
return m_r;
|
||||
}
|
||||
|
||||
|
||||
constexpr static_string::static_string(const char* str, size_t len)noexcept:
|
||||
@ -265,40 +244,24 @@ namespace rexy{
|
||||
constexpr static_string& static_string::operator=(const static_string& s)noexcept{
|
||||
m_data = s.m_data;
|
||||
m_length = s.m_length;
|
||||
m_cap = s.m_cap;
|
||||
return *this;
|
||||
}
|
||||
constexpr static_string::static_string(const char* c)noexcept:
|
||||
static_string(const_cast<char*>(c), cx::strlen(c)){}
|
||||
static_string(c, cx::strlen(c)){}
|
||||
constexpr static_string& static_string::operator=(const char* c)noexcept{
|
||||
m_data = const_cast<char*>(c);
|
||||
m_length = cx::strlen(c);
|
||||
m_cap = m_length;
|
||||
return *this;
|
||||
}
|
||||
constexpr static_string& static_string::operator=(static_string&& s)noexcept{
|
||||
m_data = s.m_data;
|
||||
m_length = s.m_length;
|
||||
m_cap = s.m_cap;
|
||||
return *this;
|
||||
}
|
||||
|
||||
namespace detail{
|
||||
template<class Targ>
|
||||
constexpr string_appender<Targ>::string_appender(Targ& t)noexcept: m_targ(t){}
|
||||
template<class Targ>
|
||||
template<class L, class R>
|
||||
constexpr void string_appender<Targ>::operator()(const string_cat_expr<L,R>& str)
|
||||
noexcept(noexcept((*this)(str.left())) && noexcept((*this)(str.right())))
|
||||
{
|
||||
(*this)(str.left());
|
||||
(*this)(str.right());
|
||||
}
|
||||
template<class Targ>
|
||||
template<class Str, std::enable_if_t<!rexy::is_template_type<Str,string_cat_expr>::value,int>>
|
||||
constexpr void string_appender<Targ>::operator()(Str&& str)
|
||||
noexcept(noexcept(m_targ.append(str.get(), str.length())))
|
||||
{
|
||||
m_targ.append(str.get(), str.length());
|
||||
}
|
||||
}
|
||||
|
||||
} //namespace rexy
|
||||
|
||||
|
||||
@ -12,6 +12,7 @@ namespace rexy{
|
||||
|
||||
static constexpr bool value = std::is_same<std::true_type,decltype(check(std::declval<std::decay_t<T>*>()))>::value;
|
||||
};
|
||||
|
||||
template<class T, template<class...> class U>
|
||||
struct is_template_type_helper{
|
||||
static constexpr bool value = false;
|
||||
@ -20,10 +21,19 @@ namespace rexy{
|
||||
struct is_template_type_helper<U<Args...>,U>{
|
||||
static constexpr bool value = true;
|
||||
};
|
||||
|
||||
template<class T, template<class...> class U>
|
||||
struct is_template_type : public is_template_type_helper<std::decay_t<T>,U>{};
|
||||
|
||||
template<class T, template<class...> class Tmpl>
|
||||
struct is_template_derived_type{
|
||||
template<class... Args>
|
||||
static std::true_type test(Tmpl<Args...>*);
|
||||
static std::false_type test(void*);
|
||||
|
||||
static constexpr bool value = std::is_same<std::true_type,decltype(test(static_cast<std::decay_t<T>*>(nullptr)))>::value;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
//Never actually used in the project. This just ensures that all syntax is correct during builds.
|
||||
|
||||
#include "rexy/binary.hpp"
|
||||
#include "rexy/binary.tpp"
|
||||
#include "rexy/expression.hpp"
|
||||
#include "rexy/filerd.hpp"
|
||||
#include "rexy/steal.hpp"
|
||||
#include "rexy/string_base.hpp"
|
||||
@ -10,6 +12,7 @@
|
||||
|
||||
#include "rexy/detail/binary_string_conv.hpp"
|
||||
#include "rexy/detail/default_allocator.hpp"
|
||||
#include "rexy/detail/string_appender.hpp"
|
||||
|
||||
#include "rexy/cx/algorithm.hpp"
|
||||
#include "rexy/cx/array.hpp"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user