488 lines
9.7 KiB
C++
488 lines
9.7 KiB
C++
#include "mtl/string.hpp"
|
|
|
|
#include <cstddef>
|
|
#include <cstring>
|
|
|
|
#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
|