diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d312a5d --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*/build/* +*.dSYM diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..a08a8f7 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,9 @@ +[submodule "course03/gtest"] + path = course03/gtest + url = git@github.com:google/googletest.git +[submodule "course03/meeting03/gtest"] + path = course03/meeting03/gtest + url = git@github.com:google/googletest.git +[submodule "course04/meeting03/gtest"] + path = course04/meeting03/gtest + url = git@github.com:google/googletest.git diff --git a/course02/homework01/Tomasz/list.h b/course02/homework01/Tomasz/list.h index eaaf001..5855725 100644 --- a/course02/homework01/Tomasz/list.h +++ b/course02/homework01/Tomasz/list.h @@ -3,6 +3,7 @@ #include #include #include +#include template class List @@ -14,63 +15,60 @@ class List T data; - Node* next; + std::unique_ptr next; Node* prev; }; -public: - class ConstIterator +public: + template + class IteratorBase : public std::iterator { protected: - ConstIterator(const List& owner, Node* node); + IteratorBase(const List* owner, Node* node); public: - using value_type = T; - using difference_type = std::ptrdiff_t; - using reference = T & ; - using pointer = T * ; - using iterator_category = std::bidirectional_iterator_tag; + iterator_type operator++(int); + iterator_type& operator++(); + iterator_type operator--(int); + iterator_type& operator--(); - ConstIterator operator++(int); - ConstIterator& operator++(); - ConstIterator operator--(int); - ConstIterator& operator--(); + iterator_value_type& operator*() const; + iterator_value_type* operator->() const; - const T& operator*() const; - const T* operator->() const; - - bool operator==(const ConstIterator& second) const; - bool operator!=(const ConstIterator& second) const; + bool operator==(const iterator_type& second) const; + bool operator!=(const iterator_type& second) const; protected: const List* mOwner; Node* mNode; + }; + class Iterator : public IteratorBase + { + protected: + Iterator(const List* owner, Node* node); friend List; }; - class MutableIterator : public ConstIterator + class ConstIterator : public IteratorBase { protected: - MutableIterator(const List& owner, Node* node); + ConstIterator(const List* owner, Node* node); + friend List; public: - MutableIterator operator++(int); - MutableIterator& operator++(); - MutableIterator operator--(int); - MutableIterator& operator--(); - - T& operator*(); - T* operator->(); - - using ConstIterator::operator*; - using ConstIterator::operator->; - - protected: - friend List; + ConstIterator(const Iterator& iter); }; using value_type = T; + using allocator_type = std::allocator; + using reference = T & ; + using const_reference = const T&; + using pointer = T * ; + using const_pointer = const T*; + using iterator = Iterator; + using const_iterator = ConstIterator; + using size_type = size_t; List(); List(const List& second); @@ -78,21 +76,21 @@ class List List& operator=(List second); - void insert(MutableIterator position, const T& value); + void insert(Iterator position, const T& value); void push_front(const T& value); void push_back(const T& value); - void erase(MutableIterator position); + void erase(Iterator position); void pop_front(); void pop_back(); void clear(); - MutableIterator begin(); + Iterator begin(); ConstIterator begin() const; ConstIterator cbegin() const; - MutableIterator end(); + Iterator end(); ConstIterator end() const; ConstIterator cend() const; @@ -115,7 +113,7 @@ class List void erase_end(); void erase_at_position(Node* node); - Node* mBegin; + std::unique_ptr mBegin; Node* mEnd; std::size_t mSize; @@ -129,108 +127,85 @@ List::Node::Node(const T& data) : { } template -List::ConstIterator::ConstIterator(const List& owner, List::Node* node) : - mOwner(&owner), +template +List::IteratorBase::IteratorBase(const List* owner, List::Node* node) : + mOwner(owner), mNode(node) { } template -List::MutableIterator::MutableIterator(const List& owner, List::Node* node) : - List::ConstIterator::ConstIterator(owner, node) +List::Iterator::Iterator(const List* owner, List::Node* node) : + List::IteratorBase::Iterator, T>::IteratorBase(owner, node) { } template -typename List::ConstIterator List::ConstIterator::operator++(int) -{ - List::ConstIterator copy = *this; - operator++(); - return copy; -} - -template -typename List::ConstIterator& List::ConstIterator::operator++() -{ - mNode = mNode ? mNode->next : mOwner->mBegin; - return *this; -} - -template -typename List::ConstIterator List::ConstIterator::operator--(int) -{ - List::ConstIterator copy = *this; - operator--(); - return copy; -} +List::ConstIterator::ConstIterator(const List* owner, List::Node* node) : + List::IteratorBase::ConstIterator, const T>::IteratorBase(owner, node) +{ } template -typename List::ConstIterator& List::ConstIterator::operator--() -{ - mNode = mNode ? mNode->prev : mOwner->mEnd; - return *this; -} +List::ConstIterator::ConstIterator(const List::Iterator& iter) : + List::IteratorBase::ConstIterator, const T>::IteratorBase(iter.mOwner, iter.mNode) +{ } template -typename List::MutableIterator List::MutableIterator::operator++(int) +template +typename iterator_type List::IteratorBase::operator++(int) { - List::MutableIterator copy = *this; + iterator_type copy(mOwner, mNode); operator++(); return copy; } template -typename List::MutableIterator& List::MutableIterator::operator++() +template +typename iterator_type& List::IteratorBase::operator++() { - mNode = mNode ? mNode->next : mOwner->mBegin; - return *this; + mNode = mNode ? mNode->next.get() : mOwner->mBegin.get(); + return static_cast(*this); } template -typename List::MutableIterator List::MutableIterator::operator--(int) +template +typename iterator_type List::IteratorBase::operator--(int) { - List::MutableIterator copy = *this; + iterator_type copy(mOwner, mNode); operator--(); return copy; } template -typename List::MutableIterator& List::MutableIterator::operator--() +template +typename iterator_type& List::IteratorBase::operator--() { mNode = mNode ? mNode->prev : mOwner->mEnd; - return *this; -} - -template -const T& List::ConstIterator::operator*() const -{ - return mNode->data; -} - -template -const T* List::ConstIterator::operator->() const -{ - return &(mNode->data); + return static_cast(*this); } template -T& List::MutableIterator::operator*() +template +iterator_value_type& List::IteratorBase::operator*() const { return mNode->data; } template -T* List::MutableIterator::operator->() +template +iterator_value_type* List::IteratorBase::operator->() const { return &(mNode->data); } template -bool List::ConstIterator::operator==(const List::ConstIterator& second) const +template +bool List::IteratorBase::operator==(const iterator_type& second) const { return mNode == second.mNode; } template -bool List::ConstIterator::operator!=(const List::ConstIterator& second) const +template +bool List::IteratorBase::operator!=(const iterator_type& second) const { return mNode != second.mNode; } @@ -269,13 +244,13 @@ List& List::operator=(List second) } template -void List::insert(List::MutableIterator position, const T& value) +void List::insert(List::Iterator position, const T& value) { assert(position.mOwner == this); if (mSize == 0) insert_first(value); - else if (position.mNode == mBegin) + else if (position.mNode == mBegin.get()) insert_begin(value); else if (position.mNode == nullptr) insert_end(value); @@ -302,13 +277,13 @@ void List::push_back(const T& value) } template -void List::erase(List::MutableIterator position) +void List::erase(List::Iterator position) { assert(position.mOwner == this); if (mSize == 1) erase_last(); - else if (position.mNode == mBegin) + else if (position.mNode == mBegin.get()) erase_begin(); else if (position.mNode == mEnd) erase_end(); @@ -342,39 +317,39 @@ void List::clear() } template -typename List::MutableIterator List::begin() +typename List::Iterator List::begin() { - return List::MutableIterator(*this, mBegin); + return List::Iterator(this, mBegin.get()); } template typename List::ConstIterator List::begin() const { - return typename List::ConstIterator(*this, mBegin); + return cbegin(); } template typename List::ConstIterator List::cbegin() const { - return typename List::ConstIterator(*this, mBegin); + return List::ConstIterator(this, mBegin.get()); } template -typename List::MutableIterator List::end() +typename List::Iterator List::end() { - return List::MutableIterator(*this, nullptr); + return List::Iterator(this, nullptr); } template typename List::ConstIterator List::end() const { - return typename List::ConstIterator(*this, nullptr); + return cend(); } template typename List::ConstIterator List::cend() const { - return typename List::ConstIterator(*this, nullptr); + return List::ConstIterator(this, nullptr); } template @@ -426,9 +401,8 @@ void List::insert_first(const T& value) { assert(mSize == 0); - auto node = new List::Node(value); - - mBegin = mEnd = node; + mBegin = std::make_unique::Node>(value); + mEnd = mBegin.get(); mSize++; } @@ -439,11 +413,11 @@ void List::insert_begin(const T& value) assert(mSize > 0); assert(mBegin != nullptr); - auto node = new List::Node(value); + auto node = std::make_unique::Node>(value); - node->next = mBegin; - mBegin->prev = node; - mBegin = node; + node->next = std::move(mBegin); + node->next->prev = node.get(); + mBegin = std::move(node); mSize++; } @@ -454,11 +428,9 @@ void List::insert_end(const T& value) assert(mSize > 0); assert(mEnd != nullptr); - auto node = new List::Node(value); - - node->prev = mEnd; - mEnd->next = node; - mEnd = node; + mEnd->next = std::make_unique::Node>(value); + mEnd->next->prev = mEnd; + mEnd = mEnd->next.get(); mSize++; } @@ -470,12 +442,12 @@ void List::insert_before_position(const T& value, List::Node* position) assert(position != nullptr); assert(position->prev != nullptr); - auto node = new List::Node(value); + auto node = std::make_unique::Node>(value); - node->next = position; + node->next = std::move(position->prev->next); node->prev = position->prev; - node->next->prev = node; - node->prev->next = node; + node->next->prev = node.get(); + node->prev->next = std::move(node); mSize++; } @@ -483,11 +455,8 @@ void List::insert_before_position(const T& value, List::Node* position) template void List::erase_last() { - assert(mSize == 1); - - delete mBegin; - - mBegin = mEnd = nullptr; + mBegin = nullptr; + mEnd = nullptr; mSize--; } @@ -498,13 +467,9 @@ void List::erase_begin() assert(mSize > 1); assert(mBegin != nullptr); - auto node = mBegin; - - mBegin = mBegin->next; + mBegin = std::move(mBegin->next); mBegin->prev = nullptr; - delete node; - mSize--; } @@ -514,13 +479,9 @@ void List::erase_end() assert(mSize > 0); assert(mEnd != nullptr); - auto node = mEnd; - mEnd = mEnd->prev; mEnd->next = nullptr; - delete node; - mSize--; } @@ -533,7 +494,7 @@ void List::erase_at_position(List::Node* node) assert(position != mEnd); node->next->prev = node->prev; - node->pred->next = node->next; + node->prev->next = std::move(node->next); delete node; diff --git a/course02/homework01/Tomasz/main.cc b/course02/homework01/Tomasz/main.cc index ffbda40..21c60ac 100644 --- a/course02/homework01/Tomasz/main.cc +++ b/course02/homework01/Tomasz/main.cc @@ -3,6 +3,7 @@ #include #include #include +#include struct TestDisposableClass { @@ -272,7 +273,7 @@ void copy_constructor_test() List b = a; a.insert(--a.end(), 10); - + auto iterA = a.begin(); assert(a.size() == 5); @@ -303,7 +304,7 @@ void assign_operator_test() a.push_back(4); List b; - + b = a; a.insert(--a.end(), 10); @@ -385,6 +386,75 @@ void call_test() assert(sum == 10); } +void max_test() +{ + List a; + + a.push_back(3); + a.push_back(1); + a.push_back(5); + a.push_back(4); + a.push_back(2); + + auto max = std::max_element(a.begin(), a.end()); + + assert(*max == 5); +} + +void count_test() +{ + List a; + + a.push_back(3); + a.push_back(1); + a.push_back(5); + a.push_back(4); + a.push_back(2); + + auto count = std::count_if(a.begin(), a.end(), [](int a) {return a >= 3; }); + + assert(count == 3); +} + +void remove_test() +{ + List a; + + a.push_back(3); + a.push_back(1); + a.push_back(5); + a.push_back(4); + a.push_back(2); + + auto end = std::remove_if(a.begin(), a.end(), [](int a) {return a >= 3; }); + + for (auto iter = a.begin(); iter != end; iter++) + assert(*iter < 3); +} + +void reverse_test() +{ + List a; + + a.push_back(1); + a.push_back(2); + a.push_back(3); + a.push_back(4); + a.push_back(5); + a.push_back(6); + + std::reverse(++a.begin(), --a.end()); + + auto iter = a.begin(); + + assert(*(iter++) == 1); + assert(*(iter++) == 5); + assert(*(iter++) == 4); + assert(*(iter++) == 3); + assert(*(iter++) == 2); + assert(*(iter++) == 6); +} + int main() { test_empty(); @@ -405,4 +475,8 @@ int main() const_iterator_test(); mutation_test(); call_test(); + max_test(); + count_test(); + remove_test(); + reverse_test(); } diff --git a/course02/homework01/danielellis/linkedlist.cc b/course02/homework01/danielellis/linkedlist.cc index ff2ac35..2347609 100644 --- a/course02/homework01/danielellis/linkedlist.cc +++ b/course02/homework01/danielellis/linkedlist.cc @@ -2,6 +2,34 @@ #include +Iterator::Iterator(LinkedListNode* lln) : mCurrentNode(lln) +{ +} + +Iterator::Iterator() : mCurrentNode(nullptr) +{ +} + +Iterator Iterator::operator++() +{ + mCurrentNode = mCurrentNode->mNext.get(); +} + +int& Iterator::operator*() +{ + return mCurrentNode->mPayload; +} + +bool Iterator::operator==(const Iterator& rhs) +{ + return (this->mCurrentNode == rhs.mCurrentNode); +} + +bool Iterator::operator!=(const Iterator& rhs) +{ + return !(*this == rhs); +} + LinkedList::LinkedList() : mSize(0) { } @@ -11,12 +39,12 @@ LinkedList::LinkedList(const LinkedList& ll) mSize = ll.Size(); if (mSize > 0) { - mStart.reset(new LinkedListNode(*ll.mStart)); + mStart = std::make_unique(*ll.mStart); LinkedListNode* ourNode = mStart.get(); LinkedListNode* theirNode = ll.mStart.get(); for (int i = 0; i < mSize - 1; ++i) { - ourNode->mNext.reset(new LinkedListNode(*(theirNode->mNext))); + ourNode->mNext = std::make_unique(*(theirNode->mNext)); ourNode = ourNode->mNext.get(); theirNode = theirNode->mNext.get(); } @@ -72,17 +100,27 @@ void LinkedList::Append(int payload) { if (Size() == 0) { - mStart.reset(new LinkedListNode(payload)); + mStart = std::make_unique(payload); mEnd = mStart.get(); } else { - mEnd->mNext.reset(new LinkedListNode(payload)); + mEnd->mNext = std::make_unique(payload); mEnd = mEnd->mNext.get(); } mSize++; } +Iterator LinkedList::Begin() +{ + return Iterator(mStart.get()); +} + +Iterator LinkedList::End() +{ + return Iterator(); +} + LinkedListNode::LinkedListNode(int payload) { mPayload = payload; diff --git a/course02/homework01/danielellis/linkedlist.h b/course02/homework01/danielellis/linkedlist.h index bb607f6..6d3c065 100644 --- a/course02/homework01/danielellis/linkedlist.h +++ b/course02/homework01/danielellis/linkedlist.h @@ -1,11 +1,12 @@ #pragma once #include +#include class LinkedListNode { public: - LinkedListNode() = default; + LinkedListNode() = delete; LinkedListNode(const LinkedListNode& lln); LinkedListNode(int payload); @@ -16,6 +17,21 @@ class LinkedListNode int mPayload; }; +class Iterator : public std::iterator +{ +public: + Iterator(); + Iterator(LinkedListNode* lln); + + int& operator*(); + Iterator operator++(); + bool operator==(const Iterator& other); + bool operator!=(const Iterator& other); + +private: + LinkedListNode* mCurrentNode; +}; + class LinkedList { public: @@ -25,6 +41,8 @@ class LinkedList int& At(int position); int At(int position) const; void Append(int payload); + Iterator Begin(); + Iterator End(); LinkedList& swap(LinkedList& ll); LinkedList& operator=(LinkedList ll); diff --git a/course02/homework01/danielellis/main.cc b/course02/homework01/danielellis/main.cc index c8ef882..88b8534 100644 --- a/course02/homework01/danielellis/main.cc +++ b/course02/homework01/danielellis/main.cc @@ -2,6 +2,23 @@ #include +int IteratorTest() +{ + LinkedList l; + + for (int i = 0; i < 100; ++i) + { + l.Append(i); + } + + int counter = 0; + for (Iterator iter = l.Begin(); iter != l.End(); ++iter) + { + assert(*iter == counter); + counter++; + } +} + int main() { #ifdef NDEBUG @@ -42,5 +59,11 @@ int main() l3.At(3) = 666; assert(l.At(3) == 2); + + IteratorTest(); + + + + return 0; } diff --git a/course02/homework01/dovile/CMakeLists.txt b/course02/homework01/dovile/CMakeLists.txt index 3ee4fc5..fd202d0 100644 --- a/course02/homework01/dovile/CMakeLists.txt +++ b/course02/homework01/dovile/CMakeLists.txt @@ -1,10 +1,10 @@ -cmake_minimum_required(VERSION 2.8) - -set(sources - main.cc - linked_list.h - linked_list.cc -) - -add_executable(main ${sources}) - +cmake_minimum_required(VERSION 2.8) + +set(sources + main.cc + linked_list.h + linked_list.tpp +) + +add_executable(main ${sources}) + diff --git a/course02/homework01/dovile/linked_list.cc b/course02/homework01/dovile/linked_list.cc index d0daef8..3ee02de 100644 --- a/course02/homework01/dovile/linked_list.cc +++ b/course02/homework01/dovile/linked_list.cc @@ -1,109 +1,85 @@ -#include "linked_list.h" -#include - -using Node = LinkedList::Node; - -LinkedList::LinkedList() -{ -} - -LinkedList::~LinkedList() -{ - clear(); -} - -void LinkedList::Insert(int key) -{ - Node* node = new Node; - node->data = key; - - if (mHead) - { - mTail->next = node; - mTail = mTail->next; - } - else - { - mHead = node; - mTail = node; - } - ++mSize; -#ifndef NDEBUG - cout << "Inserted node: " << node->data << endl; -#endif // !NDEBUG -} - -void LinkedList::Remove(int key) -{ - Node* current = mHead; - Node* previous = nullptr; - while (current) - { - if (current->data == key) - { - if (current == mHead) - { - mHead = mHead->next; - } - else - { - previous->next = current->next; - } - --mSize; -#ifndef NDEBUG - cout << "Removed node: " << current->data << endl; -#endif // !NDEBUG - delete current; - return; - } - previous = current; - current = current->next; - } - throw LinkedListError("Element was not found"); -} - -Node* LinkedList::Find(int key) -{ - Node* node = mHead; - while (node) - { - if (node->data == key) - { - return node; - } - node = node->next; - } - return End(); -} - -const Node* LinkedList::End() const -{ - return mTail; -} - -bool LinkedList::Empty() const -{ - return mSize == 0; -} - -std::size_t LinkedList::Size() const -{ - return mSize; -} - -void LinkedList::clear() -{ - Node* node = mHead; - while (node) - { - Node* nodeToDelete = node; - node = node->next; - -#ifndef NDEBUG - cout << "Deleting node: " << nodeToDelete->data << endl; -#endif // !NDEBUG - delete nodeToDelete; - } -} - - +#include "linked_list.h" + +template +void LinkedList::PushBack(T key) +{ + auto newNode = std::make_unique>(key); + + if (mHead) + { + Node* node = mHead.get(); + while (node->mNext) + { + node = node->mNext.get(); + } + node->mNext = std::move(newNode); + } + else + { + mHead = std::move(newNode); + } + ++mSize; +} + +template +void LinkedList::EraseAt(int position) +{ + if (position >= 0 && position < Size()) + { + Node* current = mHead.get(); + Node* previous = current; + while (position > 0) + { + previous = current; + current = current->mNext.get(); + --position; + } + previous->mNext = std::move(current->mNext); + --mSize; + } + else + { + throw std::out_of_range("Cannot erase element"); + } +} + +template +T& LinkedList::At(int position) const +{ + if (position < Size()) + { + auto* node = mHead.get(); + while (position > 0) + { + node = node->mNext.get(); + --position; + } + return node->mData; + } + else + { + throw std::out_of_range("Could not find the element"); + } +} + +template +std::size_t LinkedList::Size() const +{ + return mSize; +} + +template +bool LinkedList::Empty() const +{ + return Size() == 0; +} + +template +void LinkedList::Clear() +{ + mSize = 0; + mHead.reset(); +} + + + diff --git a/course02/homework01/dovile/linked_list.h b/course02/homework01/dovile/linked_list.h index cd1ca98..132dad3 100644 --- a/course02/homework01/dovile/linked_list.h +++ b/course02/homework01/dovile/linked_list.h @@ -1,70 +1,94 @@ -#include - -using namespace std; - -class LinkedList -{ - -public: - LinkedList(); - ~LinkedList(); - - struct Node - { - Node* next{ nullptr }; - int data; - }; - - void Insert(int key); - void Remove(int key); - Node* Find(int key); - const Node* End() const; - std::size_t Size() const; - bool Empty() const; - - friend ostream &operator<<(ostream&, LinkedList&); - -private: - - void clear(); - Node* find_previous(int k); - - Node* mHead{ nullptr }; - Node* mTail{ nullptr }; - std::size_t mSize = 0; -}; - -inline ostream &operator<<(ostream &output, LinkedList& linkedList) { - - LinkedList::Node* node = new LinkedList::Node; - - if (linkedList.mHead) - { - output << "LinkedList content:" << endl; - for (node = linkedList.mHead; node != 0; node = node->next) - { - output << node->data << endl; - } - } - else - { - output << "LinkedList is empty" << endl; - } - - return output; -} - -struct LinkedListError : public std::exception -{ - LinkedListError(const char* description) : - mDescription(description) - { - } - - const char* what() const throw () - { - return mDescription; - } - - const char* mDescription; -}; +#pragma once + +#include +#include + +template +struct Node +{ + explicit Node(T data) : + mData(data) {} + + std::unique_ptr> mNext; + T mData; +}; + +template +class NodeIterator : std::iterator +{ +public: + explicit NodeIterator(Node* node) + : mNode(node) {} + + NodeIterator& operator=(Node node) + { + this->mNode = node; + return *this; + } + + NodeIterator& operator++() + { + if (mNode) + mNode = mNode->mNext.get(); + + return *this; + } + + bool operator!=(const NodeIterator& iterator) + { + return mNode != iterator.mNode; + } + + T operator*() + { + return mNode->mData; + } + +private: + Node* mNode; +}; + + +template +class LinkedList +{ + using NodePointer = typename std::unique_ptr>; + typedef NodeIterator iterator; + +public: + void PushBack(T key); + void EraseAt(int position); + T& At(int position) const; + std::size_t Size() const; + bool Empty() const; + void Clear(); + iterator begin() { return iterator(mHead.get()); } + iterator end() { return iterator(nullptr); } + + template + friend std::ostream &operator<<(std::ostream&, LinkedList&); + +private: + NodePointer mHead; + std::size_t mSize = 0; +}; + +template +inline std::ostream &operator<<(std::ostream &output, LinkedList& linkedList) { + + if (linkedList.mHead) + { + auto* node = linkedList.mHead.get(); + output << "LinkedList content:\n"; + while (node) + { + output << node->mData << std::endl; + node = node->mNext.get(); + } + } + else + { + output << "LinkedList is empty."; + } + return output; +} diff --git a/course02/homework01/dovile/linked_list.tpp b/course02/homework01/dovile/linked_list.tpp new file mode 100644 index 0000000..5a6e7a9 --- /dev/null +++ b/course02/homework01/dovile/linked_list.tpp @@ -0,0 +1,82 @@ +#include "linked_list.h" + +template +void LinkedList::PushBack(T key) +{ + auto newNode = std::make_unique>(key); + + if (mHead) + { + Node* node = mHead.get(); + while (node->mNext) + { + node = node->mNext.get(); + } + node->mNext = std::move(newNode); + } + else + { + mHead = std::move(newNode); + } + ++mSize; +} + +template +void LinkedList::EraseAt(int position) +{ + if (position >= 0 && position < Size()) + { + Node* current = mHead.get(); + Node* previous = current; + while (position > 0) + { + previous = current; + current = current->mNext.get(); + --position; + } + previous->mNext = std::move(current->mNext); + --mSize; + } + else + { + throw std::out_of_range("Cannot erase element"); + } +} + +template +T& LinkedList::At(int position) const +{ + if (position < Size()) + { + auto* node = mHead.get(); + while (position > 0) + { + node = node->mNext.get(); + --position; + } + return node->mData; + } + else + { + throw std::out_of_range("Could not find the element"); + } +} + +template +std::size_t LinkedList::Size() const +{ + return mSize; +} + +template +bool LinkedList::Empty() const +{ + return Size() == 0; +} + +template +void LinkedList::Clear() +{ + mSize = 0; + mHead.reset(); +} diff --git a/course02/homework01/dovile/main.cc b/course02/homework01/dovile/main.cc index cdc9989..f1bf041 100644 --- a/course02/homework01/dovile/main.cc +++ b/course02/homework01/dovile/main.cc @@ -1,50 +1,123 @@ -#include "linked_list.h" -#include - -using namespace std; -int main() -{ -#ifdef NDEBUG -#error Compile the code in debug mode! -#endif - - LinkedList v; - bool catchedError = false; - - assert(v.Empty()); - - v.Insert(5); - v.Insert(2); - v.Insert(7); - - assert(v.Size() == 3); - assert(!v.Empty()); - - auto* node = v.Find(5); - assert(node->data == 5); - - v.Remove(2); - assert(v.Size() == 2); - - try - { - v.Remove(2); - } - catch(LinkedListError&) - { - catchedError = true; - } - assert(catchedError); - - node = v.Find(2); - assert(node == v.End()); - - cout << v << endl; - - v.Remove(5); - v.Remove(7); - - cout << v << endl; - - return 0; -} +#include "linked_list.tpp" +#include + +void test_push_back() +{ + LinkedList linkedList; + + linkedList.PushBack(0); + + assert(!linkedList.Empty()); + assert(linkedList.Size() == 1); +} + +void test_erase_at() +{ + LinkedList linkedList; + + linkedList.PushBack(0); + linkedList.PushBack(1); + linkedList.PushBack(2); + + linkedList.EraseAt(1); + + assert(linkedList.Size() == 2); +} + +void test_erase_at_bad() +{ + LinkedList linkedList; + + bool catchedError = false; + try + { + linkedList.EraseAt(0); + } + catch(std::exception&) + { + catchedError = true; + } + + assert(catchedError); +} + +void test_get_at() +{ + LinkedList linkedList; + + linkedList.PushBack(0); + linkedList.PushBack(1); + + auto& value = linkedList.At(0); + assert(value == 0); +} + +void test_get_at_bad() +{ + LinkedList linkedList; + + bool catchedError = false; + try + { + linkedList.At(0); + } + catch (std::exception&) + { + catchedError = true; + } + + assert(catchedError); +} + +void test_print_linked_list() +{ + LinkedList linkedList; + + linkedList.PushBack(5); + linkedList.PushBack(2); + linkedList.PushBack(7); + + std::cout << linkedList << std::endl; +} + +void test_iterator() +{ + LinkedList linkedList; + + linkedList.PushBack(1); + linkedList.PushBack(2); + linkedList.PushBack(3); + + int expectedValue = 1; + for (auto value : linkedList) + { + assert(value == expectedValue); + ++expectedValue; + } + + // test derefernece operator + expectedValue = 1; + for (auto it = linkedList.begin(); it != linkedList.end(); ++it) + { + assert(*it == expectedValue); + ++expectedValue; + } + +} + +int main() +{ +#ifdef NDEBUG +#error Compile the code in debug mode! +#endif + + test_push_back(); + test_erase_at(); + test_erase_at_bad(); + test_get_at(); + test_get_at_bad(); + test_print_linked_list(); + test_iterator(); + + return 0; +} diff --git a/course02/homework01/gavin/list.cpp b/course02/homework01/gavin/list.cpp index 0816ab6..68209e1 100644 --- a/course02/homework01/gavin/list.cpp +++ b/course02/homework01/gavin/list.cpp @@ -1,27 +1,29 @@ -#include +#include "list.h" #include -#include "list.h" - void List::clear() { - std::unique_ptr newList; - mFirst = std::move(newList); + mFirst.reset(); mSize = 0; } void List::insert(std::size_t pos, int data) { - if(pos == 0) + auto newElement = std::make_shared(data); + auto next = pos == size() ? nullptr : at(pos); + auto prev = pos == 0 ? nullptr : at(pos-1); + + if(next) { - push_front(data); - return; + newElement->mNext = next; + next->mPrevious = newElement; } - if(pos == size()) + if(prev) { - push_back(data); - return; + newElement->mPrevious = prev; + prev->mNext = newElement; } +<<<<<<< HEAD auto new_element = std::make_shared(data); auto next = at(pos); auto prev = next->mPrevious; @@ -30,10 +32,16 @@ void List::insert(std::size_t pos, int data) new_element->mNext = next; new_element->mPrevious = prev; +======= + if(pos == 0) + mFirst = newElement; + if(pos == size()) + mHead = newElement; +>>>>>>> gavin/master mSize++; } -std::shared_ptr List::at(std::size_t pos) const +std::shared_ptr List::at(std::size_t pos) const { if(pos >= size()) throw std::out_of_range("Index out of range"); @@ -48,45 +56,48 @@ std::shared_ptr List::at(std::size_t pos) const void List::erase(std::size_t pos) { - if(pos == 0) + auto item = at(pos); + auto prev = item->mPrevious; + auto next = item->mNext; + if(next) { - pop_front(); - return; + next->mPrevious = prev; } - if(pos == size()-1) + if(prev) { - pop_back(); - return; + prev->mNext = next; } +<<<<<<< HEAD auto item = at(pos); auto prev = item->mPrevious; auto next = item->mNext; prev.lock()->mNext = next; next->mPrevious = prev; +======= + if(pos == 0) + mFirst = next; + if(pos == size() - 1) + mHead = prev; +>>>>>>> gavin/master mSize--; } void List::push_back(int data) { - auto new_element = std::make_shared(data); - if(!mHead) - { - mHead = new_element; - mSize++; - } - mHead->mNext = new_element; - new_element->mPrevious = mHead; - mHead = new_element; - mSize++; + insert(size(), data); } void List::pop_back() { +<<<<<<< HEAD if(!mHead) throw std::runtime_error("Cannot pop from empty list"); auto prev = mHead->mPrevious; mHead = prev.lock(); mSize--; +======= + erase(size()-1); +>>>>>>> gavin/master } std::size_t List::size() const @@ -96,28 +107,12 @@ std::size_t List::size() const void List::push_front(int data) { - std::shared_ptr new_element = std::make_shared(data); - if(mFirst) - { - new_element->mNext = mFirst; - mFirst->mPrevious = new_element; - mFirst = new_element; - }else - { - mFirst = new_element; - mHead = mFirst; - } - mSize++; + insert(0, data); } void List::pop_front() { - if(size() == 0) - throw std::out_of_range("cannot pop from an empty list"); - auto new_front = mFirst->mNext; - new_front->mPrevious.reset(); - mFirst = new_front; - mSize--; + erase(0); } int& List::get(std::size_t pos) @@ -138,6 +133,49 @@ List::List(std::initializer_list elements) List::List(const List &other) { - for(std::size_t i = 0; i < other.size(); i++) + for( std::size_t i = 0; i < other.size(); i++ ) push_back(other.get(i)); } + +List &List::operator=(List other) { + std::swap(mSize, other.mSize); + std::swap(mHead, other.mHead); + std::swap(mFirst, other.mFirst); + return *this; +} + +iterator List::begin() { + return iterator(mFirst.get()); +} + +iterator List::end() { + return iterator(nullptr); +} + +iterator& iterator::operator++() { + mItr = mItr->mNext.get(); + return *this; +} + +bool iterator::operator!=(const iterator &other) { + return mItr != other.mItr; +} + +bool iterator::operator==(const iterator &other) { + return mItr == other.mItr; +} + +iterator::iterator(const iterator &other) { + mItr = other.mItr; +} + +iterator &iterator::operator=(iterator other) { + std::swap(mItr, other.mItr); + return *this; +} + +const iterator iterator::operator++(int a) { + for(int i=0; i < a; i++) + mItr = mItr->mNext.get(); + return iterator(mItr); +} diff --git a/course02/homework01/gavin/list.h b/course02/homework01/gavin/list.h index 40d8375..eb0b485 100644 --- a/course02/homework01/gavin/list.h +++ b/course02/homework01/gavin/list.h @@ -2,23 +2,47 @@ // Created by gavin on 19/12/2018. // -#include #include -#include -struct Element +struct Node { - Element(int data) : mData(data) + explicit Node(int data) : mData(data) {} int mData{}; +<<<<<<< HEAD std::shared_ptr mNext; std::weak_ptr mPrevious; +======= + std::shared_ptr mNext; + std::shared_ptr mPrevious; +}; + +class iterator : public std::iterator +{ +public: + using value_type = int; + explicit iterator(Node* itr) : mItr(itr){} + + iterator(const iterator &other); + iterator& operator=(iterator other); + + const iterator operator++(int); + iterator& operator++(); + bool operator !=(const iterator& other); + bool operator ==(const iterator& other); + int& operator*() { return mItr->mData;}; + int* operator->() { return &mItr->mData;}; + +private: + Node *mItr; +>>>>>>> gavin/master }; class List { public: - List(){}; + List() = default; List(std::initializer_list elements); List(const List &other); + List& operator=(List other); void clear(); @@ -38,10 +62,14 @@ class List { int get(std::size_t pos) const; int& get(std::size_t pos); + + iterator begin(); + iterator end(); + private: - std::shared_ptr mFirst; - std::shared_ptr mHead = mFirst; + std::shared_ptr mFirst; + std::shared_ptr mHead = mFirst; + std::shared_ptr at(std::size_t pos) const; std::size_t mSize = 0; - std::shared_ptr at(std::size_t pos) const; }; diff --git a/course02/homework01/gavin/main.cc b/course02/homework01/gavin/main.cc index fc4a835..7d38fa6 100644 --- a/course02/homework01/gavin/main.cc +++ b/course02/homework01/gavin/main.cc @@ -4,6 +4,7 @@ #include "list.h" #include #include +#include std::vector get_elements(List& list) @@ -86,6 +87,38 @@ void test_copy() assert(get_elements(list) == get_elements(list2)); } +void test_foreach() +{ + List list{1,2,3,4,5}; + int i=0; + for(const auto n : list) + i += n; + + assert(i == 15); + list = {1,1,1,1}; + std::for_each(list.begin(), list.end(), [](int x){ + assert(x == 1); + }); +} + +void test_algorithms() +{ + List list{2,2,2,2}; + assert(std::all_of(list.begin(), list.end(), [](int x) -> int{ + return x == 2; + })); + list = {1,2,1}; + assert(std::any_of(list.begin(), list.end(), [](int x) -> int{ + return x == 2; + })); + list = {1,1,1}; + std::transform(list.begin(), list.end(), list.begin(), [](int x) -> int{ + return x+1; + }); + assert(list.get(0) == 2); + +} + int main() { test_clear(); @@ -95,4 +128,6 @@ int main() test_size(); test_erase(); test_copy(); + test_foreach(); + test_algorithms(); } \ No newline at end of file diff --git a/course02/homework01/matt/linked_list.cc b/course02/homework01/matt/linked_list.cc index fd976bd..ae1d93e 100644 --- a/course02/homework01/matt/linked_list.cc +++ b/course02/homework01/matt/linked_list.cc @@ -1,4 +1,7 @@ +// Linked List +#include + template LinkedList::LinkedList() {} @@ -28,7 +31,6 @@ void LinkedList::Append(const T& data) if(mFirst==nullptr) { mFirst = std::make_unique>(data); - std::cout << mFirst->mData << std::endl; mLast = mFirst.get(); } else @@ -40,3 +42,50 @@ void LinkedList::Append(const T& data) mSize++; } +//Linked List Iterator + +template +LinkedListIterator LinkedList::begin() +{ + return LinkedListIterator{mFirst.get()}; +} + +template +LinkedListIterator LinkedList::end() +{ + return LinkedListIterator{mLast->mNext.get()}; +} + +template +std::ostream& operator<<(std::ostream& stream, const LinkedList& list) +{ + Node* ptrNode = list.mFirst.get(); + while(ptrNode != nullptr) + { + stream << ptrNode->mData << ", "; + ptrNode = ptrNode->mNext.get(); + } + + return stream; +} + +template +LinkedListIterator::LinkedListIterator(Node* ptrNode) : mPtrNode(ptrNode){} + +template +LinkedListIterator& LinkedListIterator::operator++() +{ + mPtrNode = mPtrNode->mNext.get(); +} + +template +bool LinkedListIterator::operator !=(const LinkedListIterator& other) +{ + return mPtrNode != other.mPtrNode; +} + +template +T& LinkedListIterator::operator*() +{ + return mPtrNode->mData; +} diff --git a/course02/homework01/matt/linked_list.h b/course02/homework01/matt/linked_list.h index 4b439d5..ddec738 100644 --- a/course02/homework01/matt/linked_list.h +++ b/course02/homework01/matt/linked_list.h @@ -11,6 +11,9 @@ struct Node std::unique_ptr> mNext; }; +template +class LinkedListIterator; + template class LinkedList { @@ -24,22 +27,33 @@ class LinkedList void Append(const T& data); - friend std::ostream& operator<<(std::ostream& stream, const LinkedList& list) - { - Node* ptrNode = list.mFirst.get(); - while(ptrNode != nullptr) - { - stream << ptrNode->mData << ", "; - ptrNode = ptrNode->mNext.get(); - } - - return stream; - } + LinkedListIterator begin(); + LinkedListIterator end(); + + template + friend std::ostream& operator<<(std::ostream& stream, const LinkedList& list); private: + std::unique_ptr> mFirst; Node* mLast; int mSize {}; }; +template +class LinkedListIterator: public std::iterator +{ +public: + explicit LinkedListIterator(Node* ptrNode); + + LinkedListIterator& operator++(); + + bool operator !=(const LinkedListIterator& other); + + T& operator*(); + +private: + Node* mPtrNode; +}; + #include "linked_list.cc" diff --git a/course02/homework01/matt/test_linked_list.cc b/course02/homework01/matt/test_linked_list.cc index 96b7466..c8a90b4 100644 --- a/course02/homework01/matt/test_linked_list.cc +++ b/course02/homework01/matt/test_linked_list.cc @@ -1,5 +1,6 @@ #include #include "linked_list.h" +#include int main() { @@ -8,15 +9,23 @@ int main() l.Append(2); l.Append(3); - std::cout << "l:" << l << std::endl; + std::cout << "l: " << l << std::endl; LinkedList lCopyConstructed(l); - std::cout << "lCopyConstructed:" << lCopyConstructed << std::endl; + std::cout << "lCopyConstructed: " << lCopyConstructed << std::endl; LinkedList lAssigned; lAssigned = l; - std::cout << "lAssigned:" << lAssigned << std::endl; + std::cout << "lAssigned: " << lAssigned << std::endl; + + std::cout << "iterator: "; + for(auto i: l) + std::cout << i << ", "; + std::cout << std::endl; + + std::cout << "algorithm: "; + std::for_each(l.begin(), l.end(), [](int& i) { std::cout << i << ", " ; }); + std::cout << std::endl; return 0; } - diff --git a/course02/homework01/yun/CMakeLists.txt b/course02/homework01/yun/CMakeLists.txt new file mode 100644 index 0000000..6b4cdbb --- /dev/null +++ b/course02/homework01/yun/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 2.8) +set(CMAKE_CXX_STANDARD 14) + +set(sources + main.cc + linkedlist.h + linkedlist.cpp +) + +add_executable(main ${sources}) diff --git a/course02/homework01/yun/linkedlist.cpp b/course02/homework01/yun/linkedlist.cpp new file mode 100644 index 0000000..29a95d9 --- /dev/null +++ b/course02/homework01/yun/linkedlist.cpp @@ -0,0 +1,66 @@ +#include +#include "linkedlist.h" + + + +int LinkedListInt::size() const +{ + return mSize; +} + +void LinkedListInt::push(int value) +{ + std::unique_ptr newNodePtr = std::make_unique(); + newNodePtr->mData = value; + + newNodePtr->next = std::move(mHead); + mHead = std::move(newNodePtr); + + mSize++; +} + + +int LinkedListInt::pop_head() +{ + assert(mSize > 0); + + int head = mHead->mData; + mHead = std::move(mHead->next); + + mSize--; + return head; +} + +void LinkedListInt::clear() +{ + mSize = 0; + mHead.reset(); +} + + +LinkedListIterator LinkedListIterator::operator++() +{ + if ((*nodePtr)->next){ + nodePtr = &((*nodePtr)->next); + } else { + nodePtr = nullptr; + } + return nodePtr; +} + +LinkedListIterator LinkedListIterator::operator++(int) +{ + LinkedListIterator result(*this); + ++(*this); + return result; +} + +bool LinkedListIterator::operator==(const LinkedListIterator& other) +{ + return nodePtr == other.nodePtr; +} + +bool LinkedListIterator::operator!=(const LinkedListIterator& other) +{ + return nodePtr != other.nodePtr; +} diff --git a/course02/homework01/yun/linkedlist.h b/course02/homework01/yun/linkedlist.h new file mode 100644 index 0000000..3a5ad71 --- /dev/null +++ b/course02/homework01/yun/linkedlist.h @@ -0,0 +1,58 @@ +#pragma once +#include +#include + + +struct NodeInt +{ + NodeInt(): mData(0), next(nullptr) {} + int mData; + std::unique_ptr next; +}; + + +class LinkedListIterator +: public std::iterator +{ + friend class LinkedListInt; + +public: + int operator*() { return ((*nodePtr)->mData);} + + LinkedListIterator operator++(); + LinkedListIterator operator++(int); + + bool operator==(const LinkedListIterator& other); + + bool operator!=(const LinkedListIterator& other); + +private: + LinkedListIterator() : nodePtr(nullptr) {} + LinkedListIterator(std::unique_ptr* newNodePtr) : nodePtr(newNodePtr){} + + std::unique_ptr* nodePtr; +}; + + +class LinkedListInt +{ +public: + LinkedListInt(): mSize(0), mHead(nullptr) {} + + int size() const; + + void push(int value); + + int pop_head(); + + void clear(); + + LinkedListIterator begin() {return &mHead;} + + LinkedListIterator end() {return nullptr;} + +private: + int mSize; + + std::unique_ptr mHead; +}; diff --git a/course02/homework01/yun/main.cc b/course02/homework01/yun/main.cc new file mode 100644 index 0000000..edbe0f8 --- /dev/null +++ b/course02/homework01/yun/main.cc @@ -0,0 +1,48 @@ +#include "linkedlist.h" +#include +#include +#include +#include + + +int main() +{ +#ifdef NDEBUG +#error Compile the code in debug mode! +#endif + + LinkedListInt l; + assert(l.size() == 0); + + // for (int i = 0; i < 1000000000; i++) { + // if (i % 1000000 == 0) { + // std::cout << i << std::endl; + // } + // l.push(i); + // } + + // for (int i = 0; i < 1000000000; i++) { + // l.pop_head(); + // } + + l.push(1); + assert(l.size() == 1); + l.push(2); + assert(l.size() == 2); + int head = l.pop_head(); + assert(head == 2); + assert(l.size() == 1); + l.clear(); + assert(l.size() == 0); + + l.push(4); + l.push(100); + double sum = std::accumulate(l.begin(), l.end(), 0.0); + double mean = sum / l.size(); + double sq_sum = std::inner_product(l.begin(), l.end(), l.begin(), 0.0); + double stdev = std::sqrt(sq_sum / l.size() - mean * mean); + assert(mean == 52.0); + assert(stdev == std::sqrt(2304.0)); + + return 0; +} diff --git a/course02/homework02/Tomasz/CMakeLists.txt b/course02/homework02/Tomasz/CMakeLists.txt index 819d6f3..4f2a837 100644 --- a/course02/homework02/Tomasz/CMakeLists.txt +++ b/course02/homework02/Tomasz/CMakeLists.txt @@ -5,8 +5,7 @@ set(sources message_throttler.hpp message_throttler_interface.hpp message_throttler_commons.hpp - short_circular_buffer.hpp ) add_executable(main ${sources}) - +include_directories(${Boost_INCLUDE_DIR}) \ No newline at end of file diff --git a/course02/homework02/Tomasz/main.cc b/course02/homework02/Tomasz/main.cc index 7188366..df6631f 100644 --- a/course02/homework02/Tomasz/main.cc +++ b/course02/homework02/Tomasz/main.cc @@ -7,66 +7,13 @@ using Message = int; using UserId = std::size_t; -void buffer_empty_test() -{ - short_circular_buffer buffer; - - assert(buffer.empty()); -} - -void buffer_full_test() -{ - short_circular_buffer buffer; - - buffer.push(1); - buffer.push(2); - buffer.push(3); - buffer.push(4); - - assert(buffer.full()); - assert(buffer.front() == 1); -} - -void buffer_pop_test() -{ - short_circular_buffer buffer; - - buffer.push(1); - buffer.push(2); - buffer.push(3); - buffer.push(4); - buffer.pop(); - buffer.pop(); - - assert(!buffer.full()); - assert(buffer.front() == 3); -} - -void buffer_cycle_test() -{ - short_circular_buffer buffer; - - buffer.push(1); - buffer.push(2); - buffer.push(3); - buffer.push(4); - buffer.pop(); - buffer.pop(); - buffer.push(5); - buffer.push(6); - buffer.pop(); - buffer.pop(); - buffer.pop(); - - assert(!buffer.full()); - assert(buffer.front() == 6); -} - void throttler_test() { Message last_consumed_message = 0; - auto throttler = make_message_throttler( + auto throttler = make_message_throttler( + 4, + std::chrono::milliseconds{ 1000 }, [&](const Message& message) { last_consumed_message = message; } ); @@ -82,7 +29,9 @@ void throttler_dispose_test() Message last_consumed_message = 0; Message last_disposed_message = 0; - auto throttler = make_message_throttler( + auto throttler = make_message_throttler( + 4, + std::chrono::milliseconds{ 1000 }, [&](const Message& message) { last_consumed_message = message; }, [&](const Message& message) { last_disposed_message = message; } ); @@ -103,7 +52,9 @@ void throttler_single_interface_test() Message last_consumed_message = 0; Message last_disposed_message = 0; - auto throttler = make_message_throttler( + auto throttler = make_message_throttler( + 4, + std::chrono::milliseconds{ 1000 }, [&](const Message& message) { last_consumed_message = message; }, [&](const Message& message) { last_disposed_message = message; } ); @@ -125,7 +76,9 @@ void throttler_multiple_users_test() Message last_consumed_message = 0; Message last_disposed_message = 0; - auto throttler = make_message_throttler( + auto throttler = make_message_throttler( + 4, + std::chrono::milliseconds{ 1000 }, [&](const Message& message) { last_consumed_message = message; }, [&](const Message& message) { last_disposed_message = message; } ); @@ -147,10 +100,11 @@ void throttler_timeout_test() Message last_consumed_message = 0; Message last_disposed_message = 0; - auto throttler = make_message_throttler( + auto throttler = make_message_throttler( + 4, + std::chrono::milliseconds{ -1 }, [&](const Message& message) { last_consumed_message = message; }, - [&](const Message& message) { last_disposed_message = message; }, - [](std::chrono::microseconds now, std::chrono::microseconds timestamp) { return false; } + [&](const Message& message) { last_disposed_message = message; } ); throttler.from(1).send(1); @@ -164,40 +118,16 @@ void throttler_timeout_test() assert(last_disposed_message == 0); } -void throttler_custom_timestamper_test() -{ - std::size_t timestamp = 0; - - Message last_consumed_message = 0; - Message last_disposed_message = 0; - - auto throttler = make_message_throttler( - [&](const Message& message) { last_consumed_message = message; }, - [&](const Message& message) { last_disposed_message = message; }, - [&](std::size_t now, std::size_t timestamp) { return timestamp > 0; }, - [&]() { return timestamp++; } - ); - - throttler.from(1).send(1); - throttler.from(1).send(2); - throttler.from(1).send(3); - throttler.from(1).send(4); - throttler.from(1).send(5); - throttler.from(1).send(6); - - assert(last_consumed_message == 5); - assert(last_disposed_message == 6); -} - void throttler_chrono_test() { Message last_consumed_message = 0; Message last_disposed_message = 0; - auto throttler = make_message_throttler( + auto throttler = make_message_throttler( + 4, + std::chrono::milliseconds{ 100 }, [&](const Message& message) { last_consumed_message = message; }, - [&](const Message& message) { last_disposed_message = message; }, - chrono_timestamp_threshold{ std::chrono::milliseconds{ 100 } } + [&](const Message& message) { last_disposed_message = message; } ); throttler.from(1).send(1); @@ -225,10 +155,11 @@ void throttler_chrono_partial_test() Message last_consumed_message = 0; Message last_disposed_message = 0; - auto throttler = make_message_throttler( + auto throttler = make_message_throttler( + 4, + std::chrono::milliseconds{ 100 }, [&](const Message& message) { last_consumed_message = message; }, - [&](const Message& message) { last_disposed_message = message; }, - chrono_timestamp_threshold{ std::chrono::milliseconds{ 100 } } + [&](const Message& message) { last_disposed_message = message; } ); throttler.from(1).send(1); @@ -254,10 +185,11 @@ void throttler_chrono_full_cycle_test() Message last_consumed_message = 0; Message last_disposed_message = 0; - auto throttler = make_message_throttler( + auto throttler = make_message_throttler( + 4, + std::chrono::milliseconds{ 100 }, [&](const Message& message) { last_consumed_message = message; }, - [&](const Message& message) { last_disposed_message = message; }, - chrono_timestamp_threshold{ std::chrono::milliseconds{ 100 } } + [&](const Message& message) { last_disposed_message = message; } ); throttler.from(1).send(1); @@ -282,10 +214,11 @@ void throttler_chrono_muliple_users_test() Message last_consumed_message = 0; Message last_disposed_message = 0; - auto throttler = make_message_throttler( + auto throttler = make_message_throttler( + 4, + std::chrono::milliseconds{ 100 }, [&](const Message& message) { last_consumed_message = message; }, - [&](const Message& message) { last_disposed_message = message; }, - chrono_timestamp_threshold{ std::chrono::milliseconds{ 100 } } + [&](const Message& message) { last_disposed_message = message; } ); throttler.from(1).send(1); @@ -307,16 +240,11 @@ void throttler_chrono_muliple_users_test() int main() { - buffer_empty_test(); - buffer_full_test(); - buffer_pop_test(); - buffer_cycle_test(); throttler_test(); throttler_dispose_test(); throttler_single_interface_test(); throttler_multiple_users_test(); throttler_timeout_test(); - throttler_custom_timestamper_test(); throttler_chrono_test(); throttler_chrono_partial_test(); throttler_chrono_full_cycle_test(); diff --git a/course02/homework02/Tomasz/message_throttler.hpp b/course02/homework02/Tomasz/message_throttler.hpp index dfb2e0e..b690c24 100644 --- a/course02/homework02/Tomasz/message_throttler.hpp +++ b/course02/homework02/Tomasz/message_throttler.hpp @@ -1,49 +1,53 @@ #pragma once -#include +#include +#include + +#include "message_throttler_interface.hpp" template< typename _ClientId, typename _Message, + typename _Clock, typename _MessageConsumer, - typename _MessageDisposer, - typename _Timestamp, - typename _Timestamper, - typename _TimestampThreshold, - typename _MessageThrottlerInterface, - typename _Map + typename _MessageDisposer > class message_throttler { +private: + using _MessageThrottlerInterface = message_throttler_interface<_Message, _Clock, _MessageConsumer, _MessageDisposer>; + + using _Time = decltype(_Clock{}()); + using _Duration = decltype(_Clock{}() - _Clock{}()); + public: message_throttler( - const _MessageConsumer& messageConsumer, - const _MessageDisposer& messageDisposer, - const _Timestamper& timestamper, - const _TimestampThreshold& timestampThreshold) : + std::size_t bufferSize, + _Duration threashold, + const _MessageConsumer& messageConsumer, + const _MessageDisposer& messageDisposer) : + mBufferSize(bufferSize), + mThreashold(threashold), mMessageConsumer(messageConsumer), - mMessageDisposer(messageDisposer), - mTimestamper(timestamper), - mTimestampThreshold(timestampThreshold) + mMessageDisposer(messageDisposer) { } _MessageThrottlerInterface& from(const _ClientId& clientId) { - auto element = mClients.emplace(clientId, nullptr); - auto& client = element.first->second; + auto& client = mClients[clientId]; - if (element.second) - client = std::make_unique<_MessageThrottlerInterface>(mMessageConsumer, mMessageDisposer, mTimestamper, mTimestampThreshold); + if (client == nullptr) + client = std::make_unique<_MessageThrottlerInterface>(mBufferSize, mThreashold, mMessageConsumer, mMessageDisposer); return *client; } private: + std::size_t mBufferSize; + _Duration mThreashold; + _MessageConsumer mMessageConsumer; _MessageDisposer mMessageDisposer; - _Timestamper mTimestamper; - _TimestampThreshold mTimestampThreshold; - - _Map mClients; + std::map<_ClientId, std::unique_ptr<_MessageThrottlerInterface>> mClients; }; \ No newline at end of file diff --git a/course02/homework02/Tomasz/message_throttler_commons.hpp b/course02/homework02/Tomasz/message_throttler_commons.hpp index e992f35..c813bb8 100644 --- a/course02/homework02/Tomasz/message_throttler_commons.hpp +++ b/course02/homework02/Tomasz/message_throttler_commons.hpp @@ -3,7 +3,6 @@ #include #include -#include "short_circular_buffer.hpp" #include "message_throttler.hpp" #include "message_throttler_interface.hpp" @@ -14,21 +13,7 @@ struct message_swallower { } }; -struct chrono_timestamp_threshold -{ - chrono_timestamp_threshold(std::chrono::milliseconds milliseconds) : - milliseconds(milliseconds) - { } - - bool operator()(std::chrono::milliseconds now, std::chrono::milliseconds timestamp) - { - return (now - timestamp) < milliseconds; - } - - std::chrono::milliseconds milliseconds; -}; - -struct chrono_timestamper +struct chrono_clock { std::chrono::milliseconds operator()() { @@ -38,27 +23,21 @@ struct chrono_timestamper template< typename _ClientId, - std::size_t _BufferSize, typename _Message, - typename _Timestamp = std::chrono::milliseconds, + typename _Clock = chrono_clock, typename _MessageConsumer = message_swallower<_Message>, - typename _MessageDisposer = message_swallower<_Message>, - typename _Timestamper = chrono_timestamper, - typename _TimestampThreshold = chrono_timestamp_threshold, - typename _Buffer = short_circular_buffer<_Timestamp, _BufferSize>, - typename _MessageThrottlerInterface = message_throttler_interface<_Message, _MessageConsumer, _MessageDisposer, _Timestamp, _Timestamper, _TimestampThreshold, _Buffer>, - typename _Map = std::map<_ClientId, std::unique_ptr<_MessageThrottlerInterface>> + typename _MessageDisposer = message_swallower<_Message> > -message_throttler<_ClientId, _Message, _MessageConsumer, _MessageDisposer, _Timestamp, _Timestamper, _TimestampThreshold, _MessageThrottlerInterface, _Map> make_message_throttler( +message_throttler<_ClientId, _Message, _Clock, _MessageConsumer, _MessageDisposer> make_message_throttler( + std::size_t bufferSize, + decltype(_Clock{}() - _Clock{}()) threashold, _MessageConsumer messageConsumer = {}, - _MessageDisposer messageDisposer = {}, - _TimestampThreshold timestampThreshold = { std::chrono::milliseconds {1000} }, - _Timestamper timestamper = {} + _MessageDisposer messageDisposer = {} ) { - return message_throttler<_ClientId, _Message, _MessageConsumer, _MessageDisposer, _Timestamp, _Timestamper, _TimestampThreshold, _MessageThrottlerInterface, _Map>( + return message_throttler<_ClientId, _Message, _Clock, _MessageConsumer, _MessageDisposer>( + bufferSize, + threashold, messageConsumer, - messageDisposer, - timestamper, - timestampThreshold); + messageDisposer); } \ No newline at end of file diff --git a/course02/homework02/Tomasz/message_throttler_interface.hpp b/course02/homework02/Tomasz/message_throttler_interface.hpp index e70839f..2d4c8aa 100644 --- a/course02/homework02/Tomasz/message_throttler_interface.hpp +++ b/course02/homework02/Tomasz/message_throttler_interface.hpp @@ -1,26 +1,29 @@ #pragma once +#include + template< typename _Message, + typename _Clock, typename _MessageConsumer, - typename _MessageDisposer, - typename _Timestamp, - typename _Timestamper, - typename _TimestampThreshold, - typename _Buffer + typename _MessageDisposer > class message_throttler_interface { +private: + using _Time = decltype(_Clock{}()); + using _Duration = decltype(_Clock{}() - _Clock{}()); + public: message_throttler_interface( - _MessageConsumer& messageConsumer, - _MessageDisposer& messageDisposer, - _Timestamper& timestamper, - _TimestampThreshold & timestampThreshold) : + std::size_t bufferSize, + _Duration threashold, + _MessageConsumer& messageConsumer, + _MessageDisposer& messageDisposer) : + mBuffer(bufferSize), + mThreashold(threashold), mMessageConsumer(messageConsumer), - mMessageDisposer(messageDisposer), - mTimestamper(timestamper), - mTimestampThreshold(timestampThreshold) + mMessageDisposer(messageDisposer) { } message_throttler_interface(const message_throttler_interface&) = delete; @@ -28,7 +31,7 @@ class message_throttler_interface message_throttler_interface& send(const _Message& message) { - auto now = mTimestamper(); + auto now = mClock(); try_make_space_in_buffer(now); try_send(message, now); @@ -37,13 +40,13 @@ class message_throttler_interface } private: - void try_make_space_in_buffer(const _Timestamp& now) + void try_make_space_in_buffer(const _Time& now) { - if (mBuffer.full() && !mTimestampThreshold(now, mBuffer.front())) - mBuffer.pop(); + if (mBuffer.full() && mThreashold < now - mBuffer.front()) + mBuffer.pop_front(); } - void try_send(const _Message& message, const _Timestamp& now) + void try_send(const _Message& message, const _Time& now) { if (mBuffer.full()) dispose(message); @@ -51,10 +54,10 @@ class message_throttler_interface consume(message, now); } - void consume(const _Message& message, const _Timestamp& now) + void consume(const _Message& message, const _Time& now) { mMessageConsumer(message); - mBuffer.push(now); + mBuffer.push_back(now); } void dispose(const _Message& message) @@ -62,11 +65,11 @@ class message_throttler_interface mMessageDisposer(message); } + _Clock mClock; + _Duration mThreashold; + _MessageConsumer& mMessageConsumer; _MessageDisposer& mMessageDisposer; - _Timestamper& mTimestamper; - _TimestampThreshold& mTimestampThreshold; - - _Buffer mBuffer; + boost::circular_buffer<_Time> mBuffer; }; \ No newline at end of file diff --git a/course02/homework02/Tomasz/short_circular_buffer.hpp b/course02/homework02/Tomasz/short_circular_buffer.hpp deleted file mode 100644 index be1ec21..0000000 --- a/course02/homework02/Tomasz/short_circular_buffer.hpp +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once - -#include -#include - -template -class short_circular_buffer -{ -public: - short_circular_buffer() : - mBegin(0), - mSize(0) - { } - - void push(const _Ty& value) - { - assert(!full()); - - mBuffer[crop_index(mBegin + mSize)] = value; - mSize++; - } - - void pop() - { - assert(!empty()); - - mBegin = crop_index(mBegin + 1); - mSize--; - } - - _Ty& front() - { - assert(!empty()); - - return mBuffer[mBegin]; - } - - bool empty() const - { - return mSize == 0; - } - - bool full() const - { - return mSize == _Size; - } - -private: - size_t crop_index(std::size_t index) const - { - return index % _Size; - } - - std::array<_Ty, _Size> mBuffer; - - std::size_t mBegin; - std::size_t mSize; -}; \ No newline at end of file diff --git a/course02/homework02/danielellis/Buffer.h b/course02/homework02/danielellis/Buffer.h new file mode 100644 index 0000000..c2e5992 --- /dev/null +++ b/course02/homework02/danielellis/Buffer.h @@ -0,0 +1,79 @@ +#pragma once + +#include +#include +#include +#include + +struct WindowConfig +{ + std::chrono::seconds mDuration = std::chrono::seconds(10); + int mMaxNumMessages = 5; +}; + +template +struct TimestampedMessage +{ + std::chrono::time_point mTimestamp; + Message mMessage; +}; + +template +class Buffer +{ +public: + using value_type = Message; + + Buffer(const WindowConfig& conf); + void TryToAddMessage(const Message& message); + std::vector DumpMessages() const; + +private: + bool CanAddMessage(std::chrono::time_point currentTime) const; + + WindowConfig mWindowConfig; + std::deque > mTimestampedMessages; +}; + +template +Buffer::Buffer(const WindowConfig& conf) : + mWindowConfig(conf) +{ + if (conf.mMaxNumMessages <= 0) + throw std::runtime_error("Invalid configuration: max number of messages per time window must be positive!"); +} + +template +bool Buffer::CanAddMessage(std::chrono::time_point currentTime) const +{ + if (mTimestampedMessages.size() >= mWindowConfig.mMaxNumMessages) + { + auto timestampAtStartOfWindow = mTimestampedMessages[ + mTimestampedMessages.size() - mWindowConfig.mMaxNumMessages].mTimestamp; + return (timestampAtStartOfWindow < currentTime - mWindowConfig.mDuration); + } + return true; +} + +template +void Buffer::TryToAddMessage(const Message& message) +{ + auto currentTime = std::chrono::steady_clock::now(); + if (CanAddMessage(currentTime)) + { + TimestampedMessage tsMsg; + tsMsg.mMessage = message; + tsMsg.mTimestamp = currentTime; + mTimestampedMessages.push_back(tsMsg); + } +} + +template +std::vector Buffer::DumpMessages() const +{ + std::vector result; + for (auto tsMsg : mTimestampedMessages) + result.push_back(tsMsg.mMessage); + + return result; +} diff --git a/course02/homework02/danielellis/CMakeLists.txt b/course02/homework02/danielellis/CMakeLists.txt new file mode 100644 index 0000000..5547dd1 --- /dev/null +++ b/course02/homework02/danielellis/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 2.8) + +set(sources + main.cc + SlidingWindow.h + Buffer.h +) + +add_executable(main ${sources}) diff --git a/course02/homework02/danielellis/SlidingWindow.h b/course02/homework02/danielellis/SlidingWindow.h new file mode 100644 index 0000000..cbb78c2 --- /dev/null +++ b/course02/homework02/danielellis/SlidingWindow.h @@ -0,0 +1,51 @@ +#pragma once + +#include +#include +#include +#include + +#include "Buffer.h" + +template +class SlidingWindow +{ +public: + using value_type = Message; + + SlidingWindow(const WindowConfig& conf); + void Send(int clientId, const Message& message); + std::vector DumpMessages(int clientId) const; + +private: + WindowConfig mWindowConfig; + std::map > mClientBuffers; +}; + +template +SlidingWindow::SlidingWindow(const WindowConfig& conf) : + mWindowConfig(conf) +{ + if (conf.mMaxNumMessages <= 0) + throw std::runtime_error("Invalid configuration: max number of messages per time window must be positive!"); +} + +template +void SlidingWindow::Send(int clientId, const Message& message) +{ + if (mClientBuffers.count(clientId) == 0) + mClientBuffers.insert(std::pair >(clientId, Buffer(mWindowConfig))); + + Buffer& buffer = mClientBuffers.at(clientId); + buffer.TryToAddMessage(message); +} + +template +std::vector SlidingWindow::DumpMessages(int clientId) const +{ + auto buffer = mClientBuffers.find(clientId); + if (buffer != mClientBuffers.end()) + return buffer->second.DumpMessages(); + else + return std::vector(); +} diff --git a/course02/homework02/danielellis/main.cc b/course02/homework02/danielellis/main.cc new file mode 100644 index 0000000..5dff452 --- /dev/null +++ b/course02/homework02/danielellis/main.cc @@ -0,0 +1,84 @@ +#include "SlidingWindow.h" +#include "Buffer.h" + +#include + +void TestDroppedLastMessage() +{ + WindowConfig conf; + auto slidingWindow = SlidingWindow(conf); + for (int i = 1; i < 7; ++i) + slidingWindow.Send(1, i); + + auto messageDump = slidingWindow.DumpMessages(1); + assert(messageDump.size() == 5); + int i = 1; + for (auto msg : messageDump) + { + assert(msg == i); + ++i; + } +} + +void TestMultipleClients() +{ + WindowConfig conf; + conf.mMaxNumMessages = 8; + auto slidingWindow = SlidingWindow(conf); + for (int i = 1; i < 7; ++i) + slidingWindow.Send(1, i); + + for (int i = 1; i < 15; ++i) + slidingWindow.Send(2, i); + + auto messageDump = slidingWindow.DumpMessages(1); + assert(messageDump.size() == 6); + int i = 1; + for (auto msg : messageDump) + { + assert(msg == i); + ++i; + } + + messageDump = slidingWindow.DumpMessages(2); + assert(messageDump.size() == 8); + i = 1; + for (auto msg : messageDump) + { + assert(msg == i); + ++i; + } +} + +void TestDumpQuietClient() +{ + WindowConfig conf; + auto slidingWindow = SlidingWindow(conf); + auto dump = slidingWindow.DumpMessages(1); + assert(dump.size() == 0); +} + +void TestNegativeNumMessagesInWindowConf() +{ + WindowConfig conf; + conf.mMaxNumMessages = -5; + bool failed = true; + try + { + auto slidingWindow = SlidingWindow(conf); + } + catch (std::exception e) + { + failed = false; + } + assert(!failed); +} + +int main() +{ + TestDroppedLastMessage(); + TestMultipleClients(); + TestDumpQuietClient(); + TestNegativeNumMessagesInWindowConf(); + return 0; +} diff --git a/course02/homework02/dovile/CMakeLists.txt b/course02/homework02/dovile/CMakeLists.txt new file mode 100644 index 0000000..41e1a10 --- /dev/null +++ b/course02/homework02/dovile/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 2.8) + +add_definitions(-std=c++17) + +set(sources + main.cpp + sliding_window.h + sliding_window.cpp + throttler.h + throttler.cpp +) + +add_executable(main ${sources}) + diff --git a/course02/homework02/dovile/main.cpp b/course02/homework02/dovile/main.cpp new file mode 100644 index 0000000..aa016da --- /dev/null +++ b/course02/homework02/dovile/main.cpp @@ -0,0 +1,71 @@ +#include "throttler.h" + +#include +#include + +using namespace std::chrono_literals; +using namespace std::this_thread; + + +void test_message_rejected() +{ + Throttler throttler; + int messageLimit = 2; + int intervalInSeconds = 1; + throttler.AddClient(Client(1, Client::Config(messageLimit, intervalInSeconds))); + + std::string msg = "the message"; + + assert(throttler.SendMessage(1, msg)); + sleep_for(50ms); + assert(throttler.SendMessage(1, msg)); + sleep_for(50ms); + assert(!throttler.SendMessage(1, msg)); +} + +void test_messegae_rejected_and_later_accepted() +{ + Throttler throttler; + int messageLimit = 2; + int intervalInSeconds = 1; + throttler.AddClient(Client(1, Client::Config(messageLimit, intervalInSeconds))); + + std::string msg = "message"; + + assert(throttler.SendMessage(1, msg)); + sleep_for(50ms); + assert(throttler.SendMessage(1, msg)); + sleep_for(50ms); + assert(!throttler.SendMessage(1, msg)); + sleep_for(1s); + assert(throttler.SendMessage(1, msg)); +} + +void test_all_messages_accepted() +{ + Throttler throttler; + int messageLimit = 2; + int intervalInSeconds = 1; + throttler.AddClient(Client(1, Client::Config(messageLimit, intervalInSeconds))); + + std::string msg = "message"; + + assert(throttler.SendMessage(1, msg)); + sleep_for(500ms); + assert(throttler.SendMessage(1, msg)); + sleep_for(500ms); + assert(throttler.SendMessage(1, msg)); + sleep_for(500ms); + assert(throttler.SendMessage(1, msg)); +} + +int main() +{ +#ifdef NDEBUG +#error Compile the code in debug mode! +#endif + test_message_rejected(); + test_messegae_rejected_and_later_accepted(); + test_all_messages_accepted(); + return 0; +} \ No newline at end of file diff --git a/course02/homework02/dovile/sliding_window.cpp b/course02/homework02/dovile/sliding_window.cpp new file mode 100644 index 0000000..81bf849 --- /dev/null +++ b/course02/homework02/dovile/sliding_window.cpp @@ -0,0 +1,34 @@ +#include "sliding_window.h" +#include + +bool SlidingWindow::SendMessage(const std::string& message) +{ + auto now = SteadyClock::now(); + + if (mWindow.size() < mMessageLimit) + { + mWindow.emplace_back(now); + return true; + } + else + { + bool canSend = std::any_of(mWindow.begin(), mWindow.end(), [&](SteadyClock::time_point sentTime) + { + return ((now - sentTime) > mInterval); + }); + + if (canSend) + { + mWindow.emplace_back(now); + + if (mWindow.size() > mMessageLimit) + { + mWindow.pop_front(); + } + + return true; + } + + return false; + } +} \ No newline at end of file diff --git a/course02/homework02/dovile/sliding_window.h b/course02/homework02/dovile/sliding_window.h new file mode 100644 index 0000000..bd2f067 --- /dev/null +++ b/course02/homework02/dovile/sliding_window.h @@ -0,0 +1,26 @@ +#pragma once + +#include +#include +#include + +class SlidingWindow +{ + typedef std::chrono::seconds seconds; + typedef std::chrono::steady_clock SteadyClock; + +public: + SlidingWindow(int messageLimit, int intervalInSeconds) + : + mMessageLimit(messageLimit), + mInterval(seconds(intervalInSeconds)) + { + } + + bool SendMessage(const std::string& message); + +private: + int mMessageLimit; + seconds mInterval; + std::deque mWindow; +}; \ No newline at end of file diff --git a/course02/homework02/dovile/throttler.cpp b/course02/homework02/dovile/throttler.cpp new file mode 100644 index 0000000..91bca19 --- /dev/null +++ b/course02/homework02/dovile/throttler.cpp @@ -0,0 +1,17 @@ +#include "throttler.h" + +void Throttler::AddClient(const Client& client) +{ + auto config = client.GetConfig(); + mClientChannels.try_emplace(client.GetId(), SlidingWindow(config.mMessageLimit, config.mInterval)); +} + +bool Throttler::SendMessage(const Client::id_type& clientId, const std::string& msg) +{ + auto channel = mClientChannels.find(clientId); + if (channel != mClientChannels.end()) + { + return channel->second.SendMessage(msg); + } + return false; +} diff --git a/course02/homework02/dovile/throttler.h b/course02/homework02/dovile/throttler.h new file mode 100644 index 0000000..20686c9 --- /dev/null +++ b/course02/homework02/dovile/throttler.h @@ -0,0 +1,49 @@ +#pragma once + +#include "sliding_window.h" +#include + +struct Client +{ + + struct Config + { + Config(int messageLimit, int interval) + : + mMessageLimit(messageLimit), + mInterval(interval) + { + } + + int mMessageLimit; + int mInterval; + }; + + typedef int id_type; + + Client(int id, const Config& config) + : + mId(id), + mConfig(config) + { + } + + const int& GetId() const { return mId; } + const Config& GetConfig() const { return mConfig; } + +private: + const id_type mId; + const Config& mConfig; +}; + +class Throttler +{ +public: + + void AddClient(const Client& client); + bool SendMessage(const Client::id_type& clientId, const std::string& msg); + +private: + std::map mClientChannels; +}; + diff --git a/course02/homework03/matt/test_throttle.cc b/course02/homework03/matt/test_throttle.cc new file mode 100644 index 0000000..d5255c6 --- /dev/null +++ b/course02/homework03/matt/test_throttle.cc @@ -0,0 +1,28 @@ +#include "throttle.cc" +#include +#include +#include + +int main() +{ + Throttle throttle; + + UserID id = 5; + + int i = 0; + for(; i<=20; i++) + { + std::ostringstream stringStream; + stringStream << "Hello " << i; + throttle.SendMessage(id, stringStream.str()); + } + std::this_thread::sleep_for(std::chrono::milliseconds(10000)); + + for(; i<=40; i++) + { + std::this_thread::sleep_for(std::chrono::milliseconds(800)); + std::ostringstream stringStream; + stringStream << "Hello " << i; + throttle.SendMessage(id, stringStream.str()); + } +} diff --git a/course02/homework03/matt/throttle.cc b/course02/homework03/matt/throttle.cc new file mode 100644 index 0000000..d3fab7a --- /dev/null +++ b/course02/homework03/matt/throttle.cc @@ -0,0 +1,50 @@ +#include "throttle.h" + +typedef std::chrono::milliseconds ms; +typedef std::chrono::duration fsec; + +template +double DurationToMillis(duration d) +{ + return std::chrono::duration_cast(d).count(); +} + +void Throttle::SendMessage(UserID id, std::string message) +{ + FlushMessages(id); + + TimestampedMessage tsm{message}; + auto& queue = mQueues[id]; + + Timestamp arrivalTime = Clock::now(); + + auto timeBetweenFirstLast = arrivalTime - queue.front().mArrivalTime; + auto timeToWait = mMessageInterval - timeBetweenFirstLast; + double millisToWait = DurationToMillis(timeToWait); + + if(queue.size() >= mMaxQueueSize) + { + printf("user %d message %s dropped, please wait %.0f millis \n", id, message.c_str(), millisToWait); + } + else + { + printf("user %d message %s accepted \n", id, message.c_str()); + queue.emplace_back(TimestampedMessage{message, arrivalTime}); + } +} + +void Throttle::FlushMessages(UserID id) +{ + auto& queue = mQueues[id]; + Timestamp now = Clock::now(); + while (!queue.empty()) + { + if (now - queue.front().mArrivalTime > mMessageInterval) + { + printf("user %d message %s popping \n", id, queue.front().mText.c_str()); + queue.pop_front(); + } + else + break; + } +} diff --git a/course02/homework03/matt/throttle.h b/course02/homework03/matt/throttle.h new file mode 100644 index 0000000..4d90678 --- /dev/null +++ b/course02/homework03/matt/throttle.h @@ -0,0 +1,34 @@ +#include +#include +#include +#include + +typedef int UserID; +typedef std::chrono::high_resolution_clock Clock; +typedef std::chrono::time_point Timestamp; + + +struct TimestampedMessage +{ + TimestampedMessage(std::string message, Timestamp ts): + mText(message), mArrivalTime(ts) {}; + + TimestampedMessage(std::string message): + mText(message), mArrivalTime(Clock::now()) {}; + + std::string mText; + Timestamp mArrivalTime; +}; + +class Throttle +{ +public: + void SendMessage(UserID id, std::string message); + +private: + void FlushMessages(UserID id); + + const int mMaxQueueSize = 10; + const std::chrono::milliseconds mMessageInterval{10000}; + std::unordered_map> mQueues; +}; diff --git a/course02/meeting09/CMakeLists.txt b/course02/meeting09/CMakeLists.txt new file mode 100644 index 0000000..6a3528d --- /dev/null +++ b/course02/meeting09/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 3.1) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -Wall") +add_executable(main main.cc) + diff --git a/course02/meeting09/bench.cc b/course02/meeting09/bench.cc new file mode 100644 index 0000000..dbdbf46 --- /dev/null +++ b/course02/meeting09/bench.cc @@ -0,0 +1,81 @@ +#include +#include +#include +#include +#include + +static std::uniform_int_distribution dist{0, 10000}; + +static void Set(benchmark::State& state) +{ + std::mt19937 mt{0xdeadbeef}; + + std::set s; + for (int i = 0; i < state.range(0); ++i) + s.emplace(i); + + for (auto _ : state) + { + auto it = s.find(dist(mt)); + benchmark::DoNotOptimize(&it); + } +} +BENCHMARK(Set)->Arg(32)->Arg(128)->Arg(256); + + +static void USet(benchmark::State& state) +{ + std::mt19937 mt{0xdeadbeef}; + + std::unordered_set s; + for (int i = 0; i < state.range(0); ++i) + s.emplace(i); + + for (auto _ : state) + { + auto it = s.find(dist(mt)); + benchmark::DoNotOptimize(&it); + } +} +BENCHMARK(USet)->Arg(32)->Arg(128)->Arg(256); + + + +static void Vector(benchmark::State& state) +{ + std::mt19937 mt{0xdeadbeef}; + + std::vector s; + for (int i = 0; i < state.range(0); ++i) + s.push_back(i); + + for (auto _ : state) + { + auto it = std::find(s.cbegin(), s.cend(), dist(mt)); + benchmark::DoNotOptimize(&it); + } +} +BENCHMARK(Vector)->Arg(32)->Arg(128)->Arg(256); + + + + +static void SVector(benchmark::State& state) +{ + std::mt19937 mt{0xdeadbeef}; + + std::vector s; + for (int i = 0; i < state.range(0); ++i) + s.push_back(i); + + std::sort(s.begin(), s.begin()); + + for (auto _ : state) + { + auto it = std::lower_bound(s.cbegin(), s.cend(), dist(mt)); + benchmark::DoNotOptimize(&it); + } +} +BENCHMARK(SVector)->Arg(32)->Arg(128)->Arg(256); + + diff --git a/course02/meeting09/main.cc b/course02/meeting09/main.cc new file mode 100644 index 0000000..a9d9282 --- /dev/null +++ b/course02/meeting09/main.cc @@ -0,0 +1,114 @@ +#include +#include +#include + +void* operator new(std::size_t n) +{ + std::cout << "malloc " << n << std::endl; + return malloc(n); +} + +struct Order +{ + Order() { std::cout << "Order()" << std::endl; } + Order(const std::string& id, double price, int volume) + : mID(id), mPrice(price), mVolume(volume) + { + std::cout << "Order(...)" << std::endl; + } + Order(std::string&& id, double price, int volume) + : mID(std::move(id)), mPrice(price), mVolume(volume) + { + std::cout << "Order(... temp)" << std::endl; + } + Order(const Order& order) : mID(order.mID), mPrice(order.mPrice), mVolume(order.mVolume) + { + std::cout << "Order(const Order&)" << std::endl; + } + Order& operator=(const Order& order) + { + mID = order.mID; + mPrice = order.mPrice; + mVolume = order.mVolume; + std::cout << "Order operator=(const Order&)" << std::endl; + return *this; + } + Order(Order&& order) : mID(std::move(order.mID)), mPrice(order.mPrice), mVolume(order.mVolume) + { + std::cout << "Order(Order&&)" << std::endl; + } + Order& operator=(Order&& order) + { + mID = std::move(order.mID); + mPrice = order.mPrice; + mVolume = order.mVolume; + std::cout << "Order operator=(Order&&)" << std::endl; + return *this; + } + + std::string mID; + double mPrice; + int mVolume; +}; + +class OrderStore +{ +public: + void Add(const Order& order) + { + mOrders[order.mID] = order; + } + + void Add(const std::string& id, double price, int volume) + { + const bool inserted = mOrders.emplace(id, Order{id, price, volume}).second; + if (!inserted) throw 42; + } + + void Add(std::string&& id, double price, int volume) + { + std::cout << "&&" << std::endl; + const bool inserted = mOrders.emplace(id, Order{id, price, volume}).second; + if (!inserted) throw 42; + } + + std::map mOrders; +}; + + +/* +int main() +{ + OrderStore store; + + //const Order order{"foofoofoofoofoofoofoofoofoofoofoofoofoo", 10.5, 100}; + //store.Add(order); + + store.Add("foofoofoofoofoofoofoofoofoofoofoofoofoo", 10.5, 100); + + return 0; +} +*/ + +void Print(int i) +{ + std::cout << i << std::endl; +} +void Print(std::string&& s) { std::cout << "string&&" << std::endl; } +void Print(const std::string& s) { std::cout << "const string&" << std::endl; } + +void Print(std::string& s, int i) { std::cout << s << std::endl; } +void Print(std::string& s, int& i) { std::cout << s << std::endl; } + +template +void Proxy(T&& t) +{ + Print(std::forward(t)); +} + +int main() +{ + std::string s = "foo"; + Proxy(s); +} + diff --git a/course02/project01/gavin/Asteroids/CMakeLists.txt b/course02/project01/gavin/Asteroids/CMakeLists.txt new file mode 100644 index 0000000..5822e89 --- /dev/null +++ b/course02/project01/gavin/Asteroids/CMakeLists.txt @@ -0,0 +1,28 @@ +cmake_minimum_required(VERSION 3.13) +project(homework) + +set(CMAKE_CXX_STANDARD 14) + +if (NOT DEFINED CINDER_PATH) + message(FATAL_ERROR "CINDER_PATH not set, e.g. -DCINDER_PATH=~/src/cinder") +endif() +include("${CINDER_PATH}/proj/cmake/modules/cinderMakeApp.cmake") + +if (${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU") + set(cxx_compile_options "-g -Wall -Wextra") +endif() +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${cxx_compile_options}") + +file(GLOB asteroids + "*.h" + "*.cc" + ) + +set(SOURCES ${asteroids}) + +ci_make_app( + APP_NAME "asteroids" + SOURCES ${SOURCES} + INCLUDES ${CMAKE_CURRENT_SOURCE_DIR} + CINDER_PATH ${CINDER_PATH} +) \ No newline at end of file diff --git a/course02/project01/gavin/Asteroids/Readme.md b/course02/project01/gavin/Asteroids/Readme.md new file mode 100644 index 0000000..dba4e8b --- /dev/null +++ b/course02/project01/gavin/Asteroids/Readme.md @@ -0,0 +1,23 @@ +# Asteroids +## Requirements + * LibCinder https://libcinder.org/ + * OpenGL drivers + * C++14 compatible compiler (GCC/Clang) + * Cmake 3.13+ +## Compiling & running + +To compile: + `mkdir build && cd build` + `cmake .. -DCINDER_PATH=~/Cinder` + `make` +To run: + `./asteroids` + +## Features + * Moving ship (with lasers!) + * Randomly spawning asteroids + +## TODO + * Score + * Sounds + * VR support \ No newline at end of file diff --git a/course02/project01/gavin/Asteroids/application.cc b/course02/project01/gavin/Asteroids/application.cc new file mode 100644 index 0000000..3b570a3 --- /dev/null +++ b/course02/project01/gavin/Asteroids/application.cc @@ -0,0 +1,33 @@ +// + +#include "application.h" + +// +// Created by gavinparker on 27/12/18. +Application::Application() : mGameWorld(mController), + mLastFrameTime(static_cast(getElapsedSeconds())), + mThisFrameTime(static_cast(getElapsedSeconds())){ + +} + +void Application::draw() +{ + mThisFrameTime = static_cast(getElapsedSeconds()); + auto delta = mThisFrameTime - mLastFrameTime; + + mGameWorld.Update(delta); + ci::gl::clear(); + mGameWorld.Draw(); + mLastFrameTime = mThisFrameTime; +} + +void Application::keyDown(KeyEvent event) +{ + mController.keyDown(event); +} + +void Application::keyUp(KeyEvent event) +{ + mController.keyUp(event); +} + diff --git a/course02/project01/gavin/Asteroids/application.h b/course02/project01/gavin/Asteroids/application.h new file mode 100644 index 0000000..3d4196a --- /dev/null +++ b/course02/project01/gavin/Asteroids/application.h @@ -0,0 +1,25 @@ +#pragma once +#include +#include +#include +#include "ship.h" +#include "controller.h" +#include "game_world.h" + +using namespace ci::app; + +class Application : public App { +public: + Application(); + void draw() override; + void keyDown(KeyEvent event) override; + void keyUp(KeyEvent event) override; +private: + GameWorld mGameWorld; + float mLastFrameTime; + float mThisFrameTime; + Controller mController; +}; + + +CINDER_APP( Application, RendererGl ) \ No newline at end of file diff --git a/course02/project01/gavin/Asteroids/asteroid.cc b/course02/project01/gavin/Asteroids/asteroid.cc new file mode 100644 index 0000000..f6b95ec --- /dev/null +++ b/course02/project01/gavin/Asteroids/asteroid.cc @@ -0,0 +1,46 @@ +#include "asteroid.h" +#include "utils.h" +#include +#include +#include + +Asteroid::Asteroid(GameObject& parent, glm::vec2 direction, glm::vec2 position, float size, float speed) : + Collidable(parent, Tag::Asteroid, position, size), + mDirection(direction), + mSpeed(speed) { +} + +void Asteroid::Update(float frameDelta) +{ + auto dist = mDirection * mSpeed * frameDelta; + mPosition += dist; + auto bounds = ci::app::getWindowBounds(); + if(!bounds.contains(mPosition)) + ReturnToPlayArea(bounds, mPosition); + GameObject::Update(frameDelta); +} + +void Asteroid::Draw() +{ + ci::gl::drawStrokedCircle(mPosition, mSize); + GameObject::Draw(); +} + +void Asteroid::Collide(Collidable &other) +{ + if(other.GetTag() == Tag::Laser) + { + Destroy(); + if(mSize > 5) + Break(); + } +} + +void Asteroid::Break() +{ + for(int i = 0; i < 2; i++) + { + auto direction = glm::sphericalRand(1.0); + CreateFreeGameObject(glm::normalize(direction), mPosition, mSize/2, mSpeed*2); + } +} diff --git a/course02/project01/gavin/Asteroids/asteroid.h b/course02/project01/gavin/Asteroids/asteroid.h new file mode 100644 index 0000000..126e4a4 --- /dev/null +++ b/course02/project01/gavin/Asteroids/asteroid.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include "collidable.h" + +class Asteroid : public Collidable { +public: + Asteroid(GameObject& parent, glm::vec2 direction, glm::vec2 position, float size, float speed); + + void Update(float frameDelta) override; + void Draw() override; + void Collide(Collidable& other) override; + void Break(); +private: + glm::vec2 mDirection; + float mSpeed; +}; + + diff --git a/course02/project01/gavin/Asteroids/collidable.cc b/course02/project01/gavin/Asteroids/collidable.cc new file mode 100644 index 0000000..175becd --- /dev/null +++ b/course02/project01/gavin/Asteroids/collidable.cc @@ -0,0 +1,21 @@ +#include +#include "collidable.h" +#include "game_world.h" + +Collidable::Collidable(GameObject& parent, Tag tag, glm::vec2 position, float size) : GameObject(parent, tag, position, size) +{ + //FIXME: There has to be a better way + dynamic_cast(&mRoot)->AddCollider(this); +} +//FIXME: just square hitboxes for now +bool Collidable::Overlaps(Collidable& other) +{ + const auto diff = mPosition - other.GetPosition(); + const auto dist = std::sqrt(diff.x*diff.x + diff.y*diff.y); + return dist < mSize or dist < other.GetSize(); +} + +Collidable::~Collidable() +{ + dynamic_cast(&mRoot)->RemoveCollider(this); +} diff --git a/course02/project01/gavin/Asteroids/collidable.h b/course02/project01/gavin/Asteroids/collidable.h new file mode 100644 index 0000000..793598f --- /dev/null +++ b/course02/project01/gavin/Asteroids/collidable.h @@ -0,0 +1,17 @@ +#pragma once +#include "game_object.h" + +class Collidable : public GameObject { +public: + Collidable(GameObject& parent, Tag tag, glm::vec2 position, float size); + + ~Collidable(); + bool Overlaps(Collidable& other); + + float GetSize(){return mSize;} + glm::vec2& GetPosition() { return mPosition;} + + virtual void Collide(Collidable& other) = 0; + + +}; diff --git a/course02/project01/gavin/Asteroids/controller.cc b/course02/project01/gavin/Asteroids/controller.cc new file mode 100644 index 0000000..3d615c3 --- /dev/null +++ b/course02/project01/gavin/Asteroids/controller.cc @@ -0,0 +1,26 @@ +// +// Created by gavinparker on 29/12/18. +// + +#include "controller.h" +using namespace ci::app; + +void Controller::keyUp(KeyEvent &event) +{ + auto key = event.getChar(); + mKeyMap[key] = false; +} + +void Controller::keyDown(KeyEvent &event) +{ + auto key = event.getChar(); + mKeyMap[key] = true; +} + +bool Controller::held(const char key) const +{ + if(mKeyMap.find(key) != mKeyMap.end()) + return mKeyMap.at(key); + return false; +} + diff --git a/course02/project01/gavin/Asteroids/controller.h b/course02/project01/gavin/Asteroids/controller.h new file mode 100644 index 0000000..c20ce24 --- /dev/null +++ b/course02/project01/gavin/Asteroids/controller.h @@ -0,0 +1,13 @@ +#pragma once +#include +#include +class Controller { +public: + void keyUp(ci::app::KeyEvent &event); + void keyDown(ci::app::KeyEvent &event); + bool held(char key) const; +private: + std::unordered_map mKeyMap; +}; + + diff --git a/course02/project01/gavin/Asteroids/game_object.cc b/course02/project01/gavin/Asteroids/game_object.cc new file mode 100644 index 0000000..9ba5955 --- /dev/null +++ b/course02/project01/gavin/Asteroids/game_object.cc @@ -0,0 +1,29 @@ +// +// Created by gavinparker on 10-2-19. +// + +#include + +#include "game_object.h" + +void GameObject::Update(float frameDelta) +{ + mCallbacks.erase(std::remove_if(mCallbacks.begin(), mCallbacks.end(), [this](auto &callback){return Call(callback);}), mCallbacks.end()); + mChildren.erase(std::remove_if(mChildren.begin(), mChildren.end(), [](auto &child){return child->GetDestroyed();}), mChildren.end()); + std::for_each(mChildren.begin(), mChildren.end(), [frameDelta](auto child){child->Update(frameDelta);}); +} + +bool GameObject::Call(Callback &callback) +{ + auto now = std::chrono::steady_clock::now(); + if(now > std::get<1>(callback)) + { + std::get<0>(callback)(); + return true; + } + return false; +} + +void GameObject::Draw() { + std::for_each(mChildren.begin(), mChildren.end(), [](auto child){child->Draw();}); +} diff --git a/course02/project01/gavin/Asteroids/game_object.h b/course02/project01/gavin/Asteroids/game_object.h new file mode 100644 index 0000000..05706d8 --- /dev/null +++ b/course02/project01/gavin/Asteroids/game_object.h @@ -0,0 +1,80 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include "utils.h" + +class GameObject { + +public: + GameObject(GameObject& parent, Tag tag, glm::vec2 position, float size) : mRoot(parent.GetRoot()), mParent(parent), mTag(tag), mPosition(position), mSize(size){}; + GameObject() : mRoot(*this), mParent(*this), mTag(Tag::None), mPosition(0,0), mSize(0) {}; + virtual void Update(float frameDelta); + virtual void Draw(); + + GameObject& GetParent() { return mParent;} + GameObject& GetRoot() { return mRoot;} + + Tag GetTag() { return mTag;} + bool GetDestroyed() { return mDestroyed;} + +protected: + GameObject& mRoot; + bool mDestroyed = false; + GameObject& mParent; + Tag mTag; + glm::vec2 mPosition; + float mSize; + + + + void Create(const std::shared_ptr &object) + { + mChildren.push_back(object); + } + + template + std::shared_ptr CreateGameObject(Args&&... args) + { + auto newObject = std::make_shared(*this, args...); + mChildren.push_back(newObject); + return newObject; + } + + template + std::shared_ptr CreateFreeGameObject(Args&&... args) + { + return mRoot.CreateGameObject(args...); + } + + void DestroyGameObject(std::shared_ptr ptr) + { + mChildren.erase(std::remove_if(mChildren.begin(), mChildren.end(), [ptr](auto c){return c == ptr;}),mChildren.end()); + } + + void RegisterCallback(std::function f, std::chrono::microseconds time) + { + mCallbacks.emplace_back(f, std::chrono::steady_clock::now() + time); + } + + virtual void Destroy() + { + mDestroyed = true; + } + +private: + using Callback = std::tuple, std::chrono::steady_clock::time_point>; + + std::vector> mChildren; + std::deque mCallbacks; + + bool Call(Callback &callback); + +}; + + diff --git a/course02/project01/gavin/Asteroids/game_world.cc b/course02/project01/gavin/Asteroids/game_world.cc new file mode 100644 index 0000000..3e66dfc --- /dev/null +++ b/course02/project01/gavin/Asteroids/game_world.cc @@ -0,0 +1,52 @@ +#include "game_world.h" +#include "asteroid.h" +#include "ship.h" +#include + +using namespace std::chrono_literals; + +GameWorld::GameWorld(Controller &controller) : + GameObject(), + mController(controller){ + CreateGameObject(ci::app::getWindowCenter(), glm::vec2{0.0, 1.0}, mController); + RegisterCallback([this](){ + SpawnAsteroid(); + }, 5s); +} + +void GameWorld::Update(const float frameDelta) +{ + UpdateCollisions(); + GameObject::Update(frameDelta); +} + +void GameWorld::Draw() +{ + GameObject::Draw(); +} + +void GameWorld::SpawnAsteroid() +{ + auto direction = glm::sphericalRand(1.0); + CreateGameObject(glm::vec2{1.0, 1.0}, glm::normalize(direction), 20, 30); + RegisterCallback([this](){ + SpawnAsteroid(); + }, 10s); +} + +void GameWorld::AddCollider(Collidable* collidable) +{ + mColliders.push_back(collidable); +} + +void GameWorld::UpdateCollisions() { + //FIXME: collection of references without ownership? + for(auto a : mColliders) + for(auto b : mColliders) + if(a != b and a->Overlaps(*b)) + a->Collide(*b); +} + +void GameWorld::RemoveCollider(Collidable *collidable) { + mColliders.erase(std::remove_if(mColliders.begin(), mColliders.end(), [collidable](Collidable* collider){return collider == collidable;}), mColliders.end()); +} diff --git a/course02/project01/gavin/Asteroids/game_world.h b/course02/project01/gavin/Asteroids/game_world.h new file mode 100644 index 0000000..77e1624 --- /dev/null +++ b/course02/project01/gavin/Asteroids/game_world.h @@ -0,0 +1,21 @@ +#pragma once + +#include "game_object.h" +#include "controller.h" +#include "collidable.h" + +class GameWorld : public GameObject { +public: + explicit GameWorld(Controller& controller); + void Update(float frameDelta) override; + void Draw() override; + + void AddCollider(Collidable* collidable); + void RemoveCollider(Collidable* collidable); + +private: + Controller& mController; + std::vector mColliders; + void SpawnAsteroid(); + void UpdateCollisions(); +}; \ No newline at end of file diff --git a/course02/project01/gavin/Asteroids/laser.cc b/course02/project01/gavin/Asteroids/laser.cc new file mode 100644 index 0000000..9ebc385 --- /dev/null +++ b/course02/project01/gavin/Asteroids/laser.cc @@ -0,0 +1,25 @@ +// +// Created by gavinparker on 10-2-19. +// + +#include +#include "laser.h" + +Laser::Laser(GameObject& parent, glm::vec2 direction, glm::vec2 position) : Collidable(parent, Tag::Laser, position, 1), mDirection(direction){} + +void Laser::Update(const float frameDelta) +{ + auto dist = mDirection * speed * frameDelta; + mPosition += dist; +} + +void Laser::Draw() +{ + ci::gl::drawSolidCircle(mPosition, mSize); +} + +void Laser::Collide(Collidable &other) { + if(other.GetTag() == Tag::Asteroid) + Destroy(); + +} \ No newline at end of file diff --git a/course02/project01/gavin/Asteroids/laser.h b/course02/project01/gavin/Asteroids/laser.h new file mode 100644 index 0000000..53bfd98 --- /dev/null +++ b/course02/project01/gavin/Asteroids/laser.h @@ -0,0 +1,18 @@ +#pragma once + +#include +#include "collidable.h" + +class Laser : public Collidable { +public: + Laser(GameObject& parent, glm::vec2 direction, glm::vec2 position); + ~Laser() = default; + void Update(float frameDelta) override; + void Draw() override; + void Collide(Collidable& other) override; +private: + const glm::vec2 mDirection; + const float speed = 100; +}; + + diff --git a/course02/project01/gavin/Asteroids/ship.cc b/course02/project01/gavin/Asteroids/ship.cc new file mode 100644 index 0000000..35690b3 --- /dev/null +++ b/course02/project01/gavin/Asteroids/ship.cc @@ -0,0 +1,84 @@ +#include "ship.h" +#include "utils.h" +#include "asteroid.h" +#include +#include + +using namespace std::chrono_literals; + +Ship::Ship(GameObject& parent, const glm::vec2& center, const glm::vec2& heading, Controller& controller) : Collidable(parent, Tag::Player, center, 10), + mHeading(heading), + mController(controller){ +} + + +void Ship::Update(float frameDelta) +{ + if(mController.held('w')) + Accelerate(frameDelta); + if(mController.held('a')) + Rotate(frameDelta*60.0f); + if(mController.held('d')) + Rotate(-frameDelta*60.0f); + if(mController.held('e') and ReadyToFire()) + Fire(); + mPosition += mSpeed; + auto bounds = ci::app::getWindowBounds(); + + if(!bounds.contains(mPosition)) + ReturnToPlayArea(bounds, mPosition); + + GameObject::Update(frameDelta); +} + +void Ship::Draw() +{ + + const auto front = mHeading*mSize; + const auto left = glm::vec2(mHeading.y*(mSize/3.0), -mHeading.x*(mSize/3.0)); + ci::gl::drawSolidTriangle(mPosition + front, mPosition + left, mPosition - left); + GameObject::Draw(); +} + +void Ship::Accelerate(float force) +{ + mSpeed += mHeading * force; +} + +void Ship::Rotate(float degreesClockwise) +{ + const auto rads = degreesClockwise * M_PI / 180.0; + glm::mat2x2 rotation(glm::vec2(cos(rads), sin(rads)), glm::vec2(-sin(rads), cos(rads))); + auto new_heading = mHeading * rotation; + mHeading = new_heading; + +} + +void Ship::Fire() +{ + auto laser = CreateGameObject(normalize(mHeading), mPosition); + RegisterCallback([this, laser](){DestroyGameObject(laser);}, 2s); + mLastFireTime = std::chrono::steady_clock::now(); +} + +bool Ship::ReadyToFire() +{ + return std::chrono::steady_clock::now() - mLastFireTime > 200ms; +} + +void Ship::Collide(Collidable &other) +{ + if(other.GetTag() == Tag::Asteroid) + Crash(); +} + +void Ship::Crash() +{ + for(int i=0; i < 5; i ++) + { + auto direction = glm::sphericalRand(1.0); + auto laser = CreateFreeGameObject(direction, mPosition); + } + std::cout << "you crashed!" << std::endl; + RegisterCallback([this](){Destroy();}, 20ms); +} diff --git a/course02/project01/gavin/Asteroids/ship.h b/course02/project01/gavin/Asteroids/ship.h new file mode 100644 index 0000000..5be5bb8 --- /dev/null +++ b/course02/project01/gavin/Asteroids/ship.h @@ -0,0 +1,30 @@ +#pragma once +#include +#include +#include "controller.h" +#include "laser.h" +#include "collidable.h" + + +class Ship : public Collidable { +public: + Ship(GameObject& parent, const glm::vec2 ¢er, const glm::vec2& heading, Controller& controller); + void Update(float frameDelta) override; + void Draw() override; + void Accelerate(float force); + void Rotate(float degreesClockwise); + void Fire(); + void Collide(Collidable& other) override; + +private: + glm::vec2 mHeading; + Controller& mController; + glm::vec2 mSpeed{0,0}; + std::vector> mLasers; + + std::chrono::steady_clock::time_point mLastFireTime = std::chrono::steady_clock::now(); + bool ReadyToFire(); + void Crash(); +}; + + diff --git a/course02/project01/gavin/Asteroids/utils.cc b/course02/project01/gavin/Asteroids/utils.cc new file mode 100644 index 0000000..f3d3858 --- /dev/null +++ b/course02/project01/gavin/Asteroids/utils.cc @@ -0,0 +1,14 @@ +#include +#include + +void ReturnToPlayArea(cinder::Area &bounds, glm::vec2 &pos) +{ + if(pos.x > bounds.x2) + pos.x = bounds.x1 + (pos.x - bounds.x2); + if(pos.x < bounds.x1) + pos.x = bounds.x2 - (bounds.x1 - pos.x); + if(pos.y > bounds.y2) + pos.y = bounds.y1 + (pos.y - bounds.y2); + if(pos.y < bounds.y1) + pos.y = bounds.y2 - (bounds.y1 - pos.y); +} diff --git a/course02/project01/gavin/Asteroids/utils.h b/course02/project01/gavin/Asteroids/utils.h new file mode 100644 index 0000000..0369a3f --- /dev/null +++ b/course02/project01/gavin/Asteroids/utils.h @@ -0,0 +1,13 @@ +#pragma once + +#include +#include + +enum class Tag { + None, + Player, + Laser, + Asteroid +}; + +void ReturnToPlayArea(cinder::Area &bounds, glm::vec2 &pos); \ No newline at end of file diff --git a/course03/homework00/.DS_Store b/course03/homework00/.DS_Store new file mode 100644 index 0000000..d3f0263 Binary files /dev/null and b/course03/homework00/.DS_Store differ diff --git a/course03/homework00/CMakeLists.txt b/course03/homework00/CMakeLists.txt new file mode 100644 index 0000000..5fcacf9 --- /dev/null +++ b/course03/homework00/CMakeLists.txt @@ -0,0 +1,4 @@ +cmake_minimum_required(VERSION 3.1) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -g -Wall") +add_executable(main main.cc a.h a.cc) diff --git a/course03/homework00/balint_hw/main.cpp b/course03/homework00/balint_hw/main.cpp new file mode 100644 index 0000000..99c8c53 --- /dev/null +++ b/course03/homework00/balint_hw/main.cpp @@ -0,0 +1,131 @@ +#include + +class Date { +private: + int y, m, d; + + bool yearvalid() const { return y >= 1600 && y <= 2500; } + + bool monthvalid() const { return m >= 1 && m <= 12; } + static bool isleapyear(int y) { + if (y % 4 != 0) { + return false; + } + if (y % 100 != 0) { + return true; + } + if (y % 400 != 0) { + return false; + } + return true; + } + int maxDayInMonth(int y, int m) const { + switch (m) { + case 1: + case 3: + case 5: + case 7: + case 8: + case 10: + case 12: + return 31; + case 4: + case 6: + case 9: + case 11: + return 30; + case 2: + return isleapyear(y) ? 29 : 28; + default: + throw std::runtime_error("Invalid month value"); + }; + } + int dayDiff(Date first, Date second) const { + if (first == second) { + return 0; + } + if (!(first < second)) { + return -1 * dayDiff(second, first); + } + + Date dayCnt = first.nextDay(); + int cnt = 1; + while (dayCnt < second) { + cnt++; + dayCnt = dayCnt.nextDay(); + } + return cnt; + } + +public: + Date(int y, int m, int d) : y(y), m(m), d(d){}; + Date nextDay() const { + Date firstguess = {y, m, d + 1}; + if (!firstguess.isValid()) { + firstguess = {y, m + 1, 1}; + if (!firstguess.isValid()) { + firstguess = {y + 1, 1, 1}; + } + } + return firstguess; + } + bool isValid() const { + if (!yearvalid() || !monthvalid()) { + return false; + } + if (d < 1 || d > maxDayInMonth(y, m)) { + return false; + } + return true; + } + int getY() const { return y; } + int getM() const { return m; } + int getD() const { return d; } + + bool operator==(const Date &other) const { + return std::tie(y, m, d) == std::tie(other.y, other.m, other.d); + } + bool operator<(const Date &other) const { + return std::tie(y, m, d) < std::tie(other.y, other.m, other.d); + } + int daysSinceEpoch() const { return dayDiff({1970, 1, 1}, *this); } + + std::string dayOfWeek() const { + if (!isValid()) { + throw std::runtime_error("dayOfWeek() called while !isValid()"); + } + int offset = (((daysSinceEpoch() % 7) + 7) % 7); + switch (offset) { + case 0: + return "Thursday"; + case 1: + return "Friday"; + case 2: + return "Saturday"; + case 3: + return "Sunday"; + case 4: + return "Monday"; + case 5: + return "Tuesday"; + case 6: + return "Wednesday"; + default: + throw std::logic_error("Shouldn't happen"); + } + } +}; +std::ostream &operator<<(std::ostream &strm, const Date &a) { + return strm << a.getY() << "-" << a.getM() << "-" << a.getD(); +} + +int main() { + + Date test2 = {2019, 5, 5}; + + std::cout << "Nr of days since epoch is: " << test2.daysSinceEpoch() + << std::endl; + std::cout << "Day of week is : " << test2.dayOfWeek() << std::endl; + + return 0; +} diff --git a/course03/homework00/date.cpp b/course03/homework00/date.cpp new file mode 100644 index 0000000..9dd4311 --- /dev/null +++ b/course03/homework00/date.cpp @@ -0,0 +1,28 @@ +#include "date.h" + +Date getDate() + { + int day; + int month; + int year; + + std::cout << "Which day? "; + std::cin >> day; + std::cout << "Which month? "; + std::cin >> month; + std::cout << "Which year? "; + std::cin >> year; + + Date date {day, month, year}; + + return date; + } + +int main() +{ + Date date1{17,05,1996}; + date1.print(); + + Date date2=getDate(); + date2.print(); +} diff --git a/course03/homework00/date.h b/course03/homework00/date.h new file mode 100644 index 0000000..0ceb242 --- /dev/null +++ b/course03/homework00/date.h @@ -0,0 +1,17 @@ +#ifndef DATE_H +#define DATE_H + +class Date +{ +public: + int m_day; + int m_month; + int m_year; + + void print() + { + std::cout << m_day << "/" << m_month << "/"<< m_year; + } +}; + +#endif // DATE_H diff --git a/course03/homework00/glebmineev/CMakeLists.txt b/course03/homework00/glebmineev/CMakeLists.txt new file mode 100644 index 0000000..25d6d4b --- /dev/null +++ b/course03/homework00/glebmineev/CMakeLists.txt @@ -0,0 +1,4 @@ +cmake_minimum_required(VERSION 3.1) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -g -Wall") +add_executable(main main.cc date.cc) diff --git a/course03/homework00/glebmineev/date.cc b/course03/homework00/glebmineev/date.cc new file mode 100644 index 0000000..045f2dc --- /dev/null +++ b/course03/homework00/glebmineev/date.cc @@ -0,0 +1,72 @@ +#include "date.h" +#include + +namespace Homework00 { + +Date::Date(int day, int month, int year) + : mDay(day), mMonth(month), mYear(year) +{ + if (mMonth < 1 || mMonth > 12) { throw std::runtime_error {"invalid month"}; } + if (mDay < 1 || mDay > GetDaysInCurrentMonth()) { throw std::runtime_error {"invalid day of month"}; } +} + +void Date::AddDays(int days) +{ + mDay += days; + while (mDay > GetDaysInCurrentMonth()) + { + mDay -= GetDaysInCurrentMonth(); + mMonth += 1; + NormalizeMonth(); + } + while (mDay < 1) + { + mMonth -= 1; + NormalizeMonth(); + mDay += GetDaysInCurrentMonth(); + } +} + +bool Date::IsLeapYear() const +{ + if (mYear % 400 == 0) { return true; } + if (mYear % 100 == 0) { return false; } + return mYear % 4 == 0; +} + +int Date::GetDaysInCurrentMonth() const +{ + static const int daysPerMonth[]{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + if (mMonth == 2 && IsLeapYear()) return 29; + return daysPerMonth[mMonth - 1]; +} + +int Date::GetDaysInCurrentYear() const +{ + return IsLeapYear() ? 366 : 365; +} + +void Date::NormalizeMonth() +{ + while (mMonth > 12) + { + mMonth -= 12; + ++mYear; + } + + while (mMonth < 1) + { + mMonth += 12; + --mYear; + } +} + +std::ostream& operator<<(std::ostream& os, const Date& date) +{ + os << std::setw(2) << std::setfill('0') << date.GetDayOfMonth() << '.' + << std::setw(2) << std::setfill('0') << date.GetMonth() << '.' + << std::setw(4) << std::setfill('0') << date.GetYear(); + return os; +} + +} \ No newline at end of file diff --git a/course03/homework00/glebmineev/date.h b/course03/homework00/glebmineev/date.h new file mode 100644 index 0000000..2c64030 --- /dev/null +++ b/course03/homework00/glebmineev/date.h @@ -0,0 +1,30 @@ +#pragma once + +#include + +namespace Homework00 { + +class Date +{ +public: + Date(int day, int month, int year); + void AddDays(int); + int GetDayOfMonth() const { return mDay; } + int GetMonth() const { return mMonth; } + int GetYear() const { return mYear; } + + bool IsLeapYear() const; + int GetDaysInCurrentMonth() const; + int GetDaysInCurrentYear() const; + +private: + void NormalizeMonth(); + + int mDay; + int mMonth; + int mYear; +}; + +std::ostream& operator<<(std::ostream& os, const Date& date); + +} diff --git a/course03/homework00/glebmineev/main.cc b/course03/homework00/glebmineev/main.cc new file mode 100644 index 0000000..23ecaab --- /dev/null +++ b/course03/homework00/glebmineev/main.cc @@ -0,0 +1,23 @@ +#include "date.h" +#include +#include + +int main(int argc, char** argv) +{ + Homework00::Date date{ 04, 05, 1993 }; + std::cout << "The date is " << date << std::endl; + + date.AddDays(100); + std::cout << "In 100 days from this date it will be " << date << std::endl; + + date.AddDays(900); + std::cout << "In 1000 days from this date it will be " << date << std::endl; + + date.AddDays(-1000); + std::cout << "Once again, the date is " << date << std::endl; + + date.AddDays(-1000); + std::cout << "And 1000 days before it was " << date << std::endl; + + return 0; +} diff --git a/course03/homework00/julian/.DS_Store b/course03/homework00/julian/.DS_Store new file mode 100644 index 0000000..c84bd9c Binary files /dev/null and b/course03/homework00/julian/.DS_Store differ diff --git a/course03/homework00/julian/.gitignore b/course03/homework00/julian/.gitignore new file mode 100755 index 0000000..bf797c5 --- /dev/null +++ b/course03/homework00/julian/.gitignore @@ -0,0 +1 @@ +cmake-build-debug \ No newline at end of file diff --git a/course03/homework00/julian/CMakeLists.txt b/course03/homework00/julian/CMakeLists.txt new file mode 100755 index 0000000..5187309 --- /dev/null +++ b/course03/homework00/julian/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 3.5.1) + +project(cpp_class_hw1_julianbrendl LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 14) + +add_subdirectory(src) \ No newline at end of file diff --git a/course03/homework00/julian/README.md b/course03/homework00/julian/README.md new file mode 100755 index 0000000..e69de29 diff --git a/course03/homework00/julian/src/CMakeLists.txt b/course03/homework00/julian/src/CMakeLists.txt new file mode 100755 index 0000000..abb4851 --- /dev/null +++ b/course03/homework00/julian/src/CMakeLists.txt @@ -0,0 +1,5 @@ +set(LIBRARY_NAME hw1) + +add_executable(${LIBRARY_NAME} date.h date.cc test.cc) + +target_include_directories(${LIBRARY_NAME} PUBLIC .) diff --git a/course03/homework00/julian/src/date.cc b/course03/homework00/julian/src/date.cc new file mode 100755 index 0000000..c42fb14 --- /dev/null +++ b/course03/homework00/julian/src/date.cc @@ -0,0 +1,86 @@ +#include "date.h" +#include + +namespace CppCourse { namespace Homework1 { + +Date::Date(int year, int month, int day) +: mYear(year), + mMonth(month), + mDay(day) +{ + if (mYear < 0) + throw std::runtime_error("Year is not valid."); + + if (mMonth < 0 || mMonth > 12) + throw std::runtime_error("Month is not valid."); + + // Ignoring special cases like leap years, or 30 vs 31 etc. + if (mDay < 0 || mDay > 31) + throw std::runtime_error("Day is not valid."); +} + +int Date::GetYear() const +{ + return mYear; +} + +int Date::GetMonth() const +{ + return mMonth; +} + +int Date::GetDay() const +{ + return mDay; +} + +std::string Date::ToString() const +{ + return std::to_string(mYear) + "-" + std::to_string(mMonth) + "-" + std::to_string(mDay); +} + +bool Date::operator== (const Date& other) const +{ + return mYear == other.mYear && mMonth == other.mMonth && mDay == other.mDay; +} + +bool Date::operator!= (const Date& other) const +{ + return !(*this == other); +} + +bool Date::operator< (const Date& other) const +{ + return *this != other && !(*this > other); +} + +bool Date::operator> (const Date& other) const +{ + if (mYear == other.mYear) + { + if (mMonth == other.mMonth) + { + return mDay > other.mDay; + } + else + { + return mMonth > other.mMonth; + } + } + else + { + return mYear > other.mYear; + } +} + +bool Date::operator<= (const Date& other) const +{ + return !(*this > other); +} + +bool Date::operator>= (const Date& other) const +{ + return !(*this < other); +} + +}}; \ No newline at end of file diff --git a/course03/homework00/julian/src/date.h b/course03/homework00/julian/src/date.h new file mode 100755 index 0000000..86d9f70 --- /dev/null +++ b/course03/homework00/julian/src/date.h @@ -0,0 +1,31 @@ +#pragma once + +#include + +namespace CppCourse { namespace Homework1 { + +class Date +{ +public: + Date(int year, int month, int day); + + int GetYear() const; + int GetMonth() const; + int GetDay() const; + + std::string ToString() const; + + bool operator== (const Date& other) const; + bool operator!= (const Date& other) const; + bool operator< (const Date& other) const; + bool operator> (const Date& other) const; + bool operator<= (const Date& other) const; + bool operator>= (const Date& other) const; + +private: + int mYear; + int mMonth; + int mDay; +}; + +}}; \ No newline at end of file diff --git a/course03/homework00/julian/src/test.cc b/course03/homework00/julian/src/test.cc new file mode 100755 index 0000000..e07c0f8 --- /dev/null +++ b/course03/homework00/julian/src/test.cc @@ -0,0 +1,113 @@ +#include "date.h" +#include + +typedef CppCourse::Homework1::Date Date; + +void TestEqual(const Date& date1, const Date& date2) +{ + std::cout << "Test equal: "; + bool result = date1 == date2; + + std::cout << date1.ToString() << " == " << date2.ToString() << ": " << std::to_string(result) << std::endl; +} + +void TestNotEqual(const Date& date1, const Date& date2) +{ + std::cout << "Test not equal: "; + bool result = date1 != date2; + + std::cout << date1.ToString() << " != " << date2.ToString() << ": " << std::to_string(result) << std::endl; +} + +void TestLessThan(const Date& date1, const Date& date2) +{ + std::cout << "Test less than: "; + bool result = date1 < date2; + + std::cout << date1.ToString() << " < " << date2.ToString() << ": " << std::to_string(result) << std::endl; +} + +void TestGreaterThan(const Date& date1, const Date& date2) +{ + std::cout << "Test greater than: "; + bool result = date1 > date2; + + std::cout << date1.ToString() << " > " << date2.ToString() << ": " << std::to_string(result) << std::endl; +} + +void TestLessThanEqual(const Date& date1, const Date& date2) +{ + std::cout << "Test <=: "; + bool result = date1 <= date2; + + std::cout << date1.ToString() << " <= " << date2.ToString() << ": " << std::to_string(result) << std::endl; +} + +void TestGreaterThanEqual(const Date& date1, const Date& date2) +{ + std::cout << "Test >=: "; + bool result = date1 >= date2; + + std::cout << date1.ToString() << " >= " << date2.ToString() << ": " << std::to_string(result) << std::endl; +} + +void TestCompareDates(const Date& base, const Date& lessThanBase, const Date& greaterThanBase) +{ + TestEqual(base, base); + TestEqual(base, lessThanBase); + TestEqual(base, greaterThanBase); + + std::cout << std::endl; + + TestNotEqual(base, base); + TestNotEqual(base, lessThanBase); + TestNotEqual(base, greaterThanBase); + + std::cout << std::endl; + + TestLessThan(base, base); + TestLessThan(base, lessThanBase); + TestLessThan(base, greaterThanBase); + + std::cout << std::endl; + + TestGreaterThan(base, base); + TestGreaterThan(base, lessThanBase); + TestGreaterThan(base, greaterThanBase); + + std::cout << std::endl; + + TestLessThanEqual(base, base); + TestLessThanEqual(base, lessThanBase); + TestLessThanEqual(base, greaterThanBase); + + std::cout << std::endl; + + TestGreaterThanEqual(base, base); + TestGreaterThanEqual(base, lessThanBase); + TestGreaterThanEqual(base, greaterThanBase); +} + +int main(int argc, char** argv) +{ + std::cout << "Starting tests" << std::endl; + + Date baseDay {2019, 01, 02}; + Date lessThanBaseDay {2019, 01, 01}; + Date greaterThanBaseDay {2019, 01, 03}; + + Date baseMonth {2019, 02, 01}; + Date lessThanBaseMonth {2019, 01, 01}; + Date greaterThanBaseMonth {2019, 03, 01}; + + Date baseDayYear {2020, 01, 01}; + Date lessThanBaseDayYear {2019, 01, 01}; + Date greaterThanBaseDayYear {2021, 01, 01}; + + std::cout << std::endl << "COMPARE DATES DAY" << std::endl; + TestCompareDates(baseDay, lessThanBaseDay, greaterThanBaseDay); + std::cout << std::endl << "COMPARE DATES MONTH" << std::endl; + TestCompareDates(baseMonth, lessThanBaseMonth, greaterThanBaseMonth); + std::cout << std::endl << "COMPARE DATES YEAR" << std::endl; + TestCompareDates(baseDayYear, lessThanBaseDayYear, greaterThanBaseDayYear); +} \ No newline at end of file diff --git a/course03/homework00/main.cc b/course03/homework00/main.cc new file mode 100644 index 0000000..1b92577 --- /dev/null +++ b/course03/homework00/main.cc @@ -0,0 +1,29 @@ +#include +#include + +struct Date +{ + explicit Date(int year, int month, int day) : + year{year}, + month{month}, + day{day} + {} + + void toString() { + std::cout << year << "-" << month << "-" << day << std::endl; + } + + const int year; + const int month; + const int day; +}; + + +int main() +{ + Date date{2019, 1, 12}; + + date.toString(); + + return 0; +} diff --git a/course03/homework01/balint/CMakeLists.txt b/course03/homework01/balint/CMakeLists.txt new file mode 100644 index 0000000..2e3413e --- /dev/null +++ b/course03/homework01/balint/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 3.1) + +find_package(GTest REQUIRED) +include_directories(${GTEST_INCLUDE_DIRS}) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -g -Wall") +add_executable(main main.cpp) + +add_executable(runTests tests.cpp) +target_link_libraries(runTests ${GTEST_LIBRARIES} pthread) diff --git a/course03/homework01/balint/llist.cpp b/course03/homework01/balint/llist.cpp new file mode 100644 index 0000000..45a10ce --- /dev/null +++ b/course03/homework01/balint/llist.cpp @@ -0,0 +1,131 @@ +#include +#include +#include + +struct Node +{ + int melem; + std::unique_ptr mnext; + + Node() : melem(), mnext(){}; + Node(int i) : melem(i), mnext(){}; + + ~Node() { mnext.reset(); } + Node(const Node &other) + { + if (other.melem) + { + melem = other.melem; + } + if (other.mnext) + { + mnext = std::make_unique(*other.mnext); + } + } + Node &operator=(const Node &other) + { + if (other.melem) + { + melem = other.melem; + } + if (other.mnext) + { + mnext = std::make_unique(*other.mnext); + } + return *this; + } +}; + +typedef std::unique_ptr Lst; + +class LLint +{ + public: + operator bool() const { return mlist ? mlist->melem ? true : false : false; } + ~LLint() { mlist.reset(); } + LLint(const LLint &other) { mlist = std::make_unique(*other.mlist); } + LLint &operator=(const LLint &other) + { + mlist = other.mlist ? std::make_unique(*other.mlist) : nullptr; + return *this; + } + LLint(const Lst &lst) { mlist = lst ? std::make_unique(*lst) : nullptr; } + LLint(Node n) { mlist = std::make_unique(n); } + Node copyNode() { return Node(*mlist); } + Node copyNodeMnext() { return Node(*(*mlist).mnext); } + static LLint emptyList() { return LLint(nullptr); } + // int operator[](int i) const {return nth(*this, i);} + int car() const + { + if (*this) + { + return (*mlist).melem; + } + else + { + throw std::runtime_error("Car called on empty mlist."); + } + } + LLint cdr() const + { + if (*this) + { + return LLint(mlist->mnext); + } + else + { + return LLint(nullptr); + } + } + + Lst mlist; +}; + +LLint cons(int i, LLint l) +{ + // return LLint(*(*l.mlist).mnext); + Node firstNode = Node(i); + Lst restOfList = l.mlist ? std::make_unique(*l.mlist) : nullptr; + firstNode.mnext = std::move(restOfList); + return firstNode; +} + +int nth(const LLint &l, int i) +{ + if (i < 0) + { + throw std::runtime_error("Cant index with negative index"); + } + if (i == 0) + { + return l.car(); + } + else + { + return nth(l.cdr(), i - 1); + } +} + +LLint pushBack(const LLint &l, int i) +{ + if (l) + { + return cons(l.car(), pushBack(l.cdr(), i)); + } + else + { + return LLint(i); + } +} + +int len(const LLint &l) +{ + if (l) + { + return 1 + len(l.cdr()); + } + else + { + return 0; + } +} diff --git a/course03/homework01/balint/main.cpp b/course03/homework01/balint/main.cpp new file mode 100644 index 0000000..2da18e4 --- /dev/null +++ b/course03/homework01/balint/main.cpp @@ -0,0 +1,39 @@ +#include "llist.cpp" + +// TESTS + +int main() +{ + int i; + Node n = {3}; + Node m = {4}; + Lst tmp = std::make_unique(m); + Lst tmp2 = std::make_unique(n); + Node m2 = m; + Node m3 = Node(m); + // m2.mnext = std::move(m3); + m2.mnext = std::make_unique(m3); + LLint ls1 = LLint(m3); + LLint ls3 = LLint(n); + LLint ls2 = ls1; + ls2.mlist->mnext = std::move(ls3.mlist); + // LLint ls2_cad = cad(ls2); + // std::cout<<"car of ls2: "< +#include +#include + +class LinkedListInt { +public: + bool isEmpty() const { return elem ? false : true; } + LinkedListInt static emptyList() { + LinkedListInt retval; + return retval; + }; + + LinkedListInt(int i, LinkedListInt &l) { + elem = std::make_unique(i); + if (l) { + next = std::make_unique(*(l.elem), *(l.next)); + } else { + next = std::make_unique(); + } + }; + + LinkedListInt(int i) { + elem = std::make_unique(i); + next = std::make_unique(); + }; + + LinkedListInt() : elem(), next(){}; + std::unique_ptr car() { return std::make_unique(*elem); } + + operator bool() const { return isEmpty(); } + + LinkedListInt cad() const { + if (isEmpty()) { + return emptyList(); + } + if (next->isEmpty()) { + return emptyList(); + } else { + // return LinkedListInt(*this->car(), *((*(next)).next)); + return LinkedListInt(*next->car(), *((*(next)).next)); + } + } + + LinkedListInt &operator=(const LinkedListInt &other) { + + if (other) { + auto newelem = std::make_unique(*other.elem); + elem = std::move(newelem); + if (*(other.next)) { + auto newnext = std::make_unique(*(*other.next).elem, + *(*other.next).next); + next = std::move(newnext); + } + } + return *this; + } + LinkedListInt(const LinkedListInt &other) { + if (other) { + // LinkedListInt(*(other.elem), *(other.next)) + std::unique_ptr newelem = std::make_unique(*other.elem); + elem = std::move(newelem); + + if (*(other.next)) { + auto newnext = std::make_unique(*(*other.next).elem, + *(*other.next).next); + next = std::move(newnext); + } else { + auto newnext = std::make_unique(); + next = std::move(newnext); + } + } + } + ~LinkedListInt(){ + elem.reset(); + next.reset(); + } + +private: + std::unique_ptr elem; + std::unique_ptr next; +}; + +LinkedListInt cons(int i, LinkedListInt &l) { + LinkedListInt retval = LinkedListInt(i, l); + return retval; +}; + +std::unique_ptr car(LinkedListInt l) { return l.car(); } + +LinkedListInt cad(const LinkedListInt &l) { return l.cad(); } + +LinkedListInt pushBack(LinkedListInt& orig, int newelem){ + if (orig){ + LinkedListInt tmp1 = cad(orig); + LinkedListInt tmp2 = pushBack(tmp1, newelem); + + return LinkedListInt(*car(orig), tmp2); + } + else{ + return LinkedListInt(newelem); + } +} + +int main() { + LinkedListInt test = LinkedListInt(); + if (test.isEmpty()) { + std::cout << "test is empty" << std::endl; + } + if (!test.isEmpty()) { + std::cout << "test is NOT empty" << std::endl; + } + + LinkedListInt test2 = 3; + if (test2.isEmpty()) { + std::cout << "test2 is empty" << std::endl; + } + if (!test2.isEmpty()) { + std::cout << "test2 is NOT empty" << std::endl; + } + + LinkedListInt test3 = {4, test2}; + std::cout << "test3 is empty" << std::endl; + + if (test3.isEmpty()) { + std::cout << "test3 is empty" << std::endl; + } + if (!test3) { + std::cout << "test3 is NOT empty" << std::endl; + } + + // LinkedListInt test4 = cad(test3); + LinkedListInt test4 = test3.cad(); + if (test4.isEmpty()) { + std::cout << "test4 is empty" << std::endl; + } + if (!test4.isEmpty()) { + std::cout << "test4 is NOT empty" << std::endl; + } + + LinkedListInt test5 = pushBack(test3, 99); + if (test5.isEmpty()) { + std::cout << "test5 is empty" << std::endl; + } + if (!test5.isEmpty()) { + std::cout << "test5 is NOT empty" << std::endl; + } + + return 0; +} diff --git a/course03/homework01/balint/tests.cpp b/course03/homework01/balint/tests.cpp new file mode 100644 index 0000000..4aa1fc4 --- /dev/null +++ b/course03/homework01/balint/tests.cpp @@ -0,0 +1,142 @@ +#include "gtest/gtest.h" +#include "llist.cpp" + +TEST(NodeTest, ReadingOut) +{ + Node m = {3}; + ASSERT_EQ(3, m.melem); + Node mcopy = m; + ASSERT_EQ(3, mcopy.melem); + Node m2 = {4}; + ASSERT_EQ(4, m2.melem); + mcopy = m2; + ASSERT_EQ(4, mcopy.melem); + Node m3 = Node(m2); + ASSERT_EQ(4, m3.melem); +} + +TEST(LLintTest, Creating) +{ + Node m = {3}; + LLint l1 = m; + ASSERT_EQ(3, (*l1.mlist).melem); + LLint l2 = l1; + ASSERT_EQ(3, (*l2.mlist).melem); +} + +TEST(LLintTest, cars) +{ + Node m = {3}; + LLint l1 = m; + ASSERT_EQ(3, l1.car()); +} + +TEST(LLintTest, CarOnEmptyThrows) +{ + Node m; + LLint l = m; + try + { + int i = l.car(); + i += 1; + } + catch (std::runtime_error const &err) + { + EXPECT_EQ(err.what(), std::string("Car called on empty mlist.")); + } +} +TEST(LLintTest, cdrOnEmpty) +{ + Node m; + LLint l = m; + LLint cdrOfL = l.cdr(); + int i = 99; + if (cdrOfL) + { + i = -1; + } + else + { + i = 42; + } + + ASSERT_EQ(i, 42); +} +TEST(LLintTest, consReading) +{ + LLint l = cons(1, cons(2, cons(3, cons(4, LLint::emptyList())))); + ASSERT_EQ(l.car(), 1); + ASSERT_EQ(l.cdr().car(), 2); + ASSERT_EQ(l.cdr().cdr().car(), 3); + ASSERT_EQ(l.cdr().cdr().cdr().car(), 4); +} +TEST(LLintTest, nth) +{ + LLint l = cons(1, cons(2, cons(3, cons(4, LLint::emptyList())))); + ASSERT_EQ(nth(l, 0), 1); + ASSERT_EQ(nth(l, 1), 2); + ASSERT_EQ(nth(l, 2), 3); + ASSERT_EQ(nth(l, 3), 4); + try + { + int i = nth(l, 4); + i += 1; + } + catch (std::runtime_error const &err) + { + EXPECT_EQ(err.what(), std::string("Car called on empty mlist.")); + } + try + { + int i = nth(l, -1); + i += 1; + } + catch (std::runtime_error const &err) + { + EXPECT_EQ(err.what(), std::string("Cant index with negative index")); + } +} + +TEST(LLintTest, pushBack) +{ + LLint lshort = cons(1, cons(2, cons(3, cons(4, LLint::emptyList())))); + LLint l = pushBack(lshort, 42); + ASSERT_EQ(nth(l, 0), 1); + ASSERT_EQ(nth(l, 1), 2); + ASSERT_EQ(nth(l, 2), 3); + ASSERT_EQ(nth(l, 3), 4); + ASSERT_EQ(nth(l, 4), 42); + try + { + int i = nth(l, 5); + i += 1; + } + catch (std::runtime_error const &err) + { + EXPECT_EQ(err.what(), std::string("Car called on empty mlist.")); + } + try + { + int i = nth(l, -1); + i += 1; + } + catch (std::runtime_error const &err) + { + EXPECT_EQ(err.what(), std::string("Cant index with negative index")); + } +} + +TEST(LLintTest, len) +{ + LLint l = cons(1, cons(2, cons(3, cons(4, LLint::emptyList())))); + ASSERT_EQ(len(l), 4); + ASSERT_EQ(len(l.cdr()), 3); + ASSERT_EQ(len(l.cdr().cdr()), 2); + ASSERT_EQ(len(l.cdr().cdr().cdr()), 1); + ASSERT_EQ(len(l.cdr().cdr().cdr().cdr()), 0); +} +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/course03/homework01/julian/.gitignore b/course03/homework01/julian/.gitignore new file mode 100755 index 0000000..865edf1 --- /dev/null +++ b/course03/homework01/julian/.gitignore @@ -0,0 +1,2 @@ +cmake-build-debug +gtest \ No newline at end of file diff --git a/course03/homework01/julian/CMakeLists.txt b/course03/homework01/julian/CMakeLists.txt new file mode 100755 index 0000000..519cc4f --- /dev/null +++ b/course03/homework01/julian/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION 3.5.1) + +project(cpp_class_hw2_julianbrendl LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 14) + +add_subdirectory(src) +add_subdirectory(tests) diff --git a/course03/homework01/julian/README.md b/course03/homework01/julian/README.md new file mode 100755 index 0000000..e69de29 diff --git a/course03/homework01/julian/src/CMakeLists.txt b/course03/homework01/julian/src/CMakeLists.txt new file mode 100755 index 0000000..eece0c6 --- /dev/null +++ b/course03/homework01/julian/src/CMakeLists.txt @@ -0,0 +1,10 @@ +set(LIBRARY_NAME hw2_lib) + +add_library(${LIBRARY_NAME} tuple.h linked_list.cc) + +find_package(Boost 1.58 REQUIRED) +include_directories(${Boost_INCLUDE_DIRS}) +target_link_libraries(${LIBRARY_NAME} ${Boost_LIBRARIES}) + +target_compile_options(${LIBRARY_NAME} PRIVATE ${cxx_compile_options}) +target_include_directories(${LIBRARY_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/course03/homework01/julian/src/linked_list.cc b/course03/homework01/julian/src/linked_list.cc new file mode 100644 index 0000000..9d44927 --- /dev/null +++ b/course03/homework01/julian/src/linked_list.cc @@ -0,0 +1,8 @@ +#include "tuple.h" + +namespace CppCourse { namespace Homework2 { + +// CMake would complain if there was no cc file + +}}; + diff --git a/course03/homework01/julian/tests/CMakeLists.txt b/course03/homework01/julian/tests/CMakeLists.txt new file mode 100644 index 0000000..b49e50b --- /dev/null +++ b/course03/homework01/julian/tests/CMakeLists.txt @@ -0,0 +1,17 @@ +include(gtest.cmake) + +set(sources tests.cc) + +add_executable(tests ${sources}) + +find_package(Boost 1.58 REQUIRED) +include_directories(${Boost_INCLUDE_DIRS}) + +find_package (Threads) +target_link_libraries(tests + hw2_lib + gtest + ${CMAKE_THREAD_LIBS_INIT} + ${Boost_LIBRARIES} + ) +add_test(tests tests) diff --git a/course03/homework01/julian/tests/gtest.cmake b/course03/homework01/julian/tests/gtest.cmake new file mode 100644 index 0000000..1fae6b0 --- /dev/null +++ b/course03/homework01/julian/tests/gtest.cmake @@ -0,0 +1,17 @@ +set(GOOGLETEST_ROOT gtest/googletest CACHE STRING "Google Test source root") + +include_directories(SYSTEM + ${PROJECT_SOURCE_DIR}/${GOOGLETEST_ROOT} + ${PROJECT_SOURCE_DIR}/${GOOGLETEST_ROOT}/include + ) + +set(GOOGLETEST_SOURCES + ${PROJECT_SOURCE_DIR}/${GOOGLETEST_ROOT}/src/gtest-all.cc + ${PROJECT_SOURCE_DIR}/${GOOGLETEST_ROOT}/src/gtest_main.cc + ) + +foreach(_source ${GOOGLETEST_SOURCES}) + set_source_files_properties(${_source} PROPERTIES GENERATED 1) +endforeach() + +add_library(gtest ${GOOGLETEST_SOURCES}) diff --git a/course03/homework01/julian/tests/tests.cc b/course03/homework01/julian/tests/tests.cc new file mode 100644 index 0000000..f3839a5 --- /dev/null +++ b/course03/homework01/julian/tests/tests.cc @@ -0,0 +1,112 @@ +#include "tuple.h" + +#include + +TEST(LinkedListTests, Initialization) +{ + CppCourse::Homework2::LinkedList linkedList; + EXPECT_TRUE(linkedList.isEmpty()); + EXPECT_EQ(linkedList.size(), 0); +} + +TEST(LinkedListTests, SimplePush) +{ + CppCourse::Homework2::LinkedList linkedList; + EXPECT_EQ(linkedList.size(), 0); + + linkedList.push(10); + EXPECT_EQ(linkedList.get(0), 10); + EXPECT_EQ(linkedList.size(), 1); +} + +TEST(LinkedListTests, Push) +{ + CppCourse::Homework2::LinkedList linkedList; + EXPECT_EQ(linkedList.size(), 0); + + for (int i = 0; i < 100; i++) + { + linkedList.push(i); + } + EXPECT_EQ(linkedList.size(), 100); +} + +TEST(LinkedListTests, PushAndRetrieve) +{ + CppCourse::Homework2::LinkedList linkedList; + EXPECT_EQ(linkedList.size(), 0); + + for (int i = 0; i < 100; i++) + { + linkedList.push(i); + } + EXPECT_EQ(linkedList.size(), 100); + + for (int i = 0; i < 100; i++) + { + EXPECT_EQ(linkedList.get(i), i); + } + EXPECT_EQ(linkedList.size(), 100); +} + +TEST(LinkedListTests, SimplePop) +{ + CppCourse::Homework2::LinkedList linkedList; + EXPECT_EQ(linkedList.size(), 0); + + linkedList.push(10); + EXPECT_EQ(linkedList.size(), 1); + + int value = linkedList.pop(); + EXPECT_EQ(value, 10); + EXPECT_EQ(linkedList.size(), 0); +} + +TEST(LinkedListTests, PushAndPop) +{ + CppCourse::Homework2::LinkedList linkedList; + EXPECT_EQ(linkedList.size(), 0); + + for (int i = 0; i < 100; i++) + { + linkedList.push(i); + } + EXPECT_EQ(linkedList.size(), 100); + + for (int i = 99; i >= 0; i--) + { + int value = linkedList.pop(); + EXPECT_EQ(value, i); + } + EXPECT_EQ(linkedList.size(), 0); +} + +TEST(LinkedListTests, TestIndexOutOfBounds) +{ + CppCourse::Homework2::LinkedList linkedList; + EXPECT_TRUE(linkedList.isEmpty()); + EXPECT_EQ(linkedList.size(), 0); + + for (int i = 0; i < 100; i++) + { + linkedList.push(i); + } + EXPECT_EQ(linkedList.size(), 100); + + EXPECT_ANY_THROW(linkedList.get(101)); +} + +TEST(LinkedListTests, TestEmptyPop) +{ + CppCourse::Homework2::LinkedList linkedList; + EXPECT_TRUE(linkedList.isEmpty()); + EXPECT_EQ(linkedList.size(), 0); + + EXPECT_ANY_THROW(linkedList.pop()); +} + +int main(int argc, char **argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/course03/homework01/thomas/CMakeLists.txt b/course03/homework01/thomas/CMakeLists.txt new file mode 100644 index 0000000..f671c44 --- /dev/null +++ b/course03/homework01/thomas/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 3.1) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -g -Wall") +add_executable(main main.cc list.h list.cc) + +add_executable(test test.cc list.h list.cc) +target_link_libraries(test gtest) diff --git a/course03/homework01/thomas/list.cc b/course03/homework01/thomas/list.cc new file mode 100644 index 0000000..fe56b6d --- /dev/null +++ b/course03/homework01/thomas/list.cc @@ -0,0 +1,64 @@ +#include +#include +#include "list.h" + +Node::Node(Foo value) + : mValue{value} {}; + +Node::Node(Foo value, std::unique_ptr ptr) + : next{std::move(ptr)}, mValue{value} {}; + + void Node::insert_after(Foo value) { + std::unique_ptr new_next = + std::make_unique(value, std::move(next)); + next = std::move(new_next); + } + + + + void LinkedList::push_back(Foo value) { + std::unique_ptr new_node = std::make_unique(value); + + if (!start) { + start = std::move(new_node); + } else { + Node *next = start.get(); + while (next->next) { + std::cout << next->getValue().getI() << '\n'; + next = next->next.get(); + } + next->next = std::move(new_node); + } + } + + void LinkedList::print() { + /* Used raw pointers here. Can see no way of doing it differently (except */ + /* recursion) */ + + if (!start) { + std::cout << "Empty list" << '\n'; + } + + std::cout << "Foo:" << start->getValue().getI() << '\n'; + + Node *next = start->next.get(); + while (next) { + std::cout << "Foo:" << next->getValue().getI() << '\n'; + next = next->next.get(); + } + } + int LinkedList::len() { + if (!start) { + return 0; + } else { + int n = 1; + Node *next = start.get(); + while (next->next) { + n += 1; + next = next->next.get(); + } + return n; + } + } + + diff --git a/course03/homework01/thomas/list.h b/course03/homework01/thomas/list.h new file mode 100644 index 0000000..6e601e3 --- /dev/null +++ b/course03/homework01/thomas/list.h @@ -0,0 +1,38 @@ +#include + +class Foo { +public: + explicit Foo(int i) : mI{i} {} + + int getI() { return mI; } + +private: + int mI; +}; + + +class Node { +public: + Node(Foo value); + Node(Foo value, std::unique_ptr ptr); + + void insert_after(Foo value); + Foo getValue() { return mValue; } + + std::unique_ptr next = nullptr; + +private: + Foo mValue; +}; + +class LinkedList { +public: + LinkedList() = default; + + void push_back(Foo value) ; + void print(); + int len(); +private: + std::unique_ptr start = nullptr; +}; + diff --git a/course03/homework01/thomas/main.cc b/course03/homework01/thomas/main.cc new file mode 100644 index 0000000..85b2612 --- /dev/null +++ b/course03/homework01/thomas/main.cc @@ -0,0 +1,19 @@ +#include "list.h" +#include + +int main() { + + LinkedList list; + + Foo foo{5}; + Foo foo2{6}; + + list.push_back(foo); + list.print(); + list.push_back(foo2); + list.print(); + + std::cout << list.len() << '\n'; + + return 0; +} diff --git a/course03/homework01/thomas/test.cc b/course03/homework01/thomas/test.cc new file mode 100644 index 0000000..3f5a50b --- /dev/null +++ b/course03/homework01/thomas/test.cc @@ -0,0 +1,22 @@ +#include "list.h" +#include "gtest/gtest.h" + +TEST(LinkedList, init) { LinkedList list; } + +TEST(LinkedList, length) { + LinkedList list; + EXPECT_EQ(list.len(), 0); + + Foo foo{5}; + Foo foo2{6}; + + list.push_back(foo); + EXPECT_EQ(list.len(), 1); + list.push_back(foo2); + EXPECT_EQ(list.len(), 2); +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/course03/homework02/CMakeLists.txt b/course03/homework02/CMakeLists.txt new file mode 100644 index 0000000..1bce451 --- /dev/null +++ b/course03/homework02/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 3.1) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -g -Wall") + +add_executable(main main.cc date.cc) diff --git a/course03/homework02/date.cc b/course03/homework02/date.cc new file mode 100644 index 0000000..953c707 --- /dev/null +++ b/course03/homework02/date.cc @@ -0,0 +1,73 @@ +#include "date.h" +#include + +namespace cppcourse { + +using namespace std; + +Date::Date() + : mDay{1} + , mMonth{1} + , mYear{1900} {} + +Date::Date(uint8_t day, uint8_t month, uint32_t year) + : mDay{day} + , mMonth{month} + , mYear{year} {} + +Date Date::AddDays(uint8_t days) +{ +return Date{}; +} + +Date Date::AddMonths(uint8_t months) +{ +return Date{}; +} + +Date Date::AddYears(uint32_t years) +{ +return Date{}; +} + +inline bool LeapYear(uint32_t year) +{ + return year % 4 == 0 + && year % 100 != 0 + && year % 400 == 0; +} + +inline char GetDaysInMonth(uint32_t year, uint8_t month) +{ + if (month == 2) + return LeapYear(year) ? 29 : 28; + return 31 - (month -1) % 7 % 2; +} + +bool Date::IsLeapYear() +{ + return LeapYear(mYear); +} + + +bool Date::IsValidMonth() +{ + return mMonth >= 1 && mMonth <= 12; +} + +bool Date::IsValidDay() +{ + return mDay >= 1 && mDay <= GetDaysInMonth(mMonth, mYear); +} + +bool Date::IsValid() +{ + return IsValidMonth() && IsValidDay(); +} + +void Date::Print() +{ + cout << mDay << "-" << mMonth << "-" << mYear << endl; +} + +} diff --git a/course03/homework02/date.h b/course03/homework02/date.h new file mode 100644 index 0000000..c047ec1 --- /dev/null +++ b/course03/homework02/date.h @@ -0,0 +1,33 @@ +#pragma once +#include + +namespace cppcourse { + +class Date +{ +public: + Date(); + Date(uint8_t day, uint8_t month, uint32_t year); + + Date AddDays(uint8_t days); + Date AddMonths(uint8_t months); + Date AddYears(uint32_t years); + + bool IsLeapYear(); + bool IsValid(); + + void Print(); + + //TODO: print with formatting. + //TODO: override the stream operator + //TODO: override the +/-/== operator + +private: + bool IsValidMonth(); + bool IsValidDay(); + + uint8_t mDay; + uint8_t mMonth; + uint32_t mYear; +}; +} diff --git a/course03/homework02/main.cc b/course03/homework02/main.cc new file mode 100644 index 0000000..5c29993 --- /dev/null +++ b/course03/homework02/main.cc @@ -0,0 +1,17 @@ +#include +#include +#include "date.h" + +using namespace cppcourse; + +int main(int argc, char** argv) +{ + Date d0; + d0.Print(); + std::cout << "Valid: " << d0.IsValid() << std::endl; + Date d1 {3, 12, 2019}; + d1.Print(); + std::cout << "Valid: " << d1.IsValid() << std::endl; + + return 0; +} diff --git a/course03/meeting00/CMakeLists.txt b/course03/meeting00/CMakeLists.txt new file mode 100644 index 0000000..af41c94 --- /dev/null +++ b/course03/meeting00/CMakeLists.txt @@ -0,0 +1,4 @@ +cmake_minimum_required(VERSION 3.1) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -g -Wall") +add_executable(main main.cc) diff --git a/course03/meeting00/main.cc b/course03/meeting00/main.cc new file mode 100644 index 0000000..7c2274f --- /dev/null +++ b/course03/meeting00/main.cc @@ -0,0 +1,12 @@ +#include +#include + +int main(int argc, char** argv) +{ + const std::string name{argv[1]}; + + std::string greeting = "Hello, " + name; + std::cout << greeting << std::endl; + + return 0; +} diff --git a/course03/meeting01/CMakeLists.txt b/course03/meeting01/CMakeLists.txt new file mode 100644 index 0000000..af41c94 --- /dev/null +++ b/course03/meeting01/CMakeLists.txt @@ -0,0 +1,4 @@ +cmake_minimum_required(VERSION 3.1) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -g -Wall") +add_executable(main main.cc) diff --git a/course03/meeting01/example0.h b/course03/meeting01/example0.h new file mode 100644 index 0000000..9333421 --- /dev/null +++ b/course03/meeting01/example0.h @@ -0,0 +1,8 @@ +#include + +void example0() +{ + std::uint8_t a{255}; + ++a; + std::cout << (int)a << std::endl; +} diff --git a/course03/meeting01/example1.h b/course03/meeting01/example1.h new file mode 100644 index 0000000..ce0c67c --- /dev/null +++ b/course03/meeting01/example1.h @@ -0,0 +1,8 @@ +#include + +void example1() +{ + std::int8_t a{127}; + ++a; + std::cout << (int)a << std::endl; +} diff --git a/course03/meeting01/example2.h b/course03/meeting01/example2.h new file mode 100644 index 0000000..3251bfc --- /dev/null +++ b/course03/meeting01/example2.h @@ -0,0 +1,11 @@ +#include + +std::uint8_t example2() +{ + std::uint8_t a = 100; + std::uint8_t b = 200; + + return (a + b) / 2; + //std::uint8_t c = (a + b) / 2; + //std::cout << (int)c << std::endl; +} diff --git a/course03/meeting01/example3.h b/course03/meeting01/example3.h new file mode 100644 index 0000000..377bdab --- /dev/null +++ b/course03/meeting01/example3.h @@ -0,0 +1,7 @@ +#include + +auto example3() +{ + auto c = 'A'; + return c + 1; +} diff --git a/course03/meeting01/example4.h b/course03/meeting01/example4.h new file mode 100644 index 0000000..38d25ec --- /dev/null +++ b/course03/meeting01/example4.h @@ -0,0 +1,7 @@ +#include + +auto example4() +{ + unsigned int i = 2; + return i - 10; +} diff --git a/course03/meeting01/main.cc b/course03/meeting01/main.cc new file mode 100644 index 0000000..b179c57 --- /dev/null +++ b/course03/meeting01/main.cc @@ -0,0 +1,60 @@ +#include +#include +#include +#include + +int i = 1; +int j; + +using namespace std::chrono_literals; + +int* foo() +{ + return &i; +} + +/* +int main(int argc, char** argv) +{ + int k; + + std::cout << &i << std::endl; + std::cout << &j << std::endl; + std::cout << &k << std::endl; + std::cout << "foo " << std::endl; + + std::this_thread::sleep_for(30s); + + return 0; +} +*/ + +#include "example3.h" + +#include + +int main() +{ + + //std::cout << typeid(example3()).name() << std::endl; + + double d1, d2; + //if (abs(d1 - d2) < epsilon) + + if (!std::isfinite(d1)) + throw; + + int_fast8_t k; + int kk; + uint32_t i; + + int foo = 1000; + char cc = boost::numeric_cast(foo); + + + +} + + + + diff --git a/course03/meeting02/CMakeLists.txt b/course03/meeting02/CMakeLists.txt new file mode 100644 index 0000000..5fcacf9 --- /dev/null +++ b/course03/meeting02/CMakeLists.txt @@ -0,0 +1,4 @@ +cmake_minimum_required(VERSION 3.1) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -g -Wall") +add_executable(main main.cc a.h a.cc) diff --git a/course03/meeting02/a.cc b/course03/meeting02/a.cc new file mode 100644 index 0000000..e69de29 diff --git a/course03/meeting02/a.h b/course03/meeting02/a.h new file mode 100644 index 0000000..cd40d45 --- /dev/null +++ b/course03/meeting02/a.h @@ -0,0 +1,14 @@ +#pragma once + +//#include "b.h" + +class B; + +class A +{ +public: + A(); + + int mI; + B& mB; +}; diff --git a/course03/meeting02/main.cc b/course03/meeting02/main.cc new file mode 100644 index 0000000..6e3763b --- /dev/null +++ b/course03/meeting02/main.cc @@ -0,0 +1,78 @@ +#include + +#include +#include + +// parameter-in: pass by value ONLY if size <= word +void bar(std::vector); +void bar2(const std::vector&); + +// parameter-out +void bar2(std::vector&); + +void foo(int* pi) +{ + if (pi != nullptr) + { + *pi += 1; // dereference operator + } +} + +class B +{ +public: + B(int i = 0) + { + std::cout << "B(" << i << ")" << std::endl; + } +}; + +class A +{ +public: + explicit A(int& i) :// user defined ctor + mB{i}, + mI{i}, + mJ{mI} + {} + +private: + std::vector mStrings; + B mB; + const int mI; + const int& mJ; +}; + +void foo(const A& a) {} + +int main() +{ + { + Socket s{"80.0.0.1", 123}; + } // ~Socket() + + //foo(5); + + int ii = 5; + A a{ii}; + + + + + + + int i = 5; + std::cout << &i << std::endl; + + int* pi; + { + int k = 1; + pi = &k; + } + + std::cout << *pi << std::endl; + pi = &i; // address-of operator + pi = nullptr; + + return 0; +} diff --git a/course03/meeting03/CMakeLists.txt b/course03/meeting03/CMakeLists.txt new file mode 100644 index 0000000..97bb255 --- /dev/null +++ b/course03/meeting03/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 3.1) + +include(gtest.cmake) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -g -Wall -Wextra -fsanitize=undefined") +add_executable(main main.cc date.h date.cc) + +find_package(Boost 1.58 REQUIRED) +include_directories(${Boost_INCLUDE_DIRS}) + +find_package (Threads) +target_link_libraries(main + gtest + ${CMAKE_THREAD_LIBS_INIT} + ${Boost_LIBRARIES} +) +add_test(main main) + diff --git a/course03/meeting03/date.cc b/course03/meeting03/date.cc new file mode 100644 index 0000000..3c01e5e --- /dev/null +++ b/course03/meeting03/date.cc @@ -0,0 +1,70 @@ +#include "date.h" + +#include +#include +#include + +Date::Date() : + Date(1, 1, 1970) +{} + +Date::Date(int day, int month, int year) : + mDay(day), + mMonth(month), + mYear(year) +{ + if (!IsValid()) + { + throw std::runtime_error("invalid date"); + } +} + +/* NOT NEEDED +Date::Date(const Date& other) : + Date(other.mDay, other.mMonth, other.mYear) +{} + +Date& Date::operator=(const Date& other) +{ + mDay = other.mDay; + mMonth = other.mMonth; + mYear = other.mYear; + + if (!IsValid()) + { + throw std::runtime_error("invalid date"); + } + + return *this; +} +*/ + +bool Date::IsValid() const +{ + static const std::array MonthDays{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + + return mDay > 0 && mMonth > 0 && mMonth <= 12 + && mYear != 0 // no year 0 in gregorian calendar + && (mDay <= MonthDays[mMonth - 1] || (mDay == 29 && mMonth == 2 && IsLeapYear())); +} + +bool Date::IsLeapYear() const +{ + return IsLeapYear(mYear); +} + +bool Date::IsLeapYear(int year) +{ + if (year < 1) + { + ++year; + } + + return (year % 4 == 0 && year % 100 != 0) || year % 400 ==0; +} + +std::ostream& operator<<(std::ostream& stream, const Date& date) +{ + stream << date.GetDay() << "/" << date.GetMonth() << "/" << date.GetYear(); + return stream; +} diff --git a/course03/meeting03/date.h b/course03/meeting03/date.h new file mode 100644 index 0000000..1add734 --- /dev/null +++ b/course03/meeting03/date.h @@ -0,0 +1,31 @@ +#pragma once + +#include + +class Date +{ +public: + Date(); + explicit Date(int day, int month, int year); + + // rule of zero: no dtor, no copy ctor, no assignment op + // rule of three: + //Date(const Date&); + //Date& operator=(const Date&); + + int GetDay() const { return mDay; } + int GetMonth() const { return mMonth; } + int GetYear() const { return mYear; } + + bool IsLeapYear() const; + static bool IsLeapYear(int); + +private: + bool IsValid() const; + + int mDay; + int mMonth; + int mYear; +}; + +std::ostream& operator<<(std::ostream&, const Date&); diff --git a/course03/meeting03/gtest b/course03/meeting03/gtest new file mode 160000 index 0000000..9997a83 --- /dev/null +++ b/course03/meeting03/gtest @@ -0,0 +1 @@ +Subproject commit 9997a830ee5589c2da79198bc3b60d1c47e50118 diff --git a/course03/meeting03/main.cc b/course03/meeting03/main.cc new file mode 100644 index 0000000..8a2b375 --- /dev/null +++ b/course03/meeting03/main.cc @@ -0,0 +1,51 @@ +#include "date.h" + +#include + +#include + +/* +TEST(Date, Init) +{ + Date d; + EXPECT_EQ(1, d.GetDay()); + EXPECT_EQ(1, d.GetMonth()); + EXPECT_EQ(1970, d.GetYear()); +} + +TEST(Date, Invalid) +{ + EXPECT_ANY_THROW(Date(1, 1, 0)); +} + +class DateTest : public testing::Test +{ +public: + DateTest() + { + + } + + Date mDate; +}; + +TEST_F(DateTest, LeapYear) +{ + +} +*/ + +int main() +{ + Date d{1,2,2019}; + //std::cout << Date::IsLeapYear(2019) << std::endl; + + Date d2{d}; + + Date d3; + d3 = d; + std::cout << d2.GetDay() << std::endl; + + return 0; +} + diff --git a/course03/meeting04/CMakeLists.txt b/course03/meeting04/CMakeLists.txt new file mode 100644 index 0000000..2595f30 --- /dev/null +++ b/course03/meeting04/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 3.1) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -g -Wall") +add_executable(main main.cc foo.h) +add_executable(example example.cc) diff --git a/course03/meeting04/foo.h b/course03/meeting04/foo.h new file mode 100644 index 0000000..0150a6e --- /dev/null +++ b/course03/meeting04/foo.h @@ -0,0 +1,34 @@ +#pragma once + +#include + +class Foo +{ +public: + Foo(int i) : + mI(i) + { + //std::cout << "Foo(" << i << ")" << std::endl; + } + + ~Foo() + { + //std::cout << "~Foo()" << std::endl; + } + + Foo(const Foo& other) : + mI(other.mI) + { + //std::cout << "Foo(const Foo&)" << std::endl; + } + + Foo& operator=(const Foo& other) + { + mI = other.mI; + //std::cout << "operator=(const Foo&)" << std::endl; + return *this; + } + +private: + int mI; +}; diff --git a/course03/meeting04/main.cc b/course03/meeting04/main.cc new file mode 100644 index 0000000..c33223c --- /dev/null +++ b/course03/meeting04/main.cc @@ -0,0 +1,119 @@ +#include "foo.h" + +#include +#include +#include +#include +#include + +Foo CreateFoo(int i) +{ + Foo f{i}; + + if (i == 3) + return Foo{123}; + + return f; +} + +std::unique_ptr CreateFooHeap(int i) +{ + auto f = std::make_unique(i); + + if (i == 3) + return std::make_unique(123); + + return f; +} + +class unique_ptr_foo +{ +public: + unique_ptr_foo() =default; + + explicit unique_ptr_foo(int i) : + mFooPtr(new Foo(i)) + {} + + ~unique_ptr_foo() + { + delete mFooPtr; + } + + unique_ptr_foo(const unique_ptr_foo&) =delete; + unique_ptr_foo& operator=(const unique_ptr_foo&) =delete; + + Foo& operator*() { assert(mFooPtr != nullptr); return *mFooPtr; } + Foo* operator->() { assert(mFooPtr != nullptr); return mFooPtr; } + +private: + Foo* mFooPtr = nullptr; +}; + + +class Vector +{ +public: + Vector() =default; + + void push_back(int x) + { + if (mSize == mCapacity) + { + grow(); + } + + mData[mSize] = x; + ++mSize; + } + + std::size_t size() const { return mSize; } + std::size_t capacity() const { return mCapacity; } + int operator[](std::size_t i) const { return mData[i]; } + +private: + void grow() + { + const std::size_t newCapacity = mCapacity * 2 + 1; + auto newData = std::make_unique(newCapacity); + + std::copy_n(mData.get(), mSize, newData.get()); + + mCapacity = newCapacity; + mData = std::move(newData); + } + + std::unique_ptr mData; + std::size_t mSize = 0; + std::size_t mCapacity = 0; +}; + + +int main() +{ + Vector v; + + for (std::size_t i = 0; i < 100; ++i) + v.push_back(i); + + for (std::size_t i = 0; i < v.size(); ++i) + std::cout << v[i] << std::endl; + + + unique_ptr_foo fff{4}; + + auto start = std::chrono::steady_clock::now(); + for (int i = 0; i < 1000; ++i) + { + //const Foo f = CreateFoo(2); + auto f = CreateFooHeap(2); + asm volatile("" : : "r,m"(f.get()) : "memory"); + } + auto end = std::chrono::steady_clock::now(); + std::cout << (end - start).count() / 1000. << "ns/it" << std::endl; + + const Foo f = CreateFoo(2); + //auto ff = CreateFooHeap(2); + + return 0; +} diff --git a/course03/meeting06/CMakeLists.txt b/course03/meeting06/CMakeLists.txt new file mode 100644 index 0000000..1012bef --- /dev/null +++ b/course03/meeting06/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 3.1) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -g -Wall") +add_executable(main main.cc) +add_executable(example0 example0.cc) +add_executable(example1 example1.cc) +add_executable(example2 example2.cc) +add_executable(example3 example3.cc) + diff --git a/course03/meeting06/main.cc b/course03/meeting06/main.cc new file mode 100644 index 0000000..f0fc1de --- /dev/null +++ b/course03/meeting06/main.cc @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include + +template +class Range +{ +public: + static_assert(std::is_arithmetic_v, "T is not an arithmetic"); + + using value_type = T; + using difference_type = T; + + Range() =default; + + Range(T min, T max) : + mMin(min), + mMax(max) + { + if (mMin > mMax) + { + throw std::runtime_error("range"); + } + } + + bool Contains(T value) const; + + T Min() const { return mMin; } + T Max() const { return mMax; } + +private: + T mMin = std::numeric_limits::min(); + T mMax = std::numeric_limits::max(); +}; + +template +using InclRange = Range, std::less>; + +template +bool Range::Contains(T value) const +{ + return ComparatorLower{}(value, mMin) && ComparatorUpper{}(value, mMax);//value >= mMin && value < mMax; +} + + +template +typename RangeT::difference_type distance(RangeT r) +{ + return r.Max() - r.Min(); +} + +int main() +{ + Range r{1,5}; + std::cout << std::boolalpha << r.Contains(1) << std::endl; + std::cout << std::boolalpha << r.Contains(2) << std::endl; + std::cout << std::boolalpha << r.Contains(5) << std::endl; + return 0; +} diff --git a/course03/meeting07/CMakeLists.txt b/course03/meeting07/CMakeLists.txt new file mode 100644 index 0000000..046e00f --- /dev/null +++ b/course03/meeting07/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.1) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -g -Wall") +add_executable(main forward_list.h main.cc) +add_executable(example0 example0.cc) +add_executable(example1 example1.cc) diff --git a/course03/meeting07/forward_list.h b/course03/meeting07/forward_list.h new file mode 100644 index 0000000..ef25e44 --- /dev/null +++ b/course03/meeting07/forward_list.h @@ -0,0 +1,51 @@ +#pragma once + +#include + +template +class ForwardList +{ +public: + struct Node + { + Node(T value, std::unique_ptr next) : + mValue(value), + mNext(std::move(next)) + {} + + T mValue; + std::unique_ptr mNext; + }; + + void push_front(const T& value) + { + mFirst = std::make_unique(value, std::move(mFirst)); + } + + class Iterator : public std::iterator + { + public: + Iterator& operator++() { mNode = mNode->mNext.get(); return *this; } + T& operator*() { return mNode->mValue; } + bool operator==(Iterator rhs) { return mNode == rhs.mNode; } + bool operator!=(Iterator rhs) { return !operator==(rhs); } + + private: + friend class ForwardList; + + explicit Iterator(Node* node) : + mNode(node) + {} + + Node* mNode; + }; + + using iterator = Iterator; + using value_type = T; + + iterator begin() { return Iterator{mFirst.get()}; } + iterator end() { return Iterator{nullptr}; } + +private: + std::unique_ptr mFirst; +}; diff --git a/course03/meeting07/main.cc b/course03/meeting07/main.cc new file mode 100644 index 0000000..3d66ed1 --- /dev/null +++ b/course03/meeting07/main.cc @@ -0,0 +1,56 @@ +#include +#include + +#include +#include + +#include "forward_list.h" + +template +class Array +{ +public: + T* begin() { return &mData[0]; } + T* end() { return &mData[N]; } + + T mData[N]; +}; + +template +void sortImpl(ContainerT& c, std::forward_iterator_tag) {} + +template +void sortImpl(ContainerT& c, std::random_access_iterator_tag) {} + +template +void sort(ContainerT& c) +{ + sortImpl(c, typename std::iterator_traits::iterator_category{}); +} + +int main() +{ + Array ar{0,2,4,6}; + + for (int i : ar) + std::cout << i << std::endl; + + + ForwardList f; + f.push_front(6); + f.push_front(4); + f.push_front(2); + f.push_front(0); + + for (int i : f) + std::cout << i << std::endl; + + sort(f); + + //const int s = std::accumulate(f.begin(), f.end(), 0); + //std::sort(f.begin(), f.end()); + + + + return 0; +} diff --git a/course03/meeting08/CMakeLists.txt b/course03/meeting08/CMakeLists.txt new file mode 100644 index 0000000..44813bd --- /dev/null +++ b/course03/meeting08/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.1) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -g") +add_executable(main main.cc) +add_executable(example0 example0.cc) +add_executable(example1 example1.cc) diff --git a/course03/meeting08/main.cc b/course03/meeting08/main.cc new file mode 100644 index 0000000..6b23327 --- /dev/null +++ b/course03/meeting08/main.cc @@ -0,0 +1,64 @@ +#include +#include +#include +#include +#include +#include +#include + +using namespace std::string_literals; + +struct A +{ + explicit A(std::string s) : mName(s) {} + + bool operator<(const A& rhs) const + { + return mName < rhs.mName; + } + + std::string mName; +}; + +int main() +{ + std::map m; + + + // INSERT ONLY + const bool inserted = m.emplace("foo", 3).second; + + + // UPSERT + auto& r = m[A{"foo"}]; + r.foo = 12; + m.emplace("foo", 3); + + // UPDATE ONLY + auto it = m.find(A{"foo"}); + if (it != m.cend()) + { + it->second.foo = 12; + } + + std::cout << m[A{"foo"}] << std::endl; + + //std::unordered_map m; + + + + + + //const std::vector args{argv, argv + argc}; + /* + * const int foo = std::count_if(argv, argv + argc, + [](const char* str) { return !std::strcmp(str, "foo"); }); + + std::cout << "found " << foo << " foo" << std::endl; + */ + + + + + return 0; +} diff --git a/course03/meeting09/CMakeLists.txt b/course03/meeting09/CMakeLists.txt new file mode 100644 index 0000000..a31b9bc --- /dev/null +++ b/course03/meeting09/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 3.1) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -g") +add_executable(main main.cc) +add_executable(example1 example1.cc) diff --git a/course03/meeting09/main.cc b/course03/meeting09/main.cc new file mode 100644 index 0000000..4cc14fb --- /dev/null +++ b/course03/meeting09/main.cc @@ -0,0 +1,27 @@ +#include +#include +/* +template +std::unique_ptr make_unique(Args... args) +{ + return std::unique_ptr(new T(args...)); +} + +*/ + +template +void Print(Head&& arg, Args&&... args) +{ + std::cout << arg << " "; + + if constexpr(sizeof...(args) > 0) + Print(args...); + else + std::cout << std::endl; +} + +int main() +{ + std::string ss = "foo"; + Print(ss, 5, 4.2); +} diff --git a/course03/miguel/date.cc b/course03/miguel/date.cc new file mode 100644 index 0000000..ea2b1c0 --- /dev/null +++ b/course03/miguel/date.cc @@ -0,0 +1,80 @@ +#include +#include +#include +#include + +class Date +{ +public: + + Date() : Date(1970, 1, 1) {} + + explicit Date(int year, int month, int day) : + mYear(year), + mMonth(month), + mDay(day) + { + ThrowOnInvalidDate(); + } + + int GetYear() const { return mYear; } + int GetMonth() const { return mMonth; } + int GetDay() const { return mDay; } + + void SetYear(int year) + { + mYear = year; + ThrowOnInvalidDate(); + } + + void SetMonth(int month) + { + mMonth = month; + ThrowOnInvalidDate(); + } + + void SetDay(int day) + { + mDay = day; + ThrowOnInvalidDate(); + } + +private: + int mYear, mMonth, mDay; + + bool IsValid() const + { + // Edge cases not handled + return (mYear > 0) && (mMonth > 0 && mMonth <= 12) && (mDay <= 31); + } + + class InvalidDateException {}; + + void ThrowOnInvalidDate() const + { + if (not IsValid()) + throw InvalidDateException(); + } + + friend std::ostream& operator<<(std::ostream& os, const Date& date) + { + std::stringstream ss; + ss.fill('0'); + ss << std::setw(4) << date.mYear; + ss << std::setw(2) << date.mMonth; + ss << std::setw(2) << date.mDay; + return os << ss.str(); + } +}; + +int main() +{ + Date defaultDate; + std::cout << defaultDate << std::endl; + + Date date(1993, 10, 20); + std::cout << date << std::endl; + + // Will throw + Date wrongDate(2015, 13, 20); +} diff --git a/course03/miguel/list/CMakeLists.txt b/course03/miguel/list/CMakeLists.txt new file mode 100644 index 0000000..3c37483 --- /dev/null +++ b/course03/miguel/list/CMakeLists.txt @@ -0,0 +1,23 @@ +cmake_minimum_required(VERSION 2.6) +project(list) + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +add_compile_options(-std=c++14) + +################################ +# Unit Tests +################################ +# Add test cpp file +add_executable(unit_tests unit_tests.cc list.cc) + +add_subdirectory(./googletest) + +enable_testing() +# +# Include the gtest library. gtest_SOURCE_DIR is available due to +# 'project(gtest)' above. +include_directories(./googletest/include) + +# Link test executable against gtest & gtest_main +target_link_libraries(unit_tests gtest gtest_main pthread) +add_test(unit_tests unit_tests) diff --git a/course03/miguel/list/list.cc b/course03/miguel/list/list.cc new file mode 100644 index 0000000..2fc5b43 --- /dev/null +++ b/course03/miguel/list/list.cc @@ -0,0 +1,42 @@ +#include "list.h" + +void LinkedListInt::InsertAfter(std::unique_ptr& position, int i) +{ + std::unique_ptr newNode = std::make_unique(i); + newNode->mNext = std::move(position->mNext); + position->mNext = std::move(newNode); +} + +void LinkedListInt::InsertFront(int i) +{ + std::unique_ptr node = std::make_unique(i); + node->mNext = std::move(mFirst); + mFirst = std::move(node); +} + +void LinkedListInt::RemoveAfter(std::unique_ptr& ptr) +{ + if (ptr && ptr->mNext) + ptr->mNext = std::move(ptr->mNext->mNext); + else + throw RemoveException(); +} + +void LinkedListInt::RemoveFront() +{ + if (mFirst) + mFirst = std::move(mFirst->mNext); + else + throw RemoveException(); +} + +std::unique_ptr& LinkedListInt::Next(const std::unique_ptr& node) { return node->mNext; } + +void LinkedListInt::ApplyAllImpl(std::unique_ptr& ptr, const std::function&)>& lambda) +{ + if (ptr) + { + lambda(ptr); + ApplyAllImpl(ptr->mNext, lambda); + } +} diff --git a/course03/miguel/list/list.h b/course03/miguel/list/list.h new file mode 100644 index 0000000..f134635 --- /dev/null +++ b/course03/miguel/list/list.h @@ -0,0 +1,69 @@ +#include +#include +#include + +#ifdef DEBUG +#include +#endif + +class IntNode +{ +public: + using Data = int; + + explicit IntNode(int data) + : mData{data} + {} + + ~IntNode() + { +#ifdef DEBUG + std::cout << "~Node(" << mData << ")" << std::endl; +#endif + } + + inline int Get() const { return mData; } + inline void Set(int data) { mData = data; } + +private: + Data mData; +}; + +struct ListNode : public IntNode +{ + ListNode(IntNode::Data data) + : IntNode{data}, mNext{nullptr} + {} + + std::unique_ptr mNext; +}; + +class LinkedListInt +{ +public: + + LinkedListInt() : mFirst{nullptr} {} + ~LinkedListInt() { mFirst.reset(); } + + std::unique_ptr& First() { return mFirst; } + + void InsertAfter(std::unique_ptr& position, int i); + void InsertFront(int i); + + void RemoveAfter(std::unique_ptr& ptr); + + void RemoveFront(); + + static std::unique_ptr& Next(const std::unique_ptr& node); + + void Clear() { mFirst.reset(); } + + void ApplyAll(const std::function&)> lambda) { ApplyAllImpl(mFirst, lambda); } + + class RemoveException {}; +private: + + void ApplyAllImpl(std::unique_ptr& ptr, const std::function&)>& lambda); + + std::unique_ptr mFirst = nullptr; +}; diff --git a/course03/miguel/list/unit_tests.cc b/course03/miguel/list/unit_tests.cc new file mode 100644 index 0000000..cefabfa --- /dev/null +++ b/course03/miguel/list/unit_tests.cc @@ -0,0 +1,81 @@ +#include +#include "list.h" + +struct ListTest : public ::testing::Test +{ + LinkedListInt lli; +}; + +// Just for convenience +auto& Next = LinkedListInt::Next; + +TEST_F(ListTest, Init) +{ + EXPECT_EQ(lli.First(), nullptr); +} + +TEST_F(ListTest, EmptyList_Remove) +{ + EXPECT_THROW(lli.RemoveFront(), LinkedListInt::RemoveException); +} + +TEST_F(ListTest, InsertFront) +{ + lli.InsertFront(1); + EXPECT_EQ(lli.First()->Get(), 1); +} + +TEST_F(ListTest, InsertTwoFront) +{ + lli.InsertFront(1); + lli.InsertFront(2); + + + const auto& first = lli.First(); + EXPECT_EQ(first->Get(), 2); + EXPECT_EQ(Next(first)->Get(), 1); + EXPECT_EQ(Next(Next(first)), nullptr); +} + +TEST_F(ListTest, InsertTwoFrontThenRemove) +{ + lli.InsertFront(1); + lli.InsertFront(2); + + lli.RemoveFront(); + EXPECT_EQ(lli.First()->Get(), 1); + + lli.RemoveFront(); + EXPECT_EQ(lli.First(), nullptr); +} + +TEST_F(ListTest, InsertAfter) +{ + lli.InsertFront(3); + lli.InsertFront(1); + + lli.InsertAfter(lli.First(), 2); + + EXPECT_EQ(lli.First()->Get(), 1); + EXPECT_EQ(Next(lli.First())->Get(), 2); + EXPECT_EQ(Next(Next(lli.First()))->Get(), 3); +} + +TEST_F(ListTest, RemoveAfter) +{ + lli.InsertFront(3); + lli.InsertFront(2); + lli.InsertFront(1); + + lli.RemoveAfter(lli.First()); + + EXPECT_EQ(lli.First()->Get(), 1); + EXPECT_EQ(Next(lli.First())->Get(), 3); + EXPECT_EQ(Next(Next(lli.First())), nullptr); +} + +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/course03/miguel/project/CMakeLists.txt b/course03/miguel/project/CMakeLists.txt new file mode 100644 index 0000000..6ae63c5 --- /dev/null +++ b/course03/miguel/project/CMakeLists.txt @@ -0,0 +1,37 @@ +cmake_minimum_required(VERSION 3.1) + +project(space_impact) + +set(CMAKE_CXX_STANDARD 14) + +if (NOT DEFINED CINDER_PATH) + message(FATAL_ERROR "CINDER_PATH not set, e.g. -DCINDER_PATH=~/src/cinder") +endif() +include("${CINDER_PATH}/proj/cmake/modules/cinderMakeApp.cmake") + +if (${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU") + set(cxx_compile_options "-g -Wall -Wextra") +endif() +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${cxx_compile_options}") + +set(SOURCES + application.h + application.cc + spaceimpact.h + spaceimpact.cc + spaceship.h + spaceship.cc + asteroid.h + asteroid.cc + asteroidmanager.h + asteroidmanager.cc +) + +ci_make_app( + APP_NAME "space_impact" + SOURCES ${SOURCES} + INCLUDES ${CMAKE_CURRENT_SOURCE_DIR} + CINDER_PATH ${CINDER_PATH} +) + + diff --git a/course03/miguel/project/application.cc b/course03/miguel/project/application.cc new file mode 100644 index 0000000..c14b371 --- /dev/null +++ b/course03/miguel/project/application.cc @@ -0,0 +1,68 @@ +#include "application.h" + +#include + +using namespace ci; + +static const ci::ivec2 WindowSize{1080, 300}; + +Application::Application() +: mSpaceImpact(WindowSize) +{ +} + +void Application::prepareSettings(Settings* settings) +{ + settings->setWindowSize(WindowSize); + settings->setFrameRate(60.0f); + settings->setResizable(false); + settings->setFullScreen(false); +} + +void Application::keyDown(KeyEvent event) +{ + if (event.getCode() == KeyEvent::KEY_SPACE) + mStatus = Status::PLAYING; + + mSpaceImpact.KeyDown(event); +} + +void Application::keyUp(KeyEvent event) +{ + mSpaceImpact.KeyUp(event); +} + +void Application::setup() +{ + mSpaceImpact.Setup(); +} + +void Application::draw() +{ + switch (mStatus) + { + case Status::STARTUP: + DrawStartupScreen(); + break; + case Status::PLAYING: + mSpaceImpact.Draw(); + break; + case Status::LOST: + // Ideally, I'd like to display something + // pretty here, but life's too short, I'll use + // stdout and abort :) + std::cout << "you lost" << std::endl; + exit(-1); + } +} + +void Application::update() +{ + if (mStatus == Status::STARTUP) + return; + + mStatus = mSpaceImpact.Update(); +} + +CINDER_APP(Application, ci::app::RendererGl(ci::app::RendererGl::Options().msaa(16)), &Application::prepareSettings) + diff --git a/course03/miguel/project/application.h b/course03/miguel/project/application.h new file mode 100644 index 0000000..e1ad4f2 --- /dev/null +++ b/course03/miguel/project/application.h @@ -0,0 +1,25 @@ +#pragma once + +#include +#include + +#include "spaceimpact.h" +#include "types.h" + +class Application : public ci::app::App +{ +public: + Application(); + + void keyDown(KeyEvent) override; + void keyUp(KeyEvent) override; + void setup() override; + void draw() override; + void update() override; + + static void prepareSettings(Settings*); +private: + + SpaceImpactGame::SpaceImpact mSpaceImpact; + Status mStatus {Status::STARTUP}; +}; diff --git a/course03/miguel/project/asteroid.cc b/course03/miguel/project/asteroid.cc new file mode 100644 index 0000000..70d9d7f --- /dev/null +++ b/course03/miguel/project/asteroid.cc @@ -0,0 +1,51 @@ +#include "asteroid.h" + +namespace SpaceImpactGame { + +bool Asteroid::IsAffectedByShotAtHeight(double height) const +{ + return IsAlive() + and (mPosition.y - ASTEROID_RADIUS < height) + and (mPosition.y + ASTEROID_RADIUS > height); +} + +void Asteroid::Update() +{ + mPosition.x -= mVelocity; + mAngle += 0.1; + + if (mPosition.x < 0) + { + Destroy(); + } +} + +void Asteroid::Draw() const +{ + if (not IsAlive()) + return; + + gl::color(Color::white()); + + // Make the asteroids rotate around their own center. + // Interesting maths here. We need to translate + // the object around its own axis, so we translate + // it back to the origin, then rotate, then translate it + // back to its original position. The matrices are applied + // in the opposite order because that's the natural order + // of matrix multiplication + gl::pushModelMatrix(); + gl::translate(mPosition); + gl::rotate(mAngle); + gl::translate(-mPosition); + gl::drawSolidCircle(mPosition, ASTEROID_RADIUS, 4); + gl::popModelMatrix(); +} + +void Asteroid::Reset(vec2&& position) +{ + mAlive = true; + mPosition = std::move(position); +} + +} diff --git a/course03/miguel/project/asteroid.h b/course03/miguel/project/asteroid.h new file mode 100644 index 0000000..b594682 --- /dev/null +++ b/course03/miguel/project/asteroid.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include +#include +#include + +using namespace ci; + +namespace SpaceImpactGame { + +class Asteroid +{ +public: + Asteroid(const vec2& position, float velocity) + : mPosition(position), + mVelocity(velocity) + {} + + bool IsAlive() const { return mAlive; } + bool IsAffectedByShotAtHeight(double height) const; + void Update(); + void Draw() const; + void Reset(vec2&& position); + void Destroy() { mAlive = false; } + void Faster() { mVelocity *= 1.1; } + +private: + static constexpr float ASTEROID_RADIUS {14.f}; + + vec2 mPosition; + bool mAlive {true}; + float mVelocity; + float mAngle {ci::Rand::randFloat()}; +}; + +} diff --git a/course03/miguel/project/asteroidmanager.cc b/course03/miguel/project/asteroidmanager.cc new file mode 100644 index 0000000..522cb9d --- /dev/null +++ b/course03/miguel/project/asteroidmanager.cc @@ -0,0 +1,55 @@ +#include "asteroidmanager.h" +#include "utils.h" + +namespace SpaceImpactGame { + +AsteroidManager::AsteroidManager(const vec2& bounds, int numAsteroids) +: mBounds(bounds) +{ + // Distribute asteroids randomly within the bounds + for (int i = 0; i < numAsteroids; ++i) + { + mAsteroids.emplace_back(RandInBounds(bounds), mVelocity); + } +} + +Status AsteroidManager::Update() +{ + bool continuePlaying {false}; + for(auto& asteroid : mAsteroids) + { + asteroid.Update(); + if (asteroid.IsAlive()) + { + continuePlaying = true; + } + } + + return continuePlaying ? Status::PLAYING : Status::LOST; +} + +void AsteroidManager::Draw() const +{ + for (auto& asteroid : mAsteroids) + { + asteroid.Draw(); + } + +} + +void AsteroidManager::TakeHit(double height) +{ + for (auto& asteroid : mAsteroids) + { + if (asteroid.IsAffectedByShotAtHeight(height)) + { + asteroid.Destroy(); + + // Another one will follow, but faster + asteroid.Reset(vec2{mBounds.x, cinder::Rand::randFloat() * mBounds.y}); + asteroid.Faster(); + } + } +} + +} diff --git a/course03/miguel/project/asteroidmanager.h b/course03/miguel/project/asteroidmanager.h new file mode 100644 index 0000000..bf0f5c5 --- /dev/null +++ b/course03/miguel/project/asteroidmanager.h @@ -0,0 +1,21 @@ +#pragma once + +#include "asteroid.h" +#include "types.h" + +namespace SpaceImpactGame { + +class AsteroidManager +{ +public: + AsteroidManager(const vec2& bounds, int numAsteroids); + Status Update(); + void Draw() const; + void TakeHit(double height); + +private: + std::vector mAsteroids; + const vec2& mBounds; + float mVelocity {3.2f}; +}; +} diff --git a/course03/miguel/project/shot.h b/course03/miguel/project/shot.h new file mode 100644 index 0000000..3deafd3 --- /dev/null +++ b/course03/miguel/project/shot.h @@ -0,0 +1,9 @@ +#pragma once + +namespace SpaceImpactGame { + +using ShotHeight = int; +using TimeStamp = uint64_t; +using Shot = std::pair; + +} diff --git a/course03/miguel/project/spaceimpact.cc b/course03/miguel/project/spaceimpact.cc new file mode 100644 index 0000000..b449d9e --- /dev/null +++ b/course03/miguel/project/spaceimpact.cc @@ -0,0 +1,51 @@ +#include "spaceimpact.h" + +#include +#include + +namespace SpaceImpactGame { + +SpaceImpact::SpaceImpact(const ivec2& windowSize) +: mWindowSize(windowSize), + mAsteroids(windowSize, NUM_ASTEROIDS), + mSpaceship(windowSize) + { + } + +void SpaceImpact::Setup() +{ + mSpaceship.Setup([this](ShotHeight height) mutable + { + mAsteroids.TakeHit(height); + ++mScore; + }); +; +} + +void SpaceImpact::Draw() const +{ + gl::clear(); + mSpaceship.Draw(); + mAsteroids.Draw(); + + DrawTextInPosition("Score " + std::to_string(mScore), vec2(0,0)); + DrawTextInPosition("Use 'j/k' to move and 'f' to fire. " + "Asteroids will keep coming while you keep shooting them. Hold on for as long as you can.", + vec2{0, mWindowSize.y-15}); +} +Status SpaceImpact::Update() +{ + mSpaceship.Update(); + return mAsteroids.Update(); +} + +void SpaceImpact::KeyDown(KeyEvent event) +{ + mSpaceship.KeyDown(event); +} + +void SpaceImpact::KeyUp(KeyEvent event) +{ + mSpaceship.KeyUp(event); +} +} diff --git a/course03/miguel/project/spaceimpact.h b/course03/miguel/project/spaceimpact.h new file mode 100644 index 0000000..6b4768a --- /dev/null +++ b/course03/miguel/project/spaceimpact.h @@ -0,0 +1,35 @@ +#pragma once + +#include "asteroidmanager.h" +#include "spaceship.h" +#include "utils.h" +#include "types.h" + +#include + +using namespace ci; +using namespace ci::app; + +namespace SpaceImpactGame { + +class SpaceImpact +{ +public: + SpaceImpact(const ivec2& windowSize); + + void Setup(); + void Draw() const; + Status Update(); + void KeyDown(KeyEvent event); + void KeyUp(KeyEvent event); + +private: + const ivec2& mWindowSize; + AsteroidManager mAsteroids; + Spaceship mSpaceship; + int mScore {0}; + + static constexpr int NUM_ASTEROIDS {10}; +}; + +} diff --git a/course03/miguel/project/spaceship.cc b/course03/miguel/project/spaceship.cc new file mode 100644 index 0000000..ea47f7f --- /dev/null +++ b/course03/miguel/project/spaceship.cc @@ -0,0 +1,61 @@ +#include "spaceship.h" + +namespace SpaceImpactGame { + +void Spaceship::Setup(std::function onShotCallback) +{ + mShotCallback = std::move(onShotCallback); +} + +void Spaceship::Draw() const +{ + // Draw ship + gl::color(Color{0.5,0,1}); + gl::drawSolidCircle( mPosition, 10.0f, 6 ); + + // Draw the shot + if (!mShot) + return; + + gl::color(Color{1,0,0}); + gl::drawLine({0, mShot->first}, {mWindowSize.x, mShot->first}); +} + +void Spaceship::Update() +{ + // Shot should only be seen for this amount of time + if(!!mShot && timestamp_ms() - mShot->second > SHOT_LIFE_SPAN_MS) + { + mShot = boost::none; + } + + mPosition.y += mVelocity * mMovingSign; +} + +void Spaceship::KeyDown(ci::app::KeyEvent event) +{ + + switch(event.getCode()) + { + case KeyEvent::KEY_k: mMovingSign -= 1; break; + case KeyEvent::KEY_j: mMovingSign += 1; break; + case KeyEvent::KEY_f: Shoot(); break; + } +} + +void Spaceship::KeyUp(ci::app::KeyEvent event) +{ + switch(event.getCode()) + { + case KeyEvent::KEY_k: mMovingSign +=1; break; + case KeyEvent::KEY_j: mMovingSign -=1; break; + } +} + +void Spaceship::Shoot() +{ + mShot = std::make_pair(mPosition.y, timestamp_ms()); + mShotCallback(mPosition.y); +} + +} diff --git a/course03/miguel/project/spaceship.h b/course03/miguel/project/spaceship.h new file mode 100644 index 0000000..a0465db --- /dev/null +++ b/course03/miguel/project/spaceship.h @@ -0,0 +1,51 @@ +#pragma once + +#include +#include "utils.h" +#include "shot.h" + +#include +#include +#include + +using namespace ci; +using namespace ci::app; + +namespace SpaceImpactGame { + +class Spaceship +{ +public: + explicit Spaceship(const vec2& windowSize) + : mWindowSize(windowSize), + mPosition(0, windowSize.y/2) + {} + + void Setup(std::function onShotCallback); + void Draw() const; + void Update(); + void KeyDown(KeyEvent event); + void KeyUp(KeyEvent event); + +private: + + void Shoot(); + + vec2 mPosition; + int mMovingSign = 0; + const int mVelocity {5}; + + const vec2 mWindowSize; + + // Game logic and graphics + int mNumLives { 3 }; + static const Color mShipColor; + static const Color mLaserColor; + + static constexpr double SHOT_LIFE_SPAN_MS = 200; + + boost::optional mShot; + std::function mShotCallback; +}; +} + diff --git a/course03/miguel/project/types.h b/course03/miguel/project/types.h new file mode 100644 index 0000000..335382c --- /dev/null +++ b/course03/miguel/project/types.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +enum class Status +{ + STARTUP, + LOST, + PLAYING +}; + diff --git a/course03/miguel/project/utils.h b/course03/miguel/project/utils.h new file mode 100644 index 0000000..79cb0db --- /dev/null +++ b/course03/miguel/project/utils.h @@ -0,0 +1,58 @@ +#pragma once + +#include +#include +#include + +#include + +#include "types.h" + +inline uint64_t timestamp_ms() +{ + using namespace std::chrono; + + return duration_cast(system_clock::now().time_since_epoch()).count(); +} + +inline cinder::vec2 RandInBounds(const cinder::vec2& bounds) +{ + return {cinder::Rand::randFloat() * bounds.x, + cinder::Rand::randFloat() * bounds.y}; +} + +inline void DrawTextInPosition(const std::string& text, cinder::vec2 position) +{ + using namespace ci; + + TextLayout layout; + layout.clear(ColorA(0.2, 0.2, 0.2, 0.7)); + layout.setColor(Color(1, 1, 1)); + layout.addCenteredLine(text); + + Surface8u rendered = layout.render(true, false); + auto texture = gl::Texture2d::create(rendered); + gl::draw(texture, position); +} + +inline void DrawStartupScreen() +{ + using namespace ci; + + gl::clear(Color{0.2,0.4,0.7}); + + static const char* startupMessage = "SPACEIMPACT"; + static const char* instructions = + "Use J/K to move your ship and F to fire. Press to start."; + + TextLayout layout; + layout.clear(ColorA(0.2, 0.2, 0.2, 0.7)); + layout.setColor(Color(1, 1, 1)); + layout.addCenteredLine(startupMessage); + layout.addCenteredLine(instructions); + + Surface8u rendered = layout.render(true, false); + auto texture = gl::Texture2d::create(rendered); + gl::draw(texture, vec2{40,40}); + +} diff --git a/course03/project01/CMakeLists.txt b/course03/project01/CMakeLists.txt new file mode 100644 index 0000000..f5c40af --- /dev/null +++ b/course03/project01/CMakeLists.txt @@ -0,0 +1,29 @@ +cmake_minimum_required(VERSION 3.1) + +project(snake) + +set(CMAKE_CXX_STANDARD 14) + +if (NOT DEFINED CINDER_PATH) + message(FATAL_ERROR "CINDER_PATH not set, e.g. -DCINDER_PATH=~/src/cinder") +endif() +include("${CINDER_PATH}/proj/cmake/modules/cinderMakeApp.cmake") + +if (${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU") + set(cxx_compile_options "-g -Wall -Wextra") +endif() +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${cxx_compile_options}") + +set(SOURCES + application.h + application.cc +) + +ci_make_app( + APP_NAME "snake" + SOURCES ${SOURCES} + INCLUDES ${CMAKE_CURRENT_SOURCE_DIR} + CINDER_PATH ${CINDER_PATH} +) + + diff --git a/course03/project01/README.md b/course03/project01/README.md new file mode 100644 index 0000000..faa3d39 --- /dev/null +++ b/course03/project01/README.md @@ -0,0 +1,74 @@ +Project +======= +This first project consists of developing a game with [libcinder](http://libcinder.org/)! + +There is no particular requirement, the idea is to have fun while practicing your C++ on a real project. The only important +guideline is to keep things as simple as possible — elegance comes with simplicity, and performance too, most of the time. + +You should not need anything else than what we discussed so far: classes, references, `std::vector`, small and isolated compilation units. + +We did cover templates, although I don't think you should use them here (except through STL containers). + +As earlier, I am waiting for your pull requests. Don't edit directly the files, create a directory with your name to avoid conflicts. + +Deadline: Thursday, 20th July + + + +Building libcinder +------------------ + + 1. Install the dependencies needed for libcinder — from [Ubuntu Notes on libcinder.org](https://www.libcinder.org/docs/guides/linux-notes/ubuntu.html): + +``` +sudo apt-get install libxcursor-dev \ +libxrandr-dev \ +libxinerama-dev \ +libxi-dev \ +libgl1-mesa-dev \ +libglu1-mesa-dev \ +zlib1g-dev \ +libfontconfig1-dev \ +libmpg123-dev \ +libsndfile1 \ +libsndfile1-dev \ +libpulse-dev \ +libasound2-dev \ +libcurl4-gnutls-dev \ +libgstreamer1.0-dev \ +libgstreamer-plugins-bad1.0-dev \ +libgstreamer-plugins-base1.0-dev \ +gstreamer1.0-libav \ +gstreamer1.0-alsa \ +gstreamer1.0-pulseaudio \ +gstreamer1.0-plugins-bad +``` + +NOTE: If you are using CentOS instead of Ubuntu, use `yum install` instead of `apt-get install`. + +NOTE2: I found [this link](https://github.com/cinder/Cinder/wiki/Cinder-for-Linux-%7C-Fedora-23-24-on-x86_64) about Fedora 23. The article is only one year old so it could work for CentOS. + + + 2. Build `libcinder` (here, Debug build) + +``` +git clone --recursive https://github.com/cinder/Cinder.git +cd Cinder +mkdir build && cd build +cmake -DCMAKE_BUILD_TYPE=Debug .. +make -j8 +``` + + + 3. Build your project (= from the skeleton in this directory) by configuring cmake with: + +``` +cmake -DCMAKE_BUILD_TYPE=Debug -DCINDER_PATH=~/Cinder .. + +``` + +where `~/Cinder` is the directory you cloned in step 2. + +NOTE: if you build your application in Release, then you need to build libcinder in Release too. + + diff --git a/course03/project01/application.cc b/course03/project01/application.cc new file mode 100644 index 0000000..db5c1f8 --- /dev/null +++ b/course03/project01/application.cc @@ -0,0 +1,29 @@ +#include "application.h" + +static const cinder::ivec2 WindowSize{640, 480}; + +Application::Application() +{} + +void Application::prepareSettings(Settings* settings) +{ + settings->setWindowSize(WindowSize); + settings->setFrameRate(35.0f); + settings->setResizable(false); + settings->setFullScreen(false); +} + +void Application::keyDown(ci::app::KeyEvent) +{} + +void Application::setup() +{} + +void Application::draw() +{} + +void Application::update() +{} + +CINDER_APP(Application, ci::app::RendererGl(ci::app::RendererGl::Options().msaa(16)), &Application::prepareSettings) + diff --git a/course03/project01/application.h b/course03/project01/application.h new file mode 100644 index 0000000..4e6b828 --- /dev/null +++ b/course03/project01/application.h @@ -0,0 +1,17 @@ +#pragma once + +#include +#include + +class Application : public ci::app::App +{ +public: + Application(); + + void keyDown(ci::app::KeyEvent) override; + void setup() override; + void draw() override; + void update() override; + + static void prepareSettings(Settings*); +}; diff --git a/course03/tuple-homework/julian/.gitignore b/course03/tuple-homework/julian/.gitignore new file mode 100755 index 0000000..865edf1 --- /dev/null +++ b/course03/tuple-homework/julian/.gitignore @@ -0,0 +1,2 @@ +cmake-build-debug +gtest \ No newline at end of file diff --git a/course03/tuple-homework/julian/CMakeLists.txt b/course03/tuple-homework/julian/CMakeLists.txt new file mode 100755 index 0000000..519cc4f --- /dev/null +++ b/course03/tuple-homework/julian/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION 3.5.1) + +project(cpp_class_hw2_julianbrendl LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 14) + +add_subdirectory(src) +add_subdirectory(tests) diff --git a/course03/tuple-homework/julian/README.md b/course03/tuple-homework/julian/README.md new file mode 100755 index 0000000..e69de29 diff --git a/course03/tuple-homework/julian/src/CMakeLists.txt b/course03/tuple-homework/julian/src/CMakeLists.txt new file mode 100755 index 0000000..62d6fc8 --- /dev/null +++ b/course03/tuple-homework/julian/src/CMakeLists.txt @@ -0,0 +1,10 @@ +set(LIBRARY_NAME hw_tuple_lib) + +add_library(${LIBRARY_NAME} tuple.h tuple.cc) + +find_package(Boost 1.58 REQUIRED) +include_directories(${Boost_INCLUDE_DIRS}) +target_link_libraries(${LIBRARY_NAME} ${Boost_LIBRARIES}) + +target_compile_options(${LIBRARY_NAME} PRIVATE ${cxx_compile_options}) +target_include_directories(${LIBRARY_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/course03/tuple-homework/julian/src/tuple.cc b/course03/tuple-homework/julian/src/tuple.cc new file mode 100644 index 0000000..704ded7 --- /dev/null +++ b/course03/tuple-homework/julian/src/tuple.cc @@ -0,0 +1,7 @@ +#include "tuple.h" + +namespace CppCourse { namespace TupleHomework { + +// CMake would complain if there was no cc file + +}}; diff --git a/course03/tuple-homework/julian/src/tuple.h b/course03/tuple-homework/julian/src/tuple.h new file mode 100644 index 0000000..6c8e92a --- /dev/null +++ b/course03/tuple-homework/julian/src/tuple.h @@ -0,0 +1,65 @@ +#pragma once + +#include +#include +#include + +namespace CppCourse { namespace TupleHomework { + +template +class Tuple : public Tuple { +public: + Tuple(Head head, Args... args) + : Tuple(args...), + mArgs(Tuple(args...)), + mHead(head) + { + } + + int Size() + { + return SizeHelper(mHead, mArgs); + } + + Head Get(int index) + { + if (index == 0) + return mHead; + + return mArgs.Get(--index); + } + +private: + int SizeHelper(Head head, Tuple tuple) + { + return 1 + tuple.Size(); + } + +private: + Head mHead; + Tuple mArgs; +}; + +template +class Tuple { +public: + Tuple(Head head) : mHead(head) {} + + int Size() + { + return 1; + } + + Head Get(int index) + { + if (index == 0) + return mHead; + + throw std::runtime_error("tuple index out of bounds"); + } + +private: + Head mHead; +}; + +}}; diff --git a/course03/tuple-homework/julian/tests/CMakeLists.txt b/course03/tuple-homework/julian/tests/CMakeLists.txt new file mode 100644 index 0000000..ea5b2ef --- /dev/null +++ b/course03/tuple-homework/julian/tests/CMakeLists.txt @@ -0,0 +1,17 @@ +include(gtest.cmake) + +set(sources tests.cc) + +add_executable(tests ${sources}) + +find_package(Boost 1.58 REQUIRED) +include_directories(${Boost_INCLUDE_DIRS}) + +find_package (Threads) +target_link_libraries(tests + hw_tuple_lib + gtest + ${CMAKE_THREAD_LIBS_INIT} + ${Boost_LIBRARIES} + ) +add_test(tests tests) diff --git a/course03/tuple-homework/julian/tests/gtest.cmake b/course03/tuple-homework/julian/tests/gtest.cmake new file mode 100644 index 0000000..1fae6b0 --- /dev/null +++ b/course03/tuple-homework/julian/tests/gtest.cmake @@ -0,0 +1,17 @@ +set(GOOGLETEST_ROOT gtest/googletest CACHE STRING "Google Test source root") + +include_directories(SYSTEM + ${PROJECT_SOURCE_DIR}/${GOOGLETEST_ROOT} + ${PROJECT_SOURCE_DIR}/${GOOGLETEST_ROOT}/include + ) + +set(GOOGLETEST_SOURCES + ${PROJECT_SOURCE_DIR}/${GOOGLETEST_ROOT}/src/gtest-all.cc + ${PROJECT_SOURCE_DIR}/${GOOGLETEST_ROOT}/src/gtest_main.cc + ) + +foreach(_source ${GOOGLETEST_SOURCES}) + set_source_files_properties(${_source} PROPERTIES GENERATED 1) +endforeach() + +add_library(gtest ${GOOGLETEST_SOURCES}) diff --git a/course03/tuple-homework/julian/tests/tests.cc b/course03/tuple-homework/julian/tests/tests.cc new file mode 100644 index 0000000..08d9169 --- /dev/null +++ b/course03/tuple-homework/julian/tests/tests.cc @@ -0,0 +1,22 @@ +#include "tuple.h" + +#include + +template using Tuple = CppCourse::TupleHomework::Tuple; + +TEST(TupleTests, Initialization) +{ + Tuple t = Tuple(1, 2, 3); + + EXPECT_EQ(t.Size(), 3); + EXPECT_EQ(t.Get(0), 1); + EXPECT_EQ(t.Get(1), 2); + EXPECT_EQ(t.Get(2), 3); + EXPECT_ANY_THROW(t.Get(3)); +} + +int main(int argc, char **argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/course04/homework00/README.md b/course04/homework00/README.md new file mode 100644 index 0000000..59924db --- /dev/null +++ b/course04/homework00/README.md @@ -0,0 +1,11 @@ +For next week, the homework is to develop a fixed-capacity sorted array. We didn’t touch dynamic memory allocation nor templates, so don’t use this, thanks. Example of usage: + +``` +sarray a; +a.push_back(1); +a.push_back(10); +a.push_back(-50); + +std::cout << a[0] << std::endl; // print -50 +``` + diff --git a/course04/meeting00/CMakeLists.txt b/course04/meeting00/CMakeLists.txt new file mode 100644 index 0000000..af41c94 --- /dev/null +++ b/course04/meeting00/CMakeLists.txt @@ -0,0 +1,4 @@ +cmake_minimum_required(VERSION 3.1) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -g -Wall") +add_executable(main main.cc) diff --git a/course04/meeting00/main.cc b/course04/meeting00/main.cc new file mode 100644 index 0000000..8ad8a30 --- /dev/null +++ b/course04/meeting00/main.cc @@ -0,0 +1,24 @@ +#include +#include + +int i = 0; + +int main(int argc, char* argv[]) +{ + if (argc != 2) + { + std::cerr << "usage: " << argv[0] << " name" << std::endl; + return 1; + } + + int j = 0; + + std::cout << &i << std::endl; + std::cout << &j << std::endl; + + const std::string name{argv[1]}; + const std::string greeting = "Hello, " + name; + + std::cout << greeting << std::endl; + return 0; +} diff --git a/course04/meeting01/CMakeLists.txt b/course04/meeting01/CMakeLists.txt new file mode 100644 index 0000000..af41c94 --- /dev/null +++ b/course04/meeting01/CMakeLists.txt @@ -0,0 +1,4 @@ +cmake_minimum_required(VERSION 3.1) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -g -Wall") +add_executable(main main.cc) diff --git a/course04/meeting01/main.cc b/course04/meeting01/main.cc new file mode 100644 index 0000000..12e2900 --- /dev/null +++ b/course04/meeting01/main.cc @@ -0,0 +1,101 @@ +#include +#include + +// fundamental types: by value: void foo(int i) +// for the rest: by const ref: +void Print(const int& i) +{ + std::cout << i << std::endl; +} + +int foo(int& i) // RVO / NRVO +{ + int i = 5; + return i; +} + +int main() +{ + int k; + foo(k); + std::cout << k << std::endl; + + int i = 5; // "automatic" storage + int& r = i; + assert(i == r); + + Print(r); + std::cout << i << std::endl; + std::cout << &i << std::endl; + + std::string* addressPtr; + + { + std::string address{"AmsterdamAmsterdamAmsterdamAmsterdam"}; + addressPtr = &address; + } + + std::cout << *addressPtr << std::endl; + + return 0; +} + +#if 0 + +#include +#include + + +enum struct Side { Bid, Ask }; +void foo(Side, bool useB, bool useC); + +int main() +{ + + // fundamental types + // - integral types + // - floating point + // - boolean + float f; + double d = 1 / .0; + std::cout << d << std::endl; + + // guideline 3 :Common::Price, Common::Volume, Common::Decimal + if (!std::isfinite(d)) + { + std::abort(); + } + + + /* + char c; + //short s= 66000; + int i; + long int l; + + unsigned char uc; + unsigned short us; + unsigned int ui; + */ + + // guideline: always use signed integers + using Volume = unsigned int; + Volume v = 10; + + using Volume2 = int; + Volume2 vv = -1; + + if (v > vv) + { + std::cout << "foo"; + } + + // guideline 2 : use numeric_cast + uint16_t s = 66000;//boost::numeric_cast(i); + std::cout << s << std::endl; + + + return 0; +} + +#endif diff --git a/course04/meeting02/CMakeLists.txt b/course04/meeting02/CMakeLists.txt new file mode 100644 index 0000000..af41c94 --- /dev/null +++ b/course04/meeting02/CMakeLists.txt @@ -0,0 +1,4 @@ +cmake_minimum_required(VERSION 3.1) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -g -Wall") +add_executable(main main.cc) diff --git a/course04/meeting02/example0.h b/course04/meeting02/example0.h new file mode 100644 index 0000000..9333421 --- /dev/null +++ b/course04/meeting02/example0.h @@ -0,0 +1,8 @@ +#include + +void example0() +{ + std::uint8_t a{255}; + ++a; + std::cout << (int)a << std::endl; +} diff --git a/course04/meeting02/example1.h b/course04/meeting02/example1.h new file mode 100644 index 0000000..ce0c67c --- /dev/null +++ b/course04/meeting02/example1.h @@ -0,0 +1,8 @@ +#include + +void example1() +{ + std::int8_t a{127}; + ++a; + std::cout << (int)a << std::endl; +} diff --git a/course04/meeting02/example2.h b/course04/meeting02/example2.h new file mode 100644 index 0000000..0282463 --- /dev/null +++ b/course04/meeting02/example2.h @@ -0,0 +1,10 @@ +#include + +void example2() +{ + std::uint8_t a = 100; + std::uint8_t b = 200; + + std::uint8_t c = (a + b) / 2; + std::cout << (int)c << std::endl; +} diff --git a/course04/meeting02/example3.h b/course04/meeting02/example3.h new file mode 100644 index 0000000..a779688 --- /dev/null +++ b/course04/meeting02/example3.h @@ -0,0 +1,8 @@ +#include + +void example3() +{ + auto c = 'A'; + auto c2 = c + 1; + std::cout << c2 << std::endl; +} diff --git a/course04/meeting02/example4.h b/course04/meeting02/example4.h new file mode 100644 index 0000000..bb4e22d --- /dev/null +++ b/course04/meeting02/example4.h @@ -0,0 +1,7 @@ +#include + +void example4() +{ + unsigned int i = 2; + std::cout << i - 10 << std::endl; +} diff --git a/course04/meeting02/main.cc b/course04/meeting02/main.cc new file mode 100644 index 0000000..3e29769 --- /dev/null +++ b/course04/meeting02/main.cc @@ -0,0 +1,123 @@ +#include +#include + +class String +{ +public: + static constexpr const std::size_t MaxSize = 32; + + String(); + String(const std::string&); + + std::size_t size() const { return mSize; } + std::size_t max_size() const { return MaxSize; } + std::size_t capacity() const { return MaxSize; } + + const char* c_str() const { return mData.data(); } + +private: + std::size_t mSize = 0; + std::array mData; +}; + +String::String() +{ + mData[0] = 0; +} + +String::String(const std::string& str) : + mSize{str.size()} +{ + if (mSize + 1 > max_size()) + throw std::out_of_range("..."); + + std::copy(str.data(), str.data() + mSize + 1, mData.data()); +} + +std::ostream& operator<<(std::ostream& stream, const String& str) +{ + stream << str.c_str(); + return stream; +} + +int main() +{ + String s(std::string("foofoofoofoofoofoofoofoofoo")); + std::cout << s << std::endl; + return 0; +} + + +/* +class A +{ +public: + // rule of zero + A() =default; + + // user defined ctor: this INHIBITS the default ctor + explicit A(int i) : + mI{i}, + mJ{i} + { + std::cout << "A(" << i << ")" << std::endl; + } + +private: + int mI; + const int mJ; + //int& mK; +}; + + +class B +{ +public: + B() : mA{6} // mI = 6, mJ = 6 + { + // mA = A{5}; // mI = 6, mJ = 5 ? + } + +private: + A mA; +}; + +int main() +{ + B b; + + std::vector v(10); +} +*/ + +/* + + +int main() +{ + +} +*/ +/* + +#include + +#include "example0.h" +#include "example1.h" +#include "example2.h" +#include "example3.h" +#include "example4.h" + +int main() +{ + example0(); + example1(); + example2(); + example3(); + example4(); + + return 0; +} + +*/ + diff --git a/course04/meeting03/CMakeLists.txt b/course04/meeting03/CMakeLists.txt new file mode 100644 index 0000000..6406e65 --- /dev/null +++ b/course04/meeting03/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.1) + +include(gtest.cmake) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -g -Wall -Wextra") +add_executable(main main.cc) +add_executable(raii raii.cc) + +find_package(Boost 1.58 REQUIRED) +include_directories(${Boost_INCLUDE_DIRS}) + +find_package (Threads) +target_link_libraries(main + gtest + ${CMAKE_THREAD_LIBS_INIT} + ${Boost_LIBRARIES} +) +add_test(main main) + diff --git a/course04/meeting03/gtest b/course04/meeting03/gtest new file mode 160000 index 0000000..20b5b8e --- /dev/null +++ b/course04/meeting03/gtest @@ -0,0 +1 @@ +Subproject commit 20b5b8ecc7a81d23b4716e22a2b35fd53379c8c6 diff --git a/course04/meeting03/main.cc b/course04/meeting03/main.cc new file mode 100644 index 0000000..c783c36 --- /dev/null +++ b/course04/meeting03/main.cc @@ -0,0 +1,80 @@ +#include +#include +#include + +class String +{ +public: + static constexpr const std::size_t MaxSize = 32; + + String(); + String(const std::string&); + + //~String(); + + //String(const String&); + //String& operator=(const String&); + + std::size_t size() const { return mSize; } + std::size_t max_size() const { return MaxSize; } + std::size_t capacity() const { return MaxSize; } + + const char* c_str() const { return mData.data(); } + + char at(std::size_t idx) const { return mData.at(idx); } + +private: + std::size_t mSize = 0; + std::array mData; +}; + +String::String() +{ + mData[0] = 0; +} + +String::String(const std::string& str) : + mSize{str.size()} +{ + if (mSize + 1 > max_size()) + throw std::out_of_range("..."); + + std::copy(str.data(), str.data() + mSize + 1, mData.data()); +} + +/* +String::String(const String& other) : + mSize{other.mSize}, + mData{other.mData} +{ +} + +String& String::operator=(const String& other) +{ + mSize = other.mSize; + mData = other.mData; + return *this; +} +*/ + +std::ostream& operator<<(std::ostream& stream, const String& str) +{ + stream << str.c_str(); + return stream; +} + +int main() +{ + String s(std::string("foofoofoofoofoofoofoofoofoo")); + std::cout << s << std::endl; + + String ss(s); + std::cout << ss << std::endl; + + String sss; + sss = s; + std::cout << sss << std::endl; + + return 0; +} + diff --git a/course04/meeting03/raii.cc b/course04/meeting03/raii.cc new file mode 100644 index 0000000..087ce5c --- /dev/null +++ b/course04/meeting03/raii.cc @@ -0,0 +1,88 @@ +#include +#include +#include + +class PriceListener; + +class SubscriptionHandle +{ +public: + explicit SubscriptionHandle(std::function atExit) : + mAtExit(atExit) + {} + + ~SubscriptionHandle() + { + mAtExit(); + } + + SubscriptionHandle(const SubscriptionHandle&) =delete; + +private: + std::function mAtExit; +}; + + + +class PriceSource +{ +public: + SubscriptionHandle Subscribe(PriceListener* listener) + { + const std::size_t idx = mListeners.size(); + mListeners.push_back(listener); + return SubscriptionHandle{[=]() { mListeners[idx] = nullptr; }}; + } + + void NewPrice(double price); + +private: + std::vector mListeners; +}; + +class PriceListener +{ +public: + explicit PriceListener(PriceSource& source) : + mSource(source), + mHandle{mSource.Subscribe(this)} + { + } + + // no need dtor: less code, performance + // Unsubscribe() + + void OnPrice(double price) + { + std::cout << "new price: " << price << std::endl; + mPrices.push_back(price); + } + +private: + PriceSource& mSource; + std::vector mPrices; + SubscriptionHandle mHandle; +}; + +void PriceSource::NewPrice(double price) +{ + for (const auto& listener : mListeners) + { + if (listener) + listener->OnPrice(price); + } +} + + +int main() +{ + PriceSource source; + PriceListener listener{source}; + PriceListener listener2 = listener; + + source.NewPrice(10); + source.NewPrice(1); + source.NewPrice(120); + + return 0; +} diff --git a/course04/meeting04/sorted_array.cc b/course04/meeting04/sorted_array.cc new file mode 100644 index 0000000..9e6cebe --- /dev/null +++ b/course04/meeting04/sorted_array.cc @@ -0,0 +1,16 @@ +#include "sorted_array.h" + +#include + +void SortedArray::push_back(int value) +{ + if (mSize == MaxSize) + { + throw std::out_of_range("capacity exceeded"); + } + + mData[mSize] = value; + mSize += 1; + + std::sort(mData.begin(), mData.begin() + mSize); +} diff --git a/course04/meeting04/sorted_array.h b/course04/meeting04/sorted_array.h new file mode 100644 index 0000000..1db3785 --- /dev/null +++ b/course04/meeting04/sorted_array.h @@ -0,0 +1,36 @@ +#pragma once + +#define _GLIBCXX_DEBUG 1 +#include + +class SortedArray +{ +public: + static constexpr std::size_t MaxSize = 16; + + SortedArray() =default; + explicit SortedArray(std::size_t size, int value = {}); + + void push_back(int); + + int operator[](std::size_t i) const { return mData[i]; } + int& operator[](std::size_t i) { return mData[i]; } + + int at(std::size_t i) const { return mData.at(i); } + int& at(std::size_t i) { return mData.at(i); } + + bool empty() const { return mSize == 0; } + std::size_t size() const { return mSize; } + std::size_t max_size() const { return MaxSize; } + std::size_t capacity() const { return MaxSize; } + +private: + std::size_t mSize = 0; + std::array mData; +}; + +inline SortedArray::SortedArray(std::size_t size, int value) : + mSize{size} +{ + std::fill(mData.begin(), mData.begin() + mSize, value); +} diff --git a/course04/meeting04/sorted_array.o b/course04/meeting04/sorted_array.o new file mode 100644 index 0000000..9fcc2b3 Binary files /dev/null and b/course04/meeting04/sorted_array.o differ diff --git a/course04/meeting05/main.cc b/course04/meeting05/main.cc new file mode 100644 index 0000000..9424e1e --- /dev/null +++ b/course04/meeting05/main.cc @@ -0,0 +1,63 @@ +#include +#include + +class Vector +{ +public: + Vector() =default; + + void push_back(int); + + int operator[](std::size_t i) const { return mData[i]; } + std::size_t size() const { return mSize; } + +private: + void grow(); + + std::size_t mSize = 0; + std::size_t mCapacity = 0; + std::unique_ptr mData; +}; + +void Vector::grow() +{ + const std::size_t newCapacity = mCapacity * 2 + 1; + auto newData = std::make_unique(newCapacity); + + std::copy(mData.get(), mData.get() + mSize, newData.get()); + + mCapacity = newCapacity; + mData = newData; +} + +void Vector::push_back(int value) +{ + if (mSize == mCapacity) + { + grow(); + } + + mData[mSize] = value; + mSize += 1; +} + +/* +class A +{ +public: + A(int) {} + int mI; +}; + + +int main() +{ + // RAII! + std::unique_ptr pa = std::make_unique(6); + foo(pa); + + std::cout << pa->mI << std::endl; + + return 0; +} +*/ diff --git a/course04/meeting06/main.cc b/course04/meeting06/main.cc new file mode 100644 index 0000000..7f2d4b8 --- /dev/null +++ b/course04/meeting06/main.cc @@ -0,0 +1,69 @@ +#include +#include +#include +#include +#include +#include +#include + +struct Order +{ + Volume volume; + Price price; + std::string s; +}; + +int main() +{ + std::unordered_map books; + // books[id] = newBook; + + std::map m; + m[5].s = "foo"; + + Order& order = ...; + + // 1. INSERT + const bool inserted = m.emplace(5, Order{1, 2.0, "bar"}).second; + //THROW_IF(!inserted, ".."); + + // 2. UPDATE + auto it = m.find(5); + //THROW_IF(it == m.cend(), "..."); + it->second.s = "bar"; + + // 3. UPSERT + m[5] = Order{1, 2., "foo"}; + + + + return 0; +} + +/* +int main() +{ + std::forward_list l; + + static const int IterationsCount = 10000; + + auto startTs = std::chrono::steady_clock::now(); + for (int i = 0; i < IterationsCount; ++i) + l.push_front(5); + auto endTs = std::chrono::steady_clock::now(); + + std::cout << "heap: " << std::chrono::duration_cast(endTs - startTs).count () / (double)IterationsCount << "ns/iter" << std::endl; + + std::vector v; + v.reserve(IterationsCount); + + startTs = std::chrono::steady_clock::now(); + for (int i = 0; i < IterationsCount; ++i) + v.push_back(5); + endTs = std::chrono::steady_clock::now(); + + std::cout << "stack: " << std::chrono::duration_cast(endTs - startTs).count () / (double)IterationsCount << "ns/iter" << std::endl; + + return 0; +} +*/ diff --git a/course04/meeting07/main.cc b/course04/meeting07/main.cc new file mode 100644 index 0000000..4376ed4 --- /dev/null +++ b/course04/meeting07/main.cc @@ -0,0 +1,55 @@ +#include +#include +#include +#include "min.h" + +// type "erasure" + +//struct Shape { virtual std::vector GetVertices() const =0; }; + +struct Rectangle { std::vector GetVertices() const; }; +struct Circle {}; +struct Square {}; + +template +void Draw(const Shape& shape) +{ + shape.GetVertices(); +} + +int main() +{ + int x = 1; + + if (x < 0) + std::cout << Min(5, 6) << std::endl; + else + std::cout << Min(5., 6.) << std::endl; + + std::cout << Max(5, 6) << std::endl; + return 0; +} + + +/* +#include +#include +#include + +extern "C" +{ +std::size_t strlen(const char*) { return 77; } +} + +// ODR One Definition Rule +float log(float) { return 44; } +std::size_t strlen(float) { return 77; } + +int main() +{ + std::cout << log(1.f) << std::endl; + std::cout << std::log(1.f) << std::endl; + std::cout << strlen("foo") << std::endl; + std::cout << std::strlen("foo") << std::endl; +} +*/ diff --git a/course04/meeting07/min.cc b/course04/meeting07/min.cc new file mode 100644 index 0000000..2532aaf --- /dev/null +++ b/course04/meeting07/min.cc @@ -0,0 +1,32 @@ +#include "min.h" + +namespace Internal +{ + +// Generic programming +// T should be comparable "named requirement" -> Concept TS C++20 +template +T Min(T x, T y) +{ + return y < x ? y : x; +} + +} + +int Min(int x, int y) +{ + return Internal::Min(x, y); +} + +double Min(double x, double y) +{ + return Internal::Min(x, y); +} + +template +LessThanComparable Max(LessThanComparable x, LessThanComparable y) +{ + return y < x ? x : y; +} + +template int Max(int, int); diff --git a/course04/meeting07/min.h b/course04/meeting07/min.h new file mode 100644 index 0000000..cfd5478 --- /dev/null +++ b/course04/meeting07/min.h @@ -0,0 +1,7 @@ +#pragma once + +int Min(int, int); +double Min(double, double); + +template +T Max(T, T); diff --git a/course04/meeting07/min.o b/course04/meeting07/min.o new file mode 100644 index 0000000..ede2a09 Binary files /dev/null and b/course04/meeting07/min.o differ diff --git a/course04/meeting08/main.cc b/course04/meeting08/main.cc new file mode 100644 index 0000000..6dda057 --- /dev/null +++ b/course04/meeting08/main.cc @@ -0,0 +1,59 @@ +#include +#include +#include + +template +class Less +{ +public: + bool operator()(const T& t, const T& u) const + { + return t < u; + } +}; + +// traits +template struct IsArithmetic { static constexpr bool value = false; }; +template <> struct IsArithmetic { static constexpr bool value = true; }; + +template // policy +class Range +{ +public: + static_assert(IsArithmetic::value, "T needs to be an arithmetic type"); + + Range() =default; + Range(const T& min, const T& max); + + bool Contains(const T&) const; + +private: + T mMin = {}; + T mMax = {}; +}; + +template +Range::Range(const T& min, const T& max) : + mMin{min}, mMax{max} +{} + +template +bool Range::Contains(const T& value) const +{ + return Comparator{}(mMin, value) && Comparator{}(value, mMax); +} + +template +using ExclusiveRange = Range>; + +template +using InclusiveRange = Range>; + +int main() +{ + InclusiveRange r(2, 5); + std::cout << std::boolalpha << r.Contains(2) << std::endl; + std::cout << std::boolalpha << r.Contains(3) << std::endl; + std::cout << std::boolalpha << r.Contains(5) << std::endl; + return 0; +} diff --git a/course04/meeting08/main2.cc b/course04/meeting08/main2.cc new file mode 100644 index 0000000..5375e85 --- /dev/null +++ b/course04/meeting08/main2.cc @@ -0,0 +1,36 @@ +#include +#include +#include + +template +ReturnT Min(T x, U y) +{ + std::cout << "1" << std::endl; + return y < x ? y : x; +} + +template +T Min(T x, T y) +{ + std::cout << "2" << std::endl; + return y < x ? y : x; +} + +int Min(int x, int y) +{ + std::cout << "3" << std::endl; + return y < x ? y : x; +} + +template <> +const char* Min(const char* x, const char* y) +{ + return std::strcmp(x, y) > 0 ? y : x; +} + +int main() +{ + std::cout << Min(6, 5) << std::endl; + std::cout << Min("foo", "bar") << std::endl; + return 0; +} diff --git a/course04/meeting08/min.cc b/course04/meeting08/min.cc new file mode 100644 index 0000000..d60e1fd --- /dev/null +++ b/course04/meeting08/min.cc @@ -0,0 +1,7 @@ +#include "min.h" + +template +T Min(T x, T y) +{ + return y < x ? y : x; +} diff --git a/course04/meeting08/min.h b/course04/meeting08/min.h new file mode 100644 index 0000000..d77db6e --- /dev/null +++ b/course04/meeting08/min.h @@ -0,0 +1,4 @@ +#pragma once + +template +T Min(T, T); diff --git a/course04/meeting09/forward_list.h b/course04/meeting09/forward_list.h new file mode 100644 index 0000000..e750a9d --- /dev/null +++ b/course04/meeting09/forward_list.h @@ -0,0 +1,47 @@ +#pragma once + +#include + +template +class ForwardList +{ +public: + using value_type = T; + + struct Node + { + Node(T value, std::unique_ptr next) : + mValue(value), + mNext(std::move(next)) + {} + + T mValue; + std::unique_ptr mNext; + }; + + void push_front(const T& value) + { + mFirst = std::make_unique(value, std::move(mFirst)); + } + + struct Iterator : public std::iterator + { + explicit Iterator(Node* node) : + mNode(node) + {} + + Iterator operator++() { mNode = mNode->mNext.get(); return *this; } + T& operator*() { return mNode->mValue; } + bool operator!=(Iterator other) const { return mNode != other.mNode; } + + Node* mNode; + }; + + using iterator = Iterator; + + iterator begin() { return iterator{mFirst.get()}; } + iterator end() { return iterator{nullptr}; } + +private: + std::unique_ptr mFirst; +}; diff --git a/course04/meeting10/main.cc b/course04/meeting10/main.cc new file mode 100644 index 0000000..5b1c02b --- /dev/null +++ b/course04/meeting10/main.cc @@ -0,0 +1,25 @@ +#include +#include + +void Print(const int& l, const int& r) { std::cout << "const int&, const int&" << std::endl; } +void Print(int& l, const int& r) { std::cout << "int&, const int&" << std::endl; } +void Print(const int& l, int& r) { std::cout << "const int&, int&" << std::endl; } +void Print(int& l, int& r) { std::cout << "int&, int&" << std::endl; } + +// universal reference -> modern "forward reference" +// perfect forwarding +template +void Proxy(Args&&... args) +{ + Print(std::forward(args)...); +} + +int main() +{ + for (auto&& x : v) + ; + + int i = 0; + Proxy(i, 2); + return 0; +} diff --git a/course04/meeting11/CMakeLists.txt b/course04/meeting11/CMakeLists.txt new file mode 100644 index 0000000..af41c94 --- /dev/null +++ b/course04/meeting11/CMakeLists.txt @@ -0,0 +1,4 @@ +cmake_minimum_required(VERSION 3.1) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -g -Wall") +add_executable(main main.cc) diff --git a/course04/meeting11/main.cc b/course04/meeting11/main.cc new file mode 100644 index 0000000..1b702c2 --- /dev/null +++ b/course04/meeting11/main.cc @@ -0,0 +1,57 @@ +#include +#include +#include + +template +struct Counter +{ + Counter() { ++sCtors; } + Counter(const Counter&) { ++sCopyCtors; } + Counter& operator=(const Counter&) { ++sCopyCtors; } + Counter(Counter&&) { ++sMoveCtors; } + Counter& operator=(Counter&&) { ++sMoveCtors; } + + static int sCtors; + static int sCopyCtors; + static int sMoveCtors; +}; + +template int Counter::sCtors = 0; +template int Counter::sCopyCtors = 0; +template int Counter::sMoveCtors = 0; + +struct BigObject : public Counter {}; // CRTP + +template +class Store +{ +public: + void Add(T&& value) // "sink" + { + mElements.push_back(std::move(value)); + } + + template + void Add(Args&&... args) + { + mElements.emplace_back(std::forward(args)...); // in place construction + } + + std::vector mElements; +}; + + +int main() +{ + BigObject bo; + + Store store; + store.Add(std::move(bo)); // store.Add(Counter{}); + + std::cout << BigObject::sCtors << " ctors " << std::endl; + std::cout << BigObject::sCopyCtors << " copy ctors " << std::endl; + std::cout << BigObject::sMoveCtors << " move ctors " << std::endl; + + // bo = ? + return 0; +} diff --git a/course05/homework01/skeleton/CMakeLists.txt b/course05/homework01/skeleton/CMakeLists.txt new file mode 100644 index 0000000..46c84a9 --- /dev/null +++ b/course05/homework01/skeleton/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 3.1) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -g -Wall") +add_executable(string_tests string_tests.cc) + diff --git a/course05/homework01/skeleton/string.h b/course05/homework01/skeleton/string.h new file mode 100644 index 0000000..aa0d39f --- /dev/null +++ b/course05/homework01/skeleton/string.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include + +class String +{ +public: + String(); + String(std::string); + + bool Empty() const; + std::size_t Size() const; + + // TODO +}; + +std::ostream& operator<<(std::ostream& stream, String str) +{ + // TODO + return stream; +} + diff --git a/course05/homework01/skeleton/string_tests.cc b/course05/homework01/skeleton/string_tests.cc new file mode 100644 index 0000000..c2737eb --- /dev/null +++ b/course05/homework01/skeleton/string_tests.cc @@ -0,0 +1,22 @@ +#include "string.h" + +#include + +void TestEmpty() +{ + String str; + assert(str.Empty()); +} + +int main() +{ +#ifdef NDEBUG +#error "This file needs to be built with Debug flags" +#endif + + TestEmpty(); + + // TODO: other tests + + return 0; +} diff --git a/course05/meeting00/CMakeLists.txt b/course05/meeting00/CMakeLists.txt new file mode 100644 index 0000000..af41c94 --- /dev/null +++ b/course05/meeting00/CMakeLists.txt @@ -0,0 +1,4 @@ +cmake_minimum_required(VERSION 3.1) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -g -Wall") +add_executable(main main.cc) diff --git a/course05/meeting00/README.md b/course05/meeting00/README.md new file mode 100644 index 0000000..fd6cee2 --- /dev/null +++ b/course05/meeting00/README.md @@ -0,0 +1,21 @@ +Build +===== +g++ -o main main.cc +g++ -o main -std=c++17 -g -Wall main.cc + +cmake -DCMAKE_BUILD_TYPE=Debug . +make + + +Debug +===== +gdb ./main + +Inside GDB: +r +b foo +b main.cc:13 +bt +frame +p name + diff --git a/course05/meeting00/main.cc b/course05/meeting00/main.cc new file mode 100644 index 0000000..15a2525 --- /dev/null +++ b/course05/meeting00/main.cc @@ -0,0 +1,29 @@ +#include +#include + +void bar(int j) +{ + const std::string foo = "bar"; +} + +void foo(int i) +{ + int k = 5; + bar(i); +} + +int main(int argc, char* argv[]) +{ + if (argc != 2) + { + std::cerr << "usage: " << argv[0] << " name" << std::endl; + return 1; + } + + const std::string name{argv[1]}; + const std::string greeting{"Hello, " + name}; + + std::cout << greeting << std::endl; + foo(3); + return 0; +} diff --git a/course05/meeting01/CMakeLists.txt b/course05/meeting01/CMakeLists.txt new file mode 100644 index 0000000..af41c94 --- /dev/null +++ b/course05/meeting01/CMakeLists.txt @@ -0,0 +1,4 @@ +cmake_minimum_required(VERSION 3.1) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -g -Wall") +add_executable(main main.cc) diff --git a/course05/meeting01/main.cc b/course05/meeting01/main.cc new file mode 100644 index 0000000..a2b6ef3 --- /dev/null +++ b/course05/meeting01/main.cc @@ -0,0 +1,38 @@ +#include +#include + +int main() +{ +#if 0 + // bool, char <= unsigned char <= short <= int <= unsigned + // int >= 2 bytes + // "data model": int / long + // float <= double + + // "fixed width" integers: they are not guaranteed to be defined + std::int16_t i32; + std::int64_t i64; + std::int8_t c8; + + int i = i64; + + //std::int_fast32_t f32; + //std::int_least32_t l32; + + int volume = calc_volume(); + volume -= 2; + + if (volume < 0) + throw std::runtime_error(); +#endif + + // int == signed int + // long == signed long + // char != signed char + int sum = 0; + for (unsigned char c = 0; c < 200; ++c) + sum += c; + std::cout << sum << std::endl; + + return 0; +} diff --git a/course05/meeting02/CMakeLists.txt b/course05/meeting02/CMakeLists.txt new file mode 100644 index 0000000..af41c94 --- /dev/null +++ b/course05/meeting02/CMakeLists.txt @@ -0,0 +1,4 @@ +cmake_minimum_required(VERSION 3.1) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -g -Wall") +add_executable(main main.cc) diff --git a/course05/meeting02/example0.h b/course05/meeting02/example0.h new file mode 100644 index 0000000..9333421 --- /dev/null +++ b/course05/meeting02/example0.h @@ -0,0 +1,8 @@ +#include + +void example0() +{ + std::uint8_t a{255}; + ++a; + std::cout << (int)a << std::endl; +} diff --git a/course05/meeting02/example1.h b/course05/meeting02/example1.h new file mode 100644 index 0000000..ce0c67c --- /dev/null +++ b/course05/meeting02/example1.h @@ -0,0 +1,8 @@ +#include + +void example1() +{ + std::int8_t a{127}; + ++a; + std::cout << (int)a << std::endl; +} diff --git a/course05/meeting02/example2.h b/course05/meeting02/example2.h new file mode 100644 index 0000000..49fa4e1 --- /dev/null +++ b/course05/meeting02/example2.h @@ -0,0 +1,10 @@ +#include + +void example2() +{ + std::uint8_t a = 100; + std::uint8_t b = 200; + + std::uint8_t c = (a + b) / 2; // NOTE: integer promotion + std::cout << (int)c << std::endl; +} diff --git a/course05/meeting02/example3.h b/course05/meeting02/example3.h new file mode 100644 index 0000000..3047959 --- /dev/null +++ b/course05/meeting02/example3.h @@ -0,0 +1,8 @@ +#include + +void example3() +{ + char c = 'A'; + auto c2 = c + 1; + std::cout << c2 << std::endl; +} diff --git a/course05/meeting02/example4.h b/course05/meeting02/example4.h new file mode 100644 index 0000000..bb4e22d --- /dev/null +++ b/course05/meeting02/example4.h @@ -0,0 +1,7 @@ +#include + +void example4() +{ + unsigned int i = 2; + std::cout << i - 10 << std::endl; +} diff --git a/course05/meeting02/example5.h b/course05/meeting02/example5.h new file mode 100644 index 0000000..df884e2 --- /dev/null +++ b/course05/meeting02/example5.h @@ -0,0 +1,16 @@ +#include + + +// 1- dont mix signed / unsigned +// 2- (int) "C-style cast" -> boost::numeric_cast + +void example5() +{ + int i = -1; + unsigned j = 1; + + if (i < (int)j) + std::cout << "-1 < 1" << std::endl; + else + std::cout << "-1 >= 1" << std::endl; +} diff --git a/course05/meeting02/example6.h b/course05/meeting02/example6.h new file mode 100644 index 0000000..80a01ed --- /dev/null +++ b/course05/meeting02/example6.h @@ -0,0 +1,12 @@ +#include + +void example6() +{ + short i = -1; + unsigned short j = 1; + + if (i < j) + std::cout << "-1 < 1" << std::endl; + else + std::cout << "-1 >= 1" << std::endl; +} diff --git a/course05/meeting02/main.cc b/course05/meeting02/main.cc new file mode 100644 index 0000000..4a627d7 --- /dev/null +++ b/course05/meeting02/main.cc @@ -0,0 +1,134 @@ +#include +#include + +// instance of a class = object +// class "invariants" +class Vector2D +{ +public: + Vector2D(double x, double y) : + mX{x}, + mY{y} + { + if (!std::isfinite(mX) || !std::isfinite(mY)) + throw std::runtime_error("non finite"); + } + + double GetX() const { return mX; } + double GetY() const { return mY; } + +private: + double mX; + double mY; +}; + +/* +struct Vector2D +{ + double mX; + double mY; +}; +*/ + +// class : invariants +// struct : no invariants + +struct A // struct = class + public by default +{ + A() + { + std::cout << "A()" << std::endl; + } + + explicit A(int i) + { + std::cout << "A(" << i << ")" << std::endl; + } + + ~A() + { + std::cout << "~A()" << std::endl; + } +}; + +struct B +{ + B() : + mA{5}, // initializer-list + mI{1} + { + std::cout << "B() " << std::endl; + } + + A mA; + int mI; +}; + +void foo(A a) {} + +int main() +{ + B b; + + foo(A{5}); + + A a{5}; + foo(a); + + foo(5); + + + Vector2D v{1.0, 2.0}; // stack -> sub sp, 16 + std::cout << v.GetX() << std::endl; + std::cout << sizeof(Vector2D) << std::endl; + + + return 0; +} + + + +#if 0 +#include "example0.h" +#include "example1.h" +#include "example2.h" +#include "example3.h" +#include "example4.h" +#include "example5.h" +#include "example6.h" + +#include + +#include + +int main() +{ + //example0(); + //example1(); + //example2(); + //example3(); + //example4(); + //example5(); + example6(); + + std::uint64_t volume = 1e16; + int volume2 = boost::numeric_cast(volume); // C-style cast -> *never* use it + std::cout << volume2 << std::endl; + + + using Delta = Common::StrongTypedef; // common/strong_typedef.hpp + Delta delta; + Gamma gamma = delta * 2; + + double d; + float f; + + THROW_IF(!std::isfinite(d), "..."); // common/throw_if.hpp + + if (!std::isfinite(d)) + throw std::runtime_error("..."); + + return 0; +} + +#endif diff --git a/course05/meeting03/CMakeLists.txt b/course05/meeting03/CMakeLists.txt new file mode 100644 index 0000000..edee46c --- /dev/null +++ b/course05/meeting03/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 3.1) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -g -Wall") +add_executable(main main.cc foo.h foo.cc) + diff --git a/course05/meeting03/foo.cc b/course05/meeting03/foo.cc new file mode 100644 index 0000000..2394478 --- /dev/null +++ b/course05/meeting03/foo.cc @@ -0,0 +1,22 @@ +#include "foo.h" + + +Order::Order(double price, double volume) : + mPrice{price}, + mVolume{volume} +{} + +double Order::GetOrderValue() +{ + if (!mOrderValue) + { + mOrderValue = VeryExpensiveCalculation(); + } + return mOrderValue.get(); +} + +inline double Order::VeryExpensiveCalculation() const +{ + return mPrice * mVolume * 0.1234; +} + diff --git a/course05/meeting03/foo.h b/course05/meeting03/foo.h new file mode 100644 index 0000000..4688850 --- /dev/null +++ b/course05/meeting03/foo.h @@ -0,0 +1,18 @@ + +#include + +class Order +{ +public: + Order(double price, double volume); + + double GetOrderValue(); + +//private: + double VeryExpensiveCalculation() const; + + double mPrice; + double mVolume; + boost::optional mOrderValue; +}; + diff --git a/course05/meeting03/main.cc b/course05/meeting03/main.cc new file mode 100644 index 0000000..97d0c6a --- /dev/null +++ b/course05/meeting03/main.cc @@ -0,0 +1,119 @@ +#include + +#if 0 + +// parameter "IN" +void baz(int); // <= 8 bytes (on x86) +void baz(const std::vector&); // > 8 bytes + +// parameter "OUT" or "IN-OUT" +void bar(int&); +void bar(std::vector&); + +#endif + +// pointer = optional reference + +void foo(int* pi) +{ + std::cout << *pi << std::endl; + *pi = 5; +} + +int main() +{ + int i = 123; + int& j = i; // 2) cannot "rebind" the reference + //int& k; // reference: 1) always have to bind to a value + int* pk = &i; + *pk = 0xdead; + pk = nullptr; + *pk = 0xdead; + + std::cout << i << std::endl; + std::cout << j << std::endl; + + std::cout << &i << std::endl; // &: address-of operator + std::cout << &j << std::endl; + + int* pi = &i; + std::cout << pi << std::endl; + + pi += 4; + std::cout << pi << std::endl; + std::cout << *pi << std::endl; // *: dereference operator + + j = 6; + + foo(i); + + std::cout << i << std::endl; // VALUE SEMANTICS + std::cout << j << std::endl; // VALUE SEMANTICS + + return 0; +} + + + +#if 0 + +#include "foo.h" + +// 3 steps: Preprocessor ---text---> Compilation ---- binary code .o ----> Linkage ----> binary +// Compilation +// * Parsing, lexing +// * IR -> intermediate representation ("LLVM IR") +// * Optimization on IR +// * Translation to assembly (architecture specific) +// * Optimization on assembly + +int main() +{ + Order order{1,2}; + return (int)order.VeryExpensiveCalculation(); +} + + + + +#include + +class Order +{ +public: + Order(double price, double volume) : + mPrice{price}, + mVolume{volume} + {} + + double GetOrderValue() + { + if (!mOrderValue) + { + mOrderValue = VeryExpensiveCalculation(); + } + return mOrderValue.get(); + } + +private: + double VeryExpensiveCalculation() const + { + return mPrice * mVolume * 0.1234; + } + + double mPrice; + double mVolume; + boost::optional mOrderValue; +}; + +enum struct IsDummy { Yes, No }; +enum struct IsGFD { Yes, No }; + +int main() +{ + Order order{1, 2}; + //order.mOrderValue = 100.; + return 0; +} + +#endif diff --git a/course05/meeting04/CMakeLists.txt b/course05/meeting04/CMakeLists.txt new file mode 100644 index 0000000..f395581 --- /dev/null +++ b/course05/meeting04/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION 3.1) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -g -Wall") +add_executable(main main.cc) +add_executable(example0 example0.cc) +add_executable(example1 example1.cc) + + diff --git a/course05/meeting04/main.cc b/course05/meeting04/main.cc new file mode 100644 index 0000000..7d193af --- /dev/null +++ b/course05/meeting04/main.cc @@ -0,0 +1,102 @@ +#include +#include +#include + +// 2 reasons we need dyn mem alloc +// 1) "space" reason: we _need_ to know the size of an object at build time +// 2) "lifetime" / "scope" reason + +class String +{ +public: + using value_type = char; + using size_type = std::size_t; + + String() =default; + String(const std::string&); + + String(const String&); // copy constructor + + value_type& at(size_type); + value_type at(size_type) const; + + const value_type* c_str() const { return mBuffer.get(); } + size_type size() const { return mSize; } + bool empty() const { return mSize == 0; } + +private: + size_type mSize = 0; + size_type mCapacity = 0; + std::unique_ptr mBuffer; +}; + +String::String(const std::string& str) : + mSize{str.size()}, // initializer list + mCapacity{mSize + 1}, + mBuffer{std::make_unique(mCapacity)} +{ + std::copy(str.cbegin(), str.cend(), mBuffer.get()); + mBuffer[mSize] = 0; +} + +String::String(const String& str) : + mSize{str.mSize}, + mCapacity{str.mCapacity}, + mBuffer{std::make_unique(mCapacity)} +{ + std::copy(&str.mBuffer[0], &str.mBuffer[mSize + 1], mBuffer.get()); +} + +String::value_type& String::at(size_type sz) +{ + if (sz >= mSize) + throw std::out_of_range(".."); + return mBuffer[sz]; +} + +String::value_type String::at(size_type sz) const +{ + if (sz >= mSize) + throw std::out_of_range(".."); + return mBuffer[sz]; +} + +std::ostream& operator<<(std::ostream& stream, const String& str) +{ + if (!str.empty()) + stream << str.c_str(); + return stream; +} + +int main() +{ + String str{"foobarfoobar"}; + std::cout << str << std::endl; + + String str2{str}; + String str3; + str3 = str; + str2.at(1) = 'c'; + std::cout << str2 << std::endl; + + return 0; +} + +#if 0 +struct A +{ + int mI = 123; +}; + +int main() +{ + auto pa = std::make_unique(); // "unique" ownership + + std::unique_ptr pa2 = std::make_unique(); + pa2->mI = 345; + + std::cout << pa->mI << std::endl; // unique_ptr "RAII" (Resource Acquisition Is Initialization) + std::cout << pa2->mI << std::endl; + return 0; +} +#endif