diff --git a/CMakeLists.txt b/CMakeLists.txt index 49cbdb2..c25a988 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,7 +39,7 @@ if(BUILD_TESTS) add_subdirectory(tests) endif() -set(LIBREXY_PUBLIC_HEADERS "include/rexy/rexy.hpp" "include/rexy/algorithm.hpp" "include/rexy/utility.hpp" "include/rexy/basic_string_hash.hpp" "include/rexy/hash.hpp" "include/rexy/static_string_hash.hpp" "include/rexy/string_hash.hpp" "include/rexy/mpmc_queue.hpp" "include/rexy/mpmc_queue.tpp" "include/rexy/traits.hpp" "include/rexy/steal.hpp" "include/rexy/binary.hpp" "include/rexy/expression.hpp" "include/rexy/binary_base.hpp" "include/rexy/binary_base.tpp" "include/rexy/string_base.hpp" "include/rexy/string.hpp" "include/rexy/filerd.hpp" "include/rexy/string_base.tpp" "include/rexy/allocator.hpp" "include/rexy/meta.hpp" "include/rexy/buffer.hpp" "include/rexy/buffer.tpp" "include/rexy/debug_print.hpp" "include/rexy/deferred.hpp" "include/rexy/demangle.hpp" "include/rexy/enum_traits.hpp" "include/rexy/source_location.hpp" "include/rexy/storage_for.hpp" "include/rexy/storage_for.tpp") +set(LIBREXY_PUBLIC_HEADERS "include/rexy/rexy.hpp" "include/rexy/algorithm.hpp" "include/rexy/utility.hpp" "include/rexy/basic_string_hash.hpp" "include/rexy/hash.hpp" "include/rexy/static_string_hash.hpp" "include/rexy/string_hash.hpp" "include/rexy/mpmc_queue.hpp" "include/rexy/mpmc_queue.tpp" "include/rexy/traits.hpp" "include/rexy/steal.hpp" "include/rexy/binary.hpp" "include/rexy/expression.hpp" "include/rexy/binary_base.hpp" "include/rexy/binary_base.tpp" "include/rexy/string_base.hpp" "include/rexy/string.hpp" "include/rexy/filerd.hpp" "include/rexy/string_base.tpp" "include/rexy/allocator.hpp" "include/rexy/meta.hpp" "include/rexy/buffer.hpp" "include/rexy/buffer.tpp" "include/rexy/debug_print.hpp" "include/rexy/deferred.hpp" "include/rexy/demangle.hpp" "include/rexy/enum_traits.hpp" "include/rexy/storage_for.hpp" "include/rexy/storage_for.tpp" "include/rexy/visitor.hpp") target_compile_options(rexy PRIVATE -Wall -Wextra -pedantic -std=c++20) install(TARGETS rexy @@ -52,6 +52,7 @@ install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/pc/librexy.pc" install(FILES ${LIBREXY_PUBLIC_HEADERS} 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") +install(DIRECTORY "include/rexy/compat" 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/source_location.hpp b/include/rexy/compat/source_location.hpp similarity index 98% rename from include/rexy/source_location.hpp rename to include/rexy/compat/source_location.hpp index ca992fa..ec48ac5 100644 --- a/include/rexy/source_location.hpp +++ b/include/rexy/compat/source_location.hpp @@ -32,7 +32,7 @@ #define CONSTEVAL constexpr #endif -namespace rexy{ +namespace rexy::compat{ class source_location { @@ -111,7 +111,7 @@ namespace rexy{ #include -namespace rexy{ +namespace rexy::compat{ using source_location = std::source_location; diff --git a/include/rexy/compat/to_address.hpp b/include/rexy/compat/to_address.hpp new file mode 100644 index 0000000..19d3428 --- /dev/null +++ b/include/rexy/compat/to_address.hpp @@ -0,0 +1,50 @@ +/** + This file is a part of rexy's general purpose library + Copyright (C) 2022 rexy712 + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef REXY_COMPAT_TO_ADDRESS_HPP +#define REXY_COMPAT_TO_ADDRESS_HPP + +#if __cplusplus >= 202002L + #include //to_address +#endif + + +namespace rexy::compat{ +#if __cplusplus >= 202002L + template + constexpr T* to_address(T* p)noexcept{ + return std::to_address(p); + } + template + constexpr auto to_address(const Ptr& p)noexcept{ + return std::to_address(p); + } +#else + template + constexpr T* to_address(T* p)noexcept{ + return p; + } + template + constexpr auto to_address(const Ptr& p)noexcept{ + return to_address(p.operator->()); + } +#endif + +} + +#endif diff --git a/include/rexy/cx/string.hpp b/include/rexy/cx/string.hpp index 2aeccd7..f0156d1 100644 --- a/include/rexy/cx/string.hpp +++ b/include/rexy/cx/string.hpp @@ -83,7 +83,7 @@ namespace rexy::cx{ } } - constexpr string(const rexy::string_view& str)noexcept: + constexpr string(const rexy::basic_string_view& str)noexcept: m_length(str.length()) { for(size_type i = 0;i < m_length;++i){ @@ -167,7 +167,7 @@ namespace rexy::cx{ constexpr void append(const string& s)noexcept{ append(s.get(), s.length()); } - constexpr void append(const rexy::string_view& s)noexcept{ + constexpr void append(const rexy::basic_string_view& s)noexcept{ append(s.get(), s.length()); } }; @@ -193,11 +193,11 @@ namespace rexy::cx{ } template::value,int> = 0> constexpr auto operator+(Str1&& l, const char* r)noexcept{ - return string_cat_expr(std::forward(l), rexy::string_view(r)); + return string_cat_expr(std::forward(l), rexy::basic_string_view(r)); } template::value,int> = 0> constexpr auto operator+(const char* l, Str1&& r)noexcept{ - return string_cat_expr(rexy::string_view(l), std::forward(r)); + return string_cat_expr(rexy::basic_string_view(l), std::forward(r)); } } diff --git a/include/rexy/debug_print.hpp b/include/rexy/debug_print.hpp index c526224..a4028ab 100644 --- a/include/rexy/debug_print.hpp +++ b/include/rexy/debug_print.hpp @@ -40,7 +40,7 @@ #include //fprintf, vfprintf #include //forward - #include "source_location.hpp" + #include "compat/source_location.hpp" namespace rexy::debug{ @@ -53,7 +53,7 @@ } template struct print{ - explicit print(Args&&... args, const rexy::source_location& loc = rexy::source_location::current()){ + explicit print(Args&&... args, const rexy::compat::source_location& loc = rexy::compat::source_location::current()){ std::fprintf(stderr, "%s:%s:%d: ", loc.file_name(), loc.function_name(), loc.line()); std::fprintf(stderr, std::forward(args)...); } @@ -67,7 +67,7 @@ #ifdef REXY_ENABLE_COLOR_DEBUG template struct print_succ{ - explicit print_succ(Args&&... args, const rexy::source_location& loc = rexy::source_location::current()){ + explicit print_succ(Args&&... args, const rexy::compat::source_location& loc = rexy::compat::source_location::current()){ std::fprintf(stderr, "%s", detail::color_green); std::fprintf(stderr, "%s:%s:%d: ", loc.file_name(), loc.function_name(), loc.line()); std::fprintf(stderr, std::forward(args)...); @@ -80,7 +80,7 @@ }; template struct print_info{ - explicit print_info(Args&&... args, const rexy::source_location& loc = rexy::source_location::current()){ + explicit print_info(Args&&... args, const rexy::compat::source_location& loc = rexy::compat::source_location::current()){ std::fprintf(stderr, "%s", detail::color_blue); std::fprintf(stderr, "%s:%s:%d: ", loc.file_name(), loc.function_name(), loc.line()); std::fprintf(stderr, std::forward(args)...); @@ -93,7 +93,7 @@ }; template struct print_warn{ - explicit print_warn(Args&&... args, const rexy::source_location& loc = rexy::source_location::current()){ + explicit print_warn(Args&&... args, const rexy::compat::source_location& loc = rexy::compat::source_location::current()){ std::fprintf(stderr, "%s", detail::color_yellow); std::fprintf(stderr, "%s:%s:%d: ", loc.file_name(), loc.function_name(), loc.line()); std::fprintf(stderr, std::forward(args)...); @@ -106,7 +106,7 @@ }; template struct print_error{ - explicit print_error(Args&&... args, const rexy::source_location& loc = rexy::source_location::current()){ + explicit print_error(Args&&... args, const rexy::compat::source_location& loc = rexy::compat::source_location::current()){ std::fprintf(stderr, "%s", detail::color_red); std::fprintf(stderr, "%s:%s:%d: ", loc.file_name(), loc.function_name(), loc.line()); std::fprintf(stderr, std::forward(args)...); diff --git a/include/rexy/detail/binary_string_conv.hpp b/include/rexy/detail/binary_string_conv.hpp index ed09f47..3d966f1 100644 --- a/include/rexy/detail/binary_string_conv.hpp +++ b/include/rexy/detail/binary_string_conv.hpp @@ -24,7 +24,7 @@ #include //memcpy namespace rexy{ - template = 0> + template,int> = 0> auto binary_to_string(const binary_base& b) noexcept(std::is_nothrow_constructible::value) { @@ -32,7 +32,7 @@ namespace rexy{ s.append(b.get(), b.size()); return s; } - template = 0, std::enable_if_t,typename Str::allocator_type>::value,int> = 0> + template,int> = 0, std::enable_if_t,typename Str::allocator_type>::value,int> = 0> auto binary_to_string(basic_binary&& b)noexcept{ return Str(rexy::steal(b.release()), b.size()); } diff --git a/include/rexy/static_string_hash.hpp b/include/rexy/static_string_hash.hpp index 2e1a19c..79b3404 100644 --- a/include/rexy/static_string_hash.hpp +++ b/include/rexy/static_string_hash.hpp @@ -26,7 +26,7 @@ namespace rexy{ template - struct hash> : public string_hash>{}; + struct hash> : public string_hash>{}; } diff --git a/include/rexy/steal.hpp b/include/rexy/steal.hpp index f5abdbc..3dba273 100644 --- a/include/rexy/steal.hpp +++ b/include/rexy/steal.hpp @@ -34,7 +34,7 @@ namespace rexy{ public: template - constexpr steal(U&& u) + constexpr explicit steal(U&& u) noexcept(std::is_nothrow_constructible::value): m_val(std::forward(u)){} diff --git a/include/rexy/string.hpp b/include/rexy/string.hpp index b2cd045..2bf3a10 100644 --- a/include/rexy/string.hpp +++ b/include/rexy/string.hpp @@ -33,6 +33,14 @@ namespace rexy{ extern template class basic_string>; extern template class basic_string>; + + using string_view = basic_string_view; + + extern template class basic_string_view; + extern template class basic_string_view; + extern template class basic_string_view; + extern template class basic_string_view; + } #ifdef REXY_CX_HASH_HPP diff --git a/include/rexy/string_base.hpp b/include/rexy/string_base.hpp index b2bfbe3..54feaf7 100644 --- a/include/rexy/string_base.hpp +++ b/include/rexy/string_base.hpp @@ -37,8 +37,90 @@ #include "detail/cpp20.hpp" +#if __cplusplus >= 202002L + #include +#endif + namespace rexy{ + template + class string_base; + + template + class basic_string_view + { + public: + using value_type = Char; + using size_type = size_t; + using difference_type = ptrdiff_t; + using pointer = value_type*; + using const_pointer = const value_type*; + using reference = value_type&; + using const_reference = const value_type&; + using iterator = pointer; + using const_iterator = const_pointer; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + private: + const_pointer m_data = nullptr; + size_type m_length = 0; + + public: + constexpr basic_string_view(void)noexcept; + constexpr basic_string_view(const_pointer str, size_type len)noexcept; + constexpr basic_string_view(const_pointer c)noexcept; + constexpr basic_string_view(const basic_string_view& s)noexcept; + constexpr basic_string_view(const string_base& s)noexcept; + constexpr basic_string_view(basic_string_view&& s)noexcept; + template + constexpr basic_string_view(InIter start, InIter fin)noexcept; + REXY_CPP20_CONSTEXPR ~basic_string_view(void)noexcept = default; + + constexpr basic_string_view& operator=(const_pointer c)noexcept; + constexpr basic_string_view& operator=(const basic_string_view& s)noexcept; + constexpr basic_string_view& operator=(basic_string_view&&)noexcept; + + + //Length of string not including null terminator + constexpr size_type length(void)const noexcept{return m_length;} + //direct access to managed pointer + constexpr const_pointer c_str(void)const noexcept{return m_data;} + constexpr const_pointer get(void)const noexcept{return m_data;} + constexpr operator const_pointer(void)const noexcept{return m_data;} + //true if m_data is not empty + constexpr bool valid(void)const noexcept{return m_length > 0;} + + constexpr const_reference operator[](size_type i)const noexcept{return m_data[i];} + + constexpr const_iterator search(const basic_string_view& s)const; + constexpr const_iterator search(const_pointer c)const; + template + constexpr const_iterator search(const basic_string_view& s, const Searcher& searcher)const; + template + constexpr const_iterator search(const_pointer c, const Searcher& searcher)const; + constexpr bool compare(const basic_string_view& s)const{return *this == s;} + constexpr bool compare(const_pointer c)const{return *this == c;} + + constexpr const_iterator begin(void)const{return m_data;} + constexpr const_iterator end(void)const{return m_data+m_length;} + constexpr const_iterator cbegin(void)const{return begin();} + constexpr const_iterator cend(void)const{return end();} + + constexpr const_reverse_iterator rbegin(void)const{return const_reverse_iterator(m_data+m_length);} + constexpr const_reverse_iterator rend(void)const{return const_reverse_iterator(m_data-1);} + constexpr const_reverse_iterator crbegin(void)const{return rbegin();} + constexpr const_reverse_iterator crend(void)const{return rend();} + }; + + template + basic_string_view(const T*) -> basic_string_view; + template + basic_string_view(const T*, size_t) -> basic_string_view; + + template + using static_string [[deprecated]] = basic_string_view; + //Base of all RAII strings. Its use is allowing passing of rexy strings to functions without knowing the exact type template class string_base @@ -274,6 +356,7 @@ namespace rexy{ REXY_CPP20_CONSTEXPR basic_string(size_type len, size_type cap)noexcept(noexcept(this->allocate(0))); template REXY_CPP20_CONSTEXPR basic_string(InputIt start, InputIt fin)noexcept(noexcept(this->allocate(0))); + REXY_CPP20_CONSTEXPR basic_string(const basic_string_view& sv)noexcept(noexcept(this->allocate(0))); //normal copy and move ctors REXY_CPP20_CONSTEXPR basic_string(const basic_string& b)noexcept(noexcept(this->allocate(0))); constexpr basic_string(basic_string&& s)noexcept; @@ -291,6 +374,9 @@ namespace rexy{ REXY_CPP20_CONSTEXPR basic_string& operator=(const string_base& s) noexcept(noexcept(this->allocate(0)) && noexcept(this->deallocate(nullptr,0))); + REXY_CPP20_CONSTEXPR basic_string& operator=(const basic_string_view& sv) + noexcept(noexcept(this->allocate(0)) && + noexcept(this->deallocate(nullptr,0))); //Copy from c string REXY_CPP20_CONSTEXPR basic_string& operator=(const_pointer c) noexcept(noexcept(this->allocate(0)) && @@ -355,146 +441,249 @@ namespace rexy{ template string_cat_expr(Left&&,Right&&) -> string_cat_expr; - template - class string_view : public string_base - { - public: - using value_type = typename string_base::value_type; - using size_type = typename string_base::size_type; - using difference_type = typename string_base::difference_type; - using pointer = typename string_base::pointer; - using const_pointer = typename string_base::const_pointer; - using reference = typename string_base::reference; - using const_reference = typename string_base::const_reference; - using iterator = typename string_base::iterator; - using const_iterator = typename string_base::const_iterator; +#if __cplusplus >= 202002L - public: - constexpr string_view(void)noexcept; - constexpr string_view(const_pointer str, size_type len)noexcept; - constexpr string_view(const_pointer c)noexcept; - constexpr string_view(const string_view& s)noexcept; - constexpr string_view(const string_base& s)noexcept; - constexpr string_view(string_view&& s)noexcept; - template - constexpr string_view(InIter start, InIter fin)noexcept; - REXY_CPP20_CONSTEXPR ~string_view(void)noexcept = default; - - constexpr string_view& operator=(const_pointer c)noexcept; - constexpr string_view& operator=(const string_view& s)noexcept; - constexpr string_view& operator=(string_view&&)noexcept; + template + concept BasicString = requires(T a){ + {a.length()} -> std::same_as::size_type>; + {a.c_str()} -> std::same_as::const_pointer>; + {a[0]} -> std::same_as::const_reference>; + {a.begin()} -> std::same_as::const_iterator>; + {a.end()} -> std::same_as::const_iterator>; }; - template - string_view(const T*) -> string_view; + concept StringExpr = rexy::is_template_type::value; template - string_view(const T*, size_t) -> string_view; - - template - using static_string [[deprecated]] = string_view; + concept String = BasicString || StringExpr; template struct is_string{ - static constexpr bool value = rexy::is_template_derived_type::value || rexy::is_template_type::value; + static constexpr bool value = BasicString; }; template - struct is_concrete_string{ - static constexpr bool value = rexy::is_template_derived_type::value; + static constexpr bool is_string_v = is_string::value; + template + struct are_strings{ + static constexpr bool value = (BasicString && ...); }; - namespace detail{ + template + static constexpr bool are_strings_v = are_strings::value; + template + struct is_string_expr{ + static constexpr bool value = StringExpr; + }; + template + static constexpr bool is_string_expr_v = is_string_expr::value; + template + struct are_string_expr{ + static constexpr bool value = (StringExpr && ...); + }; + template + static constexpr bool are_string_expr_v = are_string_expr::value; - template - using enable_if_string = std::enable_if_t<(is_string::value && ...),int>; - template - using enable_if_concrete_string = std::enable_if_t<(is_concrete_string::value && ...),int>; - template - using enable_if_expr_string = std::enable_if_t<(rexy::is_template_type::value && ...),int>; - - } //namespace detail - - template = 0> - constexpr bool operator==(Str1&& left, Str2&& right)noexcept{ - return left.valid() && right.valid() && left.length() == right.length() && !strcmp(left.get(), right.get()); + //Compare + template + constexpr bool operator==(Str1&& left, Str2&& right){ + return left.length() == right.length() && !strcmp(left.c_str(), right.c_str()); } - template = 0> - constexpr bool operator==(Str&& left, typename std::decay_t::const_pointer right)noexcept{ - return left.valid() && right && !strcmp(left.get(), right); - } - template = 0> - constexpr bool operator!=(Str1&& left, Str2&& right)noexcept{ - return !(left == right); - } - template = 0> - constexpr bool operator!=(Str&& left, typename std::decay_t::const_pointer right)noexcept{ - return !(left == right); + template + constexpr bool operator!=(Str1&& left, Str2&& right){ + return !(std::forward(left) == std::forward(right)); } - template = 0> + //String + string concat + template constexpr auto operator+(Left&& l, Right&& r) //uses deduction guide whereas std::is_nothrow_constructible couldn't noexcept(noexcept(::new (nullptr) string_cat_expr(std::forward(l), std::forward(r)))) { return string_cat_expr(std::forward(l), std::forward(r)); } - template = 0> + template constexpr auto operator+(typename std::decay_t::const_pointer left, Right&& right) - noexcept(noexcept(::new (nullptr) string_cat_expr(rexy::string_view(left), std::forward(right)))) + noexcept(noexcept(::new (nullptr) string_cat_expr(rexy::basic_string_view(left), std::forward(right)))) { - return string_cat_expr(rexy::string_view(left), std::forward(right)); + return string_cat_expr(rexy::basic_string_view(left), std::forward(right)); } - - template = 0> + template constexpr auto operator+(Left&& left, typename std::decay_t::const_pointer right) - noexcept(noexcept(::new (nullptr) string_cat_expr(std::forward(left), rexy::string_view(right)))) + noexcept(noexcept(::new (nullptr) string_cat_expr(std::forward(left), rexy::basic_string_view(right)))) { - return rexy::string_cat_expr(std::forward(left), rexy::string_view(right)); + return rexy::string_cat_expr(std::forward(left), rexy::basic_string_view(right)); } - template = 0, detail::enable_if_string = 0> + //String concat assign + template REXY_CPP20_CONSTEXPR 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> + template REXY_CPP20_CONSTEXPR decltype(auto) operator+=(Left& l, typename std::decay_t::const_pointer r) noexcept(noexcept(l + r) && std::is_nothrow_assignable::value) { return l = (l + r); } + +#else //__cplusplus == 202002L + + #define HAS_MEMFUN_WITH_RET(type, ret, fun, ...) \ + template \ + struct has_##fun##_f{ \ + std::false_type check(...); \ + template \ + auto check(type* u) -> std::enable_if().fun(__VA_ARGS__),ret>,std::true_type>; \ + \ + static constexpr bool value = decltype(check(std::declval()))::value; \ + }; \ + template \ + static constexpr bool has_##fun##_f_v = has_##fun##_f::value + + #define HAS_MEMOP_WITH_RET(type, ret, opname, op, ...) \ + template \ + struct has_##opname##_f{ \ + std::false_type check(...); \ + template \ + auto check(type* u) -> std::enable_if().operator op(__VA_ARGS__),ret>,std::true_type>; \ + \ + static constexpr bool value = decltype(check(std::declval()))::value; \ + }; \ + template \ + static constexpr bool has_##opname##_f_v = has_##opname##_f::value + + + HAS_MEMFUN_WITH_RET(U, typename U::size_type, length); + HAS_MEMFUN_WITH_RET(U, typename U::const_pointer, c_str); + HAS_MEMOP_WITH_RET(U, typename U::const_reference, indexop, [], 0); + HAS_MEMFUN_WITH_RET(U, typename U::const_iterator, begin); + HAS_MEMFUN_WITH_RET(U, typename U::const_iterator, end); + + #undef HAS_MEMFUN_WITH_RET + #undef HAS_MEMOP_WITH_RET + + template + struct is_string{ + static constexpr bool value = has_length_f_v && has_c_str_f_v && has_indexop_f_v && has_begin_f_v && has_end_f_v; + }; + template + static constexpr bool is_string_v = is_string::value; + template + struct are_strings{ + static constexpr bool value = (is_string::value && ...); + }; + template + static constexpr bool are_strings_v = are_strings::value; + template + struct is_string_expr{ + static constexpr bool value = rexy::is_template_type::value; + }; + template + static constexpr bool is_string_expr_v = is_string_expr::value; + template + struct are_string_expr{ + static constexpr bool value = (is_string_expr::value && ...); + }; + template + static constexpr bool are_string_expr_v = are_string_expr::value; + + //Compare + template::value,int> = 0> + constexpr bool operator==(Str1&& left, Str2&& right){ + return left.length() == right.length() && !strcmp(left.c_str(), right.c_str()); + } + template::value,int> = 0> + constexpr bool operator!=(Str1&& left, Str2&& right)noexcept{ + return !(std::forward(left) == std::forward(right)); + } + + //String + string concat + template::value,int> = 0> + constexpr auto operator+(Left&& l, Right&& r) + //uses deduction guide whereas std::is_nothrow_constructible couldn't + noexcept(noexcept(::new (nullptr) string_cat_expr(std::forward(l), std::forward(r)))) + { + return string_cat_expr(std::forward(l), std::forward(r)); + } + template::value,int> = 0> + constexpr auto operator+(typename std::decay_t::const_pointer left, Right&& right) + noexcept(noexcept(::new (nullptr) string_cat_expr(rexy::basic_string_view(left), std::forward(right)))) + { + return string_cat_expr(rexy::basic_string_view(left), std::forward(right)); + } + template::value,int> = 0> + constexpr auto operator+(Left&& left, typename std::decay_t::const_pointer right) + noexcept(noexcept(::new (nullptr) string_cat_expr(std::forward(left), rexy::basic_string_view(right)))) + { + return rexy::string_cat_expr(std::forward(left), rexy::basic_string_view(right)); + } + + + //String + expr concat + template::value && is_string_expr::value,int> = 0> + constexpr auto operator+(Left&& left, Right&& right){ + return string_cat_expr(std::forward(left), std::forward(right)); + } + template::value && is_string::value,int> = 0> + constexpr auto operator+(Left&& left, Right&& right){ + return string_cat_expr(std::forward(left), std::forward(right)); + } + + //String concat assignment + template::value,int> = 0> + REXY_CPP20_CONSTEXPR 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::value && is_string_expr::value,int> = 0> + REXY_CPP20_CONSTEXPR 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::value, int> = 0> + REXY_CPP20_CONSTEXPR decltype(auto) operator+=(Left& l, typename std::decay_t::const_pointer r) + noexcept(noexcept(l + r) && std::is_nothrow_assignable::value) + { + return l = (l + r); + } + +#endif //__cplusplus == 202002L + } #include "string_base.tpp" namespace{ [[deprecated]] - constexpr inline rexy::string_view operator"" _ss(const char* str, size_t len)noexcept{ - return rexy::string_view(str, len); + constexpr inline rexy::basic_string_view operator"" _ss(const char* str, size_t len)noexcept{ + return rexy::basic_string_view(str, len); } [[deprecated]] - constexpr inline rexy::string_view operator"" _ss(const wchar_t* str, size_t len)noexcept{ - return rexy::string_view(str, len); + constexpr inline rexy::basic_string_view operator"" _ss(const wchar_t* str, size_t len)noexcept{ + return rexy::basic_string_view(str, len); } [[deprecated]] - constexpr inline rexy::string_view operator"" _ss(const char16_t* str, size_t len)noexcept{ - return rexy::string_view(str, len); + constexpr inline rexy::basic_string_view operator"" _ss(const char16_t* str, size_t len)noexcept{ + return rexy::basic_string_view(str, len); } [[deprecated]] - constexpr inline rexy::string_view operator"" _ss(const char32_t* str, size_t len)noexcept{ - return rexy::string_view(str, len); + constexpr inline rexy::basic_string_view operator"" _ss(const char32_t* str, size_t len)noexcept{ + return rexy::basic_string_view(str, len); } - constexpr inline rexy::string_view operator"" _sv(const char* str, size_t len)noexcept{ - return rexy::string_view(str, len); + constexpr inline rexy::basic_string_view operator"" _sv(const char* str, size_t len)noexcept{ + return rexy::basic_string_view(str, len); } - constexpr inline rexy::string_view operator"" _sv(const wchar_t* str, size_t len)noexcept{ - return rexy::string_view(str, len); + constexpr inline rexy::basic_string_view operator"" _sv(const wchar_t* str, size_t len)noexcept{ + return rexy::basic_string_view(str, len); } - constexpr inline rexy::string_view operator"" _sv(const char16_t* str, size_t len)noexcept{ - return rexy::string_view(str, len); + constexpr inline rexy::basic_string_view operator"" _sv(const char16_t* str, size_t len)noexcept{ + return rexy::basic_string_view(str, len); } - constexpr inline rexy::string_view operator"" _sv(const char32_t* str, size_t len)noexcept{ - return rexy::string_view(str, len); + constexpr inline rexy::basic_string_view operator"" _sv(const char32_t* str, size_t len)noexcept{ + return rexy::basic_string_view(str, len); } template @@ -502,7 +691,7 @@ namespace{ return os << str.c_str(); } template - std::ostream& operator<<(std::ostream& os, const rexy::string_view& str){ + std::ostream& operator<<(std::ostream& os, const rexy::basic_string_view& str){ return os << str.c_str(); } diff --git a/include/rexy/string_base.tpp b/include/rexy/string_base.tpp index 8b60247..54cbe09 100644 --- a/include/rexy/string_base.tpp +++ b/include/rexy/string_base.tpp @@ -1,6 +1,6 @@ /** This file is a part of rexy's general purpose library - Copyright (C) 2020 rexy712 + Copyright (C) 2020-2022 rexy712 This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -22,11 +22,11 @@ #include //forward, move, swap, etc #include //memcpy #include //strlen, strcpy -#include //to_address #include "utility.hpp" //max #include "detail/string_appender.hpp" #include "algorithm.hpp" +#include "compat/to_address.hpp" #define STOP_STRICT_ALIAS_WARNING(x) (x) @@ -133,6 +133,13 @@ namespace rexy{ { _copy_construct_string(nullptr, len, cap); } + template + REXY_CPP20_CONSTEXPR basic_string::basic_string(const basic_string_view& sv) + noexcept(noexcept(this->allocate(0))) + { + _copy_construct_string(sv.c_str(), sv.length(), sv.length()); + } + template template REXY_CPP20_CONSTEXPR basic_string::basic_string(InputIt start, InputIt fin) @@ -200,6 +207,14 @@ namespace rexy{ return (*this = basic_string(s)); } //Copy from c string + template + REXY_CPP20_CONSTEXPR basic_string& basic_string::operator=(const basic_string_view& sv) + noexcept(noexcept(this->allocate(0)) && + noexcept(this->deallocate(nullptr,0))) + { + return _copy_string(sv.c_str(), sv.length()); + } + template REXY_CPP20_CONSTEXPR basic_string& basic_string::operator=(const_pointer c) noexcept(noexcept(this->allocate(0)) && @@ -327,7 +342,7 @@ namespace rexy{ noexcept(noexcept(this->allocate(0)) && noexcept(this->deallocate(nullptr,0))) { - if(!len) + if(!s || !len) return (*this = basic_string(rexy::steal(nullptr), 0, 0)); if(len <= this->length()){ this->set_length(len); @@ -359,63 +374,48 @@ namespace rexy{ template - constexpr string_view::string_view(void)noexcept: - string_view(nullptr, 0){} + constexpr basic_string_view::basic_string_view(void)noexcept: + basic_string_view(nullptr, 0){} template - constexpr string_view::string_view(const_pointer str, size_type len)noexcept{ - if(!str) - this->set_long_ptr(nullptr); - else - this->set_long_ptr(const_cast(str)); - this->set_long_length(len); - this->set_long_capacity(len); - } + constexpr basic_string_view::basic_string_view(const_pointer str, size_type len)noexcept: + m_data(str), m_length(len){} template - constexpr string_view::string_view(const string_view& s)noexcept: - string_view(s.get_long_ptr(), s.get_long_length()){} + constexpr basic_string_view::basic_string_view(const basic_string_view& s)noexcept: + m_data(s.m_data), m_length(s.m_length){} template - constexpr string_view::string_view(const string_base& s)noexcept: - string_view(s.c_str(), s.length()){} + constexpr basic_string_view::basic_string_view(const string_base& s)noexcept: + m_data(s.c_str()), m_length(s.length()){} template - constexpr string_view::string_view(string_view&& s)noexcept: - string_view(s.get_long_ptr(), s.get_long_length()){} + constexpr basic_string_view::basic_string_view(basic_string_view&& s)noexcept: + m_data(s.m_data), m_length(s.m_length){} template template - constexpr string_view::string_view(InIter start, InIter fin)noexcept: - string_view(std::to_address(start), fin - start){} + constexpr basic_string_view::basic_string_view(InIter start, InIter fin)noexcept: + basic_string_view(compat::to_address(start), fin - start){} template - constexpr string_view& string_view::operator=(const string_view& s)noexcept{ - this->set_long_ptr(const_cast(s.get_long_ptr())); - this->set_long_length(s.get_long_length()); - this->set_long_capacity(s.get_long_capacity()); + constexpr basic_string_view& basic_string_view::operator=(const basic_string_view& s)noexcept{ + m_data = s.m_data; + m_length = s.m_length; return *this; } template - constexpr string_view::string_view(const_pointer c)noexcept: - string_view(c, strlen(c)){} + constexpr basic_string_view::basic_string_view(const_pointer c)noexcept: + basic_string_view(c, strlen(c)){} template - constexpr string_view& string_view::operator=(const_pointer c)noexcept{ - size_type len = strlen(c); - this->set_long_ptr(const_cast(c)); - this->set_long_length(len); - this->set_long_capacity(len); + constexpr basic_string_view& basic_string_view::operator=(const_pointer c)noexcept{ + m_data = c; + m_length = strlen(c); return *this; } template - constexpr string_view& string_view::operator=(string_view&& s)noexcept{ - this->set_long_ptr(s.get_long_ptr()); - this->set_long_length(s.get_long_length()); - this->set_long_capacity(s.get_long_capacity()); + constexpr basic_string_view& basic_string_view::operator=(basic_string_view&& s)noexcept{ + m_data = s.m_data; + m_length = s.m_length; return *this; } - extern template class string_view; - extern template class string_view; - extern template class string_view; - extern template class string_view; - } //namespace rexy #undef STOP_STRICT_ALIAS_WARNING diff --git a/src/ensure.cpp b/src/ensure.cpp index b53ebcf..0d8b1fe 100644 --- a/src/ensure.cpp +++ b/src/ensure.cpp @@ -21,10 +21,10 @@ #include "rexy/meta.hpp" #include "rexy/enum_traits.hpp" #include "rexy/deferred.hpp" -#include "rexy/source_location.hpp" #include "rexy/demangle.hpp" #include "rexy/debug_print.hpp" #include "rexy/storage_for.hpp" +#include "rexy/visitor.hpp" #include "rexy/detail/binary_string_conv.hpp" #include "rexy/detail/string_appender.hpp" @@ -35,3 +35,6 @@ #include "rexy/cx/vector.hpp" #include "rexy/cx/detail/bool_specialize_base.hpp" + +#include "rexy/compat/to_address.hpp" +#include "rexy/compat/source_location.hpp" diff --git a/src/static_string.cpp b/src/static_string.cpp index 6634190..47d4363 100644 --- a/src/static_string.cpp +++ b/src/static_string.cpp @@ -20,9 +20,9 @@ namespace rexy{ - template class string_view; - template class string_view; - template class string_view; - template class string_view; + template class basic_string_view; + template class basic_string_view; + template class basic_string_view; + template class basic_string_view; }