diff --git a/practice/strings/CMakeLists.txt b/practice/strings/CMakeLists.txt new file mode 100644 index 0000000..672a107 --- /dev/null +++ b/practice/strings/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 2.8) # Проверка версии CMake. + # Если версия установленой программы + # старее указаной, произайдёт аварийный выход. + +add_executable(main imstring.h main.cpp) # Создает исполняемый файл с именем main + # из исходника main.cpp + + +set (CMAKE_CXX_FLAGS "-std=c++11") diff --git a/practice/strings/imstring.cpp b/practice/strings/imstring.cpp new file mode 100644 index 0000000..9ef1466 --- /dev/null +++ b/practice/strings/imstring.cpp @@ -0,0 +1,208 @@ +#include "imstring.h" +#include + +imstring::iterator::iterator(std::shared_ptr buffer) + : root_ (buffer) + , current_node_(buffer) { + to_next_value(); + eval_end(); +} + +imstring::iterator& imstring::iterator::operator++() { + // TODO: implement +} + +imstring::iterator imstring::iterator::operator++(int) { + auto copy(*this); + this->operator++(); + return copy; +} + +imstring::buffer::buffer(std::string const& value) + : is_concat_(false) + , value_(value) + , left_(nullptr) + , right_(nullptr) +{} + +imstring::buffer::buffer(std::shared_ptr left, std::shared_ptr right) + : is_concat_(true) + , value_("") + , left_(left) + , right_(right) +{} + +size_t imstring::buffer::size() const { + if(is_concat_) { + return (left_ ? left_->size() : 0) + + (right_ ? right_->size() : 0); + } + + return value_.size(); +} + +const char* imstring::buffer::c_str() { + if(is_concat_) { + collapse(); + } + + assert(!is_concat_); + return value_.c_str(); +} + +char imstring::buffer::get_at(size_t ix) { + if(is_concat_) { + auto left_size = left_->size(); + if(left_->size() < ix) { + return left_->get_at(ix); + } + + return right_->get_at(ix - left_size); + } + + return value_[ix]; +} + +std::string::iterator imstring::buffer::begin() { + collapse(); + return value_.begin(); +} + +std::string::iterator imstring::buffer::end() { + collapse(); + return value_.end(); +} + +void imstring::buffer::collapse() { + if (!is_concat_) return; + std::vector> primitive_buffers; + auto total_size = add_primitive_buffers(primitive_buffers); + + value_.reserve(total_size); + value_ = ""; + for (auto buffer_ptr : primitive_buffers) { + value_ += buffer_ptr->value_; + } + + right_ = left_ = nullptr; + is_concat_ = false; +} + +size_t imstring::buffer::add_primitive_buffers(std::vector>& buffers) const { + size_t total_size = 0; + + if (left_->is_concat_) { + total_size += left_->add_primitive_buffers(buffers); + } + else { + total_size += left_->size(); + buffers.push_back(left_); + } + + if(right_->is_concat_) { + total_size += right_->add_primitive_buffers(buffers); + } + else { + total_size += right_->size(); + buffers.push_back(right_); + } + + return total_size; +} + +imstring::iterator::iterator() + : root_(nullptr) + , current_node_(nullptr) + , current_pos_(std::string::iterator()) + , end_pos_(std::string::iterator()) + , stack_() +{} + +bool imstring::iterator::to_next_value() { + if (current_pos_ == end_pos_) { + return false; + } + + if (current_node_->is_concat_) { + while (current_node_->is_concat_) { + stack_.push(current_node_); + current_node_ = current_node_->left_; + } + + current_pos_ = current_node_->value_.begin(); + current_end_ = current_node_->value_.end(); + return true; + } + + + + // TODO: Complete method. +} + +void imstring::iterator::eval_end() { + auto node = root_; + while(!node->is_concat_) { + node = node->right_; + } + + end_pos_ = node->value_.end(); +} + +imstring::imstring() + : shared_buffer_(std::make_shared("")) +{} + +imstring::imstring(const char* c_str) + : shared_buffer_(std::make_shared(c_str)) +{} + +imstring::imstring(imstring const& other) + : shared_buffer_(other.shared_buffer_) +{} + +imstring::imstring(imstring&& other) + : shared_buffer_(std::move(other.shared_buffer_)) +{} + +size_t imstring::size() const { + return shared_buffer_->size(); +} + +const char* imstring::c_str() const { + return shared_buffer_->c_str(); +} + +imstring& imstring::operator+=(imstring const& other) { + shared_buffer_ = std::make_shared(shared_buffer_, other.shared_buffer_); + return *this; +} + +char imstring::operator[](int ix) const { + return shared_buffer_->get_at(ix); +} + +std::string::iterator imstring::begin() const { + return shared_buffer_->begin(); +} + +std::string::iterator imstring::end() const { + return shared_buffer_->end(); +} + +imstring::iterator imstring::_begin() const { + return iterator(shared_buffer_); +} + +imstring::iterator imstring::_end() const { + return iterator(); +} + +imstring operator+(imstring left, imstring const& right) { + return left += right; +} + +std::ostream& operator<<(std::ostream& stream, imstring const& imstring) { + // TODO: make more lazy + stream << imstring.c_str(); + return stream; +} diff --git a/practice/strings/imstring.h b/practice/strings/imstring.h new file mode 100644 index 0000000..4fb1770 --- /dev/null +++ b/practice/strings/imstring.h @@ -0,0 +1,99 @@ +#pragma once +#include +#include +#include +#include + +struct imstring; + +struct imstring { +private: + struct iterator; + struct buffer { + buffer(std::string const& value); + + buffer(std::shared_ptr left, std::shared_ptr right); + + size_t size() const; + const char* c_str(); + char get_at(size_t ix); + + std::string::iterator begin(); + std::string::iterator end(); + + friend struct iterator; + private: + void collapse(); + size_t add_primitive_buffers(std::vector>& buffers) const; + + bool is_concat_; + std::string value_; + std::shared_ptr left_; + std::shared_ptr right_; + }; // buffer + +public: + struct iterator : std::iterator { + explicit iterator(std::shared_ptr buffer); + + // all categories + iterator(iterator const& other) = default; + iterator& operator=(iterator const& other) = default; + + iterator& operator++(); + iterator operator++(int); + + // input iterator + // TODO: move out-scope + bool operator==(iterator const& other); + bool operator!=(iterator const& other); + + char operator*(); + char* operator->(); + + // forward iterator + iterator(); + + // bidirectional iterator + iterator& operator--(); + iterator operator--(int); + + private: + bool to_next_value(); + bool to_prev_value(); + void eval_end(); + std::shared_ptr root_; + + std::shared_ptr current_node_; + std::string::iterator current_pos_; + std::string::iterator current_end_; + std::string::iterator end_pos_; + + std::stack> stack_; + }; // iterator + +public: + imstring(); + imstring(const char*); + imstring(imstring const& other); + imstring(imstring && other); + imstring& operator=(imstring const& other) = delete; + + size_t size() const; + const char* c_str() const; + + imstring& operator+=(imstring const& other); + char operator[](int ix) const; + + std::string::iterator begin() const; + std::string::iterator end() const; + + iterator _begin() const; + iterator _end() const; + +private: + std::shared_ptr shared_buffer_; +}; + +imstring operator+(imstring left, imstring const& right); +std::ostream& operator<<(std::ostream& ostream, imstring const& imstring); diff --git a/practice/strings/main.cpp b/practice/strings/main.cpp new file mode 100644 index 0000000..369008e --- /dev/null +++ b/practice/strings/main.cpp @@ -0,0 +1,62 @@ +#include "imstring.h" +#include +#include +#include +#include +#include +#include + +template +void test_strings_equal(STR1& str1, STR2 &str2) +{ + assert(str1.size() == str2.size()); + assert(std::equal(str1.begin(), str1.end(), str2.begin())); + assert(std::distance(str1.begin(), str1.end()) == + std::distance(str2.begin(), str2.end())); + // call operator << before we force strings to be not lazy + std::cout << str1 << std::endl << str2 << std::endl; + assert(strcmp(str1.c_str(), str2.c_str()) == 0); +} + +void my_tests() { + std::string str("abc"); + + auto it = str.begin(); + ++it; + assert(*it == 'b'); + --it; + assert(*it == 'a'); +} + +int main() +{ + std::string str1("foo bar buzz"); + + // Test creation from implicit c string + imstring imstr1 = str1.c_str(); + test_strings_equal(str1, imstr1); + test_strings_equal(imstr1, str1); + + // Test copying of shared immutable string buffer + imstring imstr1_cp(imstr1); + test_strings_equal(str1, imstr1); + test_strings_equal(imstr1, imstr1_cp); + assert(imstr1.begin() == imstr1.begin()); + assert(imstr1.end() == imstr1.end()); + // check laziness + assert(&(*imstr1.begin()) == &(*imstr1_cp.begin())); + + // Test lazy concatenation + imstring imstr_concat1 = imstr1 + imstr1_cp; + imstring imstr_concat2 = imstr_concat1 + imstr_concat1 + + imstr1 + imstr1_cp + imstr_concat1; + std::string str_concat1 = str1 + str1; + std::string str_concat2 = str_concat1 + str_concat1 + + str1 + str1 + str_concat1; + test_strings_equal(str_concat2, imstr_concat2); + test_strings_equal(imstr_concat2, str_concat2); + + my_tests(); + + return 0; +}