From 00355a64c6adbec20157c7d213e8b45f4c78655e Mon Sep 17 00:00:00 2001 From: rexy712 Date: Sun, 19 Jun 2022 18:46:02 -0700 Subject: [PATCH] Update cx::string to be more level with string_view --- include/rexy/compat/cpp17/string_base.hpp | 34 ++++++ include/rexy/compat/cpp20/string_base.hpp | 77 +++++++------- include/rexy/compat/string_base.hpp | 34 ++++++ include/rexy/concepts/string.hpp | 73 +++++++++++++ include/rexy/cx/string.hpp | 124 ++++++++++++++-------- include/rexy/string_base.tpp | 6 +- include/rexy/string_view.hpp | 1 - include/rexy/string_view.tpp | 57 ++-------- 8 files changed, 269 insertions(+), 137 deletions(-) create mode 100644 include/rexy/compat/string_base.hpp create mode 100644 include/rexy/concepts/string.hpp diff --git a/include/rexy/compat/cpp17/string_base.hpp b/include/rexy/compat/cpp17/string_base.hpp index 6f2b657..80adf38 100644 --- a/include/rexy/compat/cpp17/string_base.hpp +++ b/include/rexy/compat/cpp17/string_base.hpp @@ -201,6 +201,40 @@ namespace rexy{ return l = (l + r); } + template::value, int> = 0> + constexpr std::size_t find_first_of(T&& t, const Char* c, std::size_t start, std::size_t size){ + if(start > t.length()){ + return rexy::npos; + } + for(auto it = t.cbegin() + start;it != t.cend();++it){ + for(std::size_t i = 0;i < size;++i){ + if(*it == c[i]){ + return it - t.cbegin(); + } + } + } + return rexy::npos; + } + + template::value, int> = 0> + constexpr std::size_t find_last_of(T&& t, const Char* c, std::size_t start, std::size_t size){ + if(start > t.length()){ + return rexy::npos; + } + + const auto b = t.cend() - 1; + const auto e = t.cbegin() - 1 - start; + + for(auto it = b;it != e;--it){ + for(std::size_t i = 0;i < size;++i){ + if(*it == c[i]){ + return it - t.cbegin(); + } + } + } + return rexy::npos; + } + } #endif diff --git a/include/rexy/compat/cpp20/string_base.hpp b/include/rexy/compat/cpp20/string_base.hpp index 3cabaf5..03c2faa 100644 --- a/include/rexy/compat/cpp20/string_base.hpp +++ b/include/rexy/compat/cpp20/string_base.hpp @@ -21,50 +21,13 @@ #include "../../string_base.hpp" -#include //convertible_to -#include //forward, as_const +#include //forward #include //decay, is_nothrow_assignable +#include "../../concepts/string.hpp" + namespace rexy{ - template - concept BasicString = requires(const T& a){ - {std::as_const(a).length()} -> std::convertible_to::size_type>; - {std::as_const(a).c_str()} -> std::convertible_to::const_pointer>; - {std::as_const(a)[0]} -> std::convertible_to::const_reference>; - {std::as_const(a).begin()} -> std::convertible_to::const_iterator>; - {std::as_const(a).end()} -> std::convertible_to::const_iterator>; - }; - template - concept StringExpr = rexy::is_template_type::value; - template - concept String = BasicString || StringExpr; - - template - struct is_string{ - static constexpr bool value = BasicString; - }; - template - static constexpr bool is_string_v = is_string::value; - template - struct are_strings{ - static constexpr bool value = (BasicString && ...); - }; - 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; - //Compare template constexpr bool operator==(Str1&& left, Str2&& right){ @@ -145,6 +108,40 @@ namespace rexy{ return l = (l + r); } + template + constexpr std::size_t find_first_of(T&& t, const Char* c, std::size_t start, std::size_t size){ + if(start > t.length()){ + return rexy::npos; + } + for(auto it = t.cbegin() + start;it != t.cend();++it){ + for(std::size_t i = 0;i < size;++i){ + if(*it == c[i]){ + return it - t.cbegin(); + } + } + } + return rexy::npos; + } + + template + constexpr std::size_t find_last_of(T&& t, const Char* c, std::size_t start, std::size_t size){ + if(start > t.length()){ + return rexy::npos; + } + + const auto b = t.cend() - 1; + const auto e = t.cbegin() - 1 - start; + + for(auto it = b;it != e;--it){ + for(std::size_t i = 0;i < size;++i){ + if(*it == c[i]){ + return it - t.cbegin(); + } + } + } + return rexy::npos; + } + } #endif diff --git a/include/rexy/compat/string_base.hpp b/include/rexy/compat/string_base.hpp new file mode 100644 index 0000000..daa4638 --- /dev/null +++ b/include/rexy/compat/string_base.hpp @@ -0,0 +1,34 @@ +/** + 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_STRING_BASE_HPP +#define REXY_COMPAT_STRING_BASE_HPP + +#include //size_t + +namespace rexy{ + static constexpr std::size_t npos = std::size_t{-1}; +} + +#ifdef __cpp_concepts + #include "cpp20/string_base.hpp" +#else + #include "cpp20/string_base.tpp" +#endif + +#endif diff --git a/include/rexy/concepts/string.hpp b/include/rexy/concepts/string.hpp new file mode 100644 index 0000000..d7ed044 --- /dev/null +++ b/include/rexy/concepts/string.hpp @@ -0,0 +1,73 @@ +/** + 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_CONCEPTS_STRING_HPP +#define REXY_CONCEPTS_STRING_HPP + +#include //decay +#include //convertible_to +#include //as_const + +#include "../traits.hpp" + +namespace rexy{ + + template + class string_cat_expr; + + template + concept BasicString = requires(const T& a){ + {std::as_const(a).length()} -> std::convertible_to::size_type>; + {std::as_const(a).c_str()} -> std::convertible_to::const_pointer>; + {std::as_const(a)[0]} -> std::convertible_to::const_reference>; + {std::as_const(a).begin()} -> std::convertible_to::const_iterator>; + {std::as_const(a).end()} -> std::convertible_to::const_iterator>; + }; + template + concept StringExpr = rexy::is_template_type::value; + template + concept String = BasicString || StringExpr; + + template + struct is_string{ + static constexpr bool value = BasicString; + }; + template + static constexpr bool is_string_v = is_string::value; + template + struct are_strings{ + static constexpr bool value = (BasicString && ...); + }; + 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; + +} + +#endif diff --git a/include/rexy/cx/string.hpp b/include/rexy/cx/string.hpp index 9e3b5b4..bcfdc80 100644 --- a/include/rexy/cx/string.hpp +++ b/include/rexy/cx/string.hpp @@ -27,11 +27,14 @@ namespace rexy::cx{ } #include "../string_base.hpp" //string_cat_expr -#include "../utility.hpp" //strlen +#include "../string_view.hpp" +#include "../utility.hpp" //strlen, strcmp #include "../detail/string_appender.hpp" #include //nothrow_invocable, integral_constant, declval, remove_cvref_t +#include //reverse_iterator #include "../compat/standard.hpp" +#include "../compat/string_base.hpp" //This is different from rexy::string_view in that this doesn't hold a pointer to a constant string array. //This holds a mutable array of data which can be modified during compile time. string_view is @@ -52,9 +55,13 @@ namespace rexy::cx{ 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; public: - static constexpr std::size_t max_size = N; + static constexpr size_type max_size = N; + static constexpr size_type npos = size_type{-1}; + public: value_type m_data[N] = {}; size_type m_length = 0; @@ -117,43 +124,59 @@ namespace rexy::cx{ constexpr string& operator=(const string&)noexcept = default; constexpr string& operator=(string&&)noexcept = default; + constexpr bool operator==(const string& s)noexcept{return !rexy::strcmp(m_data, s.m_data);} + constexpr bool operator!=(const string& s)noexcept{return rexy::strcmp(m_data, s.m_data);} - constexpr size_type length(void)const noexcept - {return m_length;} - constexpr size_type capacity(void)const noexcept - {return max_size;} - constexpr pointer c_str(void)noexcept - {return m_data;} - constexpr const_pointer c_str(void)const noexcept - {return m_data;} - constexpr pointer get(void)noexcept - {return m_data;} - constexpr const_pointer get(void)const noexcept - {return m_data;} - constexpr operator pointer(void)noexcept - {return m_data;} - constexpr operator const_pointer(void)const noexcept - {return m_data;} + constexpr size_type length(void)const noexcept{return m_length;} + constexpr size_type size(void)const noexcept{return m_length;} + constexpr size_type capacity(void)const noexcept{return max_size;} + constexpr bool empty(void)const noexcept{return m_length == 0;} - constexpr iterator begin(void)noexcept - {return m_data;} - constexpr const_iterator begin(void)const noexcept - {return m_data;} - constexpr const_iterator cbegin(void)const noexcept - {return m_data;} - constexpr iterator end(void)noexcept - {return m_data+m_length;} - constexpr const_iterator end(void)const noexcept - {return m_data+m_length;} - constexpr const_iterator cend(void)const noexcept - {return m_data+m_length;} + constexpr pointer c_str(void)noexcept{return m_data;} + constexpr const_pointer c_str(void)const noexcept{return m_data;} + constexpr pointer get(void)noexcept{return m_data;} + constexpr const_pointer get(void)const noexcept{return m_data;} + constexpr operator pointer(void)noexcept{return m_data;} + constexpr operator const_pointer(void)const noexcept{return m_data;} - constexpr bool valid(void)const noexcept - {return m_length > 0;} - constexpr reference operator[](size_type i)noexcept - {return m_data[i];} - constexpr const_reference operator[](size_type i)const noexcept - {return m_data[i];} + constexpr reference operator[](size_type i)noexcept{return m_data[i];} + constexpr const_reference operator[](size_type i)const noexcept{return m_data[i];} + constexpr reference at(size_type i)noexcept{return m_data[i];} + constexpr const_reference at(size_type i)const noexcept{return m_data[i];} + constexpr const_reference front(size_type i)const noexcept{return m_data[0];} + constexpr const_reference back(size_type i)const noexcept{return m_data[m_length-1];} + + constexpr const_iterator search(const basic_string_view& s)const{ + return two_way_search(cbegin(), cend(), s.cbegin(), s.cend()); + } + constexpr const_iterator search(const_pointer c)const{ + return search(basic_string_view{c}); + } + template + constexpr const_iterator search(const basic_string_view& s, Searcher&& searcher)const{ + return searcher(cbegin(), cend(), s.cbegin(), s.cend()); + } + template + constexpr const_iterator search(const_pointer c, Searcher&& searcher)const{ + return search(basic_string_view{c}, searcher); + } + + constexpr iterator begin(void)noexcept{return m_data;} + constexpr const_iterator begin(void)const noexcept{return m_data;} + constexpr const_iterator cbegin(void)const noexcept{return m_data;} + constexpr iterator end(void)noexcept{return m_data+m_length;} + constexpr const_iterator end(void)const noexcept{return m_data+m_length;} + constexpr const_iterator cend(void)const noexcept{return m_data+m_length;} + + 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();} + + constexpr bool valid(void)const noexcept{return m_length > 0;} + + constexpr bool compare(const string& s)const{return *this == s;} + constexpr bool compare(const_pointer c)const{return *this == c;} constexpr bool resize(size_type i)noexcept{ if(i >= capacity()){ @@ -169,12 +192,29 @@ namespace rexy::cx{ m_data[m_length++] = data[i]; } } - constexpr void append(const_pointer data)noexcept - {append(data, rexy::strlen(data));} - constexpr void append(const string& s)noexcept - {append(s.get(), s.length());} - constexpr void append(const rexy::basic_string_view& s)noexcept - {append(s.get(), s.length());} + constexpr void append(const_pointer data)noexcept{append(data, rexy::strlen(data));} + constexpr void append(const string& s)noexcept{append(s.get(), s.length());} + constexpr void append(const rexy::basic_string_view& s)noexcept{append(s.get(), s.length());} + + constexpr size_type find_first_of(value_type v, size_type start = 0)const{ + return rexy::find_first_of(*this, &v, start, 1); + } + constexpr size_type find_first_of(const_pointer c, size_type pos = 0)const{ + return rexy::find_first_of(*this, c, pos, rexy::strlen(c)); + } + constexpr size_type find_first_of(const_pointer c, size_type start, size_type size)const{ + return rexy::find_first_of(*this, c, start, size); + } + constexpr size_type find_last_of(value_type v, size_type start = 0)const{ + return rexy::find_last_of(*this, &v, start, 1); + } + constexpr size_type find_last_of(const_pointer c, size_type start = 0)const{ + return rexy::find_last_of(*this, c, start, rexy::strlen(c)); + } + constexpr size_type find_last_of(const_pointer c, size_type start, size_type size)const{ + return rexy::find_last_of(*this, c, start, size); + } + }; template string(const Char(&data)[N]) -> string; diff --git a/include/rexy/string_base.tpp b/include/rexy/string_base.tpp index a19dbed..279936c 100644 --- a/include/rexy/string_base.tpp +++ b/include/rexy/string_base.tpp @@ -28,11 +28,7 @@ #include "compat/to_address.hpp" #include "string_view.hpp" -#ifdef __cpp_concepts - #include "compat/cpp20/string_base.hpp" -#else - #include "compat/cpp17/string_base.hpp" -#endif +#include "compat/string_base.hpp" namespace rexy{ diff --git a/include/rexy/string_view.hpp b/include/rexy/string_view.hpp index 82ff986..acb957b 100644 --- a/include/rexy/string_view.hpp +++ b/include/rexy/string_view.hpp @@ -67,7 +67,6 @@ namespace rexy{ constexpr basic_string_view& operator=(const basic_string_view& s)noexcept = default; constexpr basic_string_view& operator=(basic_string_view&&)noexcept = default; - //Length of string not including null terminator constexpr size_type length(void)const noexcept{return m_length;} constexpr size_type size(void)const noexcept{return m_length;} diff --git a/include/rexy/string_view.tpp b/include/rexy/string_view.tpp index 2e073b1..12c6137 100644 --- a/include/rexy/string_view.tpp +++ b/include/rexy/string_view.tpp @@ -23,6 +23,8 @@ #include "utility.hpp" #include "string_base.hpp" +#include "compat/string_base.hpp" + namespace rexy{ template @@ -93,70 +95,27 @@ namespace rexy{ } template constexpr auto basic_string_view::find_first_of(value_type v, size_type start)const -> size_type{ - if(start >= m_length){ - return npos; - } - for(auto it = begin() + start;it != end();++it){ - if(*it == v){ - return it - begin(); - } - } - return npos; + return rexy::find_first_of(*this, &v, start, 1); } template constexpr auto basic_string_view::find_first_of(const_pointer c, size_type start)const -> size_type{ - return find_first_of(c, start, ::rexy::strlen(c)); + return rexy::find_first_of(*this, c, start, rexy::strlen(c)); } template constexpr auto basic_string_view::find_first_of(const_pointer c, size_type start, size_type size)const -> size_type{ - if(start > m_length){ - return npos; - } - for(auto it = begin() + start;it != end();++it){ - for(size_type i = 0;i < size;++i){ - if(*it == c[i]){ - return it - begin(); - } - } - } - return npos; + return rexy::find_first_of(*this, c, start, size); } template constexpr auto basic_string_view::find_last_of(value_type v, size_type start)const -> size_type{ - if(start >= m_length){ - return npos; - } - const auto b = end() - 1; - const auto e = begin() - 1 - start; - - for(auto it = b;it != e;--it){ - if(*it == v){ - return it - begin(); - } - } - return npos; + return rexy::find_last_of(*this, &v, start, 1); } template constexpr auto basic_string_view::find_last_of(const_pointer c, size_type start)const -> size_type{ - return find_last_of(c, start, ::rexy::strlen(c)); + return rexy::find_last_of(*this, c, start, rexy::strlen(c)); } template constexpr auto basic_string_view::find_last_of(const_pointer c, size_type start, size_type size)const -> size_type{ - if(start > m_length){ - return npos; - } - - const auto b = end() - 1; - const auto e = begin() - 1 - start; - - for(auto it = b;it != e;--it){ - for(size_type i = 0;i < size;++i){ - if(*it == c[i]){ - return it - begin(); - } - } - } - return npos; + return rexy::find_last_of(*this, c, start, size); } }