diff --git a/CMakeLists.txt b/CMakeLists.txt index 7ed5501..1a1f6d8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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" diff --git a/include/rexy/binary.hpp b/include/rexy/binary.hpp index bc5d0fa..0da9337 100644 --- a/include/rexy/binary.hpp +++ b/include/rexy/binary.hpp @@ -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 data, size_t size)noexcept; constexpr binary_data(rexy::steal 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 binary_cat_expr : public rexy::binary_expression + { + public: + using binary_expression::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 + operator binary_data(void) + noexcept(std::is_nothrow_constructible, size_t>::value && + std::is_nothrow_invocable>,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 + binary_cat_expr(Left&&, Right&&) -> binary_cat_expr; + + template + struct is_binary{ + static constexpr bool value = rexy::is_type::value || rexy::is_template_type::value; + }; + template + struct is_concrete_binary{ + static constexpr bool value = rexy::is_type::value; + }; namespace detail{ - std::true_type is_binary_type_helper(binary_base); - std::false_type is_binary_type_helper(...); - - template - struct is_binary_type{ - constexpr static bool value = std::is_same::type>())),std::true_type>::value; - }; - template - using enable_if_binary = std::enable_if_t<(is_binary_type::value && ...),int>; + using enable_if_binary = std::enable_if_t<(is_binary::value && ...),int>; + template + using enable_if_concrete_binary = std::enable_if_t<(is_concrete_binary::value && ...),int>; + } - template = 0> + template = 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 = 0> + template = 0> bool operator!=(Left&& l, Right&& r)noexcept{ return !(std::forward(l) == std::forward(r)); } - template - auto operator+(const rexy::binary_data& l, const rexy::binary_data& r) - noexcept(std::is_nothrow_constructible, size_t>::value) + template = 0> + auto operator+(Left&& l, Right&& r) + noexcept(noexcept(::new (nullptr) binary_cat_expr(std::forward(l), std::forward(r)))) { - rexy::binary_data 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(l), std::forward(r)); } - template - decltype(auto) operator+=(rexy::binary_data& l, const rexy::binary_data& r) - noexcept(noexcept(All::allocate(0))) + template = 0> + auto operator+(Left&& l, const char* c) + noexcept(noexcept(::new (nullptr) binary_cat_expr(std::forward(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(l), rexy::static_binary(c)); + } + template = 0> + auto operator+(const char* c, Right&& r) + noexcept(noexcept(::new (nullptr) binary_cat_expr(rexy::static_binary(c), std::forward(r)))) + { + return binary_cat_expr(rexy::static_binary(c), std::forward(r)); + } + template = 0, detail::enable_if_binary = 0> + decltype(auto) operator+=(Left& l, Right&& r) + noexcept(noexcept(l + std::forward(r)) && std::is_nothrow_assignable(r))>::value) + { + return l = (l + std::forward(r)); + } + template = 0> + decltype(auto) operator+=(Left& l, const char* c) + noexcept(noexcept(l + c) && std::is_nothrow_assignable::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 diff --git a/include/rexy/binary.tpp b/include/rexy/binary.tpp index 38c6f5f..e68a48e 100644 --- a/include/rexy/binary.tpp +++ b/include/rexy/binary.tpp @@ -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(Allocator::copy(data, size)), size){} template + binary_data::binary_data(const char* data) + noexcept(noexcept(Allocator::copy(data, 0))): + binary_data(data, cx::strlen(data)){} + template constexpr binary_data::binary_data(rexy::steal data, size_t size)noexcept: binary_base(data.value(), size){} template @@ -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(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(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 + constexpr size_t binary_cat_expr::size(void)const noexcept{ + return this->m_l.size() + this->m_r.size(); + } + + template + template + binary_cat_expr::operator binary_data(void) + noexcept(std::is_nothrow_constructible, size_t>::value && + std::is_nothrow_invocable>,decltype(*this)>::value) + { + auto sz = size(); + binary_data ret(sz); + + detail::string_appender> append(ret); + + append(*this); + return ret; + } } diff --git a/include/rexy/detail/binary_string_conv.hpp b/include/rexy/detail/binary_string_conv.hpp index 6780515..ed61f1d 100644 --- a/include/rexy/detail/binary_string_conv.hpp +++ b/include/rexy/detail/binary_string_conv.hpp @@ -57,7 +57,7 @@ namespace rexy{ l.append(r.get(), r.length()+1); return l; } - template = 0, detail::enable_if_string = 0, std::enable_if_t::value,int> = 0> + template = 0, detail::enable_if_string = 0, std::enable_if_t::value,int> = 0> decltype(auto) operator+=(L& l, R&& r) noexcept(std::is_nothrow_constructible::value && (noexcept(std::decay_t::allocator_type::allocate(0)))) diff --git a/include/rexy/detail/string_appender.hpp b/include/rexy/detail/string_appender.hpp new file mode 100644 index 0000000..8e0868e --- /dev/null +++ b/include/rexy/detail/string_appender.hpp @@ -0,0 +1,46 @@ +#ifndef REXY_STRING_APPENDER_HPP +#define REXY_STRING_APPENDER_HPP + +#include "../expression.hpp" +#include "../traits.hpp" +#include //forward + +namespace rexy::detail{ + + template + struct string_appender + { + private: + Targ& m_targ; + public: + constexpr string_appender(Targ& t)noexcept: + m_targ(t){} + template + constexpr void operator()(const binary_expression& expr) + noexcept(noexcept((*this)(expr.left())) && noexcept((*this)(expr.right()))) + { + (*this)(expr.left()); + (*this)(expr.right()); + } + template + constexpr void operator()(const unary_expression& expr) + noexcept(noexcept((*this)(expr.left()))) + { + (*this)(expr.left()); + } + template::value,int> = 0, class = decltype(std::declval().length())> + constexpr void operator()(Val&& v) + { + m_targ.append(std::forward(v).get(), std::forward(v).length()); + } + template::value,void*> = nullptr, class = decltype(std::declval().size())> + constexpr void operator()(Val&& v) + { + m_targ.append(std::forward(v).get(), std::forward(v).size()); + } + }; + + +} + +#endif diff --git a/include/rexy/expression.hpp b/include/rexy/expression.hpp new file mode 100644 index 0000000..722c2d6 --- /dev/null +++ b/include/rexy/expression.hpp @@ -0,0 +1,97 @@ +#ifndef REXY_EXPRESSION_HPP +#define REXY_EXPRESSION_HPP + +#include +#include //forward + +namespace rexy{ + + template + class binary_expression + { + static_assert(!std::is_same,void>::value, "Left value of rexy::binary_expression cannot be void!"); + static_assert(!std::is_same,void>::value, "Right value of rexy::binary_expression cannot be void!"); + + public: + using left_type = std::conditional_t::value, + std::remove_reference_t, + L>; + using right_type = std::conditional_t::value, + std::remove_reference_t, + R>; + + using left_reference = std::remove_reference_t&; + using left_const_reference = const std::remove_reference_t&; + using right_reference = std::remove_reference_t&; + using right_const_reference = const std::remove_reference_t&; + + protected: + left_type m_l; + right_type m_r; + + public: + template + constexpr binary_expression(U&& u, V&& v)noexcept: + m_l(std::forward(u)), + m_r(std::forward(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 unary_expression + { + static_assert(!std::is_same,void>::value, "Value of rexy::unary_expression cannot be void!"); + + public: + using left_type = std::conditional_t::value, + std::remove_reference_t, + L>; + using left_reference = std::remove_reference_t&; + using left_const_reference = const std::remove_reference_t&; + + using value_type = left_type; + using reference = left_reference; + using const_reference = left_const_reference; + + protected: + value_type m_l; + + public: + template + constexpr unary_expression(U&& u)noexcept: + m_l(std::forward(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 diff --git a/include/rexy/string_base.hpp b/include/rexy/string_base.hpp index 50347cf..83555a0 100644 --- a/include/rexy/string_base.hpp +++ b/include/rexy/string_base.hpp @@ -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 - struct string_appender; - } - //Like an expression template but not really template - class string_cat_expr : public string_expr + class string_cat_expr : public rexy::binary_expression { - private: - Left m_l; - Right m_r; - public: - template - constexpr string_cat_expr(T&& l, U&& r)noexcept(std::is_nothrow_constructible::value && - std::is_nothrow_constructible::value); - constexpr string_cat_expr(string_cat_expr&& s)noexcept(std::is_nothrow_constructible::value && - std::is_nothrow_constructible::value); + using binary_expression::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 operator string_intermediary(void) noexcept(std::is_nothrow_constructible, size_t>::value && std::is_nothrow_invocable>,decltype(*this)>::value); - constexpr const Left& left(void)const noexcept; - constexpr const Right& right(void)const noexcept; }; template - string_cat_expr(Left&, Right&) -> string_cat_expr; - - template - string_cat_expr(Left&&,Right&&) -> string_cat_expr; - - template - string_cat_expr(Left&,Right&&) -> string_cat_expr; - - template - string_cat_expr(Left&&,Right&) -> string_cat_expr; + string_cat_expr(Left&&,Right&&) -> string_cat_expr; class static_string : public string_base { @@ -193,15 +172,15 @@ namespace rexy{ }; + template + struct is_string{ + static constexpr bool value = rexy::is_type::value || rexy::is_template_type::value; + }; + template + struct is_concrete_string{ + static constexpr bool value = rexy::is_type::value; + }; namespace detail{ - template - struct is_string{ - static constexpr bool value = rexy::is_type::value; - }; - template - struct is_concrete_string{ - static constexpr bool value = rexy::is_type::value; - }; template using enable_if_string = std::enable_if_t<(is_string::value && ...),int>; @@ -210,19 +189,6 @@ namespace rexy{ template using enable_if_expr_string = std::enable_if_t<(rexy::is_template_type::value && ...),int>; - template - struct string_appender - { - private: - Targ& m_targ; - public: - constexpr string_appender(Targ& t)noexcept; - template - constexpr void operator()(const string_cat_expr& str) - noexcept(noexcept((*this)(str.left())) && noexcept((*this)(str.right()))); - template::value,int> = 0> - constexpr void operator()(Str&& str)noexcept(noexcept(m_targ.append(str.get(), str.length()))); - }; } //namespace detail template = 0> diff --git a/include/rexy/string_base.tpp b/include/rexy/string_base.tpp index e948688..2bdd746 100644 --- a/include/rexy/string_base.tpp +++ b/include/rexy/string_base.tpp @@ -24,6 +24,7 @@ #include //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 - template - constexpr string_cat_expr::string_cat_expr(T&& l, U&& r) - noexcept(std::is_nothrow_constructible::value && - std::is_nothrow_constructible::value): - m_l(std::forward(l)), - m_r(std::forward(r)){} - template - constexpr string_cat_expr::string_cat_expr(string_cat_expr&& s) - noexcept(std::is_nothrow_constructible::value && - std::is_nothrow_constructible::value): - m_l(std::forward(s.m_l)), - m_r(std::forward(s.m_r)){} - template constexpr size_t string_cat_expr::length(void)const noexcept{ - return m_l.length() + m_r.length(); + return this->m_l.length() + this->m_r.length(); } template template @@ -246,14 +233,6 @@ namespace rexy{ append(*this); return ret; } - template - constexpr const Left& string_cat_expr::left(void)const noexcept{ - return m_l; - } - template - constexpr const Right& string_cat_expr::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(c), cx::strlen(c)){} + static_string(c, cx::strlen(c)){} constexpr static_string& static_string::operator=(const char* c)noexcept{ m_data = const_cast(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 - constexpr string_appender::string_appender(Targ& t)noexcept: m_targ(t){} - template - template - constexpr void string_appender::operator()(const string_cat_expr& str) - noexcept(noexcept((*this)(str.left())) && noexcept((*this)(str.right()))) - { - (*this)(str.left()); - (*this)(str.right()); - } - template - template::value,int>> - constexpr void string_appender::operator()(Str&& str) - noexcept(noexcept(m_targ.append(str.get(), str.length()))) - { - m_targ.append(str.get(), str.length()); - } - } } //namespace rexy diff --git a/include/rexy/traits.hpp b/include/rexy/traits.hpp index 5d8bf87..bd074c5 100644 --- a/include/rexy/traits.hpp +++ b/include/rexy/traits.hpp @@ -12,6 +12,7 @@ namespace rexy{ static constexpr bool value = std::is_same*>()))>::value; }; + template class U> struct is_template_type_helper{ static constexpr bool value = false; @@ -20,10 +21,19 @@ namespace rexy{ struct is_template_type_helper,U>{ static constexpr bool value = true; }; - template class U> struct is_template_type : public is_template_type_helper,U>{}; + template class Tmpl> + struct is_template_derived_type{ + template + static std::true_type test(Tmpl*); + static std::false_type test(void*); + + static constexpr bool value = std::is_same*>(nullptr)))>::value; + }; + + } #endif diff --git a/src/ensure.cpp b/src/ensure.cpp index 1a6c3f2..36dc127 100644 --- a/src/ensure.cpp +++ b/src/ensure.cpp @@ -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"