/* * Acess2 C++ Library * - By John Hodge (thePowersGang) * * string (header) * - C++'s String type */ #ifndef _LIBCXX_STRING_ #define _LIBCXX_STRING_ #include "_libcxx_helpers.h" #include #include namespace std { template struct char_traits { }; template <> struct char_traits { typedef char char_type; typedef int int_type; //typedef streamoff off_type; //typedef streampos pos_type; //typedef mbstate_t state_type; static bool eq(const char_type& c, const char_type& d) { return c == d; } static bool lt(const char_type& c, const char_type& d) { return c < d; } static size_t length(const char_type* s) { size_t ret = 0; while(*s++) ret ++; return ret; } static int compare (const char_type* p, const char_type* q, size_t n) { while (n--) { if( !eq(*p,*q) ) return lt(*p,*q) ? -1 : 1; ++p; ++q; } return 0; } }; template <> struct char_traits { typedef wchar_t char_type; typedef int int_type; //typedef streamoff off_type; //typedef streampos pos_type; //typedef mbstate_t state_type; static size_t length(const char_type* s) { size_t ret = 0; while(*s++) ret ++; return ret; } static bool eq(const char_type& c, const char_type& d) { return c == d; } static bool lt(const char_type& c, const char_type& d) { return c < d; } }; extern void _throw_out_of_range(const char *message); template < class charT, class traits=char_traits, class Alloc=allocator > class basic_string { public: typedef traits traits_type; typedef Alloc allocator_type; typedef charT value_type; typedef typename allocator_type::reference reference; typedef typename allocator_type::const_reference const_reference; typedef size_t size_type; typedef charT* iterator; typedef const charT* const_iterator; private: struct dynamic_info { allocator_type m_allocator; int m_ref_count = 1; size_type m_capacity = 0; size_type m_size = 0; typename allocator_type::pointer m_data = 0; dynamic_info(const allocator_type& alloc): m_allocator(alloc) { } dynamic_info(const dynamic_info& other): m_allocator(other.m_allocator), m_ref_count(1), m_capacity(other.m_capacity), m_size(other.m_size) { m_data = m_allocator.allocate(m_capacity); for( size_type i = 0; i < m_size; i ++ ) m_data[i] = other.m_data[i]; } }; allocator_type m_allocator; dynamic_info *m_content; public: basic_string(const allocator_type& alloc = allocator_type()): m_allocator(alloc), m_content(0) { } basic_string(const basic_string& str) throw(): basic_string(allocator_type()) { *this = str; } #if _CXX11_AVAIL basic_string(basic_string&& str): m_allocator(str.m_allocator), m_content(str.m_content) { str.m_content = 0; ::_sys::debug("basic_string(move) %p %s", m_content, c_str()); } #endif basic_string(const basic_string& str, const allocator_type& alloc): basic_string(str, 0, str.length(), alloc) { } basic_string(const basic_string& str, size_type pos, size_type len = npos, const allocator_type& alloc = allocator_type()): basic_string(alloc) { if( pos < str.length() ) { if( len > str.length() - pos ) len = str.length() - pos; reserve(len); for( size_type i = 0; i < len; i ++ ) m_content->m_data[i] = str.m_content->m_data[pos+i]; m_content->m_size = len; } } basic_string(const charT *s, const allocator_type& alloc = allocator_type()): basic_string(s, traits::length(s), alloc) { } basic_string(const charT *s, size_type n, const allocator_type& alloc = allocator_type()): basic_string(alloc) { if( n > 0 ) { reserve(n); for( size_type i = 0; i < n; i ++ ) m_content->m_data[i] = s[i]; m_content->m_data[n] = 0; m_content->m_size = n; } } basic_string(size_type n, charT c, const allocator_type& alloc = allocator_type()): basic_string(alloc) { if( n > 0 ) { reserve(n); for( size_type i = 0; i < n; i ++ ) m_content->m_data[i] = c; m_content->m_data[n] = 0; m_content->m_size = n; } } #if __cplusplus < 199711L basic_string(basic_string&& str) noexcept: basic_string(allocator_type()) { } basic_string(basic_string&& str, const allocator_type& alloc) noexcept: basic_string(alloc) { m_content = str.m_content; str.m_content = 0; } #endif ~basic_string() { release_content(); } basic_string& operator=(const basic_string& str) throw() { return assign(str); } basic_string& operator=(const charT* s) { return assign(s); } basic_string& operator=(charT c) { return assign(c); } // iterators // capacity size_type size() const { return m_content ? m_content->m_size : 0; } size_type length() const { return size(); } size_type max_size() const { return -1; } void resize(size_type size, charT c = 0) { reserve(size); if( m_content->m_size < size ) { for( size_type ofs = m_content->m_size; ofs < size; ofs ++ ) m_content->m_data[ofs] = c; m_content->m_data[size] = 0; } m_content->m_size = size; m_content->m_data[size] = 0; } size_type capacity() const { return m_content ? m_content->m_capacity : 0; } void reserve(size_type size) { own_content(); size = (size+1 + 31) & ~31; if( size > m_content->m_capacity ) { auto new_area = m_allocator.allocate(size); for( size_type i = 0; i < m_content->m_size; i ++ ) new_area[i] = m_content->m_data[i]; m_allocator.deallocate(m_content->m_data, m_content->m_capacity); m_content->m_data = new_area; m_content->m_capacity = size; } } void clear() { own_content(); m_content->m_size = 0; } bool empty() const { return length() == 0; } #if _CXX11_AVAIL void shrink_to_fit(); #endif // Access reference operator[] (size_type pos) { own_content(); return m_content->m_data[pos]; } const_reference operator[] (size_type pos) const { return (m_content ? m_content->m_data[pos] : *(const charT*)0); } reference at(size_type pos) { own_content(); if(pos >= m_content->m_size) _throw_out_of_range("basic_string - at"); return m_content->m_data[pos]; } const_reference at(size_type pos) const { if(!m_content || pos >= m_content.m_size) _throw_out_of_range("basic_string - at"); return m_content->m_data[pos]; } #if _CXX11_AVAIL reference back() { own_content(); return m_content->m_data[m_content->m_size]; } const_reference back() const { return m_content->m_data[m_content->m_size]; } reference front() { own_content(); return m_content->m_data[0]; } const_reference front() const { return m_content->m_data[0]; } #endif // Modifiers basic_string& operator +=(const basic_string& str) { return append(str); } basic_string& operator +=(const charT* s) { return append(s); } basic_string& operator +=(charT c) { push_back(c); return *this; } basic_string& append(const basic_string& str) { return append(str, 0, npos); } basic_string& append(const basic_string& str, size_type subpos, size_type sublen) { if(subpos >= str.size()) _throw_out_of_range("basic_string - assign source"); if( sublen > str.size() - subpos ) sublen = str.size() - subpos; append( str.data() + subpos, sublen ); return *this; } basic_string& append(const charT* s) { return append(s, traits::length(s)); } basic_string& append(const charT* s, size_type n) { reserve(size() + n); for( size_type i = 0; i < n; i ++ ) m_content->m_data[size() + i] = s[i]; m_content->m_data[size()+n] = '\0'; m_content->m_size += n; return *this; } basic_string& append(size_type n, charT c) { reserve(size() + n); for( size_type i = 0; i < n; i ++ ) m_content->m_data[size() + i] = c; m_content->m_data[size()+n] = '\0'; m_content->m_size += n; return *this; } void push_back(charT c) { append(1, c); } basic_string& assign(const basic_string& str) throw() { // Special case, triggers copy-on-write. release_content(); m_content = str.m_content; m_content->m_ref_count ++; return *this; } basic_string& assign(const basic_string& str, size_type subpos, size_type sublen) { if(subpos >= str.size()) _throw_out_of_range("basic_string - assign source"); if( sublen > str.size() - subpos ) sublen = str.size() - subpos; return assign(str.data() + subpos, sublen); } basic_string& assign(const charT* s) { return assign(s, traits::length(s)); } basic_string& assign(const charT* s, size_type n) { release_content(); reserve(n); for( size_type i = 0; i < n; i ++ ) m_content->m_data[i] = s[i]; m_content->m_data[n] = '\0'; m_content->m_size = n; return *this; } basic_string& assign(size_type n, charT c) { release_content(); reserve(n); for( size_type i = 0; i < n; i ++ ) m_content->m_data[i] = c; m_content->m_data[n] = '\0'; m_content->m_size = n; return *this; } basic_string& insert(size_type pos, const basic_string& str); basic_string& insert(size_type pos, const basic_string& str, size_type subpos, size_type sublen); basic_string& insert(size_type pos, const charT& s); basic_string& insert(size_type pos, const charT& s, size_type n); basic_string& insert(size_type pos, size_type n, charT c); iterator insert(const_iterator p, size_type n, charT c); iterator insert(const_iterator p, charT c); template iterator insert(iterator p, InputIterator first, InputIterator last); #if _CXX11_AVAIL basic_string& insert(const_iterator p, initializer_list il); #endif basic_string& erase(size_type pos = 0, size_type len = npos); iterator erase(const_iterator p); iterator erase(const_iterator first, const_iterator last); basic_string& replace(size_type pos, size_type len, const basic_string& str); basic_string& replace(const_iterator i1, const_reference i2, const basic_string& str); basic_string& replace(size_type pos, size_type len, const basic_string& str, size_type subpos, size_type sublen); basic_string& replace(size_type pos, size_type len, const charT *s); basic_string& replace(const_iterator i1, const_reference i2, const charT* s); basic_string& replace(size_type pos, size_type len, const charT *s, size_type n); basic_string& replace(const_iterator i1, const_reference i2, const charT* s, size_type n); basic_string& replace(size_type pos, size_type len, size_type n, charT c); basic_string& replace(const_iterator i1, const_reference i2, size_type n, charT c); template basic_string& replace(const_iterator i1, const_reference i2, InputIterator first, InputIterator last); basic_string& replace(const_iterator i1, const_iterator i2, initializer_list il); void swap(basic_string& str) { auto tmp = m_content; m_content = str.m_content; str.m_content = tmp; } #if _CXX11_AVAIL void pop_back(); #endif // String operations const charT *c_str() const noexcept { // TODO: this is const, but also might need to do processing if(m_content) { _libcxx_assert(m_content->m_data[m_content->m_size] == '\0'); } return (m_content ? m_content->m_data : ""); } const charT *data() const { return (m_content ? m_content->m_data : NULL); } allocator_type get_allocator() const noexcept { return m_allocator; } size_type copy(charT* s, size_type len, size_type pos = 0) const; size_type find(const basic_string& str, size_type pos = 0) const noexcept; size_type find(const charT* s, size_type pos = 0) const; size_type find(const charT* s, size_type pos, size_type n) const; size_type find(charT c, size_type pos = 0) const noexcept; size_type rfind(const basic_string& str, size_type pos = 0) const noexcept; size_type rfind(const charT* s, size_type pos = 0) const; size_type rfind(const charT* s, size_type pos, size_type n) const; size_type rfind(charT c, size_type pos = 0) const noexcept; size_type find_first_of(const basic_string& str, size_type pos = 0) const noexcept; size_type find_first_of(const charT* s, size_type pos = 0) const; size_type find_first_of(const charT* s, size_type pos, size_type n) const; size_type find_first_of(charT c, size_type pos = 0) const noexcept; size_type find_last_of(const basic_string& str, size_type pos = 0) const noexcept; size_type find_last_of(const charT* s, size_type pos = 0) const; size_type find_last_of(const charT* s, size_type pos, size_type n) const; size_type find_last_of(charT c, size_type pos = 0) const noexcept; size_type find_first_not_of(const basic_string& str, size_type pos = 0) const noexcept; size_type find_first_not_of(const charT* s, size_type pos = 0) const; size_type find_first_not_of(const charT* s, size_type pos, size_type n) const; size_type find_first_not_of(charT c, size_type pos = 0) const noexcept; size_type find_last_not_of(const basic_string& str, size_type pos = 0) const noexcept; size_type find_last_not_of(const charT* s, size_type pos = 0) const; size_type find_last_not_of(const charT* s, size_type pos, size_type n) const; size_type find_last_not_of(charT c, size_type pos = 0) const noexcept; basic_string substr(size_type pos = 0, size_type len = npos) const; int compare(const basic_string& str) const noexcept { return compare(0, size(), str.data(), str.size()); } int compare(size_type pos, size_type len, const basic_string& str) const { _libcxx_assert(pos <= size()); _libcxx_assert(len <= size()); _libcxx_assert(pos+len <= size()); return compare(pos, len, str.data(), str.size()); } int compare(size_type pos, size_type len, const basic_string& str, size_type subpos, size_type sublen) const { // TODO: check _libcxx_assert(subpos <= str.size()); _libcxx_assert(sublen <= str.size()); _libcxx_assert(subpos+sublen <= str.size()); return compare(pos, len, str.data()+subpos, sublen); } int compare(const charT* s) const { return compare(0, npos, s, traits::length(s)); } int compare(size_type pos, size_type len, const charT* s) const { return compare(pos, len, s, traits::length(s)); } int compare(size_type pos, size_type len, const charT* s, size_type n) const { if( n <= len ) { int rv = traits::compare(data()+pos, s, n); if( rv == 0 && n < len ) { rv = -1; } return rv; } else { int rv = traits::compare(data()+pos, s, len); if(rv == 0) { rv = 1; } return rv; } } static const size_type npos = -1; private: void own_content() { if(!m_content) { m_content = new dynamic_info(m_allocator); } else if( m_content->m_ref_count > 1 ) { dynamic_info *new_cont = new dynamic_info(*m_content); m_content->m_ref_count --; m_content = new_cont; } else { // already owned } } void release_content() { if( m_content ) { m_content->m_ref_count --; if( m_content->m_ref_count == 0 ) { m_allocator.deallocate(m_content->m_data, m_content->m_capacity); delete m_content; } m_content = NULL; } } }; typedef basic_string string; #define _libcxx_str basic_string template basic_string operator+(const basic_string& lhs, const basic_string& rhs) { basic_string ret; ret.reserve(lhs.size() + rhs.size()); ret += lhs; ret += rhs; return ret; } template basic_string operator+(const basic_string& lhs, const charT* rhs) { basic_string ret; ret.reserve(lhs.size() + traits::length(rhs)); ret += lhs; ret += rhs; return ret; } template basic_string operator+(const charT* lhs, const basic_string& rhs) { basic_string ret; ret.reserve(traits::length(lhs) + rhs.size()); ret += lhs; ret += rhs; return ret; } template basic_string operator+(const basic_string& lhs, const charT rhs) { basic_string ret; ret.reserve(lhs.size() + 1); ret += lhs; ret += rhs; return ret; } template basic_string operator+(const charT lhs, const basic_string& rhs) { basic_string ret; ret.reserve(1 + rhs.size()); ret += lhs; ret += rhs; return ret; } // Three overloads each // name: Actual operator, opp: reversed operator #define _libcxx_string_def_cmp(name, opp) \ template \ bool operator name(const _libcxx_str& lhs, const _libcxx_str& rhs) { return lhs.compare(rhs) name 0; } \ template \ bool operator name(const charT* lhs, const _libcxx_str& rhs) { return rhs.compare(lhs) opp 0; } \ template \ bool operator name(const _libcxx_str& lhs, const charT* rhs) { return lhs.compare(rhs) name 0; } _libcxx_string_def_cmp(<, >) _libcxx_string_def_cmp(<=, >=) _libcxx_string_def_cmp(==, ==) _libcxx_string_def_cmp(>=, <=) _libcxx_string_def_cmp(>, <) }; #endif // vim: ft=cpp