diff options
feat(Week05): Add solutions
9 files changed, 740 insertions, 0 deletions
| -rw-r--r-- | Week05/Exercise03/Person.cpp | 40 | ||||
| -rw-r--r-- | Week05/Exercise03/Person.h | 37 | ||||
| -rw-r--r-- | Week05/Exercise03/String.cpp | 70 | ||||
| -rw-r--r-- | Week05/Exercise03/String.h | 26 | ||||
| -rw-r--r-- | Week05/Exercise03/TaxDatabase.cpp | 333 | ||||
| -rw-r--r-- | Week05/Exercise03/TaxDatabase.h | 80 | ||||
| -rw-r--r-- | Week05/Exercise03/TaxReport.cpp | 25 | ||||
| -rw-r--r-- | Week05/Exercise03/TaxReport.h | 29 | ||||
| -rw-r--r-- | Week05/Exercise03/test.cpp | 100 |
diff --git a/Week05/Exercise03/Person.cpp b/Week05/Exercise03/Person.cpp new file mode 100644 index 0000000..fb46253 --- /dev/null +++ b/Week05/Exercise03/Person.cpp @@ -0,0 +1,40 @@ +#include "Person.h" +#include <iostream> + +Person::Person(const String& firstName, const String& middleName, const String& lastName, unsigned long long phoneNumber, const String& email, unsigned short birthYear, unsigned long long PN) { + this->firstName = firstName; + this->middleName = middleName; + this->lastName = lastName; + this->phoneNumber = phoneNumber; + this->email = email; + this->birthYear = birthYear; + this->PN = PN; +} + +const String& Person::GetFirstName() const { + return firstName; +} + +const String& Person::GetMiddleName() const { + return middleName; +} + +const String& Person::GetLastName() const { + return lastName; +} + +unsigned long long Person::GetPhoneNumber() const { + return phoneNumber; +} + +const String& Person::GetEmail() const { + return email; +} + +unsigned short Person::GetBirthYear() const { + return birthYear; +} + +unsigned long long Person::GetPN() const { + return PN; +} diff --git a/Week05/Exercise03/Person.h b/Week05/Exercise03/Person.h new file mode 100644 index 0000000..046e691 --- /dev/null +++ b/Week05/Exercise03/Person.h @@ -0,0 +1,37 @@ +#ifndef _PERSON +#define _PERSON + +#include "String.h" + +class Person { + String firstName; + String middleName; + String lastName; + unsigned long long phoneNumber; + String email; + unsigned short birthYear; + unsigned long long PN; // Personal Number + +public: + Person(const String& firstName, const String& middleName, const String& lastName, unsigned long long phoneNumber, const String& email, unsigned short birthYear, unsigned long long PN); + + /* Помощни член-функции */ + + // За да създадем масив се нуждаем от празен конструктор, + // обаче отгоре дефинирахме някакъв конструктор, което + // означава че празния по подразбиране не се създава. + // Можем сами да си го дефинираме, но с този синтаксис + // можем да задължим компилатора да използва този, + // който би генерирал по принцип. + Person() = default; + + const String& GetFirstName() const; + const String& GetMiddleName() const; + const String& GetLastName() const; + unsigned long long GetPhoneNumber() const; + const String& GetEmail() const; + unsigned short GetBirthYear() const; + unsigned long long GetPN() const; +}; + +#endif /* _PERSON */ diff --git a/Week05/Exercise03/String.cpp b/Week05/Exercise03/String.cpp new file mode 100644 index 0000000..1a59ef4 --- /dev/null +++ b/Week05/Exercise03/String.cpp @@ -0,0 +1,70 @@ +#include "String.h" +#include <cstring> + +void String::free() { + delete[] str; +} + +void String::copyFrom(const String& other) { + length = other.length; + + // Не забравяме за терминиращата нула + str = new char[length + 1]; + strncpy(str, other.str, length + 1); +} + +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(const char* str) { + length = strlen(str); + this->str = new char[length + 1]; + strncpy(this->str, str, length + 1); +} + +bool String::IsTheSameAs(const String& other) const { + return strcmp(str, other.str) == 0; +} + +const char* String::GetStr() const { + return str; +} diff --git a/Week05/Exercise03/String.h b/Week05/Exercise03/String.h new file mode 100644 index 0000000..3b0aa1d --- /dev/null +++ b/Week05/Exercise03/String.h @@ -0,0 +1,26 @@ +#ifndef _STRING +#define _STRING + +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(const char* str); + + bool IsTheSameAs(const String& other) const; + const char* GetStr() const; +}; + +#endif /* _STRING */ diff --git a/Week05/Exercise03/TaxDatabase.cpp b/Week05/Exercise03/TaxDatabase.cpp new file mode 100644 index 0000000..c12c228 --- /dev/null +++ b/Week05/Exercise03/TaxDatabase.cpp @@ -0,0 +1,333 @@ +#include "TaxDatabase.h" +#include <iostream> + +void TaxDatabase::free() { + delete[] people; + delete[] reports; +} + +void TaxDatabase::copyFrom(const TaxDatabase& other) { + peopleCount = other.peopleCount; + peopleAllocated = other.peopleAllocated; + + people = new Person[peopleAllocated]; + for (unsigned i = 0; i < peopleCount; ++i) + people[i] = other.people[i]; + + reportsCount = other.reportsCount; + reportsAllocated = other.reportsAllocated; + + reports = new TaxReport[reportsAllocated]; + for (unsigned i = 0; i < reportsCount; ++i) + reports[i] = other.reports[i]; +} + +void TaxDatabase::resizePeople() { + unsigned newAllocated = peopleAllocated == 0 ? 8 : peopleAllocated * 2; + Person* newPeople = new Person[newAllocated]; + + for (unsigned i = 0; i < peopleCount; ++i) + newPeople[i] = people[i]; + + delete[] people; + people = newPeople; + peopleAllocated = newAllocated; +} + +void TaxDatabase::resizeReports() { + unsigned newAllocated = reportsAllocated == 0 ? 8 : reportsAllocated * 2; + TaxReport* newReports = new TaxReport[newAllocated]; + + for (unsigned i = 0; i < reportsCount; ++i) + newReports[i] = reports[i]; + + delete[] reports; + reports = newReports; + reportsAllocated = newAllocated; +} + +TaxDatabase::TaxDatabase() { + people = nullptr; + reports = nullptr; + peopleCount = peopleAllocated = reportsCount = reportsAllocated = 0; +} + +TaxDatabase::~TaxDatabase() { + free(); +} + +TaxDatabase::TaxDatabase(const TaxDatabase& other) { + copyFrom(other); +} + +TaxDatabase& TaxDatabase::operator=(const TaxDatabase& other) { + if (this != &other) { + free(); + copyFrom(other); + } + return *this; +} + +TaxDatabase::TaxDatabase(TaxDatabase&& other) { + people = other.people; + peopleCount = other.peopleCount; + peopleAllocated = other.peopleAllocated; + + reports = other.reports; + reportsCount = other.reportsCount; + reportsAllocated = other.reportsAllocated; + + other.people = nullptr; + other.reports = nullptr; + other.peopleCount = other.peopleAllocated = other.reportsCount = other.reportsAllocated = 0; +} + +TaxDatabase& TaxDatabase::operator=(TaxDatabase&& other) { + if (this != &other) { + free(); + + people = other.people; + peopleCount = other.peopleCount; + peopleAllocated = other.peopleAllocated; + + reports = other.reports; + reportsCount = other.reportsCount; + reportsAllocated = other.reportsAllocated; + + other.people = nullptr; + other.reports = nullptr; + other.peopleCount = other.peopleAllocated = other.reportsCount = other.reportsAllocated = 0; + } + return *this; +} + +bool TaxDatabase::RegisterPerson(const Person& person) { + for (unsigned i = 0; i < peopleCount; ++i) { + if (people[i].GetPN() == person.GetPN() || + people[i].GetPhoneNumber() == person.GetPhoneNumber() || + people[i].GetEmail().IsTheSameAs(person.GetEmail())) + { + return false; + } + } + + if (peopleCount >= peopleAllocated) + resizePeople(); + people[peopleCount++] = person; + + return true; +} + +bool TaxDatabase::LogTaxReport(const TaxReport& report) { + for (unsigned i = 0; i < reportsCount; ++i) { + if (reports[i].GetPN() == report.GetPN() && + reports[i].GetYear() == report.GetYear()) + { + return false; + } + } + + if (reportsCount >= reportsAllocated) + resizeReports(); + reports[reportsCount++] = report; + + return true; +} + +void TaxDatabase::PersonalReports(unsigned long long PN) const { + const Person* p = GetPerson(PN); + if (p == nullptr) { + std::cout << "Person not in database!" << std::endl; + return; + } + + std::cout << p->GetFirstName().GetStr() << ' ' << p->GetMiddleName().GetStr() << ' ' << p->GetLastName().GetStr() << std::endl + << "Personal No: " << p->GetPN() << " Born: " << p->GetBirthYear() << std::endl + << "Tel: " << p->GetPhoneNumber() << " Email: " << p->GetEmail().GetStr() << std::endl; + + for (unsigned i = 0; i < reportsCount; ++i) { + if (reports[i].GetPN() == PN) { + std::cout << reports[i].GetYear() + << " Income: " << reports[i].GetIncome() + << " Tax rate: " << reports[i].GetTaxRate() << std::endl; + } + } +} + +void TaxDatabase::YearlyReports(unsigned short year) const { + for (unsigned i = 0; i < reportsCount; ++i) { + if (reports[i].GetYear() != year) + continue; + + const Person* p = GetPerson(reports[i].GetPN()); + if (p != nullptr) { + std::cout << p->GetFirstName().GetStr() << ' ' << p->GetLastName().GetStr() + << " Age: " << (year - p->GetBirthYear()) + << " Income: " << reports[i].GetIncome() + << " Tax rate: " << reports[i].GetTaxRate() << std::endl; + } + } +} + +double TaxDatabase::YearlyAvgIncome(unsigned short year) const { + double incomeSum = 0.0; + unsigned reportsInYear = 0; + + for (unsigned i = 0; i < reportsCount; ++i) { + if (reports[i].GetYear() != year) + continue; + + incomeSum += reports[i].GetIncome(); + ++reportsInYear; + } + + return incomeSum / reportsInYear; +} + +double TaxDatabase::YearlyTaxedIncome(unsigned short year) const { + double profits = 0.0; + + for (unsigned i = 0; i < reportsCount; ++i) { + if (reports[i].GetYear() != year) + continue; + + profits += reports[i].GetIncome() * reports[i].GetTaxRate(); + } + + return profits; +} + +const TaxReport* TaxDatabase::GetReport(unsigned long long PN, unsigned short year) const { + for (unsigned i = 0; i < reportsCount; ++i) { + if (reports[i].GetPN() == PN && reports[i].GetYear() == year) + return reports + i; + } + return nullptr; +} + +const TaxReport* TaxDatabase::GetReportByAge(unsigned long long PN, unsigned short age) const { + const Person* p = GetPerson(PN); + + if (p == nullptr) + return nullptr; + + return GetReport(PN, p->GetBirthYear() + age); +} + +void TaxDatabase::Reports::copyFrom(const Reports& other) { + reportsCount = other.reportsCount; + + reports = new TaxReport*[reportsCount]; + for (unsigned i = 0; i < reportsCount; ++i) + reports[i] = other.reports[i]; +} + +void TaxDatabase::Reports::free() { + delete[] reports; +} + +TaxDatabase::Reports::Reports() { + reports = nullptr; + reportsCount = 0; +} + +TaxDatabase::Reports::~Reports() { + free(); +} + +TaxDatabase::Reports::Reports(const Reports& other) { + copyFrom(other); +} + +TaxDatabase::Reports& TaxDatabase::Reports::operator=(const Reports& other) { + if (this != &other) { + free(); + copyFrom(other); + } + return *this; +} + +TaxDatabase::Reports::Reports(Reports&& other) { + reports = other.reports; + reportsCount = other.reportsCount; + + other.reports = nullptr; + other.reportsCount = 0; +} + +TaxDatabase::Reports& TaxDatabase::Reports::operator=(Reports&& other) { + if (this != &other) { + free(); + + reports = other.reports; + reportsCount = other.reportsCount; + + other.reports = nullptr; + other.reportsCount = 0; + } + return *this; +} + +unsigned TaxDatabase::Reports::ReportsCount() const { + return reportsCount; +} + +const TaxReport* TaxDatabase::Reports::At(unsigned index) const { + if (index >= reportsCount) + return nullptr; + + return reports[index]; +} + +void TaxDatabase::Reports::Allocate(unsigned size) { + reportsCount = size; + if (reports != nullptr) + delete[] reports; + reports = new TaxReport*[size]; +} + +TaxReport** TaxDatabase::Reports::At(unsigned index) { + if (index >= reportsCount) + return nullptr; + + return reports + index; +} + +const TaxDatabase::Reports TaxDatabase::GetReports(unsigned long long PN, unsigned short startYear, unsigned short endYear) const { + unsigned countReports = 0; + + for (unsigned i = 0; i < reportsCount; ++i) { + if (reports[i].GetPN() == PN && startYear <= reports[i].GetYear() && reports[i].GetYear() <= endYear) + ++countReports; + } + + Reports result; + result.Allocate(countReports); + + unsigned reportIndex = 0; + for (unsigned i = 0; i < reportsCount; ++i) { + if (reports[i].GetPN() == PN && startYear <= reports[i].GetYear() && reports[i].GetYear() <= endYear) { + *result.At(reportIndex++) = reports + i; + } + } + + return result; +} + +const TaxDatabase::Reports TaxDatabase::GetReportsByAge(unsigned long long PN, unsigned short startAge, unsigned short endAge) const { + const Person* p = GetPerson(PN); + + if (p == nullptr) + return Reports(); + + return GetReports(PN, p->GetBirthYear() + startAge, p->GetBirthYear() + endAge); +} + +const Person* TaxDatabase::GetPerson(unsigned long long PN) const { + for (unsigned i = 0; i < peopleCount; ++i) { + if (people[i].GetPN() == PN) { + return people + i; + } + } + return nullptr; +} diff --git a/Week05/Exercise03/TaxDatabase.h b/Week05/Exercise03/TaxDatabase.h new file mode 100644 index 0000000..89dd1ed --- /dev/null +++ b/Week05/Exercise03/TaxDatabase.h @@ -0,0 +1,80 @@ +#ifndef _TAXDATABASE +#define _TAXDATABASE + +#include "Person.h" +#include "TaxReport.h" + +class TaxDatabase { + Person* people; + unsigned peopleCount; + unsigned peopleAllocated; + + TaxReport* reports; + unsigned reportsCount; + unsigned reportsAllocated; + + void free(); + void copyFrom(const TaxDatabase& other); + + void resizePeople(); + void resizeReports(); + +public: + TaxDatabase(); + ~TaxDatabase(); + TaxDatabase(const TaxDatabase& other); + TaxDatabase& operator=(const TaxDatabase& other); + + TaxDatabase(TaxDatabase&& other); + TaxDatabase& operator=(TaxDatabase&& other); + + bool RegisterPerson(const Person& person); + bool LogTaxReport(const TaxReport& report); + + void PersonalReports(unsigned long long PN) const; + void YearlyReports(unsigned short year) const; + + double YearlyAvgIncome(unsigned short year) const; + double YearlyTaxedIncome(unsigned short year) const; + + const TaxReport* GetReport(unsigned long long PN, unsigned short year) const; + const TaxReport* GetReportByAge(unsigned long long PN, unsigned short age) const; + + // Можем да дефинираме класове в други класове, можем да достъпим + // вътрешния клас с името "TaxDatabase::Reports". + // Достъпността на класа следва public/protected/private, в този + // случай класа е публичен. + class Reports { + TaxReport** reports; + unsigned reportsCount; + + void copyFrom(const Reports& other); + void free(); + + public: + Reports(); + ~Reports(); + Reports(const Reports& other); + Reports& operator=(const Reports& other); + + Reports(Reports&& other); + Reports& operator=(Reports&& other); + + unsigned ReportsCount() const; + const TaxReport* At(unsigned index) const; + + // Тези се използват единствено от GetReports и GetReportsByAge + // Тоест не позволяваме на върнатата стойност да бъде изменяна + void Allocate(unsigned size); + TaxReport** At(unsigned index); + }; + + const Reports GetReports(unsigned long long PN, unsigned short startYear, unsigned short endYear) const; + const Reports GetReportsByAge(unsigned long long PN, unsigned short startAge, unsigned short endAge) const; + + /* Помощни функции */ + + const Person* GetPerson(unsigned long long PN) const; +}; + +#endif /* _TAXDATABASE */ diff --git a/Week05/Exercise03/TaxReport.cpp b/Week05/Exercise03/TaxReport.cpp new file mode 100644 index 0000000..2ff321f --- /dev/null +++ b/Week05/Exercise03/TaxReport.cpp @@ -0,0 +1,25 @@ +#include "TaxReport.h" +#include <iostream> + +TaxReport::TaxReport(unsigned long long PN, unsigned short year, double income, double taxRate) { + this->PN = PN; + this->year = year; + this->income = income; + this->taxRate = taxRate; +} + +unsigned long long TaxReport::GetPN() const { + return PN; +} + +unsigned short TaxReport::GetYear() const { + return year; +} + +double TaxReport::GetIncome() const { + return income; +} + +double TaxReport::GetTaxRate() const { + return taxRate; +} diff --git a/Week05/Exercise03/TaxReport.h b/Week05/Exercise03/TaxReport.h new file mode 100644 index 0000000..1dee2a4 --- /dev/null +++ b/Week05/Exercise03/TaxReport.h @@ -0,0 +1,29 @@ +#ifndef _TAXREPORT +#define _TAXREPORT + +class TaxReport { + unsigned long long PN; // Personal Number + unsigned short year; + double income; + double taxRate; + +public: + TaxReport(unsigned long long PN, unsigned short year, double income, double taxRate); + + /* Помощни член-функции */ + + // За да създадем масив се нуждаем от празен конструктор, + // обаче отгоре дефинирахме някакъв конструктор, което + // означава че празния по подразбиране не се създава. + // Можем сами да си го дефинираме, но с този синтаксис + // можем да задължим компилатора да използва този, + // който би генерирал по принцип. + TaxReport() = default; + + unsigned long long GetPN() const; + unsigned short GetYear() const; + double GetIncome() const; + double GetTaxRate() const; +}; + +#endif /* _TAXREPORT */ diff --git a/Week05/Exercise03/test.cpp b/Week05/Exercise03/test.cpp new file mode 100644 index 0000000..9e8f43c --- /dev/null +++ b/Week05/Exercise03/test.cpp @@ -0,0 +1,100 @@ +#include "TaxDatabase.h" +#include "TaxReport.h" +#include <iostream> + +// Силно препоръчително е да тествате големи програми, +// дори да не ви се иска по условие +int main() { + TaxDatabase td; + + td.RegisterPerson(Person("Petur", "Ivanov", "Dimitrov", 888500600, "pid@mail.com", 1989, 384)); + td.RegisterPerson(Person("Konstantin", "Filiopv", "Abrahildraganovichevich", 887111000, "k@mail.com", 1992, 591)); + + td.LogTaxReport(TaxReport(384, 2009, 10000, 0.1)); + td.LogTaxReport(TaxReport(384, 2010, 15000, 0.1)); + td.LogTaxReport(TaxReport(384, 2011, 20000, 0.1)); + td.LogTaxReport(TaxReport(384, 2012, 30000, 0.1)); + td.LogTaxReport(TaxReport(384, 2013, 70000, 0.2)); + td.LogTaxReport(TaxReport(384, 2014, 100000, 0.2)); + + td.LogTaxReport(TaxReport(591, 2012, 3900, 0.1)); + td.LogTaxReport(TaxReport(591, 2013, 40000, 0.2)); + td.LogTaxReport(TaxReport(591, 2014, 45000, 0.2)); + td.LogTaxReport(TaxReport(591, 2015, 50000, 0.15)); + + td.PersonalReports(384); + td.PersonalReports(591); + + std::cout << std::endl; + + td.YearlyReports(2014); + td.YearlyReports(2015); + + std::cout << std::endl; + + std::cout << td.YearlyAvgIncome(2011) << ' ' + << td.YearlyAvgIncome(2014) << ' ' + << td.YearlyAvgIncome(2015) << std::endl; + + std::cout << std::endl; + + std::cout << td.YearlyTaxedIncome(2011) << ' ' + << td.YearlyTaxedIncome(2014) << ' ' + << td.YearlyTaxedIncome(2015) << std::endl; + + std::cout << std::endl; + + const TaxReport* r; + + r = td.GetReport(384, 2013); + if (r == nullptr) + std::cout << "No report for 2013" << std::endl; + else + std::cout << r->GetYear() << ' ' << r->GetPN() << ' ' << r->GetIncome() << ' ' << r->GetTaxRate() << std::endl; + + r = td.GetReport(384, 2015); + if (r == nullptr) + std::cout << "No report for 2015" << std::endl; + else + std::cout << r->GetYear() << ' ' << r->GetPN() << ' ' << r->GetIncome() << ' ' << r->GetTaxRate() << std::endl; + + r = td.GetReport(591, 2015); + if (r == nullptr) + std::cout << "No report for 2015" << std::endl; + else + std::cout << r->GetYear() << ' ' << r->GetPN() << ' ' << r->GetIncome() << ' ' << r->GetTaxRate() << std::endl; + + std::cout << std::endl; + + r = td.GetReportByAge(384, 20); + if (r == nullptr) + std::cout << "No report at 20" << std::endl; + else + std::cout << r->GetYear() << ' ' << r->GetPN() << ' ' << r->GetIncome() << ' ' << r->GetTaxRate() << std::endl; + + r = td.GetReportByAge(384, 21); + if (r == nullptr) + std::cout << "No report at 21" << std::endl; + else + std::cout << r->GetYear() << ' ' << r->GetPN() << ' ' << r->GetIncome() << ' ' << r->GetTaxRate() << std::endl; + + r = td.GetReportByAge(591, 23); + if (r == nullptr) + std::cout << "No report at 23" << std::endl; + else + std::cout << r->GetYear() << ' ' << r->GetPN() << ' ' << r->GetIncome() << ' ' << r->GetTaxRate() << std::endl; + + std::cout << std::endl; + + const TaxDatabase::Reports reports1 = td.GetReports(591, 2005, 2015); + for (unsigned i = 0; i < reports1.ReportsCount(); ++i) + std::cout << reports1.At(i)->GetPN() << ' ' << reports1.At(i)->GetYear() << std::endl; + + std::cout << std::endl; + + const TaxDatabase::Reports reports2 = td.GetReportsByAge(384, 20, 25); + for (unsigned i = 0; i < reports2.ReportsCount(); ++i) + std::cout << reports2.At(i)->GetPN() << ' ' << reports2.At(i)->GetYear() << std::endl; + + return 0; +} |
