From 9fa7211a2b7d006114209f99abc8b9d3ca2ba171 Mon Sep 17 00:00:00 2001
From: kaller01 <martin@kallers.se>
Date: Fri, 1 Dec 2023 15:45:17 +0100
Subject: [PATCH] seminar7-8 Co-authored-by: Albin
 <albarv340@users.noreply.github.com>

---
 seminar7/deque.cc  | 206 +++++++++++++++++++++++++++++++++++++++++++++
 seminar7/deque.h   |  38 +++++++++
 seminar7/deque.tcc | 173 +++++++++++++++++++++++++++++++++++++
 seminar8/tests.cc  |  93 ++++++++++++++++++++
 4 files changed, 510 insertions(+)
 create mode 100644 seminar7/deque.cc
 create mode 100644 seminar7/deque.h
 create mode 100644 seminar7/deque.tcc
 create mode 100644 seminar8/tests.cc

diff --git a/seminar7/deque.cc b/seminar7/deque.cc
new file mode 100644
index 0000000..b9c0f60
--- /dev/null
+++ b/seminar7/deque.cc
@@ -0,0 +1,206 @@
+#include "deque.h"
+
+#include <cassert>
+
+int main()
+{   
+    deque<int, 3> d{};
+    deque<int, 3> const& c{d};
+
+    assert(d.size() == 0);
+    assert(c.size() == 0);
+
+    try
+    {
+        d.pop_back();
+        assert(false);
+    }
+    catch (...) { }
+
+    try
+    {
+        d.pop_front();
+        assert(false);
+    }
+    catch (...) { }
+
+    try
+    {
+        d.at(0);
+        assert(false);
+    }
+    catch (...) { }
+    
+    d.push_back(1);
+    
+    assert(d.size() == 1);
+    assert(d.at(0) == 1);
+    assert(d[0] == 1);
+    assert(c.at(0) == 1);
+    assert(c[0] == 1);
+
+    int* ptr1 {&d[0]};
+    
+    d.push_back(3);
+    d.push_back(5);
+    d.push_back(2);
+
+    int* ptr2 {&d[3]};
+    
+    assert(d.size() == 4);
+    assert(d[0] == 1);
+    assert(d[1] == 3);
+    assert(d[2] == 5);
+    assert(d[3] == 2);
+    
+    d.push_front(7);
+    assert(d[0] == 7);
+    assert(d[1] == 1);
+    assert(d[2] == 3);
+    assert(d[3] == 5);
+    assert(d[4] == 2);
+
+    d.push_front(12);
+    assert(d[0] == 12);
+    assert(d[1] == 7);
+    assert(d[2] == 1);
+    assert(d[3] == 3);
+    assert(d[4] == 5);
+    assert(d[5] == 2);
+
+    d.push_front(-5);
+    assert(d[0] == -5);
+    assert(d[1] == 12);
+    assert(d[2] == 7);
+    assert(d[3] == 1);
+    assert(d[4] == 3);
+    assert(d[5] == 5);
+    assert(d[6] == 2);
+
+    d.push_back(-99);
+    assert(d[0] == -5);
+    assert(d[1] == 12);
+    assert(d[2] == 7);
+    assert(d[3] == 1);
+    assert(d[4] == 3);
+    assert(d[5] == 5);
+    assert(d[6] == 2);
+    assert(d[7] == -99);
+
+    assert(d.size() == 8);
+
+    {
+        auto cpy {d};
+        
+        cpy.pop_front();
+        assert(cpy[0] == 12);
+        assert(cpy[1] == 7);
+        assert(cpy[2] == 1);
+        assert(cpy[3] == 3);
+        assert(cpy[4] == 5);
+        assert(cpy[5] == 2);
+        assert(cpy[6] == -99);
+        assert(cpy.size() == 7);
+
+        cpy.pop_front();
+        assert(cpy[0] == 7);
+        assert(cpy[1] == 1);
+        assert(cpy[2] == 3);
+        assert(cpy[3] == 5);
+        assert(cpy[4] == 2);
+        assert(cpy[5] == -99);
+        assert(cpy.size() == 6);
+
+        cpy.pop_front();
+        assert(cpy[0] == 1);
+        assert(cpy[1] == 3);
+        assert(cpy[2] == 5);
+        assert(cpy[3] == 2);
+        assert(cpy[4] == -99);
+        assert(cpy.size() == 5);
+
+        cpy.pop_front();
+        assert(cpy[0] == 3);
+        assert(cpy[1] == 5);
+        assert(cpy[2] == 2);
+        assert(cpy[3] == -99);
+        assert(cpy.size() == 4);
+
+        cpy.pop_front();
+        assert(cpy[0] == 5);
+        assert(cpy[1] == 2);
+        assert(cpy[2] == -99);
+        assert(cpy.size() == 3);
+
+        cpy.pop_front();
+        assert(cpy[0] == 2);
+        assert(cpy[1] == -99);
+        assert(cpy.size() == 2);
+
+        cpy.pop_front();
+        assert(cpy[0] == -99);
+        assert(cpy.size() == 1);
+
+        cpy.pop_front();
+        assert(cpy.size() == 0);
+    }
+
+    {
+        auto cpy {d};
+
+        cpy.pop_back();
+        assert(cpy[0] == -5);
+        assert(cpy[1] == 12);
+        assert(cpy[2] == 7);
+        assert(cpy[3] == 1);
+        assert(cpy[4] == 3);
+        assert(cpy[5] == 5);
+        assert(cpy[6] == 2);
+        assert(cpy.size() == 7);
+
+        cpy.pop_back();
+        assert(cpy[0] == -5);
+        assert(cpy[1] == 12);
+        assert(cpy[2] == 7);
+        assert(cpy[3] == 1);
+        assert(cpy[4] == 3);
+        assert(cpy[5] == 5);
+        assert(cpy.size() == 6);
+
+        cpy.pop_back();
+        assert(cpy[0] == -5);
+        assert(cpy[1] == 12);
+        assert(cpy[2] == 7);
+        assert(cpy[3] == 1);
+        assert(cpy[4] == 3);
+        assert(cpy.size() == 5);
+
+        cpy.pop_back();
+        assert(cpy[0] == -5);
+        assert(cpy[1] == 12);
+        assert(cpy[2] == 7);
+        assert(cpy[3] == 1);
+        assert(cpy.size() == 4);
+
+        cpy.pop_back();
+        assert(cpy[0] == -5);
+        assert(cpy[1] == 12);
+        assert(cpy[2] == 7);
+        assert(cpy.size() == 3);
+
+        cpy.pop_back();
+        assert(cpy[0] == -5);
+        assert(cpy[1] == 12);
+        assert(cpy.size() == 2);
+
+        cpy.pop_back();
+        assert(cpy[0] == -5);
+        assert(cpy.size() == 1);
+
+        cpy.pop_back();
+        assert(cpy.size() == 0);
+    }
+
+    assert(*ptr1 == 1);
+    assert(*ptr2 == 2);
+}
\ No newline at end of file
diff --git a/seminar7/deque.h b/seminar7/deque.h
new file mode 100644
index 0000000..814f355
--- /dev/null
+++ b/seminar7/deque.h
@@ -0,0 +1,38 @@
+#pragma once
+
+template <typename T, unsigned chunk_size>
+class deque
+{
+private:
+    unsigned begin{};
+    unsigned data_size{10};
+    T **data = new T*[data_size] {};
+    unsigned size_internal{0};
+    unsigned chunks{1};
+
+public:
+    deque();
+    deque(deque const&);
+    deque(deque&&);
+    ~deque();
+    void push_front(T v);
+    void push_back(T v);
+    T pop_front();
+    T pop_back();
+    T& operator[](unsigned index) const;
+    T& at(unsigned index) const;
+    unsigned size() const;
+    deque& operator=(deque const&);
+    deque& operator=(deque&&);
+
+};
+/*
+
+data => |     0 | <= begin
+        | 1 2 3 |
+        |       |
+
+
+data[0][begin]
+*/
+#include "deque.tcc"
diff --git a/seminar7/deque.tcc b/seminar7/deque.tcc
new file mode 100644
index 0000000..ffa5131
--- /dev/null
+++ b/seminar7/deque.tcc
@@ -0,0 +1,173 @@
+#pragma once
+#include <algorithm>
+#include <stdexcept>
+
+template <typename T, unsigned chunk_size>
+deque<T, chunk_size>::deque()
+{
+    data[0] = new T[chunk_size]{};
+};
+
+template <typename T, unsigned chunk_size>
+deque<T, chunk_size>::~deque()
+{
+    std::for_each(data, data + chunks, [](T *&chunk)
+                  { delete[] chunk; });
+
+    delete[] data;
+};
+
+template <typename T, unsigned chunk_size>
+deque<T, chunk_size>::deque(deque const& other)
+{
+    data[0] = new T[chunk_size]{};
+    *this = other;
+};
+
+template <typename T, unsigned chunk_size>
+deque<T, chunk_size>& deque<T, chunk_size>::operator=(deque const& other)
+{
+    for (unsigned i = 0; i < other.size(); i++)
+    {
+        push_back(other[i]);
+    }
+    return *this;
+};
+
+template <typename T, unsigned chunk_size>
+deque<T, chunk_size>::deque(deque &&other)
+{
+    *this = std::move(other);
+};
+
+template <typename T, unsigned chunk_size>
+deque<T, chunk_size>& deque<T, chunk_size>::operator=(deque &&other)
+{
+    std::swap(data, other.data);
+    std::swap(data_size, other.data_size);
+    std::swap(chunks, other.chunks);
+    std::swap(size_internal, other.size_internal);
+    std::swap(begin, other.begin);
+    return *this;
+};
+
+template <typename T, unsigned chunk_size>
+void deque<T, chunk_size>::push_front(T v)
+{
+    if (begin == 0)
+    {
+        if (chunks == data_size)
+        {
+            data_size *= 2;
+            T **tmp = new T *[data_size] {};
+            std::copy(data, data + chunks, tmp + 1);
+            delete[] data;
+            data = tmp;
+        }
+        else
+        {
+            std::rotate(data, data + data_size - 1, data + data_size);
+        }
+        data[0] = new T[chunk_size]{};
+        chunks++;
+        begin = chunk_size;
+    }
+    begin--;
+    data[0][begin] = v;
+    size_internal++;
+}
+
+template <typename T, unsigned chunk_size>
+void deque<T, chunk_size>::push_back(T v)
+{
+    // Find last used index
+    unsigned end_index = (begin + size_internal) - chunk_size * (chunks - 1);
+    if (end_index == chunk_size)
+    {
+        if (chunks == data_size)
+        {
+            data_size *= 2;
+            T **tmp = new T *[data_size] {};
+            // std::copy(std::begin(data), std::end(data), std::begin(tmp));
+            std::copy(data, data + chunks, tmp);
+            delete[] data;
+            data = tmp;
+        }
+        data[chunks++] = new T[chunk_size]{};
+        // Advance to next chunk
+        end_index = 0;
+    }
+    data[chunks - 1][end_index] = v;
+    size_internal++;
+}
+
+template <typename T, unsigned chunk_size>
+T deque<T, chunk_size>::pop_front()
+{
+    if (size_internal == 0)
+    {
+        throw std::runtime_error{"hello"};
+    }
+    T popped_v = std::move(data[0][begin++]);
+    if (begin == chunk_size)
+    {
+        delete[] data[0];
+        // Left rotate
+        // std::rotate(std::begin(data), std::begin(data) + 1, std::end(data));
+        std::rotate(data, data + 1, data + data_size);
+        begin = 0;
+    }
+    size_internal--;
+    return popped_v;
+}
+
+template <typename T, unsigned chunk_size>
+T deque<T, chunk_size>::pop_back()
+{
+    if (size_internal == 0)
+    {
+        throw std::runtime_error{"hello"};
+    }
+    unsigned end_index = (begin + size_internal) - chunk_size * (chunks - 1);
+    T popped_v = std::move(data[chunks - 1][--end_index]);
+    if (end_index == 0)
+    {
+        delete[] data[--chunks];
+    }
+
+    size_internal--;
+    return popped_v;
+}
+
+template <typename T, unsigned chunk_size>
+T &deque<T, chunk_size>::operator[](unsigned index) const
+{
+    if (index >= size_internal)
+    {
+        throw std::runtime_error{"hello"};
+    }
+    unsigned chunk_index = (begin + index) % chunk_size;
+    unsigned data_index = (begin + index) / chunk_size;
+    return data[data_index][chunk_index];
+}
+
+template <typename T, unsigned chunk_size>
+T &deque<T, chunk_size>::at(unsigned index) const
+{
+    return (*this)[index];
+}
+
+template <typename T, unsigned chunk_size>
+unsigned deque<T, chunk_size>::size() const
+{
+    return size_internal;
+}
+/*
+
+data => |     0 | <= begin
+        | 1 2 3 |
+        | 4 5 6 | <= chunks
+
+
+data[0][begin]
+*/
\ No newline at end of file
diff --git a/seminar8/tests.cc b/seminar8/tests.cc
new file mode 100644
index 0000000..300a9b0
--- /dev/null
+++ b/seminar8/tests.cc
@@ -0,0 +1,93 @@
+#include <ostream>
+#include <iterator>
+#include <utility>
+#include <iostream>
+#include <vector>
+#include <map>
+#include <tuple>
+#include <array>
+#include <string>
+#include <algorithm>
+
+/* This should give the following output (or something similar at least):
+5
+{1, 2, 3}
+{(1 1), (2 2), (3 3)}
+(5 3.14)
+{hello, world}
+{{ab, c}, {def, g, hi}}
+SFINAE
+string literal
+ */
+
+void print(std::ostream &oss, char const *str)
+{
+    oss << str;
+}
+
+void print(std::ostream &oss, std::string str)
+{
+    oss << str;
+}
+
+// template <typename T>
+template <typename T, typename = std::enable_if_t<!std::is_pointer_v<T>>>
+auto print(std::ostream &oss, T t) -> decltype((oss << t), void())
+{
+    oss << t;
+}
+
+template <typename T>
+auto print(std::ostream &oss, T &t) -> decltype((*std::begin(t)), (*std::end(t)), void())
+{
+    oss << "{";
+    for (auto &&e : t)
+    {
+        print(oss, e);
+        oss << ", ";
+    }
+    oss << "}";
+}
+
+int main()
+{
+    print(std::cout, 5);
+    std::cout << std::endl;
+
+    std::vector<int> v{1, 2, 3};
+    print(std::cout, v);
+    std::cout << std::endl;
+
+    // std::map<int, int> m{{1, 1}, {2, 2}, {3, 3}};
+    // print(std::cout, m);
+    // std::cout << std::endl;
+
+    // std::tuple<int, double> t{5, 3.14};
+    // print(std::cout, t);
+    // std::cout << std::endl;
+    // int i[]{1,3,3,7};
+    // print(std::cout, i);
+    // std::cout << std::endl;
+
+    std::string s[]{"hello", "world"};
+    print(std::cout, s);
+    std::cout << std::endl;
+
+    std::array<std::vector<std::string>, 2> a{
+        std::vector<std::string>{"ab", "c"},
+        std::vector<std::string>{"def", "g", "hi"}};
+
+    print(std::cout, a);
+    std::cout << std::endl;
+
+    char const *str{"SFINAE"};
+    print(std::cout, str);
+    std::cout << std::endl;
+
+    const char literal[4] = {'a', 'b', 'c', 0};
+    print(std::cout, literal);
+    std::cout << std::endl;
+
+    print(std::cout, "string literal");
+    std::cout << std::endl;
+}
\ No newline at end of file
-- 
GitLab