From 4cad6f794d3993332fbe0c6dcb64838810165738 Mon Sep 17 00:00:00 2001 From: rexy712 Date: Fri, 24 Apr 2020 12:52:47 -0700 Subject: [PATCH] Improve readability and constexpr-ness --- CMakeLists.txt | 6 +- include/rexy/binary.hpp | 57 +++++++++---------- include/rexy/detail/binary_string_conv.hpp | 47 ++++++++-------- include/rexy/detail/util.hpp | 64 ++++++++++++++++++---- include/rexy/filerd.hpp | 14 +++-- include/rexy/string.hpp | 4 +- include/rexy/string_base.hpp | 33 +++++------ include/rexy/string_base.tpp | 51 ++++------------- src/filerd.cpp | 6 -- src/string_base.cpp | 44 --------------- 10 files changed, 147 insertions(+), 179 deletions(-) delete mode 100644 src/string_base.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 60287a5..d84bab4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,7 +14,7 @@ option(ENABLE_SHARED "Build shared library" ON) option(ENABLE_PROFILING "Enable asan" OFF) mark_as_advanced(ENABLE_PROFILING) -set(SOURCE_LIST "src/binary.cpp" "src/string_base.cpp" "src/filerd.cpp") +set(SOURCE_LIST "src/binary.cpp" "src/filerd.cpp") if(ENABLE_SHARED) add_library(rexy SHARED ${SOURCE_LIST}) set_target_properties(rexy PROPERTIES SOVERSION "${librexy_VERSION_MAJOR}.${librexy_VERSION_MINOR}.${librexy_VERSION_REVISION}") @@ -27,7 +27,8 @@ 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/steal.hpp" "include/rexy/binary.hpp" "include/rexy/string_base.hpp" "include/rexy/string.hpp" "include/rexy/filerd.hpp" "include/rexy/string_base.tpp" "include/rexy/detail/binary_string_conv.hpp" "include/rexy/detail/default_allocator.hpp" "include/rexy/detail/util.hpp") +set(LIBREXY_PUBLIC_HEADERS "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_DETAIL_HEADERS "include/rexy/detail/binary_string_conv.hpp" "include/rexy/detail/default_allocator.hpp" "include/rexy/detail/util.hpp") target_compile_options(rexy PRIVATE -Wall -Wextra -pedantic -std=c++17) install(TARGETS rexy @@ -38,6 +39,7 @@ 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(FILES ${LIBREXY_DETAIL_HEADERS} DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/rexy/detail/") configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/pc/librexy.pc.cmake.in" diff --git a/include/rexy/binary.hpp b/include/rexy/binary.hpp index 0343ff4..7eaf20b 100644 --- a/include/rexy/binary.hpp +++ b/include/rexy/binary.hpp @@ -23,10 +23,9 @@ #include //move #include //memcpy #include -#include -#include //max -#include -#include +#include "detail/util.hpp" //max +#include "detail/default_allocator.hpp" +#include "steal.hpp" #define STOP_STRICT_ALIAS_WARNING(x) (x) @@ -146,34 +145,36 @@ namespace rexy{ 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>; } -} - -template::value && rexy::detail::is_binary_type::value,void>::type* = nullptr> -bool operator==(Left&& l, Right&& r){ - return l && r && l.size() == r.size() && l.capacity() == r.capacity() && !memcmp(l.get(), r.get(), l.size()); -} -template::value && rexy::detail::is_binary_type::value,void>::type* = nullptr> -bool operator!=(Left&& l, Right&& r){ - return !(std::forward(l) == std::forward(r)); -} -template -auto operator+(const rexy::binary_data& l, const rexy::binary_data& 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; -} -template -decltype(auto) operator+=(rexy::binary_data& l, const rexy::binary_data& r){ - l.resize(l.size() + r.size()); - memcpy(l.get()+l.size(), r.get(), r.size()); - return l; -} + template = 0> + bool operator==(Left&& l, Right&& r){ + return l && r && l.size() == r.size() && l.capacity() == r.capacity() && !memcmp(l.get(), r.get(), l.size()); + } + template = 0> + bool operator!=(Left&& l, Right&& r){ + return !(std::forward(l) == std::forward(r)); + } + template + auto operator+(const rexy::binary_data& l, const rexy::binary_data& 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; + } + template + decltype(auto) operator+=(rexy::binary_data& l, const rexy::binary_data& r){ + l.resize(l.size() + r.size()); + memcpy(l.get()+l.size(), r.get(), r.size()); + return l; + } +} //namespace rexy #ifdef REXY_STRING_BASE_HPP -#include +#include "detail/binary_string_conv.hpp" #endif #endif diff --git a/include/rexy/detail/binary_string_conv.hpp b/include/rexy/detail/binary_string_conv.hpp index ec8a401..e4ec1cf 100644 --- a/include/rexy/detail/binary_string_conv.hpp +++ b/include/rexy/detail/binary_string_conv.hpp @@ -19,53 +19,54 @@ #ifndef REXY_BINARY_STRING_CONV_HPP #define REXY_BINARY_STRING_CONV_HPP -#include -#include +#include "rexy/string.hpp" +#include "rexy/binary.hpp" +#include //memcpy namespace rexy{ - template::value,void>::type* = nullptr> + template = 0> auto binary_to_string(const binary_data& b){ Str s(b.size()+1); memcpy(s.get(), b.get(), b.size()); s[b.size()] = 0; return s; } - template::value && std::is_same::type,typename Str::allocator_type>::value,void>::type* = nullptr> + template = 0, std::enable_if_t,typename Str::allocator_type>::value,int> = 0> auto binary_to_string(binary_data&& b){ Str s; s.reset(b.get(), b.size()); b.release(); return s; } - template::value,void>::type* = nullptr> + template = 0> auto string_to_binary(const string_base& s){ Bin b(s.length()+1); b.append(s.get(), s.length()+1); return b; } - template::value && std::is_same::type,typename Bin::allocator_type>::value,void>::type* = nullptr> + template = 0, std::enable_if_t,typename Bin::allocator_type>::value,int> = 0> auto string_to_binary(string_intermediary&& s){ Bin b; b.reset(s.get(), s.length()+1); s.release(); return b; } -} -template::value && rexy::detail::is_concrete_string::value,void>::type* = nullptr> -decltype(auto) operator+=(L& l, R&& r){ - l.append(r.get(), r.length()+1); - return l; -} -template::value && rexy::detail::is_string::value && !rexy::detail::is_concrete_string::value,void>::type* = nullptr> -decltype(auto) operator+=(L& l, R&& r){ - rexy::string concrete = r; - return (l = concrete); -} -template::value && rexy::detail::is_binary_type::value,void>::type* = nullptr> -decltype(auto) operator+=(L& l, R&& r){ - l.resize(l.length(), r.size() + 1); - memcpy(l.get()+l.length()+1, r.get(), r.size()); - return l; -} + template = 0, detail::enable_if_concrete_string = 0> + decltype(auto) operator+=(L& l, R&& r){ + l.append(r.get(), r.length()+1); + return l; + } + template = 0, detail::enable_if_string = 0, std::enable_if_t::value,int> = 0> + decltype(auto) operator+=(L& l, R&& r){ + rexy::string concrete = r; + return (l = concrete); + } + template = 0, detail::enable_if_binary = 0> + decltype(auto) operator+=(L& l, R&& r){ + l.resize(l.length(), r.size() + 1); + memcpy(l.get()+l.length()+1, r.get(), r.size()); + return l; + } +} //namespace rexy #endif diff --git a/include/rexy/detail/util.hpp b/include/rexy/detail/util.hpp index a25dca3..ab1aafe 100644 --- a/include/rexy/detail/util.hpp +++ b/include/rexy/detail/util.hpp @@ -19,16 +19,60 @@ #ifndef REXY_DETAIL_UTIL_HPP #define REXY_DETAIL_UTIL_HPP +#include //size_t + namespace rexy::detail{ - //including causes long compile times. so just make my own max instead - template - constexpr const T& max(const T& a, const T& b){ - return (a < b) ? b : a; - } - template - constexpr const T& min(const T& a, const T& b){ - return (a > b) ? b : a; - } -} + namespace{ + //including causes long compile times. so just make my own max instead + template + constexpr const T& max(const T& a, const T& b){ + return (a < b) ? b : a; + } + template + constexpr const T& min(const T& a, const T& b){ + return (a > b) ? b : a; + } + + constexpr size_t cx_strlen(const char* c){ + size_t i = 0; + for(;c[i];++i); + return i; + } + constexpr int cx_strcmp(const char* l, const char* r){ + using uchar = unsigned char; + for(;*l == *r && *l;++l, ++r); + return (uchar{*l}) - (uchar{*r}); + } + } //anonymous namespace +} //namespace detail + +//std::swap and std::exchange aren't constexpr until c++20 +#if __cplusplus > 201703L + #include + #define rexy_cx_swap(...) std::swap(__VA_ARGS__) + #define rexy_cx_exchange(...) std::exchange(__VA_ARGS__) +#else + #include + namespace rexy::detail{ + namespace{ + template + constexpr void cx_swap(T& a, T& b)noexcept(std::is_nothrow_move_constructible::value && + std::is_nothrow_move_assignable::value) + { + T tmp = std::move(a); + a = std::move(b); + b = std::move(tmp); + } + template + constexpr T cx_exchange(T& t, U&& u){ + T old = std::move(t); + t = std::forward(u); + return old; + } + } + } //namespace detail + #define rexy_cx_swap(...) detail::cx_swap(__VA_ARGS__) + #define rexy_cx_exchange(...) detail::cx_exchange(__VA_ARGS__) +#endif #endif diff --git a/include/rexy/filerd.hpp b/include/rexy/filerd.hpp index dd1deec..dc547f6 100644 --- a/include/rexy/filerd.hpp +++ b/include/rexy/filerd.hpp @@ -22,8 +22,8 @@ #include //FILE #include //size_t -#include -#include +#include "string.hpp" +#include "binary.hpp" namespace rexy{ @@ -34,13 +34,17 @@ namespace rexy{ FILE* m_fp = nullptr; public: - filerd(void) = default; + constexpr filerd(void) = default; filerd(const char* f, const char* mode = "r"); filerd(const filerd&) = delete; - filerd(filerd&& f); + constexpr filerd(filerd&& f): + m_fp(rexy_cx_exchange(f.m_fp, nullptr)){} ~filerd(void); filerd& operator=(const filerd&) = delete; - filerd& operator=(filerd&& f); + constexpr filerd& operator=(filerd&& f){ + rexy_cx_swap(m_fp, f.m_fp); + return *this; + } void reset(FILE* fp = nullptr); FILE* release(void); diff --git a/include/rexy/string.hpp b/include/rexy/string.hpp index b90e658..cdfc7bc 100644 --- a/include/rexy/string.hpp +++ b/include/rexy/string.hpp @@ -19,8 +19,8 @@ #ifndef REXY_STRING_HPP #define REXY_STRING_HPP -#include -#include +#include "string_base.hpp" +#include "detail/default_allocator.hpp" namespace rexy{ diff --git a/include/rexy/string_base.hpp b/include/rexy/string_base.hpp index 033c2bf..9eba175 100644 --- a/include/rexy/string_base.hpp +++ b/include/rexy/string_base.hpp @@ -23,7 +23,8 @@ #include //forward #include //size_t -#include +#include "steal.hpp" +#include "detail/util.hpp" namespace rexy{ @@ -52,7 +53,7 @@ namespace rexy{ public: //Stop managing stored pointer. Does not free. - char* release(void); + constexpr char* release(void){return rexy_cx_exchange(m_data, nullptr);} //Length of string not including null terminator constexpr size_t length(void)const{return m_length;} @@ -65,8 +66,8 @@ namespace rexy{ //true if m_data is not null constexpr bool valid(void)const{return m_data;} - char& operator[](size_t i); - const char& operator[](size_t i)const; + constexpr char& operator[](size_t i){return m_data[i];} + constexpr const char& operator[](size_t i)const{return m_data[i];} }; @@ -128,7 +129,6 @@ namespace rexy{ public: template constexpr string_cat_expr(T&& l, U&& r); - constexpr string_cat_expr(const string_cat_expr& s); constexpr string_cat_expr(string_cat_expr&& s); constexpr size_t length(void)const; @@ -139,30 +139,27 @@ namespace rexy{ }; template string_cat_expr(Left&, Right&) -> string_cat_expr; - template - string_cat_expr(const Left&, const 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(const Left&,Right&&) -> string_cat_expr; + template string_cat_expr(Left&&,Right&) -> string_cat_expr; - template - string_cat_expr(Left&&,const Right&) -> string_cat_expr; class static_string : public string_base { public: constexpr static_string(void) = default; constexpr static_string(const char* str, size_t len); - static_string(const char* c); + constexpr static_string(const char* c); constexpr static_string(const static_string& s); constexpr static_string(static_string&& s); ~static_string(void) = default; - static_string& operator=(const char* c); + constexpr static_string& operator=(const char* c); constexpr static_string& operator=(const static_string& s); constexpr static_string& operator=(static_string&&); }; @@ -200,11 +197,11 @@ namespace rexy{ }; } //namespace detail template = 0> - bool operator==(Str1&& left, Str2&& right){ - return left.valid() && right.valid() && left.length() == right.length() && !strcmp(left.get(), right.get()); + constexpr bool operator==(Str1&& left, Str2&& right){ + return left.valid() && right.valid() && left.length() == right.length() && !detail::cx_strcmp(left.get(), right.get()); } template = 0> - bool operator!=(Str1&& left, Str2&& right){ + constexpr bool operator!=(Str1&& left, Str2&& right){ return !(left == right); } @@ -232,7 +229,7 @@ namespace rexy{ } } -#include +#include "string_base.tpp" namespace{ constexpr inline rexy::static_string operator"" _ss(const char* str, size_t len){ @@ -241,7 +238,7 @@ namespace{ } #ifdef REXY_BINARY_HPP -#include +#include "detail/binary_string_conv.hpp" #endif #endif diff --git a/include/rexy/string_base.tpp b/include/rexy/string_base.tpp index 27b6f16..fc73aea 100644 --- a/include/rexy/string_base.tpp +++ b/include/rexy/string_base.tpp @@ -23,43 +23,9 @@ #include //memcpy #include //strlen, strcpy -#include //max +#include "detail/util.hpp" //max namespace rexy{ - 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 - constexpr void cx_swap(T& a, T& b){ - T tmp = std::move(a); - a = std::move(b); - b = std::move(tmp); - } - template - constexpr T cx_exchange(T& t, U&& u){ - T old = std::move(t); - t = std::forward(u); - return old; - } - } - } //namespace detail - #define cx_swap(...) detail::cx_swap(__VA_ARGS__) - #define cx_exchange(...) detail::cx_exchange(__VA_ARGS__) -#endif template constexpr string_intermediary::string_intermediary(void){} @@ -116,7 +82,7 @@ namespace rexy{ string_base(reinterpret_cast(b.m_length ? Allocator::copy(b.m_data, b.m_length+1) : nullptr), b.m_length, b.m_cap){} template constexpr string_intermediary::string_intermediary(string_intermediary&& s): - string_base(cx_exchange(s.m_data, nullptr), s.m_length, s.m_cap){} + string_base(rexy_cx_exchange(s.m_data, nullptr), s.m_length, s.m_cap){} template string_intermediary::string_intermediary(const string_base& b): @@ -140,7 +106,7 @@ namespace rexy{ } template constexpr string_intermediary& string_intermediary::operator=(string_intermediary&& s){ - cx_swap(m_data, s.m_data); + rexy_cx_swap(m_data, s.m_data); m_length = s.m_length; m_cap = s.m_cap; return *this; @@ -240,10 +206,6 @@ namespace rexy{ m_l(std::forward(l)), m_r(std::forward(r)){} template - constexpr string_cat_expr::string_cat_expr(const string_cat_expr& s): - m_l(s.m_l), - m_r(s.m_r){} - template constexpr string_cat_expr::string_cat_expr(string_cat_expr&& s): m_l(std::forward(s.m_l)), m_r(std::forward(s.m_r)){} @@ -282,6 +244,13 @@ namespace rexy{ m_length = s.m_length; return *this; } + constexpr static_string::static_string(const char* c): + static_string(const_cast(c), detail::cx_strlen(c)){} + constexpr static_string& static_string::operator=(const char* c){ + m_data = const_cast(c); + m_length = detail::cx_strlen(c); + return *this; + } constexpr static_string& static_string::operator=(static_string&& s){ m_data = s.m_data; m_length = s.m_length; diff --git a/src/filerd.cpp b/src/filerd.cpp index b882a43..d91acd7 100644 --- a/src/filerd.cpp +++ b/src/filerd.cpp @@ -25,16 +25,10 @@ namespace rexy{ filerd::filerd(const char* f, const char* mode): m_fp(fopen(f, mode)){} - filerd::filerd(filerd&& f): - m_fp(std::exchange(f.m_fp, nullptr)){} filerd::~filerd(void){ if(m_fp) fclose(m_fp); } - filerd& filerd::operator=(filerd&& f){ - std::swap(m_fp, f.m_fp); - return *this; - } void filerd::reset(FILE* fp){ if(m_fp) diff --git a/src/string_base.cpp b/src/string_base.cpp deleted file mode 100644 index a4a6445..0000000 --- a/src/string_base.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/** - This file is a part of rexy's general purpose library - Copyright (C) 2020 rexy712 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero 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 Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . -*/ - -#include "rexy/string_base.hpp" - -#include //exchange, swap -#include //memcpy -#include //strcpy, strlen - -namespace rexy{ - char* string_base::release(void){ - return std::exchange(m_data, nullptr); - } - char& string_base::operator[](size_t i){ - return m_data[i]; - } - const char& string_base::operator[](size_t i)const{ - return m_data[i]; - } - - static_string::static_string(const char* c): - static_string(const_cast(c), strlen(c)){} - static_string& static_string::operator=(const char* c){ - m_data = const_cast(c); - m_length = strlen(c); - return *this; - } - -}