Skip to content
Snippets Groups Projects
Commit 56fc8bbd authored by Kerdo Kurs's avatar Kerdo Kurs
Browse files

add kodu4

parent c90ac85b
No related branches found
No related tags found
No related merge requests found
#include <algorithm>
#include <cassert>
#include <concepts>
#include <iostream>
#include <numeric>
#include <print>
#include <sstream>
#include <type_traits>
// 1. Ülesanne
// Siin on antud põhi klassile `IntVector`, mis on sisuliselt "wrapper"
// standardteegi vektorile, mis hoiustab täisarve. Implementeeri kõik nõutud
// konstruktorid ja liikmefunktsioonid.
class IntVector {
public:
// Vaikekonstruktor, mis initsialiseerib tühja vektori
IntVector() = default;
// Konstruktor, mis initsialiseerib n-pikkuse vektori vaikeväärtusega 0
// Näide:
// IntVector v(n) peaks väärtustama liikme `m_Vec` nagu teeb seda
// `std::vector<int> v(n)`
// IntVector objekti ei tohiks saada konstrueerida järgmiselt: `IntVector v =
// n` - see ei ole korrektne.
explicit IntVector(const long n) : m_Vec(n) {}
// Konstruktor, mis initsialiseerib n-pikkuse vektori väärtusega v
// Näide:
// IntVector v(n, v) peaks väärtustama liikme `m_Vec` nagu teeb seda
// `std::vector<int> v(n, v)`
IntVector(const long n, const int val) : m_Vec(n, val) {}
// "Range" konstruktor, mis käitub kui Pythoni `range` funktsioon.
// Konstruktor on 3 argumendiga: start, end, step ning lisab vektorisse
// elemendid vahemikus [start, end) sammuga `step`. Näide:
// IntVector v(0, 10, 2) lisab vektorisse elemendid 0, 2, 4, 6 ja 8
// IntVector v(0, 2, 1) lisab vektorisse elemendid 0 ja 1
IntVector(const int begin, const int end, const int step) {
for (auto i = begin; i < end; i += step) {
m_Vec.push_back(i);
}
}
// `set(size_t i, int val)` liikmefunktsioon, mis lisab elemendi `val`
// vektoris kohale `i`. Pane tähele, et kui vektori suurus on väiksem kui i,
// siis ära elementi lisa. Liikmefunktsioon tagastab tõeväärtuse, kas element
// lisati
bool set(size_t i, int val) {
if (m_Vec.size() <= i) {
return false;
}
m_Vec[i] = val;
return true;
}
// `int sum()` liikmefunktsioon tagastab elementide summa
[[nodiscard]] int sum() {
return std::accumulate(m_Vec.begin(), m_Vec.end(), 0);
}
// `int min()` liikmefunktsioon tagastab minimaalse elemendi
// Elementide puudumise korral tagastada 0
int min() {
return std::min_element(m_Vec.begin(), m_Vec.end()) - m_Vec.begin();
}
// `int max()` liikmefunktsioon tagastab minimaalse elemendi
// Elementide puudumise korral tagastada 0
int max() {
return std::max_element(m_Vec.begin(), m_Vec.end()) - m_Vec.begin();
}
// Kuna `m_Vec` on privaatne, siis on testimiseks hea, kui saame selle
// klassist välja ka anda. Selleks teeme getter-funktsiooni. Pane tähele, et
// antud liikmefunktsioon ei tee vektorist koopiat – selle olulisusest räägime
// järgmisel nädalal.
[[nodiscard]] auto &vec() const { return m_Vec; }
// Liikmefunktsioonid `begin` ja `end` on vajalikud for-of tsükli
// kasutamiseks. Ära neid siin modifitseeri
[[nodiscard]] auto begin() const { return m_Vec.begin(); }
[[nodiscard]] auto end() const { return m_Vec.end(); }
[[nodiscard]] auto begin() { return m_Vec.begin(); }
[[nodiscard]] auto end() { return m_Vec.end(); }
private:
std::vector<int> m_Vec{};
};
// 2. Ülesanne
// Kirjuta funktsioonimall `sum(T)`, millel on tüübiparameeter T.
// Funktsioonimall tagastab antud konteineri summa. Võid eeldada, et T on alati
// konteiner ehk saad kasutada for-of tsüklit ning et konteiner hoiab endas
// int-tüüpi elemente. NB! Ära kasuta kuskil siin funktsioonimallis võtmesõna
// `auto`
template <typename T> int sum(const T &t) {
return std::accumulate(std::begin(t), std::end(t), 0);
}
// 3. Ülesanne
// Kirjuta funktsioonimall `negate(T)`, millel on tüübiparameeter T. Piira
// parameetrit T nii, et funktsioon oleks kutsutav ainult täisarvude ning
// ujukoma arvudega. Selleks uuri võtmesõna requires ning päist <concepts>.
// Funktsioon ise tagastab antud arvu vastandarvu, s.t 1 -> -1, 0 -> 0, -1 -> 1
// jne. NB! Ära kasuta kuskil siin funktsioonimallis võtmesõna `auto`
template <typename T>
requires std::integral<T> || std::floating_point<T>
T negate(T t) {
return -t;
}
// Ära seda funktsioonimalli modifitseeri!
template <typename T> bool testNegateType() {
return requires(T t) { negate(t); };
}
// 4. Ülesanne [kuni 0.3 lisapunkti]
// Kirjuta funktsioonimall `variadicSum`, mida saab välja kutsuda ükskõik mis
// arvu argumentidega. Võid eeldada, et argumentide tüübid on samad.
template <typename... T> auto variadicSum(T... args) { return (... + args); }
// 5. Ülesanne [kuni 0.5 lisapunkti]
// Kirjuta klass `MinuMap`, mis simuleerib `HashMap` või `dict`-tüüpi
// andmestruktuuri. Olgu klassil liikmefunktsioonid:
// set(std::string key, T value)
// std::optional<T> get(std::string key)
// bool exists(std::string key)
// void clear()
// void print()
// bool empty()
//
// 1. Pane tähele, et liikmefunktsioon `get` tagastab tühja std::optional<T>
// objekti (või std::nullopt) kui soovitud võtmega elementi ei leidu.
// 2. Pane tähele, et liikmefunktsioon `print` peab väljastama antud formaadis:
// <key1> -> <value1>
// <key2> -> <value2>
// Pane tähele, et iga rea lõpus peab olema reavahetus (vt ka testi
// main-funktsioonis).
// 3. Võid eeldada, et klass peab töötama ainult antud testide piires (vt
// main-funktsioon). Küll aga ei tohi lahendust hard-code'ida.
//
// Vihje: Elementide hoidmiseks võib abiks olla klass `std::pair<std::string,
// T>`. Lisaks uuri klassi `std::optional<T>`. NB! Ära kasuta standardteegi
// klassi `std::map`! Hästi sobib näiteks vektor ;)
template <typename T> class MinuMap {
public:
MinuMap() = default;
void set(std::string key, T value) {
m_Map.emplace_back(std::move(key), std::move(value));
}
std::optional<T> get(std::string key) {
auto it = std::find_if(m_Map.begin(), m_Map.end(),
[&key](auto &pair) { return pair.first == key; });
if (it == m_Map.end()) {
return std::nullopt;
}
return it->second;
}
bool exists(std::string key) {
auto it = std::find_if(m_Map.begin(), m_Map.end(),
[&key](auto &pair) { return pair.first == key; });
return it != m_Map.end();
}
void clear() { m_Map.clear(); }
void print() {
for (const auto &[key, value] : m_Map) {
std::cout << key << " -> " << value << '\n';
}
}
bool empty() { return m_Map.empty(); }
private:
std::vector<std::pair<std::string, T>> m_Map;
};
// Ära neid muutujaid ja funktsioone redigeeri.
static int g_TotalTestCount = 0;
static int g_SuccessfulTestCount = 0;
#define TEST(condition) testAssert(condition, __FILE__, __LINE__)
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 &c, const auto val) {
return std::all_of(c.begin(), c.end(),
[&val](const auto &v) { return v == 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); }
};
int main() {
// 1. ülesanne. IntVector
{
// Vaikekonstruktor
IntVector v;
TEST(v.vec().empty());
}
{
// Ühe argumendiga konstruktor
IntVector v(10);
TEST(v.vec().size() == 10);
TEST(all(v, 0));
}
{
// Kahe argumendiga konstruktor
IntVector v(10, 1);
TEST(v.vec().size() == 10);
TEST(all(v, 1));
}
{
// "Range" konstruktor
IntVector v(0, 10, 2);
TEST(equal(v.vec(), {0, 2, 4, 6, 8}));
}
{
// `set` liikmefunktsioon
IntVector v(10);
TEST(v.set(0, 1));
TEST(!v.set(11, 1));
v = IntVector(0);
TEST(!v.set(0, 1));
}
{
// `sum` liikmefunktsioon
IntVector v(10);
TEST(v.sum() == 0);
v = IntVector(10, 1);
TEST(v.sum() == 10);
}
{
// `min` ja `max` liikmefunktsioonid
IntVector v(0, 10, 1);
TEST(v.min() == 0);
TEST(v.max() == 9);
v = IntVector(0);
TEST(v.min() == 0);
TEST(v.max() == 0);
}
// 2. ülesanne. Funktsioonimall `sum`
{
std::vector v{1, 2, 3, 4, 5};
// Pane tähele, et antud funktsioonimalli peab saama kutsuda kahel viisil:
TEST(sum(v) == 15);
TEST(sum<std::vector<int>>(v) == 15);
std::array<int, 5> a{1, 2, 3, 4, 5};
TEST(sum(a) == 15);
}
// 3. ülesanne. Funktsioonimall `negate`
{
TEST(negate(1) == -1);
TEST(negate(-1) == 1);
TEST(negate(0) == 0);
TEST(testNegateType<int>());
TEST(testNegateType<float>());
TEST(testNegateType<double>());
TEST(!testNegateType<std::string>());
}
// Kui testid on siiani läbitud, on ülesanne lahendatud
// Siit edasi on lisaülesanded
// 4. ülesanne. Variadic funktsioonimall
#if 0
{
TEST(variadicSum(1, 2, 3, 4, 5) == 15);
TEST(variadicSum(0) == 0);
TEST(variadicSum(1) == 1);
}
#endif
// 5. ülesanne. Klassimall, hashmap'i "emulatsioon"
#if 0
{
MinuMap<int> map{};
TEST(map.empty());
map.set("tere", 1);
TEST(!map.empty());
TEST(map.get("tere") == std::optional(1));
TEST(map.get("tere").value() == 1);
TEST(!map.get("maailm"));
map.set("maailm", 2);
TEST(map.get("maailm").value() == 2);
TEST(map.exists("tere"));
TEST(map.exists("maailm"));
TEST(!map.exists("koer"));
std::stringstream buf;
if (CoutCapture c(buf); true) {
map.print();
}
auto str = buf.str();
TEST(str == "tere -> 1\nmaailm -> 2\n");
map.clear();
TEST(map.empty());
}
#endif
std::cout << "Testide tulemus: " << g_SuccessfulTestCount << "/"
<< g_TotalTestCount << '\n';
return g_SuccessfulTestCount != g_TotalTestCount;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment