diff options
feat(Week09): Add solutions
14 files changed, 1120 insertions, 0 deletions
| -rw-r--r-- | Week09/Exercise01/Locomotive.cpp | 81 | ||||
| -rw-r--r-- | Week09/Exercise01/Locomotive.h | 43 | ||||
| -rw-r--r-- | Week09/Exercise02/Vector.cpp | 203 | ||||
| -rw-r--r-- | Week09/Exercise02/Vector.h | 59 | ||||
| -rw-r--r-- | Week09/Exercise03/String.cpp | 153 | ||||
| -rw-r--r-- | Week09/Exercise03/String.h | 61 | ||||
| -rw-r--r-- | Week09/Exercise03/main.cpp | 15 | ||||
| -rw-r--r-- | Week09/Exercise04/Rover.cpp | 64 | ||||
| -rw-r--r-- | Week09/Exercise04/Rover.h | 27 | ||||
| -rw-r--r-- | Week09/Exercise05/String.cpp | 75 | ||||
| -rw-r--r-- | Week09/Exercise05/String.h | 28 | ||||
| -rw-r--r-- | Week09/Exercise05/StringArray.cpp | 219 | ||||
| -rw-r--r-- | Week09/Exercise05/StringArray.h | 80 | ||||
| -rw-r--r-- | Week09/Exercise05/main.cpp | 12 |
diff --git a/Week09/Exercise01/Locomotive.cpp b/Week09/Exercise01/Locomotive.cpp new file mode 100644 index 0000000..2475126 --- /dev/null +++ b/Week09/Exercise01/Locomotive.cpp @@ -0,0 +1,81 @@ +#include "Locomotive.h" +#include <cstring> + +unsigned Locomotive::GetID() const { + return ID; +} + +void Locomotive::SetID(unsigned ID) { + this->ID = ID; +} + +const char* Locomotive::GetManufacturer() const { + return manufacturer; +} + +void Locomotive::SetManufacturer(const char manufacturer[MAX_LEN]) { + strncpy(this->manufacturer, manufacturer, MAX_LEN); +} + +const char* Locomotive::GetModel() const { + return model; +} + +void Locomotive::SetModel(const char model[MAX_LEN]) { + strncpy(this->model, model, MAX_LEN); +} + +int Locomotive::GetYearOfManufacture() const { + return yearOfManufacture; +} + +void Locomotive::SetYearOfManufacture(int yearOfManufacture) { + this->yearOfManufacture = yearOfManufacture; +} + +double Locomotive::GetLength() const { + return length; +} + +void Locomotive::SetLength(double length) { + this->length = length; +} + +unsigned short Locomotive::GetCyllinders() const { + return cyllinders; +} + +void Locomotive::SetCyllinders(unsigned short cyllinders) { + this->cyllinders = cyllinders; +} + +bool Locomotive::GetSupportsMultipleWorking() const { + return supportsMultipleWorking; +} + +void Locomotive::SetSupportsMultipleWorking(bool supportsMultipleWorking) { + this->supportsMultipleWorking = supportsMultipleWorking; +} + +// Тази функция не е нужно да бъде приятелска, можеше просто да използваме +// константните селектори. +std::ofstream& operator<<(std::ofstream& ostr, const Locomotive& loc) { + ostr << "Train #" << loc.ID << std::endl + << "+ Model: " << loc.model << std::endl + << "+ Manufacturer: " << loc.manufacturer << std::endl + << "+ Year of manufacture: " << loc.yearOfManufacture << std::endl + << "- Length: " << loc.length << std::endl + << "- Engine cyllinders: " << loc.cyllinders << std::endl + << "- Multiple working: " << (loc.supportsMultipleWorking ? "Yes" : "No") << std::endl; + return ostr; +} + +// Тазу функция не е нужно да бъде приятелска, можеше просто да използваме +// мутаторите. +std::ifstream& operator>>(std::ifstream& istr, Locomotive& loc) { + istr >> loc.ID; + istr.getline(loc.model, MAX_LEN); + istr.getline(loc.manufacturer, MAX_LEN); + istr >> loc.yearOfManufacture >> loc.length >> loc.cyllinders >> loc.supportsMultipleWorking; + return istr; +} diff --git a/Week09/Exercise01/Locomotive.h b/Week09/Exercise01/Locomotive.h new file mode 100644 index 0000000..45e9f7b --- /dev/null +++ b/Week09/Exercise01/Locomotive.h @@ -0,0 +1,43 @@ +#ifndef _LOCOMOTIVE +#define _LOCOMOTIVE + +#include <fstream> + +const unsigned MAX_LEN = 1024; + +class Locomotive { + unsigned ID; + char manufacturer[MAX_LEN]; + char model[MAX_LEN]; + int yearOfManufacture; + double length; + unsigned short cyllinders; + bool supportsMultipleWorking; + +public: + unsigned GetID() const; + void SetID(unsigned ID); + + const char* GetManufacturer() const; + void SetManufacturer(const char manufacturer[MAX_LEN]); + + const char* GetModel() const; + void SetModel(const char model[MAX_LEN]); + + int GetYearOfManufacture() const; + void SetYearOfManufacture(int yearOfManufacture); + + double GetLength() const; + void SetLength(double length); + + unsigned short GetCyllinders() const; + void SetCyllinders(unsigned short cyllinders); + + bool GetSupportsMultipleWorking() const; + void SetSupportsMultipleWorking(bool supportsMultipleWorking); + + friend std::ofstream& operator<<(std::ofstream& ostr, const Locomotive& loc); + friend std::ifstream& operator>>(std::ifstream& istr, Locomotive& loc); +}; + +#endif /* _LOCOMOTIVE */ diff --git a/Week09/Exercise02/Vector.cpp b/Week09/Exercise02/Vector.cpp new file mode 100644 index 0000000..8de9091 --- /dev/null +++ b/Week09/Exercise02/Vector.cpp @@ -0,0 +1,203 @@ +#include "Vector.h" +#include <cmath> +#include <cstring> + +void Vector::free() { + delete[] numbers; +} + +void Vector::copyFrom(const Vector& other) { + numbersCount = other.numbersCount; + numbersAlloc = other.numbersAlloc; + + numbers = new double[numbersAlloc]; + for (unsigned i = 0; i < numbersCount; ++i) + numbers[i] = other.numbers[i]; +} + +Vector::Vector() { + numbers = nullptr; + numbersCount = numbersAlloc = 0; +} + +Vector::~Vector() { + free(); +} + +Vector::Vector(const Vector& other) { + copyFrom(other); +} + +Vector& Vector::operator=(const Vector& other) { + if (this != other.ptr()) { + free(); + copyFrom(other); + } + return *this; +} + +Vector::Vector(Vector&& other) { + numbers = other.numbers; + numbersCount = other.numbersCount; + numbersAlloc = other.numbersAlloc; + + other.numbers = nullptr; + other.numbersCount = other.numbersAlloc = 0; +} + +Vector& Vector::operator=(Vector&& other) { + if (this != other.ptr()) { + free(); + + numbers = other.numbers; + numbersCount = other.numbersCount; + numbersAlloc = other.numbersAlloc; + + other.numbers = nullptr; + other.numbersCount = other.numbersAlloc = 0; + } + return *this; +} + +unsigned Vector::GetCount() const { + return numbersCount; +} + +const double* Vector::GetNumbers() const { + return numbers; +} + +Vector& Vector::operator+=(const Vector& other) { + unsigned minLen = numbersCount < other.numbersCount ? numbersCount : other.numbersCount; + for (unsigned i = 0; i < minLen; ++i) + numbers[i] += other.numbers[i]; + + return *this; +} + +Vector& Vector::operator-=(const Vector& other) { + unsigned minLen = numbersCount < other.numbersCount ? numbersCount : other.numbersCount; + for (unsigned i = 0; i < minLen; ++i) + numbers[i] -= other.numbers[i]; + + return *this; +} + + +Vector& Vector::operator*=(double scalar) { + for (unsigned i = 0; i < numbersCount; ++i) + numbers[i] *= scalar; + + return *this; +} + +double Vector::operator*=(const Vector& other) { + double dotProduct = 0.0; + unsigned minLen = numbersCount < other.numbersCount ? numbersCount : other.numbersCount; + + for (unsigned i = 0; i < minLen; ++i) + dotProduct += numbers[i] * other.numbers[i]; + + return dotProduct; +} + +Vector& Vector::operator^=(const Vector& other) { + // Припомняме си, че векторното умножение работи само върху + // триизмерни вектори + if (numbersCount != 3 || other.numbersCount != 3) + return *this; + + double s[3]; + double *a = numbers, *b = other.numbers; + + s[0] = a[1] * b[2] - a[2] * b[1]; + s[1] = a[2] * b[0] - a[0] * b[2]; + s[2] = a[0] * b[1] - a[1] * b[0]; + + memcpy(a, s, sizeof(double) * 3); + + return *this; +} + +double Vector::operator&() const { + double sum = 0.0; + for (unsigned i = 0; i < numbersCount; ++i) + sum += numbers[i] * numbers[i]; + return sqrt(sum); +} + +Vector* Vector::ptr() { + return this; +} + +const Vector* Vector::ptr() const { + return this; +} + +Vector operator+(const Vector& lhs, const Vector& rhs) { + Vector ret(lhs); + ret += rhs; + return ret; +} + +Vector operator-(const Vector& lhs, const Vector& rhs) { + // Не трябва да е нужно да обясняваме защо това + // е напълно същото като логиката при operator+ + return Vector(lhs) -= rhs; +} + +Vector operator*(const Vector& lhs, double scalar) { + return Vector(lhs) *= scalar; +} + +Vector operator*(double scalar, const Vector& rhs) { + return rhs * scalar; +} + +double operator*(const Vector& lhs, const Vector& rhs) { + return Vector(lhs) *= rhs; +} + +Vector operator^(const Vector& lhs, const Vector& rhs) { + return Vector(lhs) ^= rhs; +} + +bool operator||(const Vector& lhs, const Vector& rhs) { + unsigned minLen = lhs.GetCount() < rhs.GetCount() ? lhs.GetCount() : rhs.GetCount(); + + // Под "паралелни" вектори говорим повече за "колинеарни" вектори. + // Или с други думи, считаме дали правите, образувани от центъра 0 и + // един вектор съвпада с правата, образувана от центъра 0 и другия вектор. + // Щом лежат на една права, можем да скалираме единия вектор, + // така че той да стане равен на другия. + // С други думи, за вектори x и y, и скалар s, имаме че + // x || y тогава и само тогава когато съществува s: x = s*y, + // тстк същ. s: за всяко i: x[i] = s * y[i] + // тстк същ. s: вс. i: x[i] / y[i] = s + // тстк x[0] / y[0] = x[1] / y[1] = x[2] / y[2] = ... + // + // Алтернативно можем да вземем точковото умножение на вектори x и y, + // и чрез него да намерим ъгъла между двата вектора. + // Те ще лежат на една права ако ъгъла е 0 или 180 градуса. + // С други думи, ако arccos((x * y) / (&x * &y)) е 0 или PI + for (unsigned i = 0; i < minLen - 1; ++i) { + // Това коректно ли е? Възможно ли е да имаме проблеми с такова директно сравнение? + if (lhs.GetNumbers()[i] / rhs.GetNumbers()[i] != lhs.GetNumbers()[i+1] / rhs.GetNumbers()[i+1]) + return false; + } + return true; +} + +bool operator==(const Vector& lhs, const Vector& rhs) { + if (lhs.GetCount() != rhs.GetCount()) + return false; + + for (unsigned i = 0; i < lhs.GetCount(); ++i) + if (lhs.GetNumbers()[i] != rhs.GetNumbers()[i]) + return false; + return true; +} + +bool operator!=(const Vector& lhs, const Vector& rhs) { + return !(lhs == rhs); +} diff --git a/Week09/Exercise02/Vector.h b/Week09/Exercise02/Vector.h new file mode 100644 index 0000000..bf7b0c3 --- /dev/null +++ b/Week09/Exercise02/Vector.h @@ -0,0 +1,59 @@ +#ifndef _VECTOR +#define _VECTOR + +class Vector { + double* numbers; + unsigned numbersCount; + unsigned numbersAlloc; + + void free(); + void copyFrom(const Vector& other); + +public: + Vector(); + ~Vector(); + Vector(const Vector& other); + Vector& operator=(const Vector& other); + + Vector(Vector&& other); + Vector& operator=(Vector&& other); + + unsigned GetCount() const; + const double* GetNumbers() const; + + // Добра конвенция при бинарни (двуаргументни) оператори е да + // дефинираме като член-функции съответните _= оператори (+=, -=, ...) + // и след това да дефинираме _ опеарторите (+, -, ...) като нормални + // функции, които вътрешно използват _= + + Vector& operator+=(const Vector& other); + Vector& operator-=(const Vector& other); + Vector& operator*=(double scalar); + double operator*=(const Vector& other); + Vector& operator^=(const Vector& other); + + double operator&() const; + + // Понеже предефинираме &, не можем да направим &vector, за да + // вземем указател от референция към обект. За нашите цели е нужно, + // затова си правим помощни методи които "реимплементират" същата логика. + Vector* ptr(); + const Vector* ptr() const; +}; + +Vector operator+(const Vector& lhs, const Vector& rhs); +Vector operator-(const Vector& lhs, const Vector& rhs); + +// Понеже лявия и десния аргумент се различават по тип, +// така поддържаме комутативност +Vector operator*(const Vector& lhs, double scalar); +Vector operator*(double scalar, const Vector& rhs); + +double operator*(const Vector& lhs, const Vector& rhs); +Vector operator^(const Vector& lhs, const Vector& rhs); + +bool operator||(const Vector& lhs, const Vector& rhs); +bool operator==(const Vector& lhs, const Vector& rhs); +bool operator!=(const Vector& lhs, const Vector& rhs); + +#endif /* _VECTOR */ diff --git a/Week09/Exercise03/String.cpp b/Week09/Exercise03/String.cpp new file mode 100644 index 0000000..a0b2565 --- /dev/null +++ b/Week09/Exercise03/String.cpp @@ -0,0 +1,153 @@ +#include "String.h" +#include <cstring> + +void String::free() { + delete[] str; +} + +void String::copyFrom(const String& other) { + length = other.length; + // Не забравяме за терминиращата нула + str = new char[length + 1]; + strcpy(str, other.str); +} + +String::String() { + str = nullptr; + length = 0; +} + +String::~String() { + free(); +} + +String::String(const String& other) { + copyFrom(other); +} + +String& String::operator=(const String& other) { + if (this != &other) { + free(); + copyFrom(other); + } + return *this; +} + +String::String(String&& other) { + str = other.str; + length = other.length; + + other.str = nullptr; + other.length = 0; +} + +String& String::operator=(String&& other) { + if (this != &other) { + free(); + + str = other.str; + length = other.length; + + str = nullptr; + length = 0; + } + return *this; +} + +String::String(const char* str) { + this->length = strlen(str); + this->str = new char[this->length + 1]; + strcpy(this->str, str); +} + +std::ostream& operator<<(std::ostream& ostr, const String& string) { + if (string.str == nullptr) + return ostr << ""; + return ostr << string.str; +} + +String& String::operator+=(const String& other) { + char* largerStr = new char[length + other.length + 1]; + strcpy(largerStr, str); + strcat(largerStr, other.str); + + delete[] str; + str = largerStr; + length += other.length; + + return *this; +} + +char String::operator[](unsigned index) const { + return str[index]; +} + +String::IndexRange::IndexRange(unsigned index) { + start = end = index; +} + +String::IndexRange& String::IndexRange::operator,(const IndexRange& rhs) { + if (rhs.start < this->start) + this->start = rhs.start; + if (this->end < rhs.end) + this->end = rhs.end; + return *this; +} + +String String::operator[](IndexRange range) const { + if (range.end >= length) + range.end = length - 1; + if (range.start > range.end) + return String(); + if (range.start == 0 && range.end == length - 1) + return *this; + + String substr; + substr.length = range.end - range.start + 1; + substr.str = new char[substr.length + 1]; + + strncpy(substr.str, str + range.start, substr.length); + substr.str[substr.length] = '\0'; + + return substr; +} + +bool operator==(const String& lhs, const String& rhs) { + return strcmp(lhs.str, rhs.str) == 0; +} + +bool operator!=(const String& lhs, const String& rhs) { + return !(lhs == rhs); +} + +bool operator<(const String& lhs, const String& rhs) { + return strcmp(lhs.str, rhs.str) < 0; +} + +bool operator<=(const String& lhs, const String& rhs) { + return strcmp(lhs.str, rhs.str) <= 0; +} + +bool operator>(const String& lhs, const String& rhs) { + return strcmp(lhs.str, rhs.str) > 0; +} + +bool operator>=(const String& lhs, const String& rhs) { + return strcmp(lhs.str, rhs.str) >= 0; +} + +bool operator<<(const String& lhs, const String& rhs) { + if (rhs.length > lhs.length) + return false; + return strcmp(lhs.str + (lhs.length - rhs.length), rhs.str) == 0; +} + +bool operator>>(const String& lhs, const String& rhs) { + if (lhs.length > rhs.length) + return false; + return strncmp(lhs.str, rhs.str, lhs.length) == 0; +} + +String operator+(const String& lhs, const String& rhs) { + return String(lhs) += rhs; +} diff --git a/Week09/Exercise03/String.h b/Week09/Exercise03/String.h new file mode 100644 index 0000000..674813c --- /dev/null +++ b/Week09/Exercise03/String.h @@ -0,0 +1,61 @@ +#ifndef _STRING +#define _STRING + +#include <ostream> + +class String { + char* str; + unsigned length; + + void free(); + void copyFrom(const String& other); + +public: + String(); + ~String(); + String(const String& other); + String& operator=(const String& other); + + String(String&& other); + String& operator=(String&& other); + + // Помощни член-функции, за да тестваме String + String(const char* str); + friend std::ostream& operator<<(std::ostream& ostr, const String& string); + + // Каза ни са кои оператори трябва да бъдат имплементирани, + // но както помощни функции, можем да си имплементираме и други + // оператори + String& operator+=(const String& other); + + char operator[](unsigned index) const; + + const char* te() const { + return str; + } + + struct IndexRange { + unsigned start; + unsigned end; + + IndexRange(unsigned index); + IndexRange& operator,(const IndexRange& rhs); + }; + String operator[](IndexRange range) const; + + // Алтернативно, може да създадем селектори + // GetStr който връща str указателя и GetLength, + // и тези функции няма да е нужно да са приятелски + friend bool operator==(const String& lhs, const String& rhs); + friend bool operator!=(const String& lhs, const String& rhs); + friend bool operator<(const String& lhs, const String& rhs); + friend bool operator<=(const String& lhs, const String& rhs); + friend bool operator>(const String& lhs, const String& rhs); + friend bool operator>=(const String& lhs, const String& rhs); + friend bool operator<<(const String& lhs, const String& rhs); + friend bool operator>>(const String& lhs, const String& rhs); +}; + +String operator+(const String& lhs, const String& rhs); + +#endif /* _STRING */ diff --git a/Week09/Exercise03/main.cpp b/Week09/Exercise03/main.cpp new file mode 100644 index 0000000..087b05f --- /dev/null +++ b/Week09/Exercise03/main.cpp @@ -0,0 +1,15 @@ +#include "String.h" +#include <iostream> + +int main() { + String a = "Hello"; + String b = "World"; + + String c = a + " " + b; + + std::cout << c << std::endl; + std::cout << (c << b) << ' ' << (a >> c) << std::endl; + std::cout << c[String::IndexRange(2), 7] << std::endl; + + return 0; +} diff --git a/Week09/Exercise04/Rover.cpp b/Week09/Exercise04/Rover.cpp new file mode 100644 index 0000000..dc311c7 --- /dev/null +++ b/Week09/Exercise04/Rover.cpp @@ -0,0 +1,64 @@ +#include "Rover.h" +#include <cmath> + +// Използваме полярни координати, за да опишем посоките. +// С други думи, използваме ъгъл, такъв че (1,0) е на 0 градуса (радиана), +// (0,1) е на 90 градуса, (-1,0) е на 180 градуса и (0,-1) е на 270 градуса. +// Така ако знаем посоката напред, посоката на ляво е на 90 градуса обратно +// на часовниковата стрелка от ъгъла, който описва посоката "напред". +// Аналогично, посоката на ляво е на 90 градуса по часовниковата стрелка от +// ъгъла, който описва посоката "напред". + +void Rover::moveDistByAngle(double dist, double angle) { + // https://en.wikipedia.org/wiki/Polar_coordinate_system#Converting_between_polar_and_Cartesian_coordinates + this->x += dist * cos(angle); + this->y += dist * sin(angle); +} + +Rover::Rover() { + x = y = 0; + forward = M_PI_2; +} + +Rover& operator<(double dist, Rover& rover) { + rover.moveDistByAngle(dist, rover.forward + M_PI_2); + return rover; +} + +Rover& Rover::operator>(double dist) { + this->moveDistByAngle(dist, this->forward - M_PI_2); + return *this; +} + +Rover& Rover::operator^(double dist) { + this->moveDistByAngle(dist, this->forward); + return *this; +} + +Rover& operator<<(double degrees, Rover& rover) { + rover.forward += degrees / 180.0 * M_PI; + return rover; +} + +Rover& Rover::operator>>(double degrees) { + this->forward -= degrees / 180.0 * M_PI; + return *this; +} + +std::ostream& operator<<(std::ostream& ostr, const Rover& rover) { + double forwardUnitX = cos(rover.forward), forwardUnitY = sin(rover.forward); + ostr << "Rover at (" << rover.x << ',' << rover.y + << "), looking direction (" << forwardUnitX << ',' << forwardUnitY << ')' + << std::endl; + return ostr; +} + +std::istream& operator>>(std::istream& istr, Rover& rover) { + // Очакваме координат, който описва посоката "напред" + // Например (0,1) + double forwardUnitX, forwardUnitY; + istr >> rover.x >> rover.y >> forwardUnitX >> forwardUnitY; + // https://en.wikipedia.org/wiki/Polar_coordinate_system#Converting_between_polar_and_Cartesian_coordinates + rover.forward = atan2(forwardUnitY, forwardUnitX); + return istr; +} diff --git a/Week09/Exercise04/Rover.h b/Week09/Exercise04/Rover.h new file mode 100644 index 0000000..4286f06 --- /dev/null +++ b/Week09/Exercise04/Rover.h @@ -0,0 +1,27 @@ +#ifndef _ROVER +#define _ROVER + +#include <ostream> +#include <istream> + +class Rover { + double x; + double y; + double forward; + + void moveDistByAngle(double dist, double angle); + +public: + Rover(); + + friend Rover& operator<(double dist, Rover& rover); + Rover& operator>(double dist); + Rover& operator^(double dist); + friend Rover& operator<<(double degrees, Rover& rover); + Rover& operator>>(double degrees); + + friend std::ostream& operator<<(std::ostream& ostr, const Rover& rover); + friend std::istream& operator>>(std::istream& istr, Rover& rover); +}; + +#endif /* _ROVER */ diff --git a/Week09/Exercise05/String.cpp b/Week09/Exercise05/String.cpp new file mode 100644 index 0000000..903aa60 --- /dev/null +++ b/Week09/Exercise05/String.cpp @@ -0,0 +1,75 @@ +#include "String.h" +#include <cstring> +#include <iostream> + +void String::free() { + delete[] str; +} + +void String::copyFrom(const String& other) { + length = other.length; + // Не забравяме за терминиращата нула + str = new char[length + 1]; + strcpy(str, other.str); +} + +String::String() { + str = nullptr; + length = 0; +} + +String::~String() { + free(); +} + +String::String(const String& other) { + copyFrom(other); +} + +String& String::operator=(const String& other) { + if (this != &other) { + free(); + copyFrom(other); + } + return *this; +} + +String::String(String&& other) { + str = other.str; + length = other.length; + + other.str = nullptr; + other.length = 0; +} + +String& String::operator=(String&& other) { + if (this != &other) { + free(); + + str = other.str; + length = other.length; + + other.str = nullptr; + other.length = 0; + } + return *this; +} + +String::String(unsigned length) { + this->length = length; + this->str = new char[length + 1]; + this->str[length] = '\0'; +} + +void String::Copy(const char* str) { + if (this->str == nullptr) { + length = strlen(str); + this->str = new char[length + 1]; + } + strncpy(this->str, str, length); + this->str[length] = '\0'; +} + +const char* String::GetStr() const { + return str; +} diff --git a/Week09/Exercise05/String.h b/Week09/Exercise05/String.h new file mode 100644 index 0000000..08c7a79 --- /dev/null +++ b/Week09/Exercise05/String.h @@ -0,0 +1,28 @@ +#ifndef _STRING +#define _STRING + +#include <ostream> + +class String { + char* str; + unsigned length; + + void free(); + void copyFrom(const String& other); + +public: + String(); + ~String(); + String(const String& other); + String& operator=(const String& other); + + String(String&& other); + String& operator=(String&& other); + + String(unsigned length); + void Copy(const char* other); + + const char* GetStr() const; +}; + +#endif /* _STRING */ diff --git a/Week09/Exercise05/StringArray.cpp b/Week09/Exercise05/StringArray.cpp new file mode 100644 index 0000000..c3eca35 --- /dev/null +++ b/Week09/Exercise05/StringArray.cpp @@ -0,0 +1,219 @@ +#include "StringArray.h" +#include <iostream> + +void StringArray::free() { + delete[] strings; +} + +void StringArray::copyFrom(const StringArray& other) { + stringsCount = other.stringsCount; + stringsAlloc = other.stringsAlloc; + stringsAssigned = other.stringsAssigned; + + strings = new String[stringsAlloc]; + for (unsigned i = 0; i < stringsCount; ++i) + strings[i] = other.strings[i]; +} + +void StringArray::resize() { + stringsAlloc = stringsAlloc == 0 ? 8 : stringsAlloc * 2; + String* stringsLarger = new String[stringsAlloc]; + + for (unsigned i = 0; i < stringsCount; ++i) + stringsLarger[i] = strings[i]; + + delete[] strings; + strings = stringsLarger; +} + +StringArray::StringArray() { + strings = nullptr; + stringsCount = stringsAlloc = stringsAssigned = 0; +} + +StringArray::~StringArray() { + free(); +} + +StringArray::StringArray(const StringArray& other) { + copyFrom(other); +} + +StringArray& StringArray::operator=(const StringArray& other) { + if (this != &other) { + free(); + copyFrom(other); + } + return *this; +} + +StringArray::StringArray(StringArray&& other) { + strings = other.strings; + stringsCount = other.stringsCount; + stringsAlloc = other.stringsAlloc; + stringsAssigned = other.stringsAssigned; + + other.strings = nullptr; + other.stringsCount = other.stringsAlloc = other.stringsAssigned = 0; +} + +StringArray& StringArray::operator=(StringArray&& other) { + if (this != &other) { + free(); + + strings = other.strings; + stringsCount = other.stringsCount; + stringsAlloc = other.stringsAlloc; + stringsAssigned = other.stringsAssigned; + + other.strings = nullptr; + other.stringsCount = other.stringsAlloc = other.stringsAssigned = 0; + } + return *this; +} + +void StringArray::PushLength(unsigned length) { + if (stringsCount >= stringsAlloc) + resize(); + strings[stringsCount++] = String(length); +} + +void StringArray::PushString(const char* str) { + if (stringsAssigned >= stringsAlloc) + resize(); + strings[stringsAssigned++].Copy(str); + + if (stringsAssigned > stringsCount) + stringsCount = stringsAssigned; +} + +StringArray& StringArray::operator[](const Z& expectedNumbers) { + for (unsigned i = 0; i < expectedNumbers.numbersCount; ++i) { + PushLength(expectedNumbers.numbers[i]); + } + return *this; +} + +StringArray& StringArray::operator()(const StringArray& strings) { + for (unsigned i = 0; i < strings.stringsAssigned; ++i) { + PushString(strings.strings[i].GetStr()); + } + return *this; +} + +StringArray& StringArray::operator()(const char* str) { + PushString(str); + return *this; +} + +StringArray::StringArray(const char* str) : StringArray() { + PushString(str); +} + +StringArray& StringArray::operator|(const char* str) { + PushString(str); + return *this; +} + +// Това не е нужно по условие, но ще ни е +// полезно за тестване. +std::ostream& operator<<(std::ostream& ostr, const StringArray& sa) { + for (unsigned i = 0; i < sa.stringsAssigned; ++i) + ostr << sa.strings[i].GetStr() << std::endl; + return ostr; +} + +/* Помощен клас Z */ + +void Z::free() { + delete[] numbers; +} + +void Z::copyFrom(const Z& other) { + numbersCount = other.numbersCount; + numbersAlloc = other.numbersAlloc; + + numbers = new unsigned[numbersAlloc]; + for (unsigned i = 0; i < numbersCount; ++i) + numbers[i] = other.numbers[i]; +} + +void Z::resize() { + numbersAlloc = numbersAlloc == 0 ? 8 : numbersAlloc * 2; + unsigned* numbersLarger = new unsigned[numbersAlloc]; + + for (unsigned i = 0; i < numbersCount; ++i) + numbersLarger[i] = numbers[i]; + + delete[] numbers; + numbers = numbersLarger; +} + +Z::Z() { + numbers = nullptr; + numbersCount = numbersAlloc = 0; +} + +Z::~Z() { + free(); +} + +Z::Z(const Z& other) { + copyFrom(other); +} + +Z& Z::operator=(const Z& other) { + if (this != &other) { + free(); + copyFrom(other); + } + return *this; +} + +Z::Z(Z&& other) { + numbers = other.numbers; + numbersAlloc = other.numbersAlloc; + numbersCount = other.numbersCount; + + other.numbers = nullptr; + other.numbersCount = other.numbersAlloc = 0; +} + +Z& Z::operator=(Z&& other) { + if (this != &other) { + free(); + + numbers = other.numbers; + numbersAlloc = other.numbersAlloc; + numbersCount = other.numbersCount; + + other.numbers = nullptr; + other.numbersCount = other.numbersAlloc = 0; + } + return *this; +} + +Z::Z(unsigned number) { + numbersAlloc = 8; + numbersCount = 1; + numbers = new unsigned[numbersAlloc]; + numbers[0] = number; +} + +// Това е един метод да имплементираме operator++ и operator+, +// където с ++ все едно подсказваме че ще добавяме елемент и с +// + се добавя елемента. +// Валидно е и ++ да не върши нищо и цялата логика да е в +. +// Но така задължаваме употребата на "+++". + +Z& Z::operator++(int) { + if (numbersCount + 1 >= numbersAlloc) + resize(); + return *this; +} + +Z& Z::operator+(const Z& rhs) { + for (unsigned i = 0; i < rhs.numbersCount && numbersCount < numbersAlloc; ++i) + numbers[numbersCount++] = rhs.numbers[i]; + return *this; +} diff --git a/Week09/Exercise05/StringArray.h b/Week09/Exercise05/StringArray.h new file mode 100644 index 0000000..4b15ba0 --- /dev/null +++ b/Week09/Exercise05/StringArray.h @@ -0,0 +1,80 @@ +#ifndef _STRINGARRAY +#define _STRINGARRAY + +#include "String.h" +#include <ostream> + +// Декларация на класа, за да може в StringArray +// да си го използваме преди пълната дефиниция +class Z; + +class StringArray { + String* strings; + unsigned stringsCount; + unsigned stringsAlloc; + + unsigned stringsAssigned; + + void free(); + void copyFrom(const StringArray& other); + void resize(); + +public: + StringArray(); + ~StringArray(); + StringArray(const StringArray& other); + StringArray& operator=(const StringArray& other); + + StringArray(StringArray&& other); + StringArray& operator=(StringArray&& other); + + void PushLength(unsigned length); + void PushString(const char* str); + + StringArray& operator[](const Z& expectedNumbers); + + // Можем да създадем помощен клас "PassedStrings". + // Обаче нямаме ограничение което задължава StringArray и + // PassedStrings да са различни класове. + // Можем и просто да се възползваме от StringArray, + // и да си спестим писане на код. + StringArray& operator()(const StringArray& strings); + StringArray& operator()(const char* str); + StringArray(const char* str); + + // Оператор "|" е ляво асоциативен + StringArray& operator|(const char* str); + + // Това не е нужно по условие, но ще ни е + // полезно за тестване. + friend std::ostream& operator<<(std::ostream& ostr, const StringArray& sa); +}; + +class Z { + unsigned* numbers; + unsigned numbersCount; + unsigned numbersAlloc; + + void free(); + void copyFrom(const Z& other); + void resize(); + +public: + Z(); + ~Z(); + Z(const Z& other); + Z& operator=(const Z& other); + + Z(Z&& other); + Z& operator=(Z&& other); + + Z(unsigned num); + + Z& operator++(int); + Z& operator+(const Z& rhs); + + friend StringArray; +}; + + +#endif /* _STRINGARRAY */ diff --git a/Week09/Exercise05/main.cpp b/Week09/Exercise05/main.cpp new file mode 100644 index 0000000..8bf6a6c --- /dev/null +++ b/Week09/Exercise05/main.cpp @@ -0,0 +1,12 @@ +#include "StringArray.h" +#include <iostream> + +int main() { + StringArray s; + + // Защо за числата трябва да конвертираме всички, а при | конвертираме само първия? + s[ Z(7) +++ Z(4) +++ Z(3) ] ("") (StringArray("Hello")|"World") [ Z(4) +++ Z(5) +++ Z(1) ] ("!") [ Z(2) ] (StringArray("Code")|"A"|"B"); + + std::cout << s; + return 0; +} |
