diff --git a/kodu/kodu6/inc/Funktsioonid.hpp b/kodu/kodu6/inc/Funktsioonid.hpp new file mode 100644 index 0000000000000000000000000000000000000000..594e547224692c7d920fed709546c1ba847e1190 --- /dev/null +++ b/kodu/kodu6/inc/Funktsioonid.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include <vector> + +std::vector<int> vLisaCopy(std::vector<int> v, int i) { + v.push_back(i); + return v; +} + +std::vector<int> &vLisaRef(std::vector<int> &v, int i) { + v.push_back(i); + return v; +} + +std::vector<int> *vLisaPtr(std::vector<int> *v, int i) { + v->push_back(i); + return v; +} + +std::vector<int *> iota(const int n) { + std::vector<int *> v(n); + for (int i = 0; i < n; ++i) { + v[i] = new int(i + 1); + } + return v; +} + +void destroy(std::vector<int *> &v) { + for (auto &ptr : v) { + delete ptr; + ptr = nullptr; + } +} \ No newline at end of file diff --git a/kodu/kodu6/inc/MinuVektor.hpp b/kodu/kodu6/inc/MinuVektor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..379ab2b04f56dff6dc201fa860a186af45d7d15e --- /dev/null +++ b/kodu/kodu6/inc/MinuVektor.hpp @@ -0,0 +1,114 @@ +#pragma once + +#include <cassert> +#include <optional> + +template<typename T> +class MinuVektor { +public: + MinuVektor() { + m_Buffer = new T[m_Capacity]; + } + + explicit MinuVektor(size_t capacity) + : m_Capacity(capacity) { + m_Buffer = new T[capacity]; + } + + MinuVektor(size_t capacity, T initial) + : m_Size(capacity), m_Capacity(capacity) { + m_Buffer = new T[capacity]; + for (size_t i = 0; i < m_Capacity; i++) { + m_Buffer[i] = initial; + } + } + + ~MinuVektor() { + delete[] m_Buffer; + } + + void push_back(T value) { + if (m_Size >= m_Capacity) { + resize(m_Capacity * 2); + } + + m_Buffer[m_Size++] = value; + } + + std::optional<T> get(size_t idx) { + if (idx >= m_Size) { + return std::nullopt; + } + + return m_Buffer[idx]; + } + + std::optional<T> front() { + return get(0); + } + + std::optional<T> back() { + return get(m_Size - 1); + } + + T operator[](size_t idx) { + assert(idx < m_Size); + return *get(idx); + } + + template<typename U = T> + requires std::integral<U> + static MinuVektor<U> iota(size_t sz) { + MinuVektor v(sz); + for (size_t i = 0; i < sz; i++) { + v.push_back(i); + } + return v; + } + + template<typename U> + MinuVektor<U> transform(auto fn) const { + MinuVektor<U> v(size()); + for (auto i = 0u; i < size(); i++) { + v.push_back(fn(m_Buffer[i])); + } + return v; + } + + [[nodiscard]] const T *buf() const { return m_Buffer; } + [[nodiscard]] auto size() const { return m_Size; } + [[nodiscard]] auto capacity() const { return m_Capacity; } + +private: + void resize(const size_t newCapacity) { + if (newCapacity < m_Capacity) { + return; + } + + T *newBuffer = new T[newCapacity]; + for (size_t i = 0; i < m_Capacity; i++) { + newBuffer[i] = m_Buffer[i]; + } + delete[] m_Buffer; + m_Buffer = newBuffer; + m_Capacity = newCapacity; + } + +private: + size_t m_Size{0}; + size_t m_Capacity{2}; + T *m_Buffer = nullptr; +}; + +template<typename T> +std::ostream &operator<<(std::ostream &os, MinuVektor<T> &v) { + os << '{'; + for (size_t i = 0; i < v.size(); i++) { + os << v[i]; + if (i != v.size() - 1) { + os << ", "; + } + } + os << '}'; + return os; +} \ No newline at end of file diff --git a/kodu/kodu6/inc/Sequence.hpp b/kodu/kodu6/inc/Sequence.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a3ff16aba946bd0959a6a7bc9e76dab77d4eeddb --- /dev/null +++ b/kodu/kodu6/inc/Sequence.hpp @@ -0,0 +1,95 @@ +#pragma once + +#include <cstdlib> +#include <vector> + +// أœlesanne 1. Funktsiooniobjektid ("funktor"). +// Kirjuta klass `Sequence`, mis modelleerib sisult jada, mis hoiab sealt elementide vأµtmisel jأ¤rge ning selle klassi +// objekti "kutsumisel" tagastatakse jأ¤rjekorras jأ¤rgmine element. +// Klass peab sisemiselt andmeid hoidma kuhimأ¤lus oleval mأ¤lul. Klass ei tohi kasutada STL-is olemasolevat konteinerit, +// vaid peab ise dأ¼naamiliselt mأ¤lu haldama. +// Vأµid eeldada, et jadasse elemente peale selle konstrueerimist juurde ei lisata. +// Vihjeks: on vajalik vaid أ¼ks `new` ja `delete`. Puhvrit suuremaks ega vأ¤iksemaks tegema ei pea. +// +// Klass peab kأ¤ituma jأ¤rgmiselt: +// +// Klassil on 2 konstruktorit: +// - `Sequence(const std::vector<int> &values)` - konstrueerib jada ning kopeerib kأµik vأ¤أ¤rtused kuhimأ¤llu. +// - `Sequence(const std::initializer_list<int> list)` - konstrueerib jada ning kopeerib initsialiseerimisnimekirja +// elemendid kuhimأ¤llu. +// Klass ei tohi olla vaikimisi konstrueeritav! S.t, et `Sequence s;` ei tohi tأ¶أ¶tada (nأ¤ites olemas). +// Klassi kustutamisel peab destruktor kأ¼situd mأ¤lu vabastama. +// +// Klass peab olema "kutsutav" (funktsiooniobjekti omadustega), s.t, et sellele on "kutseoperaator". +// +// Klassil peavad olema jأ¤rgmised kutseoperaatorid +// - Ilma argumendita operaator, mis tagastab jada jأ¤rjekorras jأ¤rgmise elemendi ning liigutab "jأ¤rge" edasi. +// - Operaator أ¼he argumendiga tأ¼أ¼pi `size_t skip`, mis jأ¤tab vahele `skip` elementi ning tagastab vastava elemendi. +// Samuti liigutab "jأ¤rge" edasi vastavalt vahele jأ¤etud elementide arvust. +// +// Nأ¤ide: +// Sequence s = {1, 2, 3, 4, 5}; +// const auto x = s(); // x = 1 +// // s() tagastaks hetkel 2 +// const auto y = s(1); // y = 3 +// const auto z = s(); // z = 4 +// const auto w = s(1); // peaks krahhima programmi +// +// - Operaator, mille abil on vأµimalik klassiobjekt teisendada tأµevأ¤أ¤rtuseks (`bool`). +// Nأ¤ide: +// const Sequence s = {1}; +// const bool b = static_cast<bool>(s); // b = true +// // const bool b2 = s; // pane tأ¤hele, et operaator peab olema `explicit`, et see rida ei tأ¶أ¶taks. +// +// Klassil on ka jأ¤rgmised liikmefunktsioonid +// NB! Pane tأ¤hele, et liikmefunktsioonid, mis klassi sisu ei muuda, peavad olema mأ¤rgitud vأµtmesأµnaga `const`. +// Lisaks oleks hea, kui funktsioonid, mis tagastavad midagi, vأµiksid olla mأ¤rgitud atribuudiga `[[nodiscard]]`. +// +// - `int *end()` - tagastab viimasest elemendist jأ¤rgmise. Tegelikult on see allokeeritud puhvrist vأ¤ljas, aga hea +// markeering selleks, et oleme jأµudnud puhvri lأµppu. Kأµik STL-i konteinerid teevad seda sarnaselt (vt std::vector::end()). +// - `size_t available()` - tagastab alles olevate elementide arvu. +// - `std::vector<int> vec()` - tagastab alles olevad elemendid uues vektoris ning ei tohi jada jأ¤rge edasi liigutada. +// +// Klassil on jأ¤rgmised staatilised funktsioonid: +// - `Sequence seq(const Sequence &s)` - mis konstrueerib ja tagastab jadas `s` alles jأ¤أ¤nud elementidest uue jada. +// Vihje: Antud funktsioon on lahenduv 2 reaga ;) +// +// Soovitus: Alusta lahendamist all antud mallist. +// +// NB! Pane tأ¤hele, et ilmutatud ("explicit") teste automaatselt ei tehta. Need vaatan kأ¤sitsi. + +class Sequence { +public: + Sequence() = delete; + + explicit Sequence(const std::vector<int> &values); + + Sequence(std::initializer_list<int> list); + + // !!! أ„ra neid 2 modifitseeri + Sequence(const Sequence &) = delete; + Sequence &operator=(const Sequence &) = delete; + // !!! + + ~Sequence(); + + static Sequence sec(const Sequence &s); + + [[nodiscard]] auto end() const; + + [[nodiscard]] auto available() const -> size_t; + + int operator()(); + + int operator()(size_t skip); + + explicit operator bool() const; + + [[nodiscard]] std::vector<int> vec() const; + +private: + int *m_Head; + size_t m_Size; + int *m_Ptr{}; +}; + diff --git a/kodu/kodu6/inc/Tester.hpp b/kodu/kodu6/inc/Tester.hpp new file mode 100644 index 0000000000000000000000000000000000000000..cc9bd7be717bd0644f04d88364cf861db3ebed2f --- /dev/null +++ b/kodu/kodu6/inc/Tester.hpp @@ -0,0 +1,73 @@ +#pragma once + +#include <print> +#include <functional> +#include <iostream> +#include <sstream> + +// أ„ra neid muutujaid ja funktsioone redigeeri. +static inline int g_TotalTestCount = 0; +static inline int g_SuccessfulTestCount = 0; + +#define TEST(condition) testAssert(condition, __FILE__, __LINE__) + +inline void testAssert(bool condition, const char *file, int line) { + g_TotalTestCount++; + if (!condition) { + std::cout << "VIGA: Kontroll asukohas " << file << ":" << line << " ei olnud أµige.\n"; + } else { + g_SuccessfulTestCount++; + } +} + +template<typename T> +auto equal(const T &a, const T &b) { + if (a.size() != b.size()) { + return false; + } + + return std::equal(a.begin(), a.end(), b.begin()); +} + +auto all(const auto begin, const auto end, const auto val) { + const auto fn = [&val](const auto v) -> bool { return v == val; }; + return std::all_of(begin, end, fn); +} + +auto all(const auto &c, const auto val) { + return all(std::begin(c), std::end(c), val); +} + +class CoutCapture { + std::stringstream &m_Buffer; + std::streambuf *m_Prevcout; + +public: + explicit CoutCapture(std::stringstream &buf) : m_Buffer(buf) { + m_Prevcout = std::cout.rdbuf(m_Buffer.rdbuf()); + } + + ~CoutCapture() { + std::cout.rdbuf(m_Prevcout); + } + + explicit operator bool() const { + return m_Prevcout != std::cout.rdbuf(); + } + + static bool expect(const std::string &str, auto fn) { + std::stringstream buf; + if (const CoutCapture cap(buf); cap) { + if constexpr (std::is_same_v<decltype(fn()), bool>) { + auto res = fn(); + if (!res) { + return false; + } + } else { + fn(); + } + } + + return buf.str() == str; + } +}; \ No newline at end of file diff --git a/kodu/kodu6/main.cpp b/kodu/kodu6/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7354a5a63758efbb6390c37ce4fdced1f620aa45 --- /dev/null +++ b/kodu/kodu6/main.cpp @@ -0,0 +1,166 @@ +#include <algorithm> +#include <iostream> +#include <map> +#include <numeric> +#include <ranges> + +#include "MinuVektor.hpp" + +#include "Funktsioonid.hpp" +#include "Sequence.hpp" +#include "Tester.hpp" + +int main() { + // أœlesanne 1. Sequence + { + // Konstruktor `Sequence(const std::vector<int> &values)` + const std::vector v = {1, 2, 3}; + const Sequence s(v); + TEST(s.available() == v.size()); + } + + { + // Konstruktor `Sequence(const std::initializer_list<int> list)` + const Sequence s = {1, 2, 3, 4}; + TEST(s.available() == 4); + } + + { + // operator() + Sequence s = {1, 2, 3, 4}; + std::vector<int> v(s.available()); + for (size_t i = 0; i < 4; ++i) { + v[i] = s(); + } + TEST(v.size() == 4); + TEST(equal(v, {1, 2, 3, 4})); + TEST(s.available() == 0); + + // s(); // - see peaks programmi krahhima + } + + { + // Konstruktor `Sequence(const Sequence &s)` + Sequence s = {1, 2, 3}; + s(); + const auto s2 = Sequence::sec(s); + TEST(equal(s2.vec(), {2, 3})); + } + + { + // operator(size_t) + Sequence s = {1, 2, 3, 4, 5}; + s(); + TEST(s(1) == 3); + TEST(s.available() > 0); + TEST(s() == 4); + TEST(s() == 5); + TEST(s.available() == 0); + + // s(); // - see peaks programmi krahhima + } + + { + [[maybe_unused]] Sequence s = {1}; + // s(1); // - see peaks programmi krahhima + } + + { + // operator bool + Sequence s = {1}; + TEST(static_cast<bool>(s)); + s(); + TEST(!static_cast<bool>(s)); + } + + { + // vec + const Sequence s = {1, 2}; + const auto vec = s.vec(); + TEST(equal(vec, {1, 2})); + + Sequence s2 = {1, 2}; + TEST(s2(1) == 2); + const auto vec2 = s2.vec(); + TEST(vec2.empty()); + } + + { + Sequence s = {1, 2, 3, 4, 5, 6}; + + int current = 1; + bool result = true; + + // Siin on operator bool kasulik: + while (s && result) { + const auto correct = (current++) == s(); + result &= correct; + } + TEST(result); + } + + // أœlesanne 2. Funktsioonid + // Kirjuta lahendus korrektselt pأ¤ise- ja lأ¤htekoodifailidesse nii, et + // allolevad testid lأ¤biksid Vaata, et lisaksid ka lأ¤htekoodifaili faili + // CMakeLists.txt ning impordiksid pأ¤isefaili أµigesti NB! Pane tأ¤hele, et + // funktsioonid ei ole mallid, s.t peavad olema jaotatud nii pأ¤ise- kui ka + // lأ¤htekoodifailide vahel. + // Antud أ¼lesande lahendamisel ignoreeri CLion'i antud hoiatusi koopiate ja + // reference'ide kohta. + { + std::vector v = {1, 2, 3}; + const std::vector v2 = vLisaCopy(v, 4); + TEST(equal(v2, {1, 2, 3, 4})); + TEST(equal(v, {1, 2, 3})); + } + + { + std::vector v = {1, 2, 3}; + const auto &v2 = vLisaRef(v, 4); + + // Funktsioon peab tagastama sama vektori, mis talle anti + TEST(&v == &v2); + + TEST(equal(v, {1, 2, 3, 4})); + TEST(equal(v2, {1, 2, 3, 4})); + } + + { + std::vector v = {1, 2, 3}; + const auto *v2 = vLisaPtr(&v, 4); + + // Funktsioon peab tagastama sama vektori, mis talle anti + TEST(&v == v2); + + TEST(equal(v, {1, 2, 3, 4})); + + // Mأµtle ja katseta, kas allolev rida teeb vektorist koopia? + const auto &v2Ref = *v2; + TEST(equal(v2Ref, {1, 2, 3, 4})); + } + + // أœlesanne 3. Vektor viitadest + // Kirjuta funktsioon `std::vector<int *> iota(int n)`, mis tagastab vektori, + // kus on kuhimأ¤lus allokeeritud tأ¤isarvud, mis sisaldavad vأ¤أ¤rtuseid [0, ..., + // n]. Vأµid eeldada, et `n > 0`. Kirjuta funktsioon `destroy(std::vector<int + // *> &v)`, mis vabastab kأµik tأ¤isarvud ning seab vektori viidad vأµrduma + // vأ¤أ¤rtusega `nullptr`. Vasta ka kأ¼simusele, miks argument peab olema viite + // tأ¼أ¼pi ning miks ei tohi vektorit ennast "kustutada". + { + const int N = 10; + auto vec = iota(N); + bool result = true; + for (int i = 0; i < N; ++i) { + const auto ptr = vec[i]; + const auto correct = *ptr == (i + 1); + result &= correct; + } + TEST(result); + destroy(vec); + TEST(all(vec, nullptr)); + } + + std::cout << "Testide tulemus: " << g_SuccessfulTestCount << "/" + << g_TotalTestCount << '\n'; + return g_SuccessfulTestCount != g_TotalTestCount; +} diff --git a/kodu/kodu6/src/Sequence.cpp b/kodu/kodu6/src/Sequence.cpp new file mode 100644 index 0000000000000000000000000000000000000000..47e635bbba4c802a72ad722633c38199fe144f1e --- /dev/null +++ b/kodu/kodu6/src/Sequence.cpp @@ -0,0 +1,75 @@ +#include "Sequence.hpp" + +#include <cassert> + +Sequence::Sequence(const std::vector<int> &values) + : m_Size(values.size()) { + m_Head = new int[m_Size]; + m_Ptr = m_Head; + + for (size_t i = 0; i < m_Size; ++i) { + m_Ptr[i] = values[i]; + } +} + +Sequence::Sequence(const std::initializer_list<int> list) + : m_Size(list.size()) { + m_Head = new int[m_Size]; + m_Ptr = m_Head; + + auto ptr = list.begin(); + for (size_t i = 0; i < m_Size; ++i, ++ptr) { + m_Ptr[i] = *ptr; + } +} + +Sequence::~Sequence() { + delete []m_Head; +} + +auto Sequence::end() const { + return m_Head + m_Size; +} + +auto Sequence::available() const -> size_t { + return end() - m_Ptr; +} + +int Sequence::operator()() { + assert(available()); + + const auto value = *m_Ptr; + m_Ptr++; + return value; +} + +int Sequence::operator()(const size_t skip) { + assert(skip < available()); + + for (size_t i = 0; i < skip; ++i) { + m_Ptr++; + } + const auto value = *m_Ptr; + m_Ptr++; + + return value; +} + +Sequence::operator bool() const { + return available() != 0; +} + +std::vector<int> Sequence::vec() const { + const auto size = available(); + std::vector<int> v(size); + for (size_t i = 0; i < size; ++i) { + v[i] = m_Ptr[i]; + } + + return v; +} + +Sequence Sequence::sec(const Sequence &s) { + const auto vec = s.vec(); + return Sequence(vec); +}