Improve basic_string type to include more functionality of std::string. Also add option to disable SSO if so desired

This commit is contained in:
rexy712 2022-06-22 13:30:00 -07:00
parent 1799c1640b
commit 24ef556ab7
12 changed files with 617 additions and 274 deletions

View File

@ -12,6 +12,7 @@ include_directories(BEFORE SYSTEM "${INCLUDE_PATH}")
cmake_dependent_option(ENABLE_SHARED "Build shared library" ON "NOT BUILD_HEADER_ONLY" OFF) cmake_dependent_option(ENABLE_SHARED "Build shared library" ON "NOT BUILD_HEADER_ONLY" OFF)
cmake_dependent_option(ENABLE_SSO "Use small string optimization" ON "NOT BUILD_HEADER_ONLY" ON)
option(ENABLE_PROFILING "Enable asan" OFF) option(ENABLE_PROFILING "Enable asan" OFF)
option(BUILD_TESTS "Enable testing" OFF) option(BUILD_TESTS "Enable testing" OFF)
option(BUILD_HEADER_ONLY "Enable header only build" OFF) option(BUILD_HEADER_ONLY "Enable header only build" OFF)
@ -42,6 +43,13 @@ else()
endif() endif()
set_target_properties(rexy PROPERTIES VERSION "${librexy_VERSION_MAJOR}.${librexy_VERSION_MINOR}.${librexy_VERSION_REVISION}") set_target_properties(rexy PROPERTIES VERSION "${librexy_VERSION_MAJOR}.${librexy_VERSION_MINOR}.${librexy_VERSION_REVISION}")
if(ENABLE_SSO)
set(librexy_ENABLE_SSO 1)
target_compile_options(rexy PRIVATE -DREXY_ENABLE_SSO=1)
else()
set(librexy_ENABLE_SSO 0)
target_compile_options(rexy PRIVATE -DREXY_ENABLE_SSO=0)
endif()
if(ENABLE_PROFILING) if(ENABLE_PROFILING)
target_compile_options(rexy PRIVATE -fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls) target_compile_options(rexy PRIVATE -fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls)
target_link_options(rexy PRIVATE -fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls) target_link_options(rexy PRIVATE -fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls)

View File

@ -33,12 +33,12 @@ namespace rexy{
//Requires Iterators to be LegacyRandomAccessIterators //Requires Iterators to be LegacyRandomAccessIterators
template<class HIter, class NIter> template<class HIter, class NIter>
constexpr HIter two_way_search(const HIter& hstart, const HIter& hend, const NIter& nstart, const NIter& nend); constexpr HIter two_way_search(HIter hstart, HIter hend, NIter nstart, NIter nend);
//searcher for use with generic search wrappers //searcher for use with generic search wrappers
struct two_way_searcher{ struct two_way_searcher{
template<class HIter, class NIter> template<class HIter, class NIter>
constexpr HIter operator()(const HIter& hstart, const HIter& hend, const NIter& nstart, const NIter& nend)const; constexpr HIter operator()(HIter hstart, HIter hend, NIter nstart, NIter nend)const;
}; };
} }

View File

