banan-os/BAN/include/BAN/StringView.h

260 lines
5.5 KiB
C++

#pragma once
#include <BAN/Formatter.h>
#include <BAN/ForwardList.h>
#include <BAN/Hash.h>
#include <BAN/Iterators.h>
#include <BAN/Optional.h>
#include <BAN/Vector.h>
namespace BAN
{
class StringView
{
public:
using size_type = size_t;
using const_iterator = ConstIteratorSimple<char, StringView>;
public:
constexpr StringView() {}
constexpr StringView(const char* string, size_type len = -1)
{
if (len == size_type(-1))
len = strlen(string);
m_data = string;
m_size = len;
}
StringView(const String&);
constexpr const_iterator begin() const { return const_iterator(m_data); }
constexpr const_iterator end() const { return const_iterator(m_data + m_size); }
constexpr char operator[](size_type index) const
{
ASSERT(index < m_size);
return m_data[index];
}
constexpr bool operator==(StringView other) const
{
if (m_size != other.m_size)
return false;
for (size_type i = 0; i < m_size; i++)
if (m_data[i] != other.m_data[i])
return false;
return true;
}
constexpr bool operator==(const char* other) const
{
for (size_type i = 0; i < m_size; i++)
if (m_data[i] != other[i])
return false;
return other[m_size] == '\0';
}
constexpr StringView substring(size_type index, size_type len = -1) const
{
ASSERT(index <= m_size);
if (len == size_type(-1))
len = m_size - index;
ASSERT(len <= m_size - index); // weird order to avoid overflow
StringView result;
result.m_data = m_data + index;
result.m_size = len;
return result;
}
ErrorOr<Vector<StringView>> split(char delim, bool allow_empties = false) const
{
size_type count = 0;
{
size_type start = 0;
for (size_type i = 0; i < m_size; i++)
{
if (m_data[i] == delim)
{
if (allow_empties || start != i)
count++;
start = i + 1;
}
}
if (start != m_size)
count++;
}
Vector<StringView> result;
TRY(result.reserve(count));
size_type start = 0;
for (size_type i = 0; i < m_size; i++)
{
if (m_data[i] == delim)
{
if (allow_empties || start != i)
TRY(result.push_back(this->substring(start, i - start)));
start = i + 1;
}
}
if (start < m_size || (start == m_size && allow_empties))
TRY(result.push_back(this->substring(start)));
return result;
}
ErrorOr<Vector<StringView>> split(bool(*comp)(char), bool allow_empties = false) const
{
size_type count = 0;
{
size_type start = 0;
for (size_type i = 0; i < m_size; i++)
{
if (comp(m_data[i]))
{
if (allow_empties || start != i)
count++;
start = i + 1;
}
}
if (start != m_size)
count++;
}
Vector<StringView> result;
TRY(result.reserve(count));
size_type start = 0;
for (size_type i = 0; i < m_size; i++)
{
if (comp(m_data[i]))
{
if (allow_empties || start != i)
TRY(result.push_back(this->substring(start, i - start)));
start = i + 1;
}
}
if (start < m_size || (start == m_size && allow_empties))
TRY(result.push_back(this->substring(start)));
return result;
}
constexpr char back() const
{
ASSERT(m_size > 0);
return m_data[m_size - 1];
}
constexpr char front() const
{
ASSERT(m_size > 0);
return m_data[0];
}
BAN::Optional<size_type> find(char ch) const
{
for (size_type i = 0; i < m_size; i++)
if (m_data[i] == ch)
return i;
return {};
}
BAN::Optional<size_type> find(bool(*comp)(char)) const
{
for (size_type i = 0; i < m_size; i++)
if (comp(m_data[i]))
return i;
return {};
}
BAN::Optional<size_type> rfind(char ch) const
{
for (size_type i = m_size; i > 0; i--)
if (m_data[i - 1] == ch)
return i - 1;
return {};
}
BAN::Optional<size_type> rfind(bool(*comp)(char)) const
{
for (size_type i = m_size; i > 0; i--)
if (comp(m_data[i - 1]))
return i - 1;
return {};
}
constexpr bool starts_with(BAN::StringView target) const
{
if (target.size() > m_size)
return false;
for (size_type i = 0; i < m_size - target.size(); i++)
{
bool valid = true;
for (size_type j = 0; j < target.size() && valid; j++)
valid = (m_data[i + j] == target[j]);
if (valid)
return true;
}
return false;
}
constexpr bool contains(char ch) const
{
for (size_type i = 0; i < m_size; i++)
if (m_data[i] == ch)
return true;
return false;
}
constexpr size_type count(char ch) const
{
size_type result = 0;
for (size_type i = 0; i < m_size; i++)
if (m_data[i] == ch)
result++;
return result;
}
constexpr bool empty() const { return m_size == 0; }
constexpr size_type size() const { return m_size; }
constexpr const char* data() const { return m_data; }
private:
const char* m_data = nullptr;
size_type m_size = 0;
};
template<>
struct hash<StringView>
{
hash_t operator()(StringView string) const
{
constexpr hash_t FNV_offset_basis = 0x811c9dc5;
constexpr hash_t FNV_prime = 0x01000193;
hash_t hash = FNV_offset_basis;
for (StringView::size_type i = 0; i < string.size(); i++)
{
hash *= FNV_prime;
hash ^= (uint8_t)string[i];
}
return hash;
}
};
}
inline constexpr BAN::StringView operator""_sv(const char* str, BAN::StringView::size_type len) { return BAN::StringView(str, len); }
namespace BAN::Formatter
{
template<typename F>
void print_argument(F putc, const StringView& sv, const ValueFormat&)
{
for (StringView::size_type i = 0; i < sv.size(); i++)
putc(sv[i]);
}
}