stuff-from-scratch/src/base/core/data_structures/String.cpp
2024-01-21 16:27:30 +00:00

408 lines
6.9 KiB
C++

#include "String.h"
#include "Char.h"
#include <stdio.h>
#include <stdarg.h>
String::String()
{
m_data.push_back('\0');
}
String::String(size_t size, char c)
{
m_data.resize(size, c);
m_data.push_back('\0');
}
String::String(const Vector<Byte>& data)
{
append(data);
}
String::String(const char* data)
{
append(data);
}
String String::fmt(const char* fmt, ...)
{
String ret;
va_list args;
va_start(args, fmt);
char format_delim = '%';
bool in_format = false;
while(*fmt != '\0')
{
if (*fmt == format_delim)
{
in_format = true;
}
else if(in_format && *fmt == 's')
{
in_format = false;
const auto s = va_arg(args, char*);
ret.append(s);
}
else if(in_format && *fmt == 'd')
{
in_format = false;
const auto i = va_arg(args, int);
ret += to_string(i);
}
else if(in_format && *fmt == 'c')
{
in_format = false;
const auto c = va_arg(args, int);
ret +=c;
}
else
{
ret += *fmt;
}
++fmt;
}
va_end(args);
return ret;
}
void String::append(const char* data)
{
if (data == nullptr)
{
m_data.push_back('\0');
return;
}
auto loc = data;
bool first=true;
while(*loc != '\0')
{
if (!m_data.empty() && first)
{
m_data[m_data.size() - 1] = *loc;
}
else
{
m_data.push_back(*loc);
}
first = false;
loc++;
}
m_data.push_back('\0');
}
void String::eraseIf(erasePredicate func)
{
size_t count{0};
for(size_t idx=0; idx<size(); idx++)
{
if (!func(m_data[idx]))
{
m_data[count] = m_data[idx];
count++;
}
}
m_data[count] = '\0';
}
bool String::is_whitespace() const
{
if (empty())
{
return true;
}
for(size_t idx=0;idx<size();idx++)
{
if (!Char::is_space(m_data[idx]))
{
return false;
}
}
return true;
}
const Vector<char>& String::data() const
{
return m_data;
}
bool String::empty() const
{
return m_data.empty() || m_data[0] == '\0';
}
void String::to_bytes(Vector<Byte>& bytes) const
{
if (m_data.empty())
{
return;
}
for(size_t idx=0; idx<m_data.size() - 1; idx++)
{
bytes.push_back(m_data[idx]);
}
}
size_t String::length(const char* arr)
{
size_t len{0};
while(*arr != '\0')
{
arr++;
len++;
}
return len;
}
void String::append(const Vector<Byte>& data)
{
if (data.empty())
{
m_data.push_back('\0');
return;
}
if (m_data.size() == 1 && m_data[0] == '\0')
{
m_data.clear();
}
for(const auto c : data)
{
if(c == '\0')
{
break;
}
else
{
m_data.push_back(static_cast<char>(c));
}
}
m_data.push_back('\0');
}
Pair<String, String> String::rsplit(char c) const
{
if (const auto index = rindex(c); index.valid())
{
String left;
slice(0, index.value(), left);
String right;
slice(index.value() + 1, size(), right);
return {left, right};
}
return {*this, {}};
}
bool String::slice(size_t idx, String& out) const
{
if (idx >= m_data.size())
{
return false;
}
auto ok = m_data.slice(idx, out.m_data);
if (!ok)
{
return ok;
}
out.m_data.push_back('\0');
return true;
}
bool String::slice(size_t start, size_t end, String& out) const
{
if (end >= m_data.size())
{
return false;
}
auto ok = m_data.slice(start, end, out.m_data);
if (!ok)
{
return ok;
}
out.m_data.push_back('\0');
return true;
}
Index String::rindex(char c) const
{
if (m_data.size() <= 2)
{
return {};
}
for(size_t idx=m_data.size()-2; idx >= 0; idx--)
{
if (m_data[idx] == c)
{
return Index(idx);
}
}
return {};
}
const char* String::raw() const
{
return m_data.data();
}
size_t String::size() const
{
return m_data.size() - 1;
}
void String::reverse()
{
if (m_data.size() == 1)
{
return;
}
for(size_t idx=0; idx<(m_data.size()-1)/2; idx++)
{
const auto ridx = m_data.size() - 2 - idx;
const auto tmp0 = m_data[idx];
m_data[idx] = m_data[ridx];
m_data[ridx] = tmp0;
}
}
void String::split(Vector<String>& output, char delimiter) const
{
String working_string;
bool last_was_non_delimiter{ false };
for (size_t idx = 0; idx<size(); idx++)
{
const auto c = m_data[idx];
if (c == delimiter)
{
if (last_was_non_delimiter)
{
output.push_back(working_string);
working_string = "";
last_was_non_delimiter = false;
}
}
else
{
last_was_non_delimiter = true;
working_string += c;
}
}
if (!working_string.empty())
{
output.push_back(working_string);
}
}
String String::to_string(size_t input)
{
String conv;
auto input_cpy = input;
while(input_cpy > 0)
{
const auto rem = input_cpy % 10;
conv += static_cast<char>(48 + rem);
input_cpy /= 10;
}
conv.reverse();
return conv;
}
char String::operator[](size_t idx) const
{
return m_data[idx];
}
String& String::operator<<(const char* body)
{
append(body);
return *this;
}
String& String::operator<<(const String& body)
{
*this += body;
return *this;
}
bool String::operator==(const String& other) const
{
return m_data == other.m_data;
}
bool String::operator!=(const String& other) const
{
return !(*this == other);
}
String& String::operator<<(size_t idx)
{
*this += to_string(idx);
return *this;
}
String& String::operator<<(const int idx)
{
*this += to_string(idx);
return *this;
}
void String::push_back(char c)
{
if (m_data.empty())
{
m_data.push_back('\0');
}
m_data.push_back('\0');
m_data[m_data.size()-2] = c;
}
void String::to_lower()
{
if (empty())
{
return;
}
for(size_t idx=0; idx<size(); idx++)
{
m_data[idx] = Char::to_lower(m_data[idx]);
}
}
String String::to_lower(const String& input)
{
String ret = input;
ret.to_lower();
return ret;
}
String& String::operator+=(const String& str)
{
if (m_data.empty())
{
m_data = str.m_data;
}
else
{
m_data.pop_back();
m_data.extend(str.m_data);
}
return *this;
}
String String::operator+(const String& str) const
{
auto ret = *this;
ret += str;
return ret;
}
String& String::operator+=(char c)
{
push_back(c);
return *this;
}