@ -40,7 +40,7 @@ namespace rexy{
//Requires Iterators to be LegacyRandomAccessIterators //Requires Iterators to be LegacyRandomAccessIterators
template<class HIter, class NIter> template<class HIter, class NIter>
constexpr HIter two_way_search(const HIter& hstart, const HIter& hend, const NIter& nstart, const NIter& nend){ constexpr HIter two_way_search(HIter hstart, HIter hend, NIter nstart, NIter nend){
size_t j = 0; size_t j = 0;
size_t i = 0; size_t i = 0;
size_t nlen = nend - nstart; size_t nlen = nend - nstart;
@ -99,7 +99,7 @@ namespace rexy{
} }
template<class HIter, class NIter> template<class HIter, class NIter>
constexpr HIter two_way_searcher::operator()(const HIter& hstart, const HIter& hend, const NIter& nstart, const NIter& nend)const{ constexpr HIter two_way_searcher::operator()(HIter hstart, HIter hend, NIter nstart, NIter nend)const{
return two_way_search(hstart, hend, nstart, nend); return two_way_search(hstart, hend, nstart, nend);
} }

View File

@ -24,6 +24,8 @@
#include <utility> //forward #include <utility> //forward
#include <type_traits> //{false,true}_type, declval, enable_if, remove_reference, decay #include <type_traits> //{false,true}_type, declval, enable_if, remove_reference, decay
#include "../../utility.hpp" //strlen, strncmp
namespace rexy{ namespace rexy{
#define REXY_HAS_MEMFUN_WITH_RET(type, ret, fun, ...) \ #define REXY_HAS_MEMFUN_WITH_RET(type, ret, fun, ...) \
@ -92,31 +94,29 @@ namespace rexy{
if(left.length() != right.length()){ if(left.length() != right.length()){
return false; return false;
} }
return !detail::string_compare(std::forward<Str1>(left), std::forward<Str2>(right), left.length()); return !rexy::strncmp(left.c_str(), right.c_str(), left.length()+1);
} }
template<class Str1, std::enable_if_t<are_strings<Str1>::value,int> = 0> template<class Str1, std::enable_if_t<are_strings<Str1>::value,int> = 0>
constexpr bool operator==(Str1&& left, typename std::decay_t<Str1>::const_pointer right){ constexpr bool operator==(Str1&& left, typename std::decay_t<Str1>::const_pointer right){
if(right == nullptr){ if(right == nullptr){
return false; return false;
} }
const auto rlen = detail::string_len(right); const auto rlen = rexy::strlen(right);
if(rlen != left.length()){ if(rlen != left.length()){
return false; return false;
} }
const auto minlen = min(left.length(), rlen); return !rexy::strncmp(left.c_str(), right, rlen+1);
return !detail::string_compare(left.c_str(), right, minlen+1);
} }
template<class Str1, std::enable_if_t<are_strings<Str1>::value,int> = 0> template<class Str1, std::enable_if_t<are_strings<Str1>::value,int> = 0>
constexpr bool operator==(typename std::decay_t<Str1>::const_pointer left, Str1&& right){ constexpr bool operator==(typename std::decay_t<Str1>::const_pointer left, Str1&& right){
if(left == nullptr){ if(left == nullptr){
return false; return false;
} }
const auto llen = detail::string_len(left); const auto llen = rexy::strlen(left);
if(llen != right.length()){ if(llen != right.length()){
return false; return false;
} }
const auto minlen = min(right.length(), llen); return !rexy::strncmp(left, right.c_str(), llen+1);
return !detail::string_compare(right.c_str(), left, minlen+1);
} }
template<class Str1, class Str2, std::enable_if_t<are_strings<Str1, Str2>::value,int> = 0> template<class Str1, class Str2, std::enable_if_t<are_strings<Str1, Str2>::value,int> = 0>
constexpr bool operator!=(Str1&& left, Str2&& right)noexcept{ constexpr bool operator!=(Str1&& left, Str2&& right)noexcept{

View File

@ -25,6 +25,7 @@
#include <type_traits> //decay, is_nothrow_assignable #include <type_traits> //decay, is_nothrow_assignable
#include "../../concepts/string.hpp" #include "../../concepts/string.hpp"
#include "../../utility.hpp" //strlen, strncmp
namespace rexy{ namespace rexy{
@ -34,31 +35,29 @@ namespace rexy{
if(left.length() != right.length()){ if(left.length() != right.length()){
return false; return false;
} }
return !detail::string_compare(std::forward<Str1>(left), std::forward<Str2>(right), left.length()); return !rexy::strncmp(left.c_str(), right.c_str(), left.length()+1);
} }
template<BasicString Str1> template<BasicString Str1>
constexpr bool operator==(Str1&& left, typename std::decay_t<Str1>::const_pointer right){ constexpr bool operator==(Str1&& left, typename std::decay_t<Str1>::const_pointer right){
if(right == nullptr){ if(right == nullptr){
return false; return false;
} }
const auto rlen = detail::string_len(right); const auto rlen = rexy::strlen(right);
if(rlen != left.length()){ if(rlen != left.length()){
return false; return false;
} }
const auto minlen = min(left.length(), rlen); return !rexy::strncmp(left.c_str(), right, rlen+1);
return !detail::string_compare(left.c_str(), right, minlen+1);
} }
template<BasicString Str1> template<BasicString Str1>
constexpr bool operator==(typename std::decay_t<Str1>::const_pointer left, Str1&& right){ constexpr bool operator==(typename std::decay_t<Str1>::const_pointer left, Str1&& right){
if(left == nullptr){ if(left == nullptr){
return false; return false;
} }
const auto llen = detail::string_len(left); const auto llen = rexy::strlen(left);
if(llen != right.length()){ if(llen != right.length()){
return false; return false;
} }
const auto minlen = min(right.length(), llen); return !rexy::strncmp(left, right.c_str(), llen+1);
return !detail::string_compare(right.c_str(), left, minlen+1);
} }
template<BasicString Str1, BasicString Str2> template<BasicString Str1, BasicString Str2>
constexpr bool operator!=(Str1&& left, Str2&& right){ constexpr bool operator!=(Str1&& left, Str2&& right){

View File

@ -30,5 +30,6 @@
#define LIBREXY_VERSION_MINOR @librexy_VERSION_MINOR@ #define LIBREXY_VERSION_MINOR @librexy_VERSION_MINOR@
#define LIBREXY_VERSION_REVISION @librexy_VERSION_REVISION@ #define LIBREXY_VERSION_REVISION @librexy_VERSION_REVISION@
#define LIBREXY_ENABLE_SSO @librexy_ENABLE_SSO@
#endif #endif

View File

@ -41,6 +41,10 @@
namespace rexy{ namespace rexy{
#ifndef LIBREXY_ENABLE_SSO
#define LIBREXY_ENABLE_SSO 1
#endif
template<class Char> template<class Char>
class basic_string_view; class basic_string_view;
@ -61,6 +65,7 @@ namespace rexy{
using reverse_iterator = std::reverse_iterator<iterator>; using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>; using const_reverse_iterator = std::reverse_iterator<const_iterator>;
#if LIBREXY_ENABLE_SSO != 0
private: private:
static constexpr size_type EXTRA_SDATA_LEN = 0; static constexpr size_type EXTRA_SDATA_LEN = 0;
@ -132,6 +137,12 @@ namespace rexy{
constexpr void set_short_capacity(size_type){} constexpr void set_short_capacity(size_type){}
constexpr size_type get_long_capacity(void)const{return m_data.l.capacity;} constexpr size_type get_long_capacity(void)const{return m_data.l.capacity;}
constexpr size_type get_short_capacity(void)const{return MAX_SHORT_LEN;} constexpr size_type get_short_capacity(void)const{return MAX_SHORT_LEN;}
constexpr void set_capacity(size_type s){
if(islong())
set_long_capacity(s);
else
set_short_capacity(s);
}
constexpr void set_length(size_type s){ constexpr void set_length(size_type s){
if(islong()) if(islong())
set_long_length(s); set_long_length(s);
@ -180,52 +191,134 @@ namespace rexy{
} }
return *this; return *this;
} }
public: public:
//Length of string not including null terminator
constexpr size_type length(void)const noexcept{ constexpr size_type length(void)const noexcept{
if(islong()) if(islong())
return get_long_length(); return get_long_length();
else else
return get_short_length(); return get_short_length();
} }
constexpr size_type size(void)const noexcept{
return length();
}
constexpr size_type capacity(void)const noexcept{ constexpr size_type capacity(void)const noexcept{
if(islong()) if(islong())
return get_long_capacity(); return get_long_capacity();
else else
return get_short_capacity(); return get_short_capacity();
} }
static constexpr bool uses_sso(void){return true;}
static constexpr size_type short_string_size(void){return MAX_SHORT_LEN;}
#else //LIBREXY_ENABLE_SSO
private:
//direct access to current string
pointer m_raw = nullptr;
size_type m_length = 0;
size_type m_capacity = 0;
protected:
constexpr pointer get_pointer(void){return m_raw;}
constexpr const_pointer get_pointer(void)const{return m_raw;}
constexpr void set_length(size_type s){m_length = s;}
constexpr void set_capacity(size_type s){m_capacity = s;}
constexpr bool islong(void)const{return true;}
constexpr pointer set_short_ptr(void){return m_raw;}
constexpr pointer set_long_ptr(pointer ptr){return m_raw = ptr;}
protected:
constexpr string_base(void)noexcept = default;
//Initialize without copying
constexpr string_base(pointer data, size_type len, size_type cap)noexcept:
m_raw(data),
m_length(len),
m_capacity(cap){}
constexpr string_base(pointer data, size_type len)noexcept:
string_base(data, len, len){}
//Copy ctor, copy length+capacity+short string, not long string value
constexpr string_base(const string_base& s)noexcept:
m_raw(s.m_raw),
m_length(s.m_length),
m_capacity(s.m_capacity){}
constexpr string_base(string_base&& s)noexcept:
m_raw(std::exchange(s.m_raw, nullptr)),
m_length(s.m_length),
m_capacity(s.m_capacity){}
REXY_CPP20_CONSTEXPR ~string_base(void)noexcept = default;
constexpr string_base& operator=(string_base&& s)noexcept{
std::swap(m_raw, s.m_raw);
m_length = s.m_length;
m_capacity = s.m_capacity;
return *this;
}
public:
constexpr size_type length(void)const noexcept{
return m_length;
}
constexpr size_type capacity(void)const noexcept{
return m_capacity;
}
static constexpr bool uses_sso(void){return false;}
static constexpr size_type short_string_size(void){return 0;}
#endif //LIBREXY_ENABLE_SSO
public:
//Length of string not including null terminator
constexpr size_type size(void)const noexcept{
return length();
}
constexpr size_type max_size(void)const noexcept{
return size_type{-2};
}
//direct access to managed pointer //direct access to managed pointer
constexpr pointer c_str(void)noexcept{return get_pointer();} constexpr pointer c_str(void)noexcept{return get_pointer();}
constexpr const_pointer c_str(void)const noexcept{return get_pointer();} constexpr const_pointer c_str(void)const noexcept{return get_pointer();}
constexpr pointer get(void)noexcept{return get_pointer();} constexpr pointer data(void)noexcept{return get_pointer();}
constexpr const_pointer get(void)const noexcept{return get_pointer();} constexpr const_pointer data(void)const noexcept{return get_pointer();}
constexpr operator pointer(void)noexcept{return get_pointer();} constexpr operator basic_string_view<value_type>(void)const noexcept{return basic_string_view<value_type>(begin(), end());}
constexpr operator const_pointer(void)const noexcept{return get_pointer();}
//true if m_data is not empty //true if m_data is not empty
constexpr bool valid(void)const noexcept{return length() > 0;} constexpr bool valid(void)const noexcept{return length() > 0;}
constexpr bool empty(void)const noexcept{return length() == 0;}
constexpr reference operator[](size_type i)noexcept{return get_pointer()[i];} constexpr reference operator[](size_type i)noexcept{return get_pointer()[i];}
constexpr const_reference operator[](size_type i)const noexcept{return get_pointer()[i];} constexpr const_reference operator[](size_type i)const noexcept{return get_pointer()[i];}
constexpr reference at(size_type i)noexcept{return get_pointer()[i];}
constexpr const_reference at(size_type i)const noexcept{return get_pointer()[i];}
constexpr const_iterator search(const string_base& s)const; constexpr const_iterator search(basic_string_view<value_type> sv)const;
constexpr iterator search(basic_string_view<value_type> sv);
constexpr const_iterator search(const_pointer c)const; constexpr const_iterator search(const_pointer c)const;
constexpr iterator search(const string_base& s);
constexpr iterator search(const_pointer c); constexpr iterator search(const_pointer c);
template<class Searcher> template<class Searcher>
constexpr const_iterator search(const string_base& s, const Searcher& searcher)const;
template<class Searcher>
constexpr const_iterator search(const_pointer c, const Searcher& searcher)const; constexpr const_iterator search(const_pointer c, const Searcher& searcher)const;
template<class Searcher> template<class Searcher>
constexpr iterator search(const string_base& s, const Searcher& searcher);
template<class Searcher>
constexpr iterator search(const_pointer c, const Searcher& searcher); constexpr iterator search(const_pointer c, const Searcher& searcher);
constexpr bool starts_with(basic_string_view<value_type> sv)const noexcept;
constexpr bool starts_with(value_type v)const noexcept;
constexpr bool starts_with(const_pointer str)const noexcept;
constexpr bool ends_with(basic_string_view<value_type> sv)const noexcept;
constexpr bool ends_with(value_type v)const noexcept;
constexpr bool ends_with(const_pointer str)const noexcept;
constexpr bool contains(basic_string_view<value_type> sv)const noexcept;
constexpr bool contains(value_type v)const noexcept;
constexpr bool contains(const_pointer str)const noexcept;
//TODO more compares
constexpr bool compare(const string_base& s)const{return *this == s;} constexpr bool compare(const string_base& s)const{return *this == s;}
constexpr bool compare(basic_string_view<value_type> s)const{return *this == s;}
constexpr bool compare(const_pointer c)const{return *this == c;} constexpr bool compare(const_pointer c)const{return *this == c;}
constexpr size_type find_first_of(value_type v, size_type start = 0)const;
constexpr size_type find_first_of(const_pointer c, size_type pos = 0)const;
constexpr size_type find_first_of(const_pointer c, size_type pos, size_type size)const;
constexpr size_type find_last_of(value_type v, size_type start = 0)const;
constexpr size_type find_last_of(const_pointer c, size_type pos = 0)const;
constexpr size_type find_last_of(const_pointer c, size_type pos, size_type size)const;
constexpr reference front(void)noexcept{return *get_pointer();}
constexpr const_reference front(void)const noexcept{return *get_pointer();}
constexpr reference back(void)noexcept{return *(get_pointer() + length() - 1);}
constexpr const_reference back(void)const noexcept{return *(get_pointer() + length() - 1);}
constexpr iterator begin(void){return get_pointer();} constexpr iterator begin(void){return get_pointer();}
constexpr const_iterator begin(void)const{return get_pointer();} constexpr const_iterator begin(void)const{return get_pointer();}
constexpr iterator end(void){return get_pointer()+length();} constexpr iterator end(void){return get_pointer()+length();}
@ -240,8 +333,22 @@ namespace rexy{
constexpr const_reverse_iterator crbegin(void)const{return rbegin();} constexpr const_reverse_iterator crbegin(void)const{return rbegin();}
constexpr const_reverse_iterator crend(void)const{return rend();} constexpr const_reverse_iterator crend(void)const{return rend();}
static constexpr bool uses_sso(void){return true;} constexpr void clear(void)noexcept;
static constexpr size_type short_string_size(void){return MAX_SHORT_LEN;}
constexpr basic_string_view<value_type> create_view(void)const noexcept;
constexpr basic_string_view<value_type> create_view(const_iterator start, const_iterator fin)const noexcept;
[[deprecated]] constexpr pointer get(void)noexcept{return get_pointer();}
[[deprecated]] constexpr const_pointer get(void)const noexcept{return get_pointer();}
[[deprecated]] constexpr operator pointer(void)noexcept{return get_pointer();}
[[deprecated]] constexpr operator const_pointer(void)const noexcept{return get_pointer();}
[[deprecated]] constexpr const_iterator search(const string_base& s)const;
[[deprecated]] constexpr iterator search(const string_base& s);
template<class Searcher>
[[deprecated]] constexpr const_iterator search(const string_base& s, const Searcher& searcher)const;
template<class Searcher>
[[deprecated]] constexpr iterator search(const string_base& s, const Searcher& searcher);
}; };
@ -270,6 +377,8 @@ namespace rexy{
noexcept(is_nothrow_allocator_v<Alloc>); noexcept(is_nothrow_allocator_v<Alloc>);
REXY_CPP20_CONSTEXPR basic_string& _copy_string(const_pointer s, size_type len) REXY_CPP20_CONSTEXPR basic_string& _copy_string(const_pointer s, size_type len)
noexcept(is_nothrow_allocator_v<Alloc>); noexcept(is_nothrow_allocator_v<Alloc>);
template<class InputIt>
REXY_CPP20_CONSTEXPR basic_string& _insert_impl(size_type pos, InputIt start, size_type insert_count)noexcept(is_nothrow_allocator_v<Alloc>);
public: public:
constexpr basic_string(void)noexcept; constexpr basic_string(void)noexcept;
@ -308,9 +417,9 @@ namespace rexy{
//Replace managed pointer. Frees existing value //Replace managed pointer. Frees existing value
REXY_CPP20_CONSTEXPR void reset(pointer val = nullptr)noexcept(is_nothrow_allocator_v<Alloc>); REXY_CPP20_CONSTEXPR void reset(pointer val = nullptr)noexcept(is_nothrow_allocator_v<Alloc>);
REXY_CPP20_CONSTEXPR void reset(pointer val, size_type len)noexcept(is_nothrow_allocator_v<Alloc>); REXY_CPP20_CONSTEXPR void reset(pointer val, size_type len)noexcept(is_nothrow_allocator_v<Alloc>);
REXY_CPP20_CONSTEXPR bool resize(size_type newsize)noexcept(is_nothrow_allocator_v<Alloc>); REXY_CPP20_CONSTEXPR bool reserve(size_type newsize)noexcept(is_nothrow_allocator_v<Alloc>);
REXY_CPP20_CONSTEXPR void shrink_to_fit(void)noexcept(is_nothrow_allocator_v<Alloc>);
//TODO more insert
REXY_CPP20_CONSTEXPR basic_string& insert(size_type pos, size_type insert_count, value_type v)noexcept(is_nothrow_allocator_v<Alloc>); REXY_CPP20_CONSTEXPR basic_string& insert(size_type pos, size_type insert_count, value_type v)noexcept(is_nothrow_allocator_v<Alloc>);
REXY_CPP20_CONSTEXPR basic_string& insert(size_type pos, value_type v)noexcept(is_nothrow_allocator_v<Alloc>); REXY_CPP20_CONSTEXPR basic_string& insert(size_type pos, value_type v)noexcept(is_nothrow_allocator_v<Alloc>);
REXY_CPP20_CONSTEXPR basic_string& insert(size_type pos, const_pointer str)noexcept(is_nothrow_allocator_v<Alloc>); REXY_CPP20_CONSTEXPR basic_string& insert(size_type pos, const_pointer str)noexcept(is_nothrow_allocator_v<Alloc>);
@ -319,10 +428,10 @@ namespace rexy{
REXY_CPP20_CONSTEXPR basic_string& insert(size_type pos, const basic_string& other, size_type index_str, size_type count = npos)noexcept(is_nothrow_allocator_v<Alloc>); REXY_CPP20_CONSTEXPR basic_string& insert(size_type pos, const basic_string& other, size_type index_str, size_type count = npos)noexcept(is_nothrow_allocator_v<Alloc>);
REXY_CPP20_CONSTEXPR basic_string& insert(const_iterator pos, value_type v)noexcept(is_nothrow_allocator_v<Alloc>); REXY_CPP20_CONSTEXPR basic_string& insert(const_iterator pos, value_type v)noexcept(is_nothrow_allocator_v<Alloc>);
REXY_CPP20_CONSTEXPR basic_string& insert(const_iterator pos, size_type count, value_type v)noexcept(is_nothrow_allocator_v<Alloc>); REXY_CPP20_CONSTEXPR basic_string& insert(const_iterator pos, size_type count, value_type v)noexcept(is_nothrow_allocator_v<Alloc>);
template<class InIt> template<class InputIt>
REXY_CPP20_CONSTEXPR basic_string& insert(const_iterator pos, InIt start, InIt last)noexcept(is_nothrow_allocator_v<Alloc>); REXY_CPP20_CONSTEXPR basic_string& insert(const_iterator pos, InputIt start, InputIt last)noexcept(is_nothrow_allocator_v<Alloc>);
template<class InIt> template<class InputIt>
REXY_CPP20_CONSTEXPR basic_string& insert(size_type pos, InIt start, InIt last)noexcept(is_nothrow_allocator_v<Alloc>); REXY_CPP20_CONSTEXPR basic_string& insert(size_type pos, InputIt start, InputIt last)noexcept(is_nothrow_allocator_v<Alloc>);
REXY_CPP20_CONSTEXPR basic_string& insert(const_iterator pos, std::initializer_list<value_type> list)noexcept(is_nothrow_allocator_v<Alloc>); REXY_CPP20_CONSTEXPR basic_string& insert(const_iterator pos, std::initializer_list<value_type> list)noexcept(is_nothrow_allocator_v<Alloc>);
template<class StringView> template<class StringView>
REXY_CPP20_CONSTEXPR auto insert(size_type pos, const StringView& sv)noexcept(is_nothrow_allocator_v<Alloc>) -> REXY_CPP20_CONSTEXPR auto insert(size_type pos, const StringView& sv)noexcept(is_nothrow_allocator_v<Alloc>) ->
@ -330,16 +439,20 @@ namespace rexy{
template<class StringView> template<class StringView>
REXY_CPP20_CONSTEXPR auto insert(size_type pos, const StringView& sv, size_type index_str, size_type count = npos)noexcept(is_nothrow_allocator_v<Alloc>) -> REXY_CPP20_CONSTEXPR auto insert(size_type pos, const StringView& sv, size_type index_str, size_type count = npos)noexcept(is_nothrow_allocator_v<Alloc>) ->
std::enable_if_t<std::is_convertible_v<const StringView&, basic_string_view<value_type>> && !std::is_convertible_v<const StringView&,const_pointer>>; std::enable_if_t<std::is_convertible_v<const StringView&, basic_string_view<value_type>> && !std::is_convertible_v<const StringView&,const_pointer>>;
REXY_CPP20_CONSTEXPR void push_back(value_type data)
noexcept(is_nothrow_allocator_v<Alloc>);
REXY_CPP20_CONSTEXPR void append(const_pointer data, size_type len)
noexcept(is_nothrow_allocator_v<Alloc>);
REXY_CPP20_CONSTEXPR void append(const_pointer data)
noexcept(is_nothrow_allocator_v<Alloc>);
template<class InputIt> template<class InputIt>
REXY_CPP20_CONSTEXPR void append(InputIt start, InputIt fin) REXY_CPP20_CONSTEXPR basic_string& append(InputIt start, InputIt fin)noexcept(is_nothrow_allocator_v<Alloc>);
noexcept(is_nothrow_allocator_v<Alloc>);
REXY_CPP20_CONSTEXPR basic_string& append(const_pointer data, size_type len)noexcept(is_nothrow_allocator_v<Alloc>);
REXY_CPP20_CONSTEXPR basic_string& append(const_pointer data)noexcept(is_nothrow_allocator_v<Alloc>);
REXY_CPP20_CONSTEXPR basic_string& append(const basic_string& other)noexcept(is_nothrow_allocator_v<Alloc>);
REXY_CPP20_CONSTEXPR void push_back(value_type data)noexcept(is_nothrow_allocator_v<Alloc>);
constexpr void pop_back(void)noexcept;
constexpr basic_string& erase(size_type index = 0, size_type count = npos)noexcept;
constexpr iterator erase(const_iterator pos)noexcept;
constexpr iterator erase(const_iterator first, const_iterator last)noexcept;
template<REXY_ALLOCATOR_CONCEPT A = allocator_type> template<REXY_ALLOCATOR_CONCEPT A = allocator_type>
REXY_CPP20_CONSTEXPR basic_string<value_type,A> substring(size_type start, size_type end)const; REXY_CPP20_CONSTEXPR basic_string<value_type,A> substring(size_type start, size_type end)const;
@ -348,8 +461,8 @@ namespace rexy{
REXY_CPP20_CONSTEXPR pointer release(void)noexcept(is_nothrow_allocator_v<Alloc>); REXY_CPP20_CONSTEXPR pointer release(void)noexcept(is_nothrow_allocator_v<Alloc>);
using detail::hasallocator<Alloc>::allocator; using detail::hasallocator<Alloc>::allocator;
constexpr basic_string_view<value_type> create_view(void)const noexcept;
constexpr basic_string_view<value_type> create_view(const_iterator start, const_iterator fin)const noexcept; [[deprecated]] REXY_CPP20_CONSTEXPR bool resize(size_type newsize)noexcept(is_nothrow_allocator_v<Alloc>);
}; };
//Like an expression template but not really //Like an expression template but not really
@ -386,32 +499,6 @@ namespace rexy{
template<class Left, class Right> template<class Left, class Right>
string_cat_expr(Left&&,Right&&) -> string_cat_expr<Left&&,Right&&>; string_cat_expr(Left&&,Right&&) -> string_cat_expr<Left&&,Right&&>;
namespace detail{
template<class Left, class Right>
constexpr int string_compare(Left&& left, Right&& right, size_t maxlen){
for(size_t i = 0;i < maxlen;++i){
const auto diff = left[i] - right[i];
if(diff != 0){
return diff;
}
if(left[i] == 0 || right[i] == 0){
return diff;
}
}
return 0;
}
template<class Str>
constexpr size_t string_len(const Str* str){
if(!str){
return 0;
}
size_t i;
for(i = 0;str[i] != 0;++i);
return i;
}
}
} }
#include "string_base.tpp" #include "string_base.tpp"

View File

@ -33,8 +33,18 @@
namespace rexy{ namespace rexy{
template<class Char> template<class Char>
constexpr auto string_base<Char>::search(const string_base& s)const -> const_iterator{ constexpr auto string_base<Char>::search(basic_string_view<value_type> sv)const -> const_iterator{
return two_way_search(cbegin(), cend(), s.begin(), s.end()); if(sv.length() > length()){
return cend();
}
return two_way_search(cbegin(), cend(), sv.cbegin(), sv.cend());
}
template<class Char>
constexpr auto string_base<Char>::search(basic_string_view<value_type> sv) -> iterator{
if(sv.length() > length()){
return end();
}
return two_way_search(begin(), end(), sv.cbegin(), sv.cend());
} }
template<class Char> template<class Char>
constexpr auto string_base<Char>::search(const_pointer c)const -> const_iterator{ constexpr auto string_base<Char>::search(const_pointer c)const -> const_iterator{
@ -42,60 +52,138 @@ namespace rexy{
return two_way_search(cbegin(), cend(), c, c + len); return two_way_search(cbegin(), cend(), c, c + len);
} }
template<class Char> template<class Char>
constexpr auto string_base<Char>::search(const string_base& s) -> iterator{
return two_way_search(begin(), end(), s.begin(), s.end());
}
template<class Char>
constexpr auto string_base<Char>::search(const_pointer c) -> iterator{ constexpr auto string_base<Char>::search(const_pointer c) -> iterator{
const auto len = rexy::strlen(c); const auto len = rexy::strlen(c);
return two_way_search(begin(), end(), c, c + len); return two_way_search(begin(), end(), c, c + len);
} }
template<class Char> template<class Char>
template<class Searcher> template<class Searcher>
constexpr auto string_base<Char>::search(const string_base& s, const Searcher& searcher)const -> const_iterator{
return searcher(cbegin(), cend(), s.begin(), s.end());
}
template<class Char>
template<class Searcher>
constexpr auto string_base<Char>::search(const_pointer c, const Searcher& searcher)const -> const_iterator{ constexpr auto string_base<Char>::search(const_pointer c, const Searcher& searcher)const -> const_iterator{
const auto len = rexy::strlen(c); const auto len = rexy::strlen(c);
return searcher(cbegin(), cend(), c, c + len); return searcher(cbegin(), cend(), c, c + len);
} }
template<class Char> template<class Char>
template<class Searcher> template<class Searcher>
constexpr auto string_base<Char>::search(const string_base& s, const Searcher& searcher) -> iterator{
return searcher(begin(), end(), s.begin(), s.end());
}
template<class Char>
template<class Searcher>
constexpr auto string_base<Char>::search(const_pointer c, const Searcher& searcher) -> iterator{ constexpr auto string_base<Char>::search(const_pointer c, const Searcher& searcher) -> iterator{
const auto len = rexy::strlen(c); const auto len = rexy::strlen(c);
return searcher(begin(), end(), c, c + len); return searcher(begin(), end(), c, c + len);
} }
template<class Char>
constexpr bool string_base<Char>::starts_with(basic_string_view<value_type> sv)const noexcept{
return basic_string_view<value_type>(data(), length()).starts_with(sv);
}
template<class Char>
constexpr bool string_base<Char>::starts_with(value_type v)const noexcept{
return front() == v;
}
template<class Char>
constexpr bool string_base<Char>::starts_with(const_pointer str)const noexcept{
return starts_with(basic_string_view<value_type>(str));
}
template<class Char>
constexpr bool string_base<Char>::ends_with(basic_string_view<value_type> sv)const noexcept{
return basic_string_view<value_type>(data(), length()).ends_with(sv);
}
template<class Char>
constexpr bool string_base<Char>::ends_with(value_type v)const noexcept{
return back() == v;
}
template<class Char>
constexpr bool string_base<Char>::ends_with(const_pointer str)const noexcept{
return ends_with(basic_string_view<value_type>(str));
}
template<class Char>
constexpr bool string_base<Char>::contains(basic_string_view<value_type> sv)const noexcept{
return basic_string_view<value_type>(data(), length()).contains(sv);
}
template<class Char>
constexpr bool string_base<Char>::contains(value_type v)const noexcept{
return basic_string_view<value_type>(data(), length()).contains(v);
}
template<class Char>
constexpr bool string_base<Char>::contains(const_pointer str)const noexcept{
return contains(basic_string_view<value_type>(str));
}
template<class Char>
constexpr auto string_base<Char>::find_first_of(value_type v, size_type start)const -> size_type{
return rexy::find_first_of(*this, &v, start, 1);
}
template<class Char>
constexpr auto string_base<Char>::find_first_of(const_pointer c, size_type pos)const -> size_type{
return rexy::find_first_of(*this, c, pos, rexy::strlen(c));
}
template<class Char>
constexpr auto string_base<Char>::find_first_of(const_pointer c, size_type pos, size_type size)const -> size_type{
return rexy::find_first_of(*this, c, pos, size);
}
template<class Char>
constexpr auto string_base<Char>::find_last_of(value_type v, size_type start)const -> size_type{
return rexy::find_last_of(*this, &v, start, 1);
}
template<class Char>
constexpr auto string_base<Char>::find_last_of(const_pointer c, size_type pos)const -> size_type{
return rexy::find_last_of(*this, c, pos, rexy::strlen(c));
}
template<class Char>
constexpr auto string_base<Char>::find_last_of(const_pointer c, size_type pos, size_type size)const -> size_type{
return rexy::find_last_of(*this, c, pos, size);
}
template<class Char>
constexpr void string_base<Char>::clear(void)noexcept{
set_length(0);
get_pointer()[0] = 0;
}
template<class Char>
constexpr auto string_base<Char>::create_view(void)const noexcept -> basic_string_view<value_type>{
return basic_string_view<value_type>(data(), length());
}
template<class Char>
constexpr auto string_base<Char>::create_view(const_iterator start, const_iterator fin)const noexcept -> basic_string_view<value_type>{
return basic_string_view<value_type>(start, fin);
}
//allocate string if longer than small string capacity, copy otherwise //allocate string if longer than small string capacity, copy otherwise
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc> template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
REXY_CPP20_CONSTEXPR void basic_string<Char,Alloc>::_copy_construct_string(const_pointer data, size_type len, size_type cap) REXY_CPP20_CONSTEXPR void basic_string<Char,Alloc>::_copy_construct_string(const_pointer data, size_type len, size_type cap)
noexcept(is_nothrow_allocator_v<Alloc>) noexcept(is_nothrow_allocator_v<Alloc>)
{ {
if(cap > this->get_short_capacity()){ if constexpr(string_base<Char>::uses_sso()){
this->set_islong_flag(true); if(cap > string_base<Char>::short_string_size()){
pointer raw = this->set_long_ptr(this->allocate(sizeof(value_type)*(cap+1))); pointer raw = this->set_long_ptr(this->allocate(sizeof(value_type)*(cap+1)));
if(data) if(data){
rexy::memcpy(raw, data, sizeof(value_type)*len); rexy::memcpy(raw, data, sizeof(value_type)*len);
}
raw[len] = 0; raw[len] = 0;
this->set_long_length(len); this->set_long_length(len);
this->set_long_capacity(cap); this->set_long_capacity(cap);
}else{ }else{
this->set_islong_flag(false);
pointer raw = this->set_short_ptr(); pointer raw = this->set_short_ptr();
if(data) if(data){
rexy::memcpy(raw, data, sizeof(value_type)*len); rexy::memcpy(raw, data, sizeof(value_type)*len);
}
raw[len] = 0; raw[len] = 0;
this->set_short_length(len); this->set_short_length(len);
this->set_short_capacity(cap); this->set_short_capacity(cap);
} }
}else{
if(cap == 0){
return;
}
pointer raw = this->set_long_ptr(this->allocate(sizeof(value_type)*(cap+1)));
if(data){
rexy::memcpy(raw, data, sizeof(value_type)*len);
}
raw[len] = 0;
this->set_length(len);
this->set_capacity(cap);
}
} }
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc> template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
@ -178,7 +266,7 @@ namespace rexy{
noexcept(is_nothrow_allocator_v<Alloc>) noexcept(is_nothrow_allocator_v<Alloc>)
{ {
if(this->islong()){ if(this->islong()){
this->deallocate(this->get_pointer(), sizeof(value_type)*(this->get_long_capacity()+1)); this->deallocate(this->get_pointer(), sizeof(value_type)*(this->capacity()+1));
} }
} }
@ -233,32 +321,42 @@ namespace rexy{
noexcept(is_nothrow_allocator_v<Alloc>) noexcept(is_nothrow_allocator_v<Alloc>)
{ {
if(this->islong()) if(this->islong())
this->deallocate(this->get_long_ptr(),sizeof(value_type)*(this->get_long_capacity()+1)); this->deallocate(this->get_pointer(),sizeof(value_type)*(this->capacity()+1));
this->set_islong_flag(true);
this->set_long_ptr(val); this->set_long_ptr(val);
if constexpr(string_base<Char>::uses_sso()){
this->set_long_length(len); this->set_long_length(len);
this->set_long_capacity(len); this->set_long_capacity(len);
}else{
this->set_length(len);
this->set_capacity(len);
}
} }
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc> template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
REXY_CPP20_CONSTEXPR bool basic_string<Char,Alloc>::resize(size_type newsize) REXY_CPP20_CONSTEXPR bool basic_string<Char,Alloc>::reserve(size_type newsize)noexcept(is_nothrow_allocator_v<Alloc>){
noexcept(is_nothrow_allocator_v<Alloc>)
{
if(newsize < this->capacity()) if(newsize < this->capacity())
return false; return false;
if(!this->islong() && newsize < this->get_short_capacity()) if(!this->islong() && newsize < string_base<Char>::short_string_size())
return false; return false;
return (*this = basic_string(this->get_pointer(), newsize)); return (*this = basic_string(this->get_pointer(), newsize));
} }
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
REXY_CPP20_CONSTEXPR void basic_string<Char,Alloc>::shrink_to_fit(void)noexcept(is_nothrow_allocator_v<Alloc>){
if(this->length() == this->capacity()){
return;
}
*this = basic_string(this->get_pointer(), this->length(), this->length());
}
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc> template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
REXY_CPP20_CONSTEXPR auto basic_string<Char,Alloc>::insert(size_type pos, size_type insert_count, value_type v)noexcept(is_nothrow_allocator_v<Alloc>) -> basic_string&{ REXY_CPP20_CONSTEXPR auto basic_string<Char,Alloc>::insert(size_type pos, size_type insert_count, value_type v)noexcept(is_nothrow_allocator_v<Alloc>) -> basic_string&{
struct insert_adapter{ struct insert_adapter{
size_type max;
value_type val; value_type val;
constexpr insert_adapter& operator++(void)noexcept{ constexpr insert_adapter& operator++(void)noexcept{
--max; return *this;
}
constexpr insert_adapter operator++(int)noexcept{
return *this; return *this;
} }
constexpr value_type operator*(void)const noexcept{ constexpr value_type operator*(void)const noexcept{
@ -269,41 +367,40 @@ namespace rexy{
constexpr bool operator!=(const insert_adapter& other)const = default; constexpr bool operator!=(const insert_adapter& other)const = default;
}; };
return insert(pos, insert_adapter{insert_count, v}, insert_adapter{0, v}); return _insert_impl(pos, insert_adapter{v}, insert_count);
} }
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc> template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
REXY_CPP20_CONSTEXPR auto basic_string<Char,Alloc>::insert(size_type pos, value_type v)noexcept(is_nothrow_allocator_v<Alloc>) -> basic_string&{ REXY_CPP20_CONSTEXPR auto basic_string<Char,Alloc>::insert(size_type pos, value_type v)noexcept(is_nothrow_allocator_v<Alloc>) -> basic_string&{
return insert(pos, size_type{1}, v); return _insert_impl(pos, &v, 1);
} }
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc> template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
REXY_CPP20_CONSTEXPR auto basic_string<Char,Alloc>::insert(size_type pos, const_pointer str)noexcept(is_nothrow_allocator_v<Alloc>) -> basic_string&{ REXY_CPP20_CONSTEXPR auto basic_string<Char,Alloc>::insert(size_type pos, const_pointer str)noexcept(is_nothrow_allocator_v<Alloc>) -> basic_string&{
const size_type slen = rexy::strlen(str); return _insert_impl(pos, str, rexy::strlen(str));
return insert(pos, str, str + slen);
} }
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc> template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
REXY_CPP20_CONSTEXPR auto basic_string<Char,Alloc>::insert(size_type pos, const_pointer str, size_type insert_count)noexcept(is_nothrow_allocator_v<Alloc>) -> basic_string&{ REXY_CPP20_CONSTEXPR auto basic_string<Char,Alloc>::insert(size_type pos, const_pointer str, size_type insert_count)noexcept(is_nothrow_allocator_v<Alloc>) -> basic_string&{
return insert(pos, str, str + insert_count); return _insert_impl(pos, str, insert_count);
} }
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc> template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
REXY_CPP20_CONSTEXPR auto basic_string<Char,Alloc>::insert(size_type pos, const basic_string& other)noexcept(is_nothrow_allocator_v<Alloc>) -> basic_string&{ REXY_CPP20_CONSTEXPR auto basic_string<Char,Alloc>::insert(size_type pos, const basic_string& other)noexcept(is_nothrow_allocator_v<Alloc>) -> basic_string&{
return insert(pos, other.begin(), other.end()); return _insert_impl(pos, other.begin(), other.length());
} }
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc> template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
REXY_CPP20_CONSTEXPR auto basic_string<Char,Alloc>::insert(size_type pos, const basic_string& other, size_type index_str, size_type count)noexcept(is_nothrow_allocator_v<Alloc>) -> basic_string&{ REXY_CPP20_CONSTEXPR auto basic_string<Char,Alloc>::insert(size_type pos, const basic_string& other, size_type index_str, size_type count)noexcept(is_nothrow_allocator_v<Alloc>) -> basic_string&{
return insert(pos, other.begin() + index_str, other.begin() + index_str + count); return _insert_impl(pos, other.begin() + index_str, count);
} }
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc> template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
REXY_CPP20_CONSTEXPR auto basic_string<Char,Alloc>::insert(const_iterator pos, value_type v)noexcept(is_nothrow_allocator_v<Alloc>) -> basic_string&{ REXY_CPP20_CONSTEXPR auto basic_string<Char,Alloc>::insert(const_iterator pos, value_type v)noexcept(is_nothrow_allocator_v<Alloc>) -> basic_string&{
return insert(pos, size_type{1}, v); return _insert_impl(pos - this->begin(), &v, 1);
} }
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc> template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
REXY_CPP20_CONSTEXPR auto basic_string<Char,Alloc>::insert(const_iterator pos, size_type count, value_type v)noexcept(is_nothrow_allocator_v<Alloc>) -> basic_string&{ REXY_CPP20_CONSTEXPR auto basic_string<Char,Alloc>::insert(const_iterator pos, size_type count, value_type v)noexcept(is_nothrow_allocator_v<Alloc>) -> basic_string&{
return insert(pos - this->begin(), count, v); return insert(pos - this->begin(), count, v);
} }
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc> template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
template<class InIt> template<class InputIt>
REXY_CPP20_CONSTEXPR auto basic_string<Char,Alloc>::insert(const_iterator pos, InIt start, InIt last)noexcept(is_nothrow_allocator_v<Alloc>) -> basic_string&{ REXY_CPP20_CONSTEXPR auto basic_string<Char,Alloc>::insert(const_iterator pos, InputIt start, InputIt last)noexcept(is_nothrow_allocator_v<Alloc>) -> basic_string&{
return insert(pos - this->begin(), std::move(start), std::move(last)); return insert(pos - this->begin(), std::move(start), std::move(last));
} }
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc> template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
@ -326,29 +423,32 @@ namespace rexy{
} }
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc> template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
template<class InIt> template<class InputIt>
REXY_CPP20_CONSTEXPR auto basic_string<Char,Alloc>::insert(size_type pos, InIt start, InIt last)noexcept(is_nothrow_allocator_v<Alloc>) -> basic_string&{ REXY_CPP20_CONSTEXPR auto basic_string<Char,Alloc>::insert(size_type pos, InputIt start, InputIt last)noexcept(is_nothrow_allocator_v<Alloc>) -> basic_string&{
const size_type len = this->length();
size_type insert_count = 0; size_type insert_count = 0;
for(auto it = start;it != last;++it, ++insert_count){} for(auto it = start;it != last;++it, ++insert_count){}
resize(rexy::max(pos + insert_count, len + insert_count)); return _insert_impl(pos, start, insert_count);
const size_type move_count = rexy::min<size_type>(0, len - pos);
const auto ptr = this->get_pointer();
for(size_type i = move_count+1;i > 0;--i){
const size_type index = i + pos;
ptr[index] = ptr[index-1];
} }
{ template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
size_type i = 0; REXY_CPP20_CONSTEXPR auto basic_string<Char,Alloc>::append(const_pointer data, size_type len)noexcept(is_nothrow_allocator_v<Alloc>) -> basic_string&{
for(auto it = start;it != last;++it,++i){ return _insert_impl(this->length(), data, len);
ptr[pos+i] = *it;
} }
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
REXY_CPP20_CONSTEXPR auto basic_string<Char,Alloc>::append(const_pointer data)noexcept(is_nothrow_allocator_v<Alloc>) -> basic_string&{
if(data){
append(data, rexy::strlen(data));
} }
this->set_length(len + insert_count);
return *this; return *this;
} }
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
REXY_CPP20_CONSTEXPR auto basic_string<Char,Alloc>::append(const basic_string& other)noexcept(is_nothrow_allocator_v<Alloc>) -> basic_string&{
return _insert_impl(this->length(), other.data(), other.length());
}
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
template<class InputIt>
REXY_CPP20_CONSTEXPR auto basic_string<Char,Alloc>::append(InputIt start, InputIt fin)noexcept(is_nothrow_allocator_v<Alloc>) -> basic_string&{
return insert(this->length(), start, fin);
}
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc> template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
REXY_CPP20_CONSTEXPR void basic_string<Char,Alloc>::push_back(value_type data) REXY_CPP20_CONSTEXPR void basic_string<Char,Alloc>::push_back(value_type data)
@ -356,57 +456,41 @@ namespace rexy{
{ {
append(&data, 1); append(&data, 1);
} }
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
constexpr void basic_string<Char,Alloc>::pop_back(void)noexcept{
erase(this->end() - 1);
}
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc> template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
REXY_CPP20_CONSTEXPR void basic_string<Char,Alloc>::append(const_pointer data, size_type len) constexpr auto basic_string<Char,Alloc>::erase(size_type index, size_type count)noexcept -> basic_string&{
noexcept(is_nothrow_allocator_v<Alloc>) const auto len = this->length();
{ const auto rem_count = std::min(count, len - index);
size_type mylen = this->length(); const auto end_pos = index + rem_count;
size_type mycap = this->capacity(); const auto relocate_count = len - end_pos + 1; //include terminator
pointer raw = this->get_pointer();
if(mylen+len <= mycap){ {
rexy::memcpy(raw+mylen, data, sizeof(value_type)*len); auto* src = this->get_pointer() + end_pos;
this->set_length(mylen+len); auto* dst = this->get_pointer() + index;
raw[mylen+len] = 0; for(size_type i = 0;i < relocate_count;++i){
}else{ *dst++ = *src++;
auto newsize = max(mylen+len, mycap*2);
basic_string tmp(newsize);
tmp.append(raw, mylen);
tmp.append(data, len);
*this = std::move(tmp);
} }
} }
this->set_length(len - rem_count);
return *this;
}
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc> template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
REXY_CPP20_CONSTEXPR void basic_string<Char,Alloc>::append(const_pointer data) constexpr auto basic_string<Char,Alloc>::erase(const_iterator pos)noexcept -> iterator{
noexcept(is_nothrow_allocator_v<Alloc>) const auto pos_index = pos - this->begin();
{ erase(pos - this->begin(), 1);
if(data) return this->begin() + pos_index;
append(data, rexy::strlen(data));
} }
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc> template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
template<class InputIt> constexpr auto basic_string<Char,Alloc>::erase(const_iterator first, const_iterator last)noexcept -> iterator{
REXY_CPP20_CONSTEXPR void basic_string<Char,Alloc>::append(InputIt start, InputIt fin) const auto distance = last - first;
noexcept(is_nothrow_allocator_v<Alloc>) const auto start_pos = first - this->begin();
{ erase(start_pos, distance);
size_type append_len = fin - start; return this->begin() + start_pos;
size_type my_len = this->length();
size_type my_cap = this->capacity();
pointer raw = this->get_pointer();
if(my_len + append_len > my_cap){
*this = basic_string(raw, my_len, max(my_len+append_len, my_cap*2));
raw = this->get_pointer();
my_cap *= 2;
}
size_type i = 0;
for(auto it = start;it != fin;++it,++i){
raw[my_len + i] = *it;
}
this->set_length(my_len + append_len);
raw[my_len + i] = 0;
} }
@ -428,29 +512,23 @@ namespace rexy{
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc> template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
REXY_CPP20_CONSTEXPR auto basic_string<Char,Alloc>::release(void)noexcept(is_nothrow_allocator_v<Alloc>) -> pointer{ REXY_CPP20_CONSTEXPR auto basic_string<Char,Alloc>::release(void)noexcept(is_nothrow_allocator_v<Alloc>) -> pointer{
if(this->islong()){ if(this->islong()){
pointer raw = this->get_long_ptr(); pointer raw = this->get_pointer();
this->set_islong_flag(false);
this->set_short_ptr(); this->set_short_ptr();
this->set_short_length(0); this->set_length(0);
return raw; return raw;
} }
size_type len = this->get_short_length(); if constexpr(string_base<Char>::uses_sso()){
pointer raw = this->get_short_ptr(); size_type len = this->length();
pointer raw = this->get_pointer();
pointer retval = this->allocate(sizeof(value_type)*len+1); pointer retval = this->allocate(sizeof(value_type)*len+1);
rexy::memcpy(retval, raw, sizeof(value_type)*len); rexy::memcpy(retval, raw, sizeof(value_type)*len);
retval[len] = 0; retval[len] = 0;
raw[0] = 0; raw[0] = 0;
this->set_short_length(0); this->set_length(0);
return retval; return retval;
}else{
return nullptr; //not possible to reach
} }
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
constexpr auto basic_string<Char,Alloc>::create_view(void)const noexcept -> basic_string_view<value_type>{
const auto ptr = this->get_pointer();
return basic_string_view<value_type>(ptr, ptr + this->length());
}
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
constexpr auto basic_string<Char,Alloc>::create_view(const_iterator start, const_iterator fin)const noexcept -> basic_string_view<value_type>{
return basic_string_view<value_type>(start, fin);
} }
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc> template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
@ -468,7 +546,29 @@ namespace rexy{
} }
return (*this = basic_string(s, len)); return (*this = basic_string(s, len));
} }
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
template<class InputIt>
REXY_CPP20_CONSTEXPR auto basic_string<Char,Alloc>::_insert_impl(size_type pos, InputIt start, size_type insert_count)noexcept(is_nothrow_allocator_v<Alloc>) -> basic_string&{
const size_type len = this->length();
const size_type after_pos_count = len > pos ? len - pos : 0;
basic_string newstr(rexy::max(pos + insert_count, len + insert_count));
auto* ptr = newstr.get_pointer();
rexy::memcpy(ptr, this->get_pointer(), sizeof(value_type) * pos);
ptr += pos;
for(size_type i = 0;i < insert_count;++i){
*ptr++ = *start++;
}
rexy::memcpy(ptr, this->get_pointer() + pos, sizeof(value_type) * after_pos_count);
ptr += after_pos_count;
*ptr = 0; //null terminator
newstr.set_length(len + insert_count);
return (*this = std::move(newstr));
}
template<class Left, class Right> template<class Left, class Right>
constexpr auto string_cat_expr<Left,Right>::length(void)const noexcept -> size_type{ constexpr auto string_cat_expr<Left,Right>::length(void)const noexcept -> size_type{
@ -488,6 +588,30 @@ namespace rexy{
} }
template<class Char>
[[deprecated]] constexpr auto string_base<Char>::search(const string_base& s)const -> const_iterator{
return two_way_search(cbegin(), cend(), s.begin(), s.end());
}
template<class Char>
[[deprecated]] constexpr auto string_base<Char>::search(const string_base& s) -> iterator{
return two_way_search(begin(), end(), s.begin(), s.end());
}
template<class Char>
template<class Searcher>
[[deprecated]] constexpr auto string_base<Char>::search(const string_base& s, const Searcher& searcher)const -> const_iterator{
return searcher(cbegin(), cend(), s.begin(), s.end());
}
template<class Char>
template<class Searcher>
[[deprecated]] constexpr auto string_base<Char>::search(const string_base& s, const Searcher& searcher) -> iterator{
return searcher(begin(), end(), s.begin(), s.end());
}
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
[[deprecated]] REXY_CPP20_CONSTEXPR bool basic_string<Char,Alloc>::resize(size_type newsize)noexcept(is_nothrow_allocator_v<Alloc>){
return reserve(newsize);
}
} //namespace rexy } //namespace rexy
#endif #endif

View File

@ -70,27 +70,38 @@ namespace rexy{
//Length of string not including null terminator //Length of string not including null terminator
constexpr size_type length(void)const noexcept{return m_length;} constexpr size_type length(void)const noexcept{return m_length;}
constexpr size_type size(void)const noexcept{return m_length;} constexpr size_type size(void)const noexcept{return m_length;}
constexpr bool empty(void)const noexcept{return m_length == 0;}
//direct access to managed pointer //direct access to managed pointer
constexpr const_pointer c_str(void)const noexcept{return m_data;} constexpr const_pointer c_str(void)const noexcept{return m_data;}
constexpr const_pointer data(void)const noexcept{return m_data;} constexpr const_pointer data(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 //true if m_data is not empty
constexpr bool valid(void)const noexcept{return m_length > 0;} constexpr bool valid(void)const noexcept{return m_length > 0;}
constexpr bool empty(void)const noexcept{return m_length == 0;}
constexpr const_reference operator[](size_type i)const noexcept{return m_data[i];} constexpr const_reference operator[](size_type i)const noexcept{return m_data[i];}
constexpr const_reference at(size_type i)const 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 front(void)const noexcept{return m_data[0];}
constexpr const_reference back(size_type i)const noexcept{return m_data[m_length-1];} constexpr const_reference back(void)const noexcept{return m_data[m_length-1];}
constexpr const_iterator it_at(size_type i)const noexcept{return m_data + i;} constexpr const_iterator it_at(size_type i)const noexcept{return m_data + i;}
constexpr const_iterator search(const basic_string_view& s)const; constexpr const_iterator search(basic_string_view s)const;
constexpr const_iterator search(const_pointer c)const; constexpr const_iterator search(const_pointer c)const;
template<class Searcher> template<class Searcher>
constexpr const_iterator search(const basic_string_view& s, const Searcher& searcher)const; constexpr const_iterator search(basic_string_view s, const Searcher& searcher)const;
template<class Searcher> template<class Searcher>
constexpr const_iterator search(const_pointer c, const Searcher& searcher)const; constexpr const_iterator search(const_pointer c, const Searcher& searcher)const;
constexpr bool starts_with(basic_string_view sv)const;
constexpr bool starts_with(value_type v)const;
constexpr bool starts_with(const_pointer str)const;
constexpr bool ends_with(basic_string_view sv)const;
constexpr bool ends_with(value_type v)const;
constexpr bool ends_with(const_pointer str)const;
constexpr bool contains(basic_string_view sv)const;
constexpr bool contains(value_type sv)const;
constexpr bool contains(const_pointer str)const;
constexpr bool compare(const basic_string_view& s)const{return *this == s;} constexpr bool compare(const basic_string_view& s)const{return *this == s;}
constexpr bool compare(const_pointer c)const{return *this == c;} constexpr bool compare(const_pointer c)const{return *this == c;}
@ -115,6 +126,10 @@ namespace rexy{
constexpr size_type find_last_of(value_type v, size_type start = 0)const; constexpr size_type find_last_of(value_type v, size_type start = 0)const;
constexpr size_type find_last_of(const_pointer c, size_type pos = 0)const; constexpr size_type find_last_of(const_pointer c, size_type pos = 0)const;
constexpr size_type find_last_of(const_pointer c, size_type pos, size_type size)const; constexpr size_type find_last_of(const_pointer c, size_type pos, size_type size)const;
[[deprecated]] constexpr const_pointer get(void)const noexcept{return m_data;}
[[deprecated]] constexpr operator const_pointer(void)const noexcept{return m_data;}
}; };
template<class T> template<class T>

View File

@ -22,6 +22,7 @@
#include "compat/to_address.hpp" #include "compat/to_address.hpp"
#include "utility.hpp" #include "utility.hpp"
#include "string_base.hpp" #include "string_base.hpp"
#include "algorithm.hpp" //two_way_search
#include "compat/string_base.hpp" #include "compat/string_base.hpp"
@ -49,7 +50,7 @@ namespace rexy{
} }
template<class Char> template<class Char>
constexpr auto basic_string_view<Char>::search(const basic_string_view& s)const -> const_iterator{ constexpr auto basic_string_view<Char>::search(basic_string_view s)const -> const_iterator{
return two_way_search(cbegin(), cend(), s.cbegin(), s.cend()); return two_way_search(cbegin(), cend(), s.cbegin(), s.cend());
} }
template<class Char> template<class Char>
@ -59,7 +60,7 @@ namespace rexy{
} }
template<class Char> template<class Char>
template<class Searcher> template<class Searcher>
constexpr auto basic_string_view<Char>::search(const basic_string_view& s, const Searcher& searcher)const -> const_iterator{ constexpr auto basic_string_view<Char>::search(basic_string_view s, const Searcher& searcher)const -> const_iterator{
return searcher(cbegin(), cend(), s.cbegin(), s.cend()); return searcher(cbegin(), cend(), s.cbegin(), s.cend());
} }
template<class Char> template<class Char>
@ -69,6 +70,70 @@ namespace rexy{
return search(tmp, searcher); return search(tmp, searcher);
} }
template<class Char>
constexpr bool basic_string_view<Char>::starts_with(basic_string_view sv)const{
if(sv.length() > length()){
return false;
}
auto it = two_way_search(begin(), begin() + sv.length(), sv.cbegin(), sv.cend());
if(it == begin()){
return true;
}
return false;
}
template<class Char>
constexpr bool basic_string_view<Char>::starts_with(value_type v)const{
return front() == v;
}
template<class Char>
constexpr bool basic_string_view<Char>::starts_with(const_pointer s)const{
return starts_with(basic_string_view(s));
}
template<class Char>
constexpr bool basic_string_view<Char>::ends_with(basic_string_view sv)const{
if(sv.length() > length()){
return false;
}
const auto start = end() - sv.length();
auto it = two_way_search(start, end(), sv.cbegin(), sv.cend());
if(it == start){
return true;
}
return false;
}
template<class Char>
constexpr bool basic_string_view<Char>::ends_with(value_type v)const{
return back() == v;
}
template<class Char>
constexpr bool basic_string_view<Char>::ends_with(const_pointer s)const{
return ends_with(basic_string_view(s));
}
template<class Char>
constexpr bool basic_string_view<Char>::contains(basic_string_view sv)const{
const auto it = two_way_search(cbegin(), cend(), sv.cbegin(), sv.cend());
if(it != cend()){
return true;
}
return false;
}
template<class Char>
constexpr bool basic_string_view<Char>::contains(value_type v)const{
for(size_type i = 0;i < length();++i){
if(m_data[i] == v){
return true;
}
}
return false;
}
template<class Char>
constexpr bool basic_string_view<Char>::contains(const_pointer str)const{
return contains(basic_string_view(str));
}
template<class Char> template<class Char>
constexpr basic_string_view<Char> basic_string_view<Char>::substr(size_type pos, size_type count)const{ constexpr basic_string_view<Char> basic_string_view<Char>::substr(size_type pos, size_type count)const{
const size_type real_count = rexy::min(count, length() - pos); const size_type real_count = rexy::min(count, length() - pos);

View File

@ -106,7 +106,7 @@ namespace rexy{
return fwrite(c, 1, bytes, m_fp); return fwrite(c, 1, bytes, m_fp);
} }
size_t filerd::write(const rexy::string_base<char>& c)noexcept{ size_t filerd::write(const rexy::string_base<char>& c)noexcept{
return write(c.get(), c.length()); return write(c.data(), c.length());
} }
} }

View File

@ -19,18 +19,16 @@ void check_empty_construction(){
if(str1.length() != 0) if(str1.length() != 0)
error("length() should return 0 on default init\n"); error("length() should return 0 on default init\n");
if(test_str::uses_sso()){ if(test_str::uses_sso()){
if(str1.get()[0] != 0) if(str1.data()[0] != 0)
error("get() should return an empty, zero length string\n"); error("data() should return an empty, zero length string\n");
}else{ }else{
if(str1.get() != nullptr) if(str1.data() != nullptr)
error("get() should return a null string\n"); error("data() should return a null string\n");
} }
if(str1.valid()) if(str1.valid())
error("valid() should return false on empty string\n"); error("valid() should return false on empty string\n");
if(str1.get() != str1.c_str()) if(str1.data() != str1.c_str())
error("c_str() should be a synonymn of get()\n"); error("c_str() should be a synonymn of data()\n");
if(char* c = str1;c != str1.get())
error("conversion to pointer type should be synonymous with get()\n");
test_str str2(str1); test_str str2(str1);
if(str2.length() != str1.length()) if(str2.length() != str1.length())
@ -38,11 +36,11 @@ void check_empty_construction(){
if(str2.capacity() != str1.capacity()) if(str2.capacity() != str1.capacity())
error("copy construction on empty string should give equivalent capacity()\n"); error("copy construction on empty string should give equivalent capacity()\n");
if(test_str::uses_sso()){ if(test_str::uses_sso()){
if(str2.get()[0] != str1.get()[0]) if(str2.data()[0] != str1.data()[0])
error("copy construction on empty string should give equivalent get()\n"); error("copy construction on empty string should give equivalent data()\n");
}else{ }else{
if(str2.get() != str1.get()) if(str2.data() != str1.data())
error("copy construction on empty string should give equivalent get()\n"); error("copy construction on empty string should give equivalent data()\n");
} }
test_str str3(std::move(str2)); test_str str3(std::move(str2));
@ -51,11 +49,11 @@ void check_empty_construction(){
if(str3.capacity() != str1.capacity()) if(str3.capacity() != str1.capacity())
error("move construction on empty string should give equivalent capacity()\n"); error("move construction on empty string should give equivalent capacity()\n");
if(test_str::uses_sso()){ if(test_str::uses_sso()){
if(str3.get()[0] != str1.get()[0]) if(str3.data()[0] != str1.data()[0])
error("move construction on empty string should give equivalent get()\n"); error("move construction on empty string should give equivalent data()\n");
}else{ }else{
if(str3.get() != str1.get()) if(str3.data() != str1.data())
error("move construction on empty string should give equivalent get()\n"); error("move construction on empty string should give equivalent data()\n");
} }
} }
@ -69,24 +67,24 @@ void check_short_construction(){
error("short constructed string 'a' should be length() == 1\n"); error("short constructed string 'a' should be length() == 1\n");
if(str1.capacity() != cap) if(str1.capacity() != cap)
error("short constructed string 'a' should be capacity() == short_string_size()\n"); error("short constructed string 'a' should be capacity() == short_string_size()\n");
if(strcmp(str1.get(), "a")) if(strcmp(str1.data(), "a"))
error("short constructed string 'a' should be !strcmp(get(), \"a\")\n"); error("short constructed string 'a' should be !strcmp(data(), \"a\")\n");
test_str str2(str1); test_str str2(str1);
if(str2.length() != str1.length()) if(str2.length() != str1.length())
error("short copy constructed string should have equal length()\n"); error("short copy constructed string should have equal length()\n");
if(str2.capacity() != str1.capacity()) if(str2.capacity() != str1.capacity())
error("short copy constructed string should have equal capacity()\n"); error("short copy constructed string should have equal capacity()\n");
if(strcmp(str2.get(), str1.get())) if(strcmp(str2.data(), str1.data()))
error("short copy constructed string should have equivalent get()\n"); error("short copy constructed string should have equivalent data()\n");
test_str str3(std::move(str2)); test_str str3(std::move(str2));
if(str3.length() != str1.length()) if(str3.length() != str1.length())
error("short move constructed string should have equal length()\n"); error("short move constructed string should have equal length()\n");
if(str3.capacity() != str1.capacity()) if(str3.capacity() != str1.capacity())
error("short move constructed string should have equal capacity()\n"); error("short move constructed string should have equal capacity()\n");
if(strcmp(str3.get(), str1.get())) if(strcmp(str3.data(), str1.data()))
error("short move constructed string should have equivalent get()\n"); error("short move constructed string should have equivalent data()\n");
} }
void check_long_construction(){ void check_long_construction(){
const char* data = "this is a really long string that should ensure that it makes a dynamic allocation even if it has a big buffer."; const char* data = "this is a really long string that should ensure that it makes a dynamic allocation even if it has a big buffer.";
@ -96,24 +94,24 @@ void check_long_construction(){
error("long constructed string should be length() == strlen(data)\n"); error("long constructed string should be length() == strlen(data)\n");
if(str1.capacity() < len) if(str1.capacity() < len)
error("long constructed string should be capacity() >= strlen(data)\n"); error("long constructed string should be capacity() >= strlen(data)\n");
if(strcmp(str1.get(), data)) if(strcmp(str1.data(), data))
error("long constructed string should be !strcmp(get(), data)\n"); error("long constructed string should be !strcmp(data(), data)\n");
test_str str2(str1); test_str str2(str1);
if(str2.length() != str1.length()) if(str2.length() != str1.length())
error("long copy constructed string should have equal length()\n"); error("long copy constructed string should have equal length()\n");
if(str2.capacity() != str1.capacity()) if(str2.capacity() != str1.capacity())
error("long copy constructed string should have equal capacity()\n"); error("long copy constructed string should have equal capacity()\n");
if(strcmp(str2.get(), str1.get())) if(strcmp(str2.data(), str1.data()))
error("long copy constructed string should have equivalent get()\n"); error("long copy constructed string should have equivalent data()\n");
test_str str3(std::move(str2)); test_str str3(std::move(str2));
if(str3.length() != str1.length()) if(str3.length() != str1.length())
error("long move constructed string should have equal length()\n"); error("long move constructed string should have equal length()\n");
if(str3.capacity() != str1.capacity()) if(str3.capacity() != str1.capacity())
error("long move constructed string should have equal capacity()\n"); error("long move constructed string should have equal capacity()\n");
if(strcmp(str3.get(), str1.get())) if(strcmp(str3.data(), str1.data()))
error("long move constructed string should have equivalent get()\n"); error("long move constructed string should have equivalent data()\n");
} }
void check_short_assignment(){ void check_short_assignment(){
if(!test_str::uses_sso()) if(!test_str::uses_sso())
@ -128,8 +126,8 @@ void check_short_assignment(){
error("short assigned string 'a' should be length() == 1\n"); error("short assigned string 'a' should be length() == 1\n");
if(str1.capacity() != cap) if(str1.capacity() != cap)
error("short assigned string 'a' should be capacity() == short_string_size()\n"); error("short assigned string 'a' should be capacity() == short_string_size()\n");
if(strcmp(str1.get(), "a")) if(strcmp(str1.data(), "a"))
error("short assigned string 'a' should be !strcmp(get(), \"a\")\n"); error("short assigned string 'a' should be !strcmp(data(), \"a\")\n");
test_str str2("ba"); test_str str2("ba");
str2 = str1; str2 = str1;
@ -137,8 +135,8 @@ void check_short_assignment(){
error("short copy assigned string should have equal length()\n"); error("short copy assigned string should have equal length()\n");
if(str2.capacity() != str1.capacity()) if(str2.capacity() != str1.capacity())
error("short copy assigned string should have equal capacity()\n"); error("short copy assigned string should have equal capacity()\n");
if(strcmp(str2.get(), str1.get())) if(strcmp(str2.data(), str1.data()))
error("short copy assigned string should have equivalent get()\n"); error("short copy assigned string should have equivalent data()\n");
test_str str3("cb"); test_str str3("cb");
str3 = std::move(str2); str3 = std::move(str2);
@ -146,8 +144,8 @@ void check_short_assignment(){
error("short move assigned string should have equal length()\n"); error("short move assigned string should have equal length()\n");
if(str3.capacity() != str1.capacity()) if(str3.capacity() != str1.capacity())
error("short move assigned string should have equal capacity()\n"); error("short move assigned string should have equal capacity()\n");
if(strcmp(str3.get(), str1.get())) if(strcmp(str3.data(), str1.data()))
error("short move assigned string should have equivalent get()\n"); error("short move assigned string should have equivalent data()\n");
test_str str4(longstartdata); test_str str4(longstartdata);
str4 = str1; str4 = str1;
@ -155,8 +153,8 @@ void check_short_assignment(){
error("long->short copy assigned string should have equal length()\n"); error("long->short copy assigned string should have equal length()\n");
if(str4.capacity() < str1.capacity()) if(str4.capacity() < str1.capacity())
error("long->short copy assigned string should have equal or greater capacity()\n"); error("long->short copy assigned string should have equal or greater capacity()\n");
if(strcmp(str4.get(), str1.get())) if(strcmp(str4.data(), str1.data()))
error("long->short copy assigned string should have equivalent get()\n"); error("long->short copy assigned string should have equivalent data()\n");
test_str str5(longstartdata); test_str str5(longstartdata);
str5 = std::move(str4); str5 = std::move(str4);
@ -164,8 +162,8 @@ void check_short_assignment(){
error("long->short move assigned string should have equal length()\n"); error("long->short move assigned string should have equal length()\n");
if(str5.capacity() < str1.capacity()) if(str5.capacity() < str1.capacity())
error("long->short move assigned string should have equal or greater capacity()\n"); error("long->short move assigned string should have equal or greater capacity()\n");
if(strcmp(str5.get(), str1.get())) if(strcmp(str5.data(), str1.data()))
error("long->short move assigned string should have equivalent get()\n"); error("long->short move assigned string should have equivalent data()\n");
} }
void check_long_assignment(){ void check_long_assignment(){
const char* startdata1 = "this is another really long string that should ensure that it makes some sort of dyn alloc for big buf"; const char* startdata1 = "this is another really long string that should ensure that it makes some sort of dyn alloc for big buf";
@ -178,8 +176,8 @@ void check_long_assignment(){
error("long assigned string should be length() == strlen(data)\n"); error("long assigned string should be length() == strlen(data)\n");
if(str1.capacity() < len) if(str1.capacity() < len)
error("long assigned string should be capacity() >= strlen(data)\n"); error("long assigned string should be capacity() >= strlen(data)\n");
if(strcmp(str1.get(), data)) if(strcmp(str1.data(), data))
error("long assigned string should be !strcmp(get(), data)\n"); error("long assigned string should be !strcmp(data(), data)\n");
test_str str2(startdata1); test_str str2(startdata1);
str2 = str1; str2 = str1;
@ -187,8 +185,8 @@ void check_long_assignment(){
error("long copy assigned string should have equal length()\n"); error("long copy assigned string should have equal length()\n");
if(str2.capacity() != str1.capacity()) if(str2.capacity() != str1.capacity())
error("long copy assigned string should have equal capacity()\n"); error("long copy assigned string should have equal capacity()\n");
if(strcmp(str2.get(), str1.get())) if(strcmp(str2.data(), str1.data()))
error("long copy assigned string should have equivalent get()\n"); error("long copy assigned string should have equivalent data()\n");
test_str str3(startdata1); test_str str3(startdata1);
str3 = std::move(str2); str3 = std::move(str2);
@ -196,8 +194,8 @@ void check_long_assignment(){
error("long move assigned string should have equal length()\n"); error("long move assigned string should have equal length()\n");
if(str3.capacity() != str1.capacity()) if(str3.capacity() != str1.capacity())
error("long move assigned string should have equal capacity()\n"); error("long move assigned string should have equal capacity()\n");
if(strcmp(str3.get(), str1.get())) if(strcmp(str3.data(), str1.data()))
error("long move assigned string should have equivalent get()\n"); error("long move assigned string should have equivalent data()\n");
test_str str4(startdata2); test_str str4(startdata2);
str4 = str1; str4 = str1;
@ -205,8 +203,8 @@ void check_long_assignment(){
error("short->long copy assigned string should have equal length()\n"); error("short->long copy assigned string should have equal length()\n");
if(str4.capacity() != str1.capacity()) if(str4.capacity() != str1.capacity())
error("short->long copy assigned string should have equal capacity()\n"); error("short->long copy assigned string should have equal capacity()\n");
if(strcmp(str4.get(), str1.get())) if(strcmp(str4.data(), str1.data()))
error("short->long copy assigned string should have equivalent get()\n"); error("short->long copy assigned string should have equivalent data()\n");
test_str str5(startdata2); test_str str5(startdata2);
str5 = std::move(str4); str5 = std::move(str4);
@ -214,8 +212,8 @@ void check_long_assignment(){
error("short->long move assigned string should have equal length()\n"); error("short->long move assigned string should have equal length()\n");
if(str5.capacity() != str1.capacity()) if(str5.capacity() != str1.capacity())
error("short->long move assigned string should have equal capacity()\n"); error("short->long move assigned string should have equal capacity()\n");
if(strcmp(str5.get(), str1.get())) if(strcmp(str5.data(), str1.data()))
error("short->long move assigned string should have equivalent get()\n"); error("short->long move assigned string should have equivalent data()\n");
} }
void check_short_append(){ void check_short_append(){
test_str str1; test_str str1;
@ -224,10 +222,10 @@ void check_short_append(){
str1.append("a"); str1.append("a");
str1.append("b"); str1.append("b");
str1.append(str2); str1.append(str2);
if(strcmp(str1.get(), "abbc")) if(strcmp(str1.data(), "abbc"))
error("short append should have resulted in abbc\n"); error("short append should have resulted in abbc\n");
str1.append(str3); str1.append(str3);
if(strcmp(str1, "abbcreally long string that should trigger a short to long conversion in the string")) if(strcmp(str1.c_str(), "abbcreally long string that should trigger a short to long conversion in the string"))
error("short->long append should have resulted in abbcreally long string that should trigger a short to long conversion in the string\n"); error("short->long append should have resulted in abbcreally long string that should trigger a short to long conversion in the string\n");
} }
void check_long_append(){ void check_long_append(){
@ -235,21 +233,65 @@ void check_long_append(){
const char* appendeddata = "this is another really long string that should ensure that it makes some sort of dyn alloc for big bufstuff"; const char* appendeddata = "this is another really long string that should ensure that it makes some sort of dyn alloc for big bufstuff";
test_str str1(startdata1); test_str str1(startdata1);
str1.append("stuff"); str1.append("stuff");
if(strcmp(str1.get(), appendeddata)) if(strcmp(str1.c_str(), appendeddata))
error("long append should have resulted in this is another really long string that should ensure that it makes some sort of dyn alloc for big bufstuff\n"); error("long append should have resulted in this is another really long string that should ensure that it makes some sort of dyn alloc for big bufstuff\n");
} }
void check_substring(){ void check_substring(){
rexy::string test = "this is a test string"; rexy::string test = "this is a test string";
rexy::string test2 = test.substring(5, 7); rexy::string test2 = test.substring(5, 7);
if(strcmp(test2.get(), "is") || test2.length() != 2) if(strcmp(test2.c_str(), "is") || test2.length() != 2)
error("substring operation should have resulted in 'is'\n"); error("substring operation should have resulted in 'is'\n");
} }
void check_string_search(){ void check_string_search(){
rexy::string test1 = "this is a test string"; rexy::string test1 = "this is a test string";
rexy::string test2 = "string"; rexy::string test2 = "string";
auto res = test1.search(test2); auto res = test1.search(test2.create_view());
if(test1 + 15 != res){ if(test1.data() + 15 != res){
error("string search operation did not result in a correct result"); error("string search operation did not result in a correct result\n");
}
}
void check_string_insert(){
rexy::string test = "this is a string";
auto it = test.search("string");
if(it == test.end()){
error("string search failed\n");
}
test.insert(it - test.begin(), "test ", 5);
if(test != "this is a test string" || test.length() != 21){
error("string insert operation failed\n");
}
test.insert(0, "wow ");
if(test != "wow this is a test string" || test.length() != 25){
error("string insert operation 2 failed\n");
}
test.insert(test.length(), " oof");
if(test != "wow this is a test string oof" || test.length() != 29){
error("string insert operation 3 failed\n");
}
}
void check_string_erase(){
rexy::string test = "this is a test string";
test.erase(0, 5);
if(test != "is a test string" || test.length() != 16){
error("string erase operation 1 did not result in a correct result\n");
}
test.erase(5, 5);
if(test != "is a string" || test.length() != 11){
error("string erase operation 2 did not result in a correct result\n");
}
test.erase(9, 2);
if(test != "is a stri" || test.length() != 9){
error("string erase operation 3 did not result in a correct result\n");
}
test.erase(8, 2);
if(test != "is a str" || test.length() != 8){
error("string erase operation 4 did not result in a correct result\n");
}
test.pop_back();
if(test != "is a st" || test.length() != 7){
error("string erase operation 5 did not result in a correct result\n");
} }
} }
@ -263,4 +305,6 @@ int main(){
check_long_append(); check_long_append();
check_substring(); check_substring();
check_string_search(); check_string_search();
check_string_insert();
check_string_erase();
} }