#pragma once #include #include #include #include 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 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(m_index) - static_cast(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 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 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(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& buffer() const { return m_buffer; } [[nodiscard]] const std::vector& 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 m_buffer{}; std::vector m_lengths{}; }; }