From 6ad2bb5968e62afc6d8f2629b855df0b1288993c Mon Sep 17 00:00:00 2001
From: Kerdo Kurs <kerdokurs@gmail.com>
Date: Wed, 26 Mar 2025 14:03:26 +0200
Subject: [PATCH] add kodu6

---
 kodu/kodu6/inc/Funktsioonid.hpp |  33 +++++++
 kodu/kodu6/inc/MinuVektor.hpp   | 114 ++++++++++++++++++++++
 kodu/kodu6/inc/Sequence.hpp     |  95 ++++++++++++++++++
 kodu/kodu6/inc/Tester.hpp       |  73 ++++++++++++++
 kodu/kodu6/main.cpp             | 166 ++++++++++++++++++++++++++++++++
 kodu/kodu6/src/Sequence.cpp     |  75 +++++++++++++++
 6 files changed, 556 insertions(+)
 create mode 100644 kodu/kodu6/inc/Funktsioonid.hpp
 create mode 100644 kodu/kodu6/inc/MinuVektor.hpp
 create mode 100644 kodu/kodu6/inc/Sequence.hpp
 create mode 100644 kodu/kodu6/inc/Tester.hpp
 create mode 100644 kodu/kodu6/main.cpp
 create mode 100644 kodu/kodu6/src/Sequence.cpp

diff --git a/kodu/kodu6/inc/Funktsioonid.hpp b/kodu/kodu6/inc/Funktsioonid.hpp
new file mode 100644
index 0000000..594e547
--- /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 0000000..379ab2b
--- /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 0000000..a3ff16a
--- /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 0000000..cc9bd7b
--- /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 0000000..7354a5a
--- /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 0000000..47e635b
--- /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);
+}
-- 
GitLab