Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions practice/strings/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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")
208 changes: 208 additions & 0 deletions practice/strings/imstring.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
#include "imstring.h"
#include <cassert>

imstring::iterator::iterator(std::shared_ptr<buffer> 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<buffer> left, std::shared_ptr<buffer> 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<std::shared_ptr<buffer>> 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<std::shared_ptr<buffer>>& 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<buffer>(""))
{}

imstring::imstring(const char* c_str)
: shared_buffer_(std::make_shared<buffer>(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<buffer>(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;
}
99 changes: 99 additions & 0 deletions practice/strings/imstring.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
#pragma once
#include <string>
#include <memory>
#include <vector>
#include <stack>

struct imstring;

struct imstring {
private:
struct iterator;
struct buffer {
buffer(std::string const& value);

buffer(std::shared_ptr<buffer> left, std::shared_ptr<buffer> 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<std::shared_ptr<buffer>>& buffers) const;

bool is_concat_;
std::string value_;
std::shared_ptr<buffer> left_;
std::shared_ptr<buffer> right_;
}; // buffer

public:
struct iterator : std::iterator<std::bidirectional_iterator_tag, char> {
explicit iterator(std::shared_ptr<buffer> 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<buffer> root_;

std::shared_ptr<buffer> current_node_;
std::string::iterator current_pos_;
std::string::iterator current_end_;
std::string::iterator end_pos_;

std::stack<std::shared_ptr<buffer>> 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<buffer> shared_buffer_;
};

imstring operator+(imstring left, imstring const& right);
std::ostream& operator<<(std::ostream& ostream, imstring const& imstring);
62 changes: 62 additions & 0 deletions practice/strings/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#include "imstring.h"
#include <string>
#include <cassert>
#include <cstring>
#include <iterator>
#include <algorithm>
#include <iostream>

template<class STR1, class STR2>
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;
}