Files
Z3D/include/util/string_list.hpp
2024-12-22 16:58:40 +01:00

259 lines
5.3 KiB
C++

#pragma once
#include <vector>
#include <string_view>
#include <span>
#include <cinttypes>
namespace ztu
{
class string_list_iterator
{
public:
using iterator_category = std::random_access_iterator_tag;
using value_type = std::string_view;
using difference_type = std::ptrdiff_t;
using pointer = const value_type*;
using reference = const value_type&;
string_list_iterator(
std::string_view buffer,
std::span<const std::uint32_t> lengths,
std::size_t index,
std::size_t char_offset)
: m_buffer{ buffer }, m_lengths{ lengths }, m_index{ index }, m_char_offset{ char_offset } {}
value_type operator*() const
{
return m_buffer.substr(m_char_offset, m_lengths[m_index]);
}
string_list_iterator& operator++()
{
++m_index;
m_char_offset += m_lengths[m_index];
return *this;
}
string_list_iterator operator++(int)
{
auto tmp = *this;
++(*this);
return tmp;
}
string_list_iterator& operator--()
{
--m_index;
m_char_offset -= m_lengths[m_index];
return *this;
}
string_list_iterator operator--(int)
{
auto tmp = *this;
--(*this);
return tmp;
}
string_list_iterator& operator+=(difference_type n)
{
const auto negative = n < difference_type{ 0 };
const auto positive = n > difference_type{ 0 };
const auto step = difference_type{ positive } - difference_type{ negative };
n = negative ? -n : n;
while (n--)
{
m_char_offset += step * m_lengths[m_index];
m_index += step;
}
return *this;
}
string_list_iterator& operator-=(const difference_type n)
{
return *this += -n;
}
string_list_iterator operator+(const difference_type n) const
{
auto tmp = *this;
return tmp += n;
}
string_list_iterator operator-(const difference_type n) const
{
auto tmp = *this;
return tmp -= n;
}
difference_type operator-(const string_list_iterator& other) const
{
return static_cast<difference_type>(m_index) - static_cast<difference_type>(other.m_index);
}
value_type operator[](const difference_type n) const
{
auto tmp = *this;
tmp += n;
return *tmp;
}
bool operator==(const string_list_iterator& other) const {
return m_index == other.m_index && m_char_offset == other.m_char_offset;
}
bool operator!=(const string_list_iterator& other) const {
return !(*this == other);
}
bool operator<(const string_list_iterator& other) const {
return m_index < other.m_index;
}
bool operator<=(const string_list_iterator& other) const {
return m_index <= other.m_index;
}
bool operator>(const string_list_iterator& other) const {
return m_index > other.m_index;
}
bool operator>=(const string_list_iterator& other) const {
return m_index >= other.m_index;
}
private:
std::string_view m_buffer;
std::span<const std::uint32_t> m_lengths;
std::size_t m_index;
std::size_t m_char_offset;
};
class string_list
{
using index_type = std::uint32_t;
using iterator = string_list_iterator;
public:
string_list() = default;
string_list(std::initializer_list<std::string_view> init)
{
for (const auto& str : init) {
push_back(str);
}
}
void reserve(const std::size_t characters, const std::size_t lengths)
{
m_buffer.reserve(characters);
m_lengths.reserve(lengths);
}
std::size_t character_count() const
{
return m_buffer.size();
}
void push_back(const std::string_view& str)
{
m_buffer.reserve(m_buffer.size() + str.length() + 1);
m_buffer.insert(m_buffer.end(), str.begin(), str.end());
m_buffer.push_back('\0');
m_lengths.push_back(static_cast<index_type>(str.size()));
}
void push_back(const string_list& list)
{
m_buffer.insert(m_buffer.end(), list.m_buffer.begin(), list.m_buffer.end());
m_lengths.insert(m_lengths.end(), list.m_lengths.begin(), list.m_lengths.end());
}
void pop_back()
{
m_buffer.resize(m_buffer.size() - m_lengths.back());
m_lengths.pop_back();
}
[[nodiscard]] std::string_view operator[](index_type index) const
{
auto offset = std::size_t{};
for (index_type i{}; i != index; ++i)
{
offset += m_lengths[i];
}
return { &m_buffer[offset], m_lengths[index] };
}
[[nodiscard]] index_type size() const
{
return m_lengths.size();
}
[[nodiscard]] bool empty() const
{
return m_lengths.empty();
}
void clear()
{
m_buffer.clear();
m_lengths.clear();
}
void reserve(index_type new_cap)
{
m_buffer.reserve(new_cap);
m_lengths.reserve(new_cap);
}
[[nodiscard]] index_type capacity() const
{
return m_buffer.capacity();
}
[[nodiscard]] iterator begin() const
{
return iterator{
std::string_view{ m_buffer.data(), m_buffer.size() },
m_lengths,
0, 0
};
}
[[nodiscard]] iterator end() const
{
return iterator{
std::string_view{ m_buffer.data(), m_buffer.size() },
m_lengths,
m_lengths.size(),
m_buffer.size()
};
}
[[nodiscard]] const std::vector<char>& buffer() const
{
return m_buffer;
}
[[nodiscard]] const std::vector<index_type>& string_lengths() const
{
return m_lengths;
}
void swap(string_list& other) noexcept
{
m_buffer.swap(other.m_buffer);
m_lengths.swap(other.m_lengths);
}
private:
std::vector<char> m_buffer{};
std::vector<index_type> m_lengths{};
};
}