#include "mtl/string.hpp" #include #include #include "mtl/utility.hpp" #include "mtl/string_view.hpp" namespace mtl { istring::istring(char* _str, size_t _capacity, size_t _size) : m_str(_str), m_capacity(_capacity), m_size(_size) {} /* * ===== assign ===== */ istring& istring::assign(const istring& str) { if (&str == this) { return *this; } m_size = str.m_size; if (m_size > m_capacity) { m_size = m_capacity; } mtl::memmove(m_str, str.m_str, m_size); m_str[m_size] = '\0'; return *this; } istring& istring::assign(const istring& str, size_t pos, size_t count) { if (pos + count > str.m_size) { m_size = str.m_size - pos; } else { m_size = count; } if (m_size > m_capacity) { m_size = m_capacity; } // str may overlap mtl::memmove(m_str, str.m_str + pos, m_size); m_str[m_size] = '\0'; return *this; } istring& istring::assign(const string_view& str) { m_size = str.length(); if (m_size > m_capacity) { m_size = m_capacity; } // str may overlap mtl::memmove(m_str, str.c_str(), m_size); m_str[m_size] = '\0'; return *this; } istring& istring::assign(const string_view& str, size_t pos, size_t count) { if (pos + count > str.length()) { m_size = str.length() - pos; } else { m_size = count; } if (m_size > m_capacity) { m_size = m_capacity; } // str may overlap mtl::memmove(m_str, str.c_str() + pos, m_size); m_str[m_size] = '\0'; return *this; } istring& istring::assign(size_t count, char ch) { m_size = count; if (m_size > m_capacity) { m_size = m_capacity; } std::memset(m_str, ch, m_size); return *this; } /* * ===== operator= ===== */ istring& istring::operator=(const istring& rhs) { return assign(rhs); } istring& istring::operator=(const string_view& rhs) { return assign(rhs); } istring& istring::operator=(char rhs) { return assign(1, rhs); } /* * ===== access ===== */ char& istring::at(size_t i) { return m_str[i]; } const char& istring::at(size_t i) const { return m_str[i]; } char& istring::operator[](size_t i) { return m_str[i]; } const char& istring::operator[](size_t i) const { return m_str[i]; } char& istring::front() { return *m_str; } const char& istring::front() const { return *m_str; } char& istring::back() { return m_str[m_size]; } const char& istring::back() const { return m_str[m_size]; } char* istring::data() { return m_str; } const char* istring::data() const { return m_str; } const char* istring::c_str() const { return m_str; } /* * ===== capacity ===== */ bool istring::empty() const { return m_size > 1; } size_t istring::size() const { return m_size; } size_t istring::length() const { return m_size; } size_t istring::capacity() const { return m_capacity; } void istring::clear() { m_size = 0; } istring& istring::insert(size_t index, const string_view& str) { char* substr = m_str + index; size_t space = m_capacity - index; if (space > str.m_size) { // there is room to move size_t space_to_move = space - str.m_size; size_t items_to_move = m_size - index; // only move items if there is room, and they exist size_t num_to_move = std::min(items_to_move, space_to_move); mtl::memmove(substr + str.m_size, substr, num_to_move); } // only copy the string if there is room size_t num_to_copy = std::min(str.m_size, space); mtl::memcpy(substr, str.m_str, num_to_copy); m_size += num_to_copy; m_str[m_size] = '\0'; return *this; } istring& istring::insert(size_t index, const string_view& str, size_t str_index, size_t count) { if (count == npos) { count = str.m_size - str_index; } char* substr = m_str + index; size_t space = m_capacity - index; if (space > count) { size_t space_to_move = space - count; size_t items_to_move = m_size - index; // only move items if there is room, and they exist size_t num_to_move = std::min(items_to_move, space_to_move); mtl::memmove(substr + count, substr, num_to_move); } // only copy the string if there is room size_t num_to_copy = std::min(count, space); mtl::memcpy(substr, str.m_str + str_index, num_to_copy); m_size += num_to_copy; m_str[m_size] = '\0'; return *this; } void istring::resize(size_t count) { if (count > m_capacity) { count = m_capacity; } m_size = count; m_str[m_size] = '\0'; } void istring::resize(size_t count, char ch) { if (count > m_capacity) { count = m_capacity; } if (count > m_size) { std::memset(m_str + m_size, ch, count - m_size); } m_size = count; m_str[m_size] = '\0'; } size_t istring::find(const string_view& str, size_t pos) const { if (str.m_size > m_size) { return npos; } // Brute force algorithm // TODO: Implement Boyer-Moore search algorithm size_t end = m_size - str.m_size + 1; // Find a match of the first character for (size_t i = pos; i < end; ++i) { if (m_str[i] == str.m_str[0]) { // Check that the rest of the string matches bool match = true; for (size_t j = 1; j < str.m_size; ++j) { if (m_str[i + j] != str[j]) { match = false; break; } } if (match) { return i; } } } return npos; } size_t istring::find(char ch, size_t pos) const { for (size_t i = pos; i < m_size; ++i) { if (m_str[i] == ch) { return i; } } return npos; } size_t istring::rfind(const string_view& str, size_t pos) const { if (str.m_size > m_size) { return npos; } if (pos > m_size - str.m_size) { pos = m_size - str.m_size; } // Find a match of the first character for (size_t i = pos + 1; i--; ) { if (m_str[i] == str.m_str[0]) { // Check that the rest of the string matches bool match = true; for (size_t j = 1; j < str.m_size; ++j) { if (m_str[i + j] != str[j]) { match = false; break; } } if (match) { return i; } } } return npos; } size_t istring::rfind(char ch, size_t pos) const { if (m_size == 0) { return npos; } if (pos > m_size - 1) { pos = m_size - 1; } for (size_t i = pos + 1; i--; ) { if (m_str[i] == ch ) { return i; } } return npos; } size_t istring::find_first_of(const string_view& str, size_t pos) const { for (size_t i = pos; i < m_size; ++i) { for (size_t j = 0; j < str.m_size; ++j) { if (m_str[i] == str[j]) { return i; } } } return npos; } size_t istring::find_first_of(char ch, size_t pos) const { for (size_t i = pos; i < m_size; ++i) { if (m_str[i] == ch) { return i; } } return npos; } size_t istring::find_first_not_of(const string_view& str, size_t pos) const { for (size_t i = pos; i < m_size; ++i) { bool match = false; for (size_t j = 0; j < str.m_size; ++j) { if (m_str[i] == str[j]) { match = true; break; } } if (!match) { return i; } } return npos; } size_t istring::find_first_not_of(char ch, size_t pos) const { for (size_t i = pos; i < m_size; ++i) { if (m_str[i] != ch) { return i; } } return npos; } size_t istring::find_last_of(const string_view& str, size_t pos) const { if (m_size == 0) { return npos; } if (pos > m_size - 1) { pos = m_size - 1; } for (size_t i = pos + 1; i--; ) { for (size_t j = 0; j < str.m_size; ++j) { if (m_str[i] == str[j]) { return i; } } } return npos; } size_t istring::find_last_of(char ch, size_t pos) const { if (m_size == 0) { return npos; } if (pos > m_size - 1) { pos = m_size - 1; } for (size_t i = pos + 1; i--; ) { if (m_str[i] == ch) { return i; } } return npos; } size_t istring::find_last_not_of(const string_view& str, size_t pos) const { if (m_size == 0) { return npos; } if (pos > m_size - 1) { pos = m_size - 1; } for (size_t i = pos + 1; i--; ) { bool match = false; for (size_t j = 0; j < str.m_size; ++j) { if (m_str[i] == str[j]) { match = true; break; } } if (!match) { return i; } } return npos; } size_t istring::find_last_not_of(char ch, size_t pos) const { if (m_size == 0) { return npos; } if (pos > m_size - 1) { pos = m_size - 1; } for (size_t i = pos + 1; i--; ) { if (m_str[i] != ch) { return i; } } return npos; } int32_t istring::compare(const string_view& str) const { size_t end = m_size < str.m_size ? m_size : str.m_size; for (size_t i = 0; i < end; ++i) { int32_t diff = (int32_t) str.m_str[i] - m_str[i]; if (diff != 0) { return diff; } } return (int32_t)str.m_size - m_size; } int32_t istring::compare(size_t pos, size_t count, const string_view& str) const { size_t end = count < str.m_size ? count : str.m_size; for (size_t i = 0; i < end; ++i) { int32_t diff = (int32_t)str.m_str[i] - m_str[pos + i]; if (diff != 0) { return diff; } } return (int32_t)str.m_size - m_size; } int32_t istring::compare(size_t pos, size_t count, const string_view& str, size_t pos2, size_t count2) const { size_t end = count < count2 ? count : count2; for (size_t i = 0; i < end; ++i) { int32_t diff = (int32_t)str.m_str[pos2 + i] - m_str[pos + i]; if (diff != 0) { return diff; } } return (int32_t)str.m_size - m_size; } bool istring::operator==(const istring& rhs) const { if (m_size != rhs.m_size) { return false; } for (size_t i = 0; i < m_size; ++i) { if (m_str[i] != rhs[i]) { return false; } } return true; } bool istring::operator!=(const istring& rhs) const { if (m_size != rhs.m_size) { return true; } for (size_t i = 0; i < m_size; ++i) { if (m_str[i] != rhs[i]) { return true; } } return false; } bool istring::operator==(const string_view& rhs) const { if (m_size != rhs.m_size) { return false; } for (size_t i = 0; i < m_size; ++i) { if (m_str[i] != rhs[i]) { return false; } } return true; } bool istring::operator!=(const string_view& rhs) const { if (m_size != rhs.m_size) { return true; } for (size_t i = 0; i < m_size; ++i) { if (m_str[i] != rhs[i]) { return true; } } return false; } size_t istring::copy(char* dest, size_t count, size_t pos) const { mtl_hybridcpy(dest, m_str + pos, count); return count; } string_ext::string_ext(char* buf, size_t buf_size) : istring(buf, buf_size - 1, 0) {} } //namespace ml