Update cx::string to be more level with string_view
This commit is contained in:
parent
e5d8c0f567
commit
00355a64c6
@ -201,6 +201,40 @@ namespace rexy{
|
||||
return l = (l + r);
|
||||
}
|
||||
|
||||
template<class T, class Char, std::enable_if_t<is_string<T>::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<class T, class Char, std::enable_if_t<is_string<T>::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
|
||||
|
||||
@ -21,50 +21,13 @@
|
||||
|
||||
#include "../../string_base.hpp"
|
||||
|
||||
#include <concepts> //convertible_to
|
||||
#include <utility> //forward, as_const
|
||||
#include <utility> //forward
|
||||
#include <type_traits> //decay, is_nothrow_assignable
|
||||
|
||||
#include "../../concepts/string.hpp"
|
||||
|
||||
namespace rexy{
|
||||
|
||||
template<class T>
|
||||
concept BasicString = requires(const T& a){
|
||||
{std::as_const(a).length()} -> std::convertible_to<typename std::decay_t<T>::size_type>;
|
||||
{std::as_const(a).c_str()} -> std::convertible_to<typename std::decay_t<T>::const_pointer>;
|
||||
{std::as_const(a)[0]} -> std::convertible_to<typename std::decay_t<T>::const_reference>;
|
||||
{std::as_const(a).begin()} -> std::convertible_to<typename std::decay_t<T>::const_iterator>;
|
||||
{std::as_const(a).end()} -> std::convertible_to<typename std::decay_t<T>::const_iterator>;
|
||||
};
|
||||
template<class T>
|
||||
concept StringExpr = rexy::is_template_type<T,string_cat_expr>::value;
|
||||
template<class T>
|
||||
concept String = BasicString<T> || StringExpr<T>;
|
||||
|
||||
template<class T>
|
||||
struct is_string{
|
||||
static constexpr bool value = BasicString<T>;
|
||||
};
|
||||
template<class T>
|
||||
static constexpr bool is_string_v = is_string<T>::value;
|
||||
template<class... Ts>
|
||||
struct are_strings{
|
||||
static constexpr bool value = (BasicString<Ts> && ...);
|
||||
};
|
||||
template<class... Ts>
|
||||
static constexpr bool are_strings_v = are_strings<Ts...>::value;
|
||||
template<class T>
|
||||
struct is_string_expr{
|
||||
static constexpr bool value = StringExpr<T>;
|
||||
};
|
||||
template<class T>
|
||||
static constexpr bool is_string_expr_v = is_string_expr<T>::value;
|
||||
template<class... Ts>
|
||||
struct are_string_expr{
|
||||
static constexpr bool value = (StringExpr<Ts> && ...);
|
||||
};
|
||||
template<class... Ts>
|
||||
static constexpr bool are_string_expr_v = are_string_expr<Ts...>::value;
|
||||
|
||||
//Compare
|
||||
template<BasicString Str1, BasicString Str2>
|
||||
constexpr bool operator==(Str1&& left, Str2&& right){
|
||||
@ -145,6 +108,40 @@ namespace rexy{
|
||||
return l = (l + r);
|
||||
}
|
||||
|
||||
template<BasicString T, class Char>
|
||||
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<BasicString T, class Char>
|
||||
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
|
||||
|
||||
34
include/rexy/compat/string_base.hpp
Normal file
34
include/rexy/compat/string_base.hpp
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef REXY_COMPAT_STRING_BASE_HPP
|
||||
#define REXY_COMPAT_STRING_BASE_HPP
|
||||
|
||||
#include <cstddef> //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
|
||||
73
include/rexy/concepts/string.hpp
Normal file
73
include/rexy/concepts/string.hpp
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef REXY_CONCEPTS_STRING_HPP
|
||||
#define REXY_CONCEPTS_STRING_HPP
|
||||
|
||||
#include <type_traits> //decay
|
||||
#include <concepts> //convertible_to
|
||||
#include <utility> //as_const
|
||||
|
||||
#include "../traits.hpp"
|
||||
|
||||
namespace rexy{
|
||||
|
||||
template<class Left, class Right>
|
||||
class string_cat_expr;
|
||||
|
||||
template<class T>
|
||||
concept BasicString = requires(const T& a){
|
||||
{std::as_const(a).length()} -> std::convertible_to<typename std::decay_t<T>::size_type>;
|
||||
{std::as_const(a).c_str()} -> std::convertible_to<typename std::decay_t<T>::const_pointer>;
|
||||
{std::as_const(a)[0]} -> std::convertible_to<typename std::decay_t<T>::const_reference>;
|
||||
{std::as_const(a).begin()} -> std::convertible_to<typename std::decay_t<T>::const_iterator>;
|
||||
{std::as_const(a).end()} -> std::convertible_to<typename std::decay_t<T>::const_iterator>;
|
||||
};
|
||||
template<class T>
|
||||
concept StringExpr = rexy::is_template_type<T,string_cat_expr>::value;
|
||||
template<class T>
|
||||
concept String = BasicString<T> || StringExpr<T>;
|
||||
|
||||
template<class T>
|
||||
struct is_string{
|
||||
static constexpr bool value = BasicString<T>;
|
||||
};
|
||||
template<class T>
|
||||
static constexpr bool is_string_v = is_string<T>::value;
|
||||
template<class... Ts>
|
||||
struct are_strings{
|
||||
static constexpr bool value = (BasicString<Ts> && ...);
|
||||
};
|
||||
template<class... Ts>
|
||||
static constexpr bool are_strings_v = are_strings<Ts...>::value;
|
||||
template<class T>
|
||||
struct is_string_expr{
|
||||
static constexpr bool value = StringExpr<T>;
|
||||
};
|
||||
template<class T>
|
||||
static constexpr bool is_string_expr_v = is_string_expr<T>::value;
|
||||
template<class... Ts>
|
||||
struct are_string_expr{
|
||||
static constexpr bool value = (StringExpr<Ts> && ...);
|
||||
};
|
||||
template<class... Ts>
|
||||
static constexpr bool are_string_expr_v = are_string_expr<Ts...>::value;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -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 <type_traits> //nothrow_invocable, integral_constant, declval, remove_cvref_t
|
||||
#include <iterator> //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<iterator>;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_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<value_type>& 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<value_type>{c});
|
||||
}
|
||||
template<class Searcher>
|
||||
constexpr const_iterator search(const basic_string_view<value_type>& s, Searcher&& searcher)const{
|
||||
return searcher(cbegin(), cend(), s.cbegin(), s.cend());
|
||||
}
|
||||
template<class Searcher>
|
||||
constexpr const_iterator search(const_pointer c, Searcher&& searcher)const{
|
||||
return search(basic_string_view<value_type>{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<value_type>& 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<value_type>& 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<class Char, std::size_t N>
|
||||
string(const Char(&data)[N]) -> string<N, Char>;
|
||||
|
||||
@ -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{
|
||||
|
||||
|
||||
@ -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;}
|
||||
|
||||
@ -23,6 +23,8 @@
|
||||
#include "utility.hpp"
|
||||
#include "string_base.hpp"
|
||||
|
||||
#include "compat/string_base.hpp"
|
||||
|
||||
namespace rexy{
|
||||
|
||||
template<class Char>
|
||||
@ -93,70 +95,27 @@ namespace rexy{
|
||||
}
|
||||
template<class Char>
|
||||
constexpr auto basic_string_view<Char>::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<class Char>
|
||||
constexpr auto basic_string_view<Char>::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<class Char>
|
||||
constexpr auto basic_string_view<Char>::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<class Char>
|
||||
constexpr auto basic_string_view<Char>::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<class Char>
|
||||
constexpr auto basic_string_view<Char>::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<class Char>
|
||||
constexpr auto basic_string_view<Char>::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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user