Created
March 16, 2022 09:25
-
-
Save VTroyanGolovyan/84a1deb7229858d5d96bf9d4cbde0ec1 to your computer and use it in GitHub Desktop.
COW
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
cmake_minimum_required(VERSION 3.21) | |
project(COWS) | |
set(CMAKE_CXX_STANDARD 20) | |
add_executable(COWS main.cpp COWString.cpp StringImpl.cpp) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Created by Владислав on 09.03.2022. | |
// | |
#include "COWString.h" | |
CowString::CowString(const std::string_view& s) | |
: control_block_(new StringImpl(s)){ | |
} | |
CowString::CowString(const CowString& other) { | |
control_block_ = other.control_block_; | |
control_block_->IncRefs(); | |
} | |
CowString::CowString(CowString&& other) noexcept { | |
control_block_ = other.control_block_; | |
other.control_block_ = new StringImpl(""); | |
} | |
CowString& CowString::operator=(const CowString& other) { | |
if (this != std::addressof(other)) { | |
if (control_block_ != nullptr && control_block_->Refs() == 1) { | |
delete control_block_; | |
} else if (control_block_ != nullptr) { | |
control_block_->DecRefs(); | |
} | |
control_block_ = other.control_block_; | |
control_block_->IncRefs(); | |
} | |
return *this; | |
} | |
CowString& CowString::operator=(CowString&& other) noexcept { | |
if (this != std::addressof(other)) { | |
control_block_ = other.control_block_; | |
other.control_block_ = new StringImpl("");; | |
} | |
return *this; | |
} | |
char CowString::At(size_t i) const { | |
return control_block_->At(i); | |
} | |
char const* CowString::GetData() const { | |
return control_block_->GetData(); | |
} | |
CowString::CharReference CowString::operator[](size_t index) { | |
return {this, index}; | |
} | |
char CowString::operator[](size_t index) const { | |
return control_block_->At(index); | |
} | |
CowString& CowString::operator+=(const CowString& other) { | |
CopyOnWrite(); | |
*control_block_ += std::string_view(other); | |
return *this; | |
} | |
CowString& CowString::operator+=(const std::string_view& other) { | |
CopyOnWrite(); | |
*control_block_ += std::string_view(other); | |
return *this; | |
} | |
CowString CowString::operator+(const CowString& other) const { | |
auto temp = *this; | |
temp += other; | |
return temp; | |
} | |
CowString CowString::operator+(const std::string_view& other) const { | |
auto temp = *this; | |
temp += other; | |
return temp; | |
} | |
bool CowString::operator==(const CowString& other) const { | |
return *control_block_ == *other.control_block_; | |
} | |
bool CowString::operator==(const std::string_view& other) const { | |
return *control_block_ == other; | |
} | |
bool CowString::operator!=(const CowString& other) const { | |
return *control_block_ != *other.control_block_; | |
} | |
bool CowString::operator!=(const std::string_view& other) const { | |
return *control_block_ != other; | |
} | |
CowString::operator std::string_view() const { | |
return std::string_view(*control_block_); | |
} | |
CowString::~CowString() { | |
if (control_block_ != nullptr && control_block_->Refs() == 1) { | |
delete control_block_; | |
} else if (control_block_ != nullptr){ | |
control_block_->DecRefs(); | |
} | |
} | |
void CowString::CopyOnWrite() { | |
if (control_block_->Refs() > 1) { | |
control_block_->DecRefs(); | |
control_block_ = new StringImpl(*control_block_); | |
} | |
} | |
CowString::CharReference::CharReference( | |
CowString* owner, | |
size_t index | |
) : owner_(owner), index_(index) {} | |
CowString::CharReference& CowString::CharReference::operator=(const char& other) { | |
if ((*owner_->control_block_)[index_] == other) { | |
return *this; | |
} | |
owner_->CopyOnWrite(); | |
(*owner_->control_block_)[index_] = other; | |
return *this; | |
} | |
CowString::CharReference::operator char() { | |
return (*owner_->control_block_)[index_]; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <string_view> | |
#include "StringImpl.h" | |
class CowString { | |
public: | |
class CharReference { | |
public: | |
CharReference( | |
CowString* owner, | |
size_t index | |
); | |
CharReference& operator=(const char& other); | |
operator char(); | |
private: | |
CowString* owner_; | |
size_t index_; | |
}; | |
template<bool IsConst> | |
class Iterator { | |
public: | |
using reference_type = std::conditional_t<IsConst, char, CharReference>; | |
using owner_ptr_type = std::conditional_t<IsConst, const CowString*, CowString*>; | |
Iterator(owner_ptr_type owner, size_t index) : str_(owner), index_(index) {} | |
Iterator<IsConst>& operator++() { | |
++index_; | |
return *this; | |
} | |
Iterator<IsConst> operator++(int) { | |
auto cpy = *this; | |
++index_; | |
return cpy; | |
} | |
Iterator<IsConst>& operator--() { | |
--index_; | |
return *this; | |
} | |
Iterator<IsConst> operator--(int) { | |
auto cpy = *this; | |
--index_; | |
return cpy; | |
} | |
reference_type operator[](size_t i) { | |
return CharReference(const_cast<CowString*>(str_), index_ + i); | |
} | |
reference_type operator*() { | |
return CharReference(const_cast<CowString*>(str_), index_); | |
} | |
reference_type operator[](size_t i) const { | |
return str_->At(index_ + i); | |
} | |
reference_type operator*() const { | |
return str_->At(index_); | |
} | |
bool operator==(const Iterator<IsConst>& other) const { | |
return index_ == other.index_; | |
} | |
bool operator!=(const Iterator<IsConst>& other) const { | |
return index_ != other.index_; | |
} | |
private: | |
size_t index_; | |
owner_ptr_type str_; | |
}; | |
typedef Iterator<false> iterator; | |
typedef Iterator<true> const_iterator; | |
iterator begin() { | |
return {this, 0}; | |
} | |
iterator end() { | |
return {this, control_block_->Size()}; | |
} | |
const_iterator begin() const { | |
return {this, 0}; | |
} | |
const_iterator end() const { | |
return {this, control_block_->Size()}; | |
} | |
friend class CharReference; | |
CowString(const std::string_view& s); | |
CowString(const CowString& other); | |
CowString(CowString&& other) noexcept; | |
CowString& operator=(const CowString& other); | |
CowString& operator=(CowString&& other) noexcept; | |
char const* GetData() const; | |
char At(size_t i) const; | |
CharReference operator[](size_t index); | |
char operator[](size_t index) const; | |
CowString& operator+=(const CowString& other); | |
CowString& operator+=(const std::string_view& other); | |
CowString operator+(const CowString& other) const; | |
CowString operator+(const std::string_view& other) const; | |
bool operator==(const CowString& other) const; | |
bool operator==(const std::string_view& other) const; | |
bool operator!=(const CowString& other) const; | |
bool operator!=(const std::string_view& other) const; | |
explicit operator std::string_view() const; | |
~CowString(); | |
private: | |
void CopyOnWrite(); | |
StringImpl* control_block_; | |
}; | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include "COWString.h" | |
int main() { | |
const CowString str1("hello"); | |
CowString str2 = str1; | |
assert(str1.GetData() == str2.GetData()); | |
str2[0] = 'h'; | |
assert(str1.GetData() == str2.GetData()); | |
str2 += " world"; | |
assert(str1.GetData() != str2.GetData()); | |
for (const auto ch : str1) { | |
assert(std::isalpha(ch)); | |
} | |
const auto* const str2_data = str2.GetData(); | |
str2[5] = '_'; | |
assert("hello_world" == str2); | |
assert(str2 == "hello_world"); | |
assert(str2_data == str2.GetData()); | |
str2 = str1; | |
assert("hello" == str2); | |
assert(str1.GetData() == str2.GetData()); | |
const CowString& const_str2 = str2; | |
assert('e' == const_str2.At(1)); | |
auto it1 = str1.begin(); | |
auto it2 = str2.begin(); | |
auto const_it2 = const_str2.begin(); | |
*it2 = 'H'; | |
assert("Hello" == str2); | |
assert("Hello" != str1); | |
assert('h' == *it1); | |
assert('H' == *it2); | |
assert('H' == *const_it2); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Created by Владислав on 09.03.2022. | |
// | |
#include "StringImpl.h" | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Created by Владислав on 09.03.2022. | |
// | |
#ifndef COWS_STRINGIMPL_H | |
#define COWS_STRINGIMPL_H | |
#include <string> | |
#include <string_view> | |
class StringImpl { | |
public: | |
StringImpl(const std::string_view& data) : data_(data), ref_count_(1) { | |
} | |
StringImpl(const StringImpl& other) : data_(other.data_), ref_count_(1) { | |
} | |
StringImpl(StringImpl&& other) { | |
} | |
StringImpl& operator=(const StringImpl& other) { | |
data_ = other.data_; | |
ref_count_ = 1; | |
return *this; | |
} | |
void IncRefs() { | |
++ref_count_; | |
} | |
size_t Size() { | |
return data_.size(); | |
} | |
void DecRefs() { | |
--ref_count_; | |
} | |
size_t Refs() { | |
return ref_count_; | |
} | |
char const* GetData() { | |
return data_.data(); | |
} | |
bool operator==(const std::string_view& other) const { | |
return data_ == other; | |
} | |
bool operator!=(const std::string_view& other) const { | |
return data_ != other; | |
} | |
StringImpl& operator += (const std::string_view& other) { | |
data_ += other; | |
return *this; | |
} | |
char& operator[](size_t index) { | |
return data_[index]; | |
} | |
operator std::string_view() { | |
return data_; | |
} | |
char At(size_t i) { | |
return data_[i]; | |
} | |
private: | |
std::string data_; | |
size_t ref_count_; | |
}; | |
#endif //COWS_STRINGIMPL_H |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment