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:
parent
1799c1640b
commit
24ef556ab7
@ -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_SSO "Use small string optimization" ON "NOT BUILD_HEADER_ONLY" ON)
|
||||
option(ENABLE_PROFILING "Enable asan" OFF)
|
||||
option(BUILD_TESTS "Enable testing" OFF)
|
||||
option(BUILD_HEADER_ONLY "Enable header only build" OFF)
|
||||
@ -42,6 +43,13 @@ else()
|
||||
endif()
|
||||
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)
|
||||
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)
|
||||
|
||||
@ -33,12 +33,12 @@ namespace rexy{
|
||||
|
||||
//Requires Iterators to be LegacyRandomAccessIterators
|
||||
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
|
||||
struct two_way_searcher{
|
||||
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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@ -40,7 +40,7 @@ namespace rexy{
|
||||
|
||||
//Requires Iterators to be LegacyRandomAccessIterators
|
||||
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 i = 0;
|
||||
size_t nlen = nend - nstart;
|
||||
@ -99,7 +99,7 @@ namespace rexy{
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@ -24,6 +24,8 @@
|
||||
#include <utility> //forward
|
||||
#include <type_traits> //{false,true}_type, declval, enable_if, remove_reference, decay
|
||||
|
||||
#include "../../utility.hpp" //strlen, strncmp
|
||||
|
||||
namespace rexy{
|
||||
|
||||
#define REXY_HAS_MEMFUN_WITH_RET(type, ret, fun, ...) \
|
||||
@ -92,31 +94,29 @@ namespace rexy{
|
||||
if(left.length() != right.length()){
|
||||
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>
|
||||
constexpr bool operator==(Str1&& left, typename std::decay_t<Str1>::const_pointer right){
|
||||
if(right == nullptr){
|
||||
return false;
|
||||
}
|
||||
const auto rlen = detail::string_len(right);
|
||||
const auto rlen = rexy::strlen(right);
|
||||
if(rlen != left.length()){
|
||||
return false;
|
||||
}
|
||||
const auto minlen = min(left.length(), rlen);
|
||||
return !detail::string_compare(left.c_str(), right, minlen+1);
|
||||
return !rexy::strncmp(left.c_str(), right, rlen+1);
|
||||
}
|
||||
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){
|
||||
if(left == nullptr){
|
||||
return false;
|
||||
}
|
||||
const auto llen = detail::string_len(left);
|
||||
const auto llen = rexy::strlen(left);
|
||||
if(llen != right.length()){
|
||||
return false;
|
||||
}
|
||||
const auto minlen = min(right.length(), llen);
|
||||
return !detail::string_compare(right.c_str(), left, minlen+1);
|
||||
return !rexy::strncmp(left, right.c_str(), llen+1);
|
||||
}
|
||||
template<class Str1, class Str2, std::enable_if_t<are_strings<Str1, Str2>::value,int> = 0>
|
||||
constexpr bool operator!=(Str1&& left, Str2&& right)noexcept{
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
#include <type_traits> //decay, is_nothrow_assignable
|
||||
|
||||
#include "../../concepts/string.hpp"
|
||||
#include "../../utility.hpp" //strlen, strncmp
|
||||
|
||||
namespace rexy{
|
||||
|
||||
@ -34,31 +35,29 @@ namespace rexy{
|
||||
if(left.length() != right.length()){
|
||||
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>
|
||||
constexpr bool operator==(Str1&& left, typename std::decay_t<Str1>::const_pointer right){
|
||||
if(right == nullptr){
|
||||
return false;
|
||||
}
|
||||
const auto rlen = detail::string_len(right);
|
||||
const auto rlen = rexy::strlen(right);
|
||||
if(rlen != left.length()){
|
||||
return false;
|
||||
}
|
||||
const auto minlen = min(left.length(), rlen);
|
||||
return !detail::string_compare(left.c_str(), right, minlen+1);
|
||||
return !rexy::strncmp(left.c_str(), right, rlen+1);
|
||||
}
|
||||
template<BasicString Str1>
|
||||
constexpr bool operator==(typename std::decay_t<Str1>::const_pointer left, Str1&& right){
|
||||
if(left == nullptr){
|
||||
return false;
|
||||
}
|
||||
const auto llen = detail::string_len(left);
|
||||
const auto llen = rexy::strlen(left);
|
||||
if(llen != right.length()){
|
||||
return false;
|
||||
}
|
||||
const auto minlen = min(right.length(), llen);
|
||||
return !detail::string_compare(right.c_str(), left, minlen+1);
|
||||
return !rexy::strncmp(left, right.c_str(), llen+1);
|
||||
}
|
||||
template<BasicString Str1, BasicString Str2>
|
||||
constexpr bool operator!=(Str1&& left, Str2&& right){
|
||||
|
||||
@ -30,5 +30,6 @@
|
||||
#define LIBREXY_VERSION_MINOR @librexy_VERSION_MINOR@
|
||||
#define LIBREXY_VERSION_REVISION @librexy_VERSION_REVISION@
|
||||
|
||||
#define LIBREXY_ENABLE_SSO @librexy_ENABLE_SSO@
|
||||
|
||||
#endif
|
||||
|
||||
@ -41,6 +41,10 @@
|
||||
|
||||
namespace rexy{
|
||||
|
||||
#ifndef LIBREXY_ENABLE_SSO
|
||||
#define LIBREXY_ENABLE_SSO 1
|
||||
#endif
|
||||
|
||||
template<class Char>
|
||||
class basic_string_view;
|
||||
|
||||
@ -61,6 +65,7 @@ namespace rexy{
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
|
||||
#if LIBREXY_ENABLE_SSO != 0
|
||||
private:
|
||||
static constexpr size_type EXTRA_SDATA_LEN = 0;
|
||||
|
||||
@ -132,6 +137,12 @@ namespace rexy{
|
||||
constexpr void set_short_capacity(size_type){}
|
||||
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 void set_capacity(size_type s){
|
||||
if(islong())
|
||||
set_long_capacity(s);
|
||||
else
|
||||
set_short_capacity(s);
|
||||
}
|
||||
constexpr void set_length(size_type s){
|
||||
if(islong())
|
||||
set_long_length(s);
|
||||
@ -180,52 +191,134 @@ namespace rexy{
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
public:
|
||||
//Length of string not including null terminator
|
||||
constexpr size_type length(void)const noexcept{
|
||||
if(islong())
|
||||
return get_long_length();
|
||||
else
|
||||
return get_short_length();
|
||||
}
|
||||
constexpr size_type size(void)const noexcept{
|
||||
return length();
|
||||
}
|
||||
constexpr size_type capacity(void)const noexcept{
|
||||
if(islong())
|
||||
return get_long_capacity();
|
||||
else
|
||||
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
|
||||
constexpr pointer c_str(void)noexcept{return get_pointer();}
|
||||
constexpr const_pointer c_str(void)const noexcept{return get_pointer();}
|
||||
constexpr pointer get(void)noexcept{return get_pointer();}
|
||||
constexpr const_pointer get(void)const noexcept{return get_pointer();}
|
||||
constexpr operator pointer(void)noexcept{return get_pointer();}
|
||||
constexpr operator const_pointer(void)const noexcept{return get_pointer();}
|
||||
constexpr pointer data(void)noexcept{return get_pointer();}
|
||||
constexpr const_pointer data(void)const noexcept{return get_pointer();}
|
||||
constexpr operator basic_string_view<value_type>(void)const noexcept{return basic_string_view<value_type>(begin(), end());}
|
||||
|
||||
//true if m_data is not empty
|
||||
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 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 iterator search(const string_base& s);
|
||||
constexpr iterator search(const_pointer c);
|
||||
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;
|
||||
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 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(basic_string_view<value_type> s)const{return *this == s;}
|
||||
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 const_iterator begin(void)const{return get_pointer();}
|
||||
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 crend(void)const{return rend();}
|
||||
|
||||
static constexpr bool uses_sso(void){return true;}
|
||||
static constexpr size_type short_string_size(void){return MAX_SHORT_LEN;}
|
||||
constexpr void clear(void)noexcept;
|
||||
|
||||
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>);
|
||||
REXY_CPP20_CONSTEXPR basic_string& _copy_string(const_pointer s, size_type len)
|
||||
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:
|
||||
constexpr basic_string(void)noexcept;
|
||||
@ -308,9 +417,9 @@ namespace rexy{
|
||||
//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, 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, 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>);
|
||||
@ -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(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>);
|
||||
template<class InIt>
|
||||
REXY_CPP20_CONSTEXPR basic_string& insert(const_iterator pos, InIt start, InIt last)noexcept(is_nothrow_allocator_v<Alloc>);
|
||||
template<class InIt>
|
||||
REXY_CPP20_CONSTEXPR basic_string& insert(size_type pos, InIt start, InIt last)noexcept(is_nothrow_allocator_v<Alloc>);
|
||||
template<class InputIt>
|
||||
REXY_CPP20_CONSTEXPR basic_string& insert(const_iterator pos, InputIt start, InputIt last)noexcept(is_nothrow_allocator_v<Alloc>);
|
||||
template<class InputIt>
|
||||
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>);
|
||||
template<class StringView>
|
||||
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>
|
||||
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>>;
|
||||
|
||||
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>
|
||||
REXY_CPP20_CONSTEXPR void append(InputIt start, InputIt fin)
|
||||
noexcept(is_nothrow_allocator_v<Alloc>);
|
||||
REXY_CPP20_CONSTEXPR basic_string& append(InputIt start, InputIt fin)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>
|
||||
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>);
|
||||
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
|
||||
@ -386,32 +499,6 @@ namespace rexy{
|
||||
template<class Left, class 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"
|
||||
|
||||
@ -33,8 +33,18 @@
|
||||
namespace rexy{
|
||||
|
||||
template<class Char>
|
||||
constexpr auto string_base<Char>::search(const string_base& s)const -> const_iterator{
|
||||
return two_way_search(cbegin(), cend(), s.begin(), s.end());
|
||||
constexpr auto string_base<Char>::search(basic_string_view<value_type> sv)const -> const_iterator{
|
||||
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>
|
||||
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);
|
||||
}
|
||||
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{
|
||||
const auto len = rexy::strlen(c);
|
||||
return two_way_search(begin(), end(), c, c + len);
|
||||
}
|
||||
template<class Char>
|
||||
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{
|
||||
const auto len = rexy::strlen(c);
|
||||
return searcher(cbegin(), cend(), c, c + len);
|
||||
}
|
||||
template<class Char>
|
||||
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{
|
||||
const auto len = rexy::strlen(c);
|
||||
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
|
||||
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)
|
||||
noexcept(is_nothrow_allocator_v<Alloc>)
|
||||
{
|
||||
if(cap > this->get_short_capacity()){
|
||||
this->set_islong_flag(true);
|
||||
if constexpr(string_base<Char>::uses_sso()){
|
||||
if(cap > string_base<Char>::short_string_size()){
|
||||
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);
|
||||
}
|
||||
raw[len] = 0;
|
||||
this->set_long_length(len);
|
||||
this->set_long_capacity(cap);
|
||||
}else{
|
||||
this->set_islong_flag(false);
|
||||
pointer raw = this->set_short_ptr();
|
||||
if(data)
|
||||
if(data){
|
||||
rexy::memcpy(raw, data, sizeof(value_type)*len);
|
||||
}
|
||||
raw[len] = 0;
|
||||
this->set_short_length(len);
|
||||
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>
|
||||
@ -178,7 +266,7 @@ namespace rexy{
|
||||
noexcept(is_nothrow_allocator_v<Alloc>)
|
||||
{
|
||||
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>)
|
||||
{
|
||||
if(this->islong())
|
||||
this->deallocate(this->get_long_ptr(),sizeof(value_type)*(this->get_long_capacity()+1));
|
||||
this->set_islong_flag(true);
|
||||
this->deallocate(this->get_pointer(),sizeof(value_type)*(this->capacity()+1));
|
||||
this->set_long_ptr(val);
|
||||
if constexpr(string_base<Char>::uses_sso()){
|
||||
this->set_long_length(len);
|
||||
this->set_long_capacity(len);
|
||||
}else{
|
||||
this->set_length(len);
|
||||
this->set_capacity(len);
|
||||
}
|
||||
}
|
||||
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
|
||||
REXY_CPP20_CONSTEXPR bool basic_string<Char,Alloc>::resize(size_type newsize)
|
||||
noexcept(is_nothrow_allocator_v<Alloc>)
|
||||
{
|
||||
REXY_CPP20_CONSTEXPR bool basic_string<Char,Alloc>::reserve(size_type newsize)noexcept(is_nothrow_allocator_v<Alloc>){
|
||||
if(newsize < this->capacity())
|
||||
return false;
|
||||
if(!this->islong() && newsize < this->get_short_capacity())
|
||||
if(!this->islong() && newsize < string_base<Char>::short_string_size())
|
||||
return false;
|
||||
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>
|
||||
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{
|
||||
size_type max;
|
||||
value_type val;
|
||||
|
||||
constexpr insert_adapter& operator++(void)noexcept{
|
||||
--max;
|
||||
return *this;
|
||||
}
|
||||
constexpr insert_adapter operator++(int)noexcept{
|
||||
return *this;
|
||||
}
|
||||
constexpr value_type operator*(void)const noexcept{
|
||||
@ -269,41 +367,40 @@ namespace rexy{
|
||||
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>
|
||||
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>
|
||||
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(pos, str, str + slen);
|
||||
return _insert_impl(pos, str, rexy::strlen(str));
|
||||
}
|
||||
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&{
|
||||
return insert(pos, str, str + insert_count);
|
||||
return _insert_impl(pos, str, insert_count);
|
||||
}
|
||||
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&{
|
||||
return insert(pos, other.begin(), other.end());
|
||||
return _insert_impl(pos, other.begin(), other.length());
|
||||
}
|
||||
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&{
|
||||
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>
|
||||
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>
|
||||
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);
|
||||
}
|
||||
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
|
||||
template<class InIt>
|
||||
REXY_CPP20_CONSTEXPR auto basic_string<Char,Alloc>::insert(const_iterator pos, InIt start, InIt last)noexcept(is_nothrow_allocator_v<Alloc>) -> basic_string&{
|
||||
template<class InputIt>
|
||||
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));
|
||||
}
|
||||
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
|
||||
@ -326,29 +423,32 @@ namespace rexy{
|
||||
}
|
||||
|
||||
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
|
||||
template<class InIt>
|
||||
REXY_CPP20_CONSTEXPR auto basic_string<Char,Alloc>::insert(size_type pos, InIt start, InIt last)noexcept(is_nothrow_allocator_v<Alloc>) -> basic_string&{
|
||||
const size_type len = this->length();
|
||||
template<class InputIt>
|
||||
REXY_CPP20_CONSTEXPR auto basic_string<Char,Alloc>::insert(size_type pos, InputIt start, InputIt last)noexcept(is_nothrow_allocator_v<Alloc>) -> basic_string&{
|
||||
size_type insert_count = 0;
|
||||
for(auto it = start;it != last;++it, ++insert_count){}
|
||||
resize(rexy::max(pos + insert_count, len + 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];
|
||||
return _insert_impl(pos, start, insert_count);
|
||||
}
|
||||
{
|
||||
size_type i = 0;
|
||||
for(auto it = start;it != last;++it,++i){
|
||||
ptr[pos+i] = *it;
|
||||
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
|
||||
REXY_CPP20_CONSTEXPR auto basic_string<Char,Alloc>::append(const_pointer data, size_type len)noexcept(is_nothrow_allocator_v<Alloc>) -> basic_string&{
|
||||
return _insert_impl(this->length(), data, len);
|
||||
}
|
||||
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;
|
||||
}
|
||||
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>
|
||||
REXY_CPP20_CONSTEXPR void basic_string<Char,Alloc>::push_back(value_type data)
|
||||
@ -356,57 +456,41 @@ namespace rexy{
|
||||
{
|
||||
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>
|
||||
REXY_CPP20_CONSTEXPR void basic_string<Char,Alloc>::append(const_pointer data, size_type len)
|
||||
noexcept(is_nothrow_allocator_v<Alloc>)
|
||||
{
|
||||
size_type mylen = this->length();
|
||||
size_type mycap = this->capacity();
|
||||
pointer raw = this->get_pointer();
|
||||
constexpr auto basic_string<Char,Alloc>::erase(size_type index, size_type count)noexcept -> basic_string&{
|
||||
const auto len = this->length();
|
||||
const auto rem_count = std::min(count, len - index);
|
||||
const auto end_pos = index + rem_count;
|
||||
const auto relocate_count = len - end_pos + 1; //include terminator
|
||||
|
||||
if(mylen+len <= mycap){
|
||||
rexy::memcpy(raw+mylen, data, sizeof(value_type)*len);
|
||||
this->set_length(mylen+len);
|
||||
raw[mylen+len] = 0;
|
||||
}else{
|
||||
auto newsize = max(mylen+len, mycap*2);
|
||||
basic_string tmp(newsize);
|
||||
tmp.append(raw, mylen);
|
||||
tmp.append(data, len);
|
||||
*this = std::move(tmp);
|
||||
{
|
||||
auto* src = this->get_pointer() + end_pos;
|
||||
auto* dst = this->get_pointer() + index;
|
||||
for(size_type i = 0;i < relocate_count;++i){
|
||||
*dst++ = *src++;
|
||||
}
|
||||
}
|
||||
this->set_length(len - rem_count);
|
||||
return *this;
|
||||
}
|
||||
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
|
||||
REXY_CPP20_CONSTEXPR void basic_string<Char,Alloc>::append(const_pointer data)
|
||||
noexcept(is_nothrow_allocator_v<Alloc>)
|
||||
{
|
||||
if(data)
|
||||
append(data, rexy::strlen(data));
|
||||
constexpr auto basic_string<Char,Alloc>::erase(const_iterator pos)noexcept -> iterator{
|
||||
const auto pos_index = pos - this->begin();
|
||||
erase(pos - this->begin(), 1);
|
||||
return this->begin() + pos_index;
|
||||
}
|
||||
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
|
||||
template<class InputIt>
|
||||
REXY_CPP20_CONSTEXPR void basic_string<Char,Alloc>::append(InputIt start, InputIt fin)
|
||||
noexcept(is_nothrow_allocator_v<Alloc>)
|
||||
{
|
||||
size_type append_len = fin - start;
|
||||
|
||||
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;
|
||||
constexpr auto basic_string<Char,Alloc>::erase(const_iterator first, const_iterator last)noexcept -> iterator{
|
||||
const auto distance = last - first;
|
||||
const auto start_pos = first - this->begin();
|
||||
erase(start_pos, distance);
|
||||
return this->begin() + start_pos;
|
||||
}
|
||||
|
||||
|
||||
@ -428,29 +512,23 @@ namespace rexy{
|
||||
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
|
||||
REXY_CPP20_CONSTEXPR auto basic_string<Char,Alloc>::release(void)noexcept(is_nothrow_allocator_v<Alloc>) -> pointer{
|
||||
if(this->islong()){
|
||||
pointer raw = this->get_long_ptr();
|
||||
this->set_islong_flag(false);
|
||||
pointer raw = this->get_pointer();
|
||||
this->set_short_ptr();
|
||||
this->set_short_length(0);
|
||||
this->set_length(0);
|
||||
return raw;
|
||||
}
|
||||
size_type len = this->get_short_length();
|
||||
pointer raw = this->get_short_ptr();
|
||||
if constexpr(string_base<Char>::uses_sso()){
|
||||
size_type len = this->length();
|
||||
pointer raw = this->get_pointer();
|
||||
pointer retval = this->allocate(sizeof(value_type)*len+1);
|
||||
rexy::memcpy(retval, raw, sizeof(value_type)*len);
|
||||
retval[len] = 0;
|
||||
raw[0] = 0;
|
||||
this->set_short_length(0);
|
||||
this->set_length(0);
|
||||
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>
|
||||
@ -468,7 +546,29 @@ namespace rexy{
|
||||
}
|
||||
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>
|
||||
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
|
||||
|
||||
#endif
|
||||
|
||||
@ -70,27 +70,38 @@ namespace rexy{
|
||||
//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;}
|
||||
constexpr bool empty(void)const noexcept{return m_length == 0;}
|
||||
//direct access to managed pointer
|
||||
constexpr const_pointer c_str(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
|
||||
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 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_reference front(void)const noexcept{return m_data[0];}
|
||||
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 search(const basic_string_view& s)const;
|
||||
constexpr const_iterator search(basic_string_view s)const;
|
||||
constexpr const_iterator search(const_pointer c)const;
|
||||
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>
|
||||
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_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(const_pointer c, size_type pos = 0)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>
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
#include "compat/to_address.hpp"
|
||||
#include "utility.hpp"
|
||||
#include "string_base.hpp"
|
||||
#include "algorithm.hpp" //two_way_search
|
||||
|
||||
#include "compat/string_base.hpp"
|
||||
|
||||
@ -49,7 +50,7 @@ namespace rexy{
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
template<class Char>
|
||||
@ -59,7 +60,7 @@ namespace rexy{
|
||||
}
|
||||
template<class Char>
|
||||
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());
|
||||
}
|
||||
template<class Char>
|
||||
@ -69,6 +70,70 @@ namespace rexy{
|
||||
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>
|
||||
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);
|
||||
|
||||
@ -106,7 +106,7 @@ namespace rexy{
|
||||
return fwrite(c, 1, bytes, m_fp);
|
||||
}
|
||||
size_t filerd::write(const rexy::string_base<char>& c)noexcept{
|
||||
return write(c.get(), c.length());
|
||||
return write(c.data(), c.length());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -19,18 +19,16 @@ void check_empty_construction(){
|
||||
if(str1.length() != 0)
|
||||
error("length() should return 0 on default init\n");
|
||||
if(test_str::uses_sso()){
|
||||
if(str1.get()[0] != 0)
|
||||
error("get() should return an empty, zero length string\n");
|
||||
if(str1.data()[0] != 0)
|
||||
error("data() should return an empty, zero length string\n");
|
||||
}else{
|
||||
if(str1.get() != nullptr)
|
||||
error("get() should return a null string\n");
|
||||
if(str1.data() != nullptr)
|
||||
error("data() should return a null string\n");
|
||||
}
|
||||
if(str1.valid())
|
||||
error("valid() should return false on empty string\n");
|
||||
if(str1.get() != str1.c_str())
|
||||
error("c_str() should be a synonymn of get()\n");
|
||||
if(char* c = str1;c != str1.get())
|
||||
error("conversion to pointer type should be synonymous with get()\n");
|
||||
if(str1.data() != str1.c_str())
|
||||
error("c_str() should be a synonymn of data()\n");
|
||||
|
||||
test_str str2(str1);
|
||||
if(str2.length() != str1.length())
|
||||
@ -38,11 +36,11 @@ void check_empty_construction(){
|
||||
if(str2.capacity() != str1.capacity())
|
||||
error("copy construction on empty string should give equivalent capacity()\n");
|
||||
if(test_str::uses_sso()){
|
||||
if(str2.get()[0] != str1.get()[0])
|
||||
error("copy construction on empty string should give equivalent get()\n");
|
||||
if(str2.data()[0] != str1.data()[0])
|
||||
error("copy construction on empty string should give equivalent data()\n");
|
||||
}else{
|
||||
if(str2.get() != str1.get())
|
||||
error("copy construction on empty string should give equivalent get()\n");
|
||||
if(str2.data() != str1.data())
|
||||
error("copy construction on empty string should give equivalent data()\n");
|
||||
}
|
||||
|
||||
test_str str3(std::move(str2));
|
||||
@ -51,11 +49,11 @@ void check_empty_construction(){
|
||||
if(str3.capacity() != str1.capacity())
|
||||
error("move construction on empty string should give equivalent capacity()\n");
|
||||
if(test_str::uses_sso()){
|
||||
if(str3.get()[0] != str1.get()[0])
|
||||
error("move construction on empty string should give equivalent get()\n");
|
||||
if(str3.data()[0] != str1.data()[0])
|
||||
error("move construction on empty string should give equivalent data()\n");
|
||||
}else{
|
||||
if(str3.get() != str1.get())
|
||||
error("move construction on empty string should give equivalent get()\n");
|
||||
if(str3.data() != str1.data())
|
||||
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");
|
||||
if(str1.capacity() != cap)
|
||||
error("short constructed string 'a' should be capacity() == short_string_size()\n");
|
||||
if(strcmp(str1.get(), "a"))
|
||||
error("short constructed string 'a' should be !strcmp(get(), \"a\")\n");
|
||||
if(strcmp(str1.data(), "a"))
|
||||
error("short constructed string 'a' should be !strcmp(data(), \"a\")\n");
|
||||
|
||||
test_str str2(str1);
|
||||
if(str2.length() != str1.length())
|
||||
error("short copy constructed string should have equal length()\n");
|
||||
if(str2.capacity() != str1.capacity())
|
||||
error("short copy constructed string should have equal capacity()\n");
|
||||
if(strcmp(str2.get(), str1.get()))
|
||||
error("short copy constructed string should have equivalent get()\n");
|
||||
if(strcmp(str2.data(), str1.data()))
|
||||
error("short copy constructed string should have equivalent data()\n");
|
||||
|
||||
test_str str3(std::move(str2));
|
||||
if(str3.length() != str1.length())
|
||||
error("short move constructed string should have equal length()\n");
|
||||
if(str3.capacity() != str1.capacity())
|
||||
error("short move constructed string should have equal capacity()\n");
|
||||
if(strcmp(str3.get(), str1.get()))
|
||||
error("short move constructed string should have equivalent get()\n");
|
||||
if(strcmp(str3.data(), str1.data()))
|
||||
error("short move constructed string should have equivalent data()\n");
|
||||
}
|
||||
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.";
|
||||
@ -96,24 +94,24 @@ void check_long_construction(){
|
||||
error("long constructed string should be length() == strlen(data)\n");
|
||||
if(str1.capacity() < len)
|
||||
error("long constructed string should be capacity() >= strlen(data)\n");
|
||||
if(strcmp(str1.get(), data))
|
||||
error("long constructed string should be !strcmp(get(), data)\n");
|
||||
if(strcmp(str1.data(), data))
|
||||
error("long constructed string should be !strcmp(data(), data)\n");
|
||||
|
||||
test_str str2(str1);
|
||||
if(str2.length() != str1.length())
|
||||
error("long copy constructed string should have equal length()\n");
|
||||
if(str2.capacity() != str1.capacity())
|
||||
error("long copy constructed string should have equal capacity()\n");
|
||||
if(strcmp(str2.get(), str1.get()))
|
||||
error("long copy constructed string should have equivalent get()\n");
|
||||
if(strcmp(str2.data(), str1.data()))
|
||||
error("long copy constructed string should have equivalent data()\n");
|
||||
|
||||
test_str str3(std::move(str2));
|
||||
if(str3.length() != str1.length())
|
||||
error("long move constructed string should have equal length()\n");
|
||||
if(str3.capacity() != str1.capacity())
|
||||
error("long move constructed string should have equal capacity()\n");
|
||||
if(strcmp(str3.get(), str1.get()))
|
||||
error("long move constructed string should have equivalent get()\n");
|
||||
if(strcmp(str3.data(), str1.data()))
|
||||
error("long move constructed string should have equivalent data()\n");
|
||||
}
|
||||
void check_short_assignment(){
|
||||
if(!test_str::uses_sso())
|
||||
@ -128,8 +126,8 @@ void check_short_assignment(){
|
||||
error("short assigned string 'a' should be length() == 1\n");
|
||||
if(str1.capacity() != cap)
|
||||
error("short assigned string 'a' should be capacity() == short_string_size()\n");
|
||||
if(strcmp(str1.get(), "a"))
|
||||
error("short assigned string 'a' should be !strcmp(get(), \"a\")\n");
|
||||
if(strcmp(str1.data(), "a"))
|
||||
error("short assigned string 'a' should be !strcmp(data(), \"a\")\n");
|
||||
|
||||
test_str str2("ba");
|
||||
str2 = str1;
|
||||
@ -137,8 +135,8 @@ void check_short_assignment(){
|
||||
error("short copy assigned string should have equal length()\n");
|
||||
if(str2.capacity() != str1.capacity())
|
||||
error("short copy assigned string should have equal capacity()\n");
|
||||
if(strcmp(str2.get(), str1.get()))
|
||||
error("short copy assigned string should have equivalent get()\n");
|
||||
if(strcmp(str2.data(), str1.data()))
|
||||
error("short copy assigned string should have equivalent data()\n");
|
||||
|
||||
test_str str3("cb");
|
||||
str3 = std::move(str2);
|
||||
@ -146,8 +144,8 @@ void check_short_assignment(){
|
||||
error("short move assigned string should have equal length()\n");
|
||||
if(str3.capacity() != str1.capacity())
|
||||
error("short move assigned string should have equal capacity()\n");
|
||||
if(strcmp(str3.get(), str1.get()))
|
||||
error("short move assigned string should have equivalent get()\n");
|
||||
if(strcmp(str3.data(), str1.data()))
|
||||
error("short move assigned string should have equivalent data()\n");
|
||||
|
||||
test_str str4(longstartdata);
|
||||
str4 = str1;
|
||||
@ -155,8 +153,8 @@ void check_short_assignment(){
|
||||
error("long->short copy assigned string should have equal length()\n");
|
||||
if(str4.capacity() < str1.capacity())
|
||||
error("long->short copy assigned string should have equal or greater capacity()\n");
|
||||
if(strcmp(str4.get(), str1.get()))
|
||||
error("long->short copy assigned string should have equivalent get()\n");
|
||||
if(strcmp(str4.data(), str1.data()))
|
||||
error("long->short copy assigned string should have equivalent data()\n");
|
||||
|
||||
test_str str5(longstartdata);
|
||||
str5 = std::move(str4);
|
||||
@ -164,8 +162,8 @@ void check_short_assignment(){
|
||||
error("long->short move assigned string should have equal length()\n");
|
||||
if(str5.capacity() < str1.capacity())
|
||||
error("long->short move assigned string should have equal or greater capacity()\n");
|
||||
if(strcmp(str5.get(), str1.get()))
|
||||
error("long->short move assigned string should have equivalent get()\n");
|
||||
if(strcmp(str5.data(), str1.data()))
|
||||
error("long->short move assigned string should have equivalent data()\n");
|
||||
}
|
||||
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";
|
||||
@ -178,8 +176,8 @@ void check_long_assignment(){
|
||||
error("long assigned string should be length() == strlen(data)\n");
|
||||
if(str1.capacity() < len)
|
||||
error("long assigned string should be capacity() >= strlen(data)\n");
|
||||
if(strcmp(str1.get(), data))
|
||||
error("long assigned string should be !strcmp(get(), data)\n");
|
||||
if(strcmp(str1.data(), data))
|
||||
error("long assigned string should be !strcmp(data(), data)\n");
|
||||
|
||||
test_str str2(startdata1);
|
||||
str2 = str1;
|
||||
@ -187,8 +185,8 @@ void check_long_assignment(){
|
||||
error("long copy assigned string should have equal length()\n");
|
||||
if(str2.capacity() != str1.capacity())
|
||||
error("long copy assigned string should have equal capacity()\n");
|
||||
if(strcmp(str2.get(), str1.get()))
|
||||
error("long copy assigned string should have equivalent get()\n");
|
||||
if(strcmp(str2.data(), str1.data()))
|
||||
error("long copy assigned string should have equivalent data()\n");
|
||||
|
||||
test_str str3(startdata1);
|
||||
str3 = std::move(str2);
|
||||
@ -196,8 +194,8 @@ void check_long_assignment(){
|
||||
error("long move assigned string should have equal length()\n");
|
||||
if(str3.capacity() != str1.capacity())
|
||||
error("long move assigned string should have equal capacity()\n");
|
||||
if(strcmp(str3.get(), str1.get()))
|
||||
error("long move assigned string should have equivalent get()\n");
|
||||
if(strcmp(str3.data(), str1.data()))
|
||||
error("long move assigned string should have equivalent data()\n");
|
||||
|
||||
test_str str4(startdata2);
|
||||
str4 = str1;
|
||||
@ -205,8 +203,8 @@ void check_long_assignment(){
|
||||
error("short->long copy assigned string should have equal length()\n");
|
||||
if(str4.capacity() != str1.capacity())
|
||||
error("short->long copy assigned string should have equal capacity()\n");
|
||||
if(strcmp(str4.get(), str1.get()))
|
||||
error("short->long copy assigned string should have equivalent get()\n");
|
||||
if(strcmp(str4.data(), str1.data()))
|
||||
error("short->long copy assigned string should have equivalent data()\n");
|
||||
|
||||
test_str str5(startdata2);
|
||||
str5 = std::move(str4);
|
||||
@ -214,8 +212,8 @@ void check_long_assignment(){
|
||||
error("short->long move assigned string should have equal length()\n");
|
||||
if(str5.capacity() != str1.capacity())
|
||||
error("short->long move assigned string should have equal capacity()\n");
|
||||
if(strcmp(str5.get(), str1.get()))
|
||||
error("short->long move assigned string should have equivalent get()\n");
|
||||
if(strcmp(str5.data(), str1.data()))
|
||||
error("short->long move assigned string should have equivalent data()\n");
|
||||
}
|
||||
void check_short_append(){
|
||||
test_str str1;
|
||||
@ -224,10 +222,10 @@ void check_short_append(){
|
||||
str1.append("a");
|
||||
str1.append("b");
|
||||
str1.append(str2);
|
||||
if(strcmp(str1.get(), "abbc"))
|
||||
if(strcmp(str1.data(), "abbc"))
|
||||
error("short append should have resulted in abbc\n");
|
||||
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");
|
||||
}
|
||||
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";
|
||||
test_str str1(startdata1);
|
||||
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");
|
||||
}
|
||||
void check_substring(){
|
||||
rexy::string test = "this is a test string";
|
||||
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");
|
||||
}
|
||||
void check_string_search(){
|
||||
rexy::string test1 = "this is a test string";
|
||||
rexy::string test2 = "string";
|
||||
auto res = test1.search(test2);
|
||||
if(test1 + 15 != res){
|
||||
error("string search operation did not result in a correct result");
|
||||
auto res = test1.search(test2.create_view());
|
||||
if(test1.data() + 15 != res){
|
||||
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_substring();
|
||||
check_string_search();
|
||||
check_string_insert();
|
||||
check_string_erase();
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user