#ifndef __ZSL_String__
#define __ZSL_String__
#include <iostream>
#include <algorithm>
using namespace std;
template<typename CharT> class ZSL_String;
using String = ZSL_String<char>;
template<typename CharT>
class ZSL_String
{
public:
using value_type = CharT;
using pointer = value_type*;
using const_pointer = const value_type*;
using iterator = value_type*;
using const_iterator = const value_type*;
using reference = value_type&;
using const_reference = const value_type&;
using difference_type = ptrdiff_t;
using size_type = size_t;
private:
iterator start;
iterator finish;
iterator end_of_storage;
static size_type nops;
public://text
void print() const
{
iterator it = start;
while(it != finish)
cout << *it;
}
private:
iterator allocator(size_type n) {
iterator it = new value_type[n];
return it;
}
void fill(iterator first1, iterator last1, iterator first2, iterator last2){
while(first1 != last1 && first2 != last2){
*first1 = *first2;
++first1, ++first2;
}
}
void fill_c(size_type n, const CharT& c){
iterator it = start;
while(it != finish)
*it = c;
}
void destroy(pointer p) { p->~CharT(); }
void construct(pointer p, value_type value) { new(p)CharT(value); }
void deallocate() { delete []start; }
void insert_aux(size_type pos, size_type count, iterator it);
int compare_aux(iterator first1, iterator last1, iterator first2, iterator last2);
void assign_aux(iterator first, iterator last);
public:
ZSL_String() : start(0), finish(0), end_of_storage(0) {}
ZSL_String(const CharT* s){
start = allocator(strlen(s));
finish = start + strlen(s);
end_of_storage = finish;
for(int i = 0; i < strlen(s); ++i)
start[i] = s[i];
}
ZSL_String(size_type count, const CharT& c){
start = allocator(count);
finish = start + count;
end_of_storage = finish;
fill_c(count, c);
}
ZSL_String(iterator first, iterator last){
start = allocator(last - first);
finish = start + (last - first);
end_of_storage = finish;
fill(start, finish, first, last);
}
ZSL_String(initializer_list<CharT> ilist){
start = allocator(ilist.size());
finish = start + ilist.size();
end_of_storage = finish;
fill(start, finish, ilist.begin(), ilist.end());
}
ZSL_String(ZSL_String<CharT>&& other) noexcept
: start(other.start), finish(other.finish), end_of_storage(other.end_of_storage)
{
other.start = other.finish = other.end_of_storage = nullptr;
}
ZSL_String(const ZSL_String<CharT>& str)
{
start = allocator(str.size());
finish = start + str.size();
end_of_storage = finish;
for(int i = 0; i < str.size(); ++i)
start[i] = str[i];
}
ZSL_String<CharT>& operator= (const ZSL_String<CharT>& str)
{
if(this != &str)
{
deallocate();
start = allocator(str.size());
finish = start + str.size();
end_of_storage = finish;
for(int i = 0; i < str.size(); ++i)
start[i] = str[i];
}
return *this;
}
ZSL_String<CharT>& operator= (const CharT* s)
{
if(start != s)
{
deallocate();
start = allocator(strlen(s));
finish = start + strlen(s);
end_of_storage = finish;
for(int i = 0; i < strlen(s); ++i)
start[i] = s[i];
}
return *this;
}
ZSL_String<CharT>& operator= (ZSL_String<CharT>&& str) noexcept
{
if(this != &str)
{
deallocate();
start = str.start;
finish = str.finish;
end_of_storage = str.end_of_storage;
str.start = str.finish = str.end_of_storage = nullptr;
}
return *this;
}
~ZSL_String(){ deallocate(); }
ZSL_String<CharT>& assign(size_type count, CharT c)
{
if(count < capacity())
{
clear(start, finish);
while(count--) construct(finish++, c);
}
else
{
deallocate();
start = allocator(count);
finish = start;
while(count--) coustruct(finish++, c);
end_of_storage = finish;
}
return *this;
}
ZSL_String<CharT>& assign(const ZSL_String<CharT>& str)
{
assign_aux(str.begin(), str.end());
return *this;
}
ZSL_String<CharT>& assign(const ZSL_String<CharT>& str, size_type pos, size_type count)
{
if(pos + count > str.size())
{
deallocate();
throw "out of range";
}
assign_aux(str.begin() + pos, str.begin() + pos + count);
return *this;
}
ZSL_String<CharT>& assign(const CharT *s, size_type count)
{
if(count > strlen(s))
{
deallocate();
throw "out of range";
}
assign_aux(s, s + count);
return *this;
}
ZSL_String<CharT>& assign(const CharT *s)
{
assign_aux(s, s + strlen(s));
return *this;
}
ZSL_String<CharT>& assign(iterator first, iterator last)
{
assign_aux(first, last);
return *this;
}
ZSL_String<CharT>& assign(initializer_list<CharT> ilist)
{
assign_aux(ilist.begin(), ilist.end());
return *this;
}
const_reference operator[] (size_type pos) const { return *(start + pos); }
reference operator[] (size_type pos) { return *(start + pos); }
const_reference at(size_type pos) const
{
if(pos > size())
{
deallocate();
throw "out_of_range";
}
return *(start + pos);
}
reference at(size_type pos){ return const_cast<CharT&>(static_cast<const ZSL_String&>(*this).at(pos)); }
reference front() { return *start; }
const_reference front() const { return *start; }
const_reference back() const
{
if(size() == 0)
return *finish;
return *(finish - 1);
}
reference back() { return const_cast<CharT&>(static_cast<const ZSL_String&>(*this).back()); }
const_iterator cbegin() const { return start; }
iterator begin() { return start; }
const_iterator cend() const { return finish; }
iterator end(){ return finish; }
pointer data() { return start; }
const_pointer data() const { return start; }
const_pointer c_str() const { return start; }
bool empty() const { return finish == start; }
size_type size() const { return finish - start; }
size_type length() const { return finish - start; }
size_type capacity() const { return end_of_storage - start; }
size_type max_size() const { return size_type(-1)/sizeof(CharT); }
void clear()
{
while(finish != start)
{
--finish;
destroy(finish);
}
}
ZSL_String<CharT>& insert(size_type index, size_type count, const CharT& c)
{
iterator it = &c;
insert_aux(index, count, it);
return *this;
}
ZSL_String<CharT>& insert(size_type index, const CharT* str)
{
insert_aux(index, strlen(str), str);
return *this;
}
ZSL_String<CharT>& insert(size_type index, const ZSL_String<CharT>& str)
{
insert_aux(index, str.size(), str.start);
return *this;
}
ZSL_String<CharT>& erase(size_type pos, size_type count)
{
if(pos + count > size())
{
deallocate();
throw "out of range";
}
else
{
for(int i = pos; i < pos + count; ++i)
*(start + i) = *(start + i + count);
for(int i = pos + count; i < size(); ++i)
{
--finish;
destroy(finish);
}
while(--count)
{
--end_of_storage;
iterator tmp = end_of_storage;
--tmp;
end_of_storage = tmp;
}
}
return *this;
}
iterator erase(iterator pos)
{
for(int i = pos; i < size() - 1; ++i)
start[i] = start[i + 1];
--finish;
destroy(finish);
return pos;
}
iterator erase(const_iterator pos) { return static_cast<ZSL_String<CharT>&>(*this).erase(pos); }
iterator erase(iterator first, iterator last)
{
if((last - first) > size())
{
deallocate();
throw "out of range";
}
size_type len = last - first;
while(first != last)
{
*first = *(first + len);
++first;
}
while(len--)
{
--finish;
destroy(finish);
}
return first;
}
iterator erase(const_iterator first, const_iterator last)
{
return static_cast<ZSL_String<CharT>&>(*this).erase(first, last);
}
void push_back(const CharT& c)
{
//////////////////////////////////////////////////////
ZSL_String<CharT> tmp(1, c);
insert_aux(size(), 1, tmp.start);
}
void pop_back()
{
--finish;
destroy(finish);
}
ZSL_String<CharT>& append(size_type count, const CharT& c)
{
insert(size(), count, c);
return *this;
}
ZSL_String<CharT>& append(const ZSL_String<CharT>& str)
{
insert(size(), str.size(), str.start);
return *this;
}
ZSL_String<CharT>& append(const ZSL_String& str, size_type pos, size_type count)
{
if(pos + count > str.size())
{
deallocate();
throw "out of range";
}
insert(size(), count, str.start + pos);
return *this;
}
ZSL_String<CharT>& append(const CharT* str, size_type count)
{
//////////////////////////////////////////////////////
ZSL_String<CharT> tmp(str);
insert(tmp, 0, count);
return *this;
}
ZSL_String<CharT>& append(const CharT* str)
{
append(str, strlen(str));
return *this;
}
ZSL_String<CharT>& operator+= (const ZSL_String<CharT>& str)
{
append(str);
return *this;
}
ZSL_String<CharT>& operator+= (const CharT& c)
{
push_back(c);
return *this;
}
ZSL_String<CharT>& operator+= (const CharT* str)
{
append(str);
return *this;
}
int compare(const ZSL_String<CharT>& str) const
{
return compare_aux(start, finish, str.start, str.finish);
}
int compare(size_type pos, size_type count, const ZSL_String<CharT>& str) const
{
if(count + pos > size())
{
deallocate();
throw "out_of_range";
}
return compare_aux(start + pos, start + pos + count, str.start, str.finish);
}
int compare(size_type pos1, size_type count1, const ZSL_String<CharT>& str, size_type pos2, size_type count2)
{
if((pos1 + count1 > size()) || (pos2 + count2 > str.size()))
{
deallocate();
throw "out_of_range";
}
return compare_aux(start + pos1, start + pos1 + count1, str.start + pos2, str.start + pos2 + count2);
}
int compare(const CharT* str) const
{
//////////
ZSL_String<CharT> tmp(str);
return compare_aux(start, finish, tmp.start, tmp.finish);
}
int compare(size_type pos, size_type count, const CharT* str) const
{
//////////
ZSL_String<CharT> tmp(str);
return compare_aux(start + pos, start + pos + count, tmp.start, tmp.finish);
}
int compare(size_type pos1, size_type count1, const CharT* str, size_type count2) const
{
/////////
ZSL_String<CharT> tmp(str);
return compare_aux(start + pos1, start + pos1 + count1, tmp.start, tmp.start + count2);
}
ZSL_String<CharT>& replace(size_type pos, size_type count, const ZSL_String<CharT>& str)
{
return replace(pos, count, str, 0, str.size());
}
ZSL_String<CharT>& replace(size_type pos1, size_type count1, const ZSL_String<CharT>& str, size_type pos2, size_type count2)
{
size_type len = size();
if((pos1 + count1 > len) || (pos2 + count2) > str.size())
{
deallocate();
throw "out of range";
}
size_type pos = pos1 + count1;
iterator new_start = allocator(len + count2 - count1);
for(int i = 0; i < pos1; ++i)
new_start[i] = start[i];
for(int i = pos1; i < pos1 + count2; ++i)
new_start[i] = str[pos2++];
for(int i = pos1 + count2; i < len + count2 - count1; ++i)
new_start[i] = start[pos++];
deallocate();
start = new_start;
finish = start + len + count2 - count1;
end_of_storage = finish;
return *this;
}
ZSL_String<CharT> substr(size_type pos, size_type count) const
{
if(pos + count > size())
{
deallocate();
throw "out of range";
}
return new ZSL_String<CharT>(start + pos, start + pos + count);
}
size_type copy(CharT* dest, size_type pos, size_type count) const
{
if(pos + count > size())
{
deallocate();
throw "out of range";
}
for(int i = pos; i < pos + count; ++i)
*dest++ = start[i];
return count;
}
void resize(size_type count);
void resize(size_type count, const CharT& c);
void swap(ZSL_String& other)
{
using std::swap;
swap(start, other.start);
swap(finish, other.finish);
}
size_type find(const ZSL_String& str, size_type pos = 0) const
{
if(pos > size())
{
deallocate();
throw "out of range";
}
while((start + pos) != finish)
{
if(compare_aux(start + pos, start + pos + str.size(), str.start, str.finish) == 0)
return pos;
++pos;
}
return -1;
}
size_type find(const CharT* str, size_type pos, size_type count) const
{
if(pos + count > size())
{
deallocate();
throw "out of range";
}
while((start + pos + count) != finish)
{
if(compare(start + pos, start + pos + count, str) == 0)
return pos;
++pos;
}
return -1;
}
size_type find(const CharT* str, size_type pos = 0) const
{
if(pos > size())
{
deallocate();
throw "out of range";
}
while((start + pos) != finish)
{
if(compare(start + pos, start + pos + strlen(str), str) == 0)
return pos;
++pos;
}
return -1;
}
size_type find(const CharT& c, size_type pos = 0) const
{
if(pos > size())
{
deallocate();
throw "out of range";
}
while(*(start + pos) != c)
++pos;
return pos;
}
};
template<typename CharT>
size_t ZSL_String<CharT>::nops = -1;
template<typename CharT>
void ZSL_String<CharT>::insert_aux(size_type pos, size_type count, iterator it)
{
if(pos + count < capacity())
{
iterator new_finish = start + pos + count;
while(count)
{
--new_finish;
construct(new_finish, *(--finish));
}
while((start + pos) != new_finish)
*(start + pos) = *it++;
finish = start + pos + count;
}
else
{
iterator new_start = allocator(size() + count);
for (int i = 0; i < pos; ++i, ++start)
new_start[i] = *start;
for (int i = pos; i < pos + count; ++i, ++it)
new_start[i] = *it;
for (int i = pos + count; i < size() + count; ++i, ++start)
new_start[i] = *start;
deallocate();
start = new_start;
finish = start + size() + count;
end_of_storage = finish;
}
}
template<typename CharT>
int ZSL_String<CharT>::compare_aux(iterator first1, iterator last1, iterator first2, iterator last2)
{
int comp;
while(first1 != last1 && first2 != last2)
{
if(strcmp(*first1, *first2) == 0)
{
comp = 0;
continue;
}
else
return strcmp(*first1, *first2);
}
if(comp == 0 && first1 != last1)
return 1;
if(comp == 0 && first2 != last2)
return -1;
}
template<typename CharT>
void ZSL_String<CharT>::assign_aux(iterator first, iterator last)
{
size_type s = last - first;
if(s <= capacity())
{
clear(start, finish);
while(s--) construct(finish, *first++);
}
else
{
deallocate();
start = allocator(s);
finish = start;
while(s--) construct(finish, *first++);
end_of_storage = finish;
}
}
template<typename CharT>
void ZSL_String<CharT>::resize(size_type count)
{
if(count <= size())
{
while(finish != (start + count))
{
--finish;
destroy(finish);
}
}
if(count > capacity())
{
iterator new_start = allocator(count);
finish = new_start;
for(int i = 0; i < size(); ++i)
*finish++ = start[i];
deallocate();
start = new_start;
end_of_storage = start + count;
}
}
template<typename CharT>
void ZSL_String<CharT>::resize(size_type count, const CharT& c)
{
if(count <= size())
{
while(finish != (start + count))
{
--finish;
destroy(finish);
}
}
else if(count <= capacity())
{
while(finish != (start + count))
{
*finish = c;
++finish;
}
}
else
{
iterator new_start = allocator(count);
finish = new_start;
for(int i = 0; i < size(); ++i)
*finish++ = start[i];
for(int i = size(); i < count; ++i)
*finish++ = c;
deallocate();
start = new_start;
end_of_storage = finish;
}
}
template<typename CharT>
ZSL_String<CharT> operator+ (ZSL_String<CharT>& str1, ZSL_String<CharT>& str2)
{
str1.append(str2);
return str1;
}
template<typename CharT>
ZSL_String<CharT> operator+ (CharT& c, ZSL_String<CharT>& str)
{
ZSL_String<CharT> tmp(c);
tmp.append(str);
return tmp;
}
template<typename CharT>
ZSL_String<CharT> operator+ (ZSL_String<CharT>& str, CharT& c)
{
str.push_back(c);
return str;
}
template<typename CharT>
ZSL_String<CharT> operator+ (CharT* str1, ZSL_String<CharT>& str2)
{
ZSL_String<CharT> newStr(str1);
newStr.append(str2);
return newStr;
}
template<typename CharT>
ZSL_String<CharT> operator+ (ZSL_String<CharT>& str1, CharT* str2)
{
str1.append(str2);
return str1;
}
template<typename CharT>
bool operator== (const ZSL_String<CharT>& str1, const ZSL_String<CharT>& str2)
{
return str1.compare(str2) == 0;
}
template<typename CharT>
bool operator!= (const ZSL_String<CharT>& str1, const ZSL_String<CharT>& str2)
{
return !(str1 == str2);
}
template<typename CharT>
bool operator< (const ZSL_String<CharT>& str1, const ZSL_String<CharT>& str2)
{
return str1.compare(str2) == -1;
}
template<typename CharT>
bool operator> (const ZSL_String<CharT>& str1, const ZSL_String<CharT>& str2)
{
return str1.compare(str2) == 1;
}
template<typename CharT>
bool operator<= (const ZSL_String<CharT>& str1, const ZSL_String<CharT>& str2)
{
return (str1.compare(str2) == -1) || (str1.compare(str2) == 0);
}
template<typename CharT>
bool operator>= (const ZSL_String<CharT>& str1, const ZSL_String<CharT>& str2)
{
return !(str1 <= str2);
}
#endif //__ZSL_String__