Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #ifndef CONTAINERS_HPP_
- #define CONTAINERS_HPP_
- #include <functional>
- #include <fstream>
- namespace containers
- {
- template <typename T>
- struct Node
- {
- Node<T> *next;
- T value;
- explicit Node(T v, Node<T> *n) : next{n}, value{v} {}
- };
- template <typename T>
- class Container
- {
- protected:
- Node<T> *head;
- Node<T> *tail;
- private:
- template <typename X = T, typename std::enable_if<std::is_arithmetic<X>::value, X>::type* = nullptr>
- static const std::function<T(const std::string&)> create_convert()
- {
- static auto c = [](const std::string &s) { return std::stoi(s); };
- return c;
- }
- template <typename X = T, typename std::enable_if<std::is_same<X, std::string>::value, X>::type* = nullptr>
- static const std::function<T(const std::string&)> create_convert()
- {
- static auto c = [](const std::string &s) { return s; };
- return c;
- }
- const std::function<T(const std::string&)> convert = create_convert();
- public:
- Container() : head{nullptr}, tail{nullptr} {}
- virtual void push(T i) = 0;
- virtual ~Container()
- {
- auto tmp = head;
- while (tmp) {
- auto next = tmp->next;
- delete tmp;
- tmp = next;
- }
- }
- bool empty() const
- {
- return head == nullptr;
- }
- void load(std::string filepath)
- {
- std::string s;
- std::ifstream f;
- f.open(filepath);
- while (std::getline(f, s))
- push(convert(s));
- }
- void save(std::string filepath) const
- {
- std::ifstream f;
- f.open(filepath);
- map([&f](const T& i) { f << i << '\n'; });
- f.close();
- }
- void map(std::function<void(T)> f) const
- {
- for(auto i = head; i; i = i->next)
- f(i->value);
- }
- void map(std::function<void(T&)> f)
- {
- for(auto i = head; i; i = i->next)
- f(i->value);
- }
- void map(std::function<void(const T&)> f) const
- {
- for(auto i = head; i; i = i->next)
- f(i->value);
- }
- };
- template <typename T>
- class Stack : public Container<T>
- {
- using Container<T>::head;
- void deepcopy(Node<T> *n)
- {
- if(n) {
- deepcopy(n->next);
- push(n->value);
- }
- }
- public:
- Stack() : Container<T>{} {}
- template <typename ... Args>
- Stack(Args ... args) : Container<T>{}
- {
- push(args...);
- }
- Stack(const Stack &other) : Container<T>{}
- {
- deepcopy(other.head);
- }
- Stack& operator=(const Stack &other) = default;
- template <typename ... Args>
- void push(T i, Args ... args)
- {
- push(i);
- push(args...);
- }
- void push(T i)
- {
- head = new Node<T>{i, head};
- }
- T pop()
- {
- if(this->empty()) return T{};
- auto tmp = head;
- auto v = tmp->value;
- head = head->next;
- delete tmp;
- return v;
- }
- };
- template <typename T>
- class Queue : public Container<T>
- {
- using Container<T>::head;
- using Container<T>::tail;
- void deepcopy(Node<T> *n)
- {
- if(n) {
- push(n->value);
- deepcopy(n->next);
- }
- }
- public:
- Queue() : Container<T>{} {}
- template <typename ... Args>
- Queue(Args ... args) : Container<T>{}
- {
- push(args...);
- }
- Queue(const Queue &other) : Container<T>{}
- {
- deepcopy(other.head);
- }
- Queue& operator=(const Queue &other) = default;
- template <typename ... Args>
- void push(T i, Args ... args)
- {
- push(i);
- push(args...);
- }
- void push(T i)
- {
- if (this->empty()) {
- auto tmp = new Node<T>{i, head};
- head = tail = tmp;
- } else {
- auto tmp = new Node<T>{i, nullptr};
- tail->next = tmp;
- tail = tmp;
- }
- }
- T pop()
- {
- if(this->empty()) return T{};
- auto tmp = head;
- auto v = tmp->value;
- head = head->next;
- if (this->empty())
- tail = nullptr;
- delete tmp;
- return v;
- }
- };
- // "And now for the tricky bit" - Robert Virding
- //
- // Sfortunatamente non sono riusito ad implementare SFINAE utilizzando il C++
- // 11. L'idea è di poter restringe i tipi accetatti dal template secondo una
- // discriminante. In questo caso la discriminante sarebbe la possibilità di
- // poter utilizzare gli operatori di confronto booleani sul tipo di parametro
- // passato.
- //
- // In C++ 17:
- //
- // template <typename T,
- // typename = std::enable_if_t<
- // std::disjunction_v<std::is_arithmetic<T>, std::is_member_function_pointer<decltype(&T::operator==)>>>>
- //
- // Mentre in C++ 20 utilizzando i concetti:
- //
- // template <typename T> requires requires { &T::operator<=>; }
- //
- // Questo codice al fallimento produrebbe un errore simile:
- //
- // no member named 'operator<=>' in 'Foo'
- //
- // Decisamente molto più leggibile rispetto al libro di errori prodotto da del codice che non utilizza ne SFINAE ne concetti:
- //
- // In file included from main.cpp:1:containers.hpp: In instantiation of ‘static const std::function<bool(const T&, const T&)> containers::List<T>::create_compare() [with T = containers::Stack<int>]’:
- // containers.hpp:262:72: required from ‘containers::List<T>::List() [with T = containers::Stack<int>]’
- // main.cpp:7:19: required from here
- // containers.hpp:258:71: error: no match for ‘operator<’ (operand types are ‘const containers::Stack<int>’ and ‘const containers::Stack<int>’)
- // 258 | static auto c = [](const T &lhs, const T &rhs) -> bool { return lhs < rhs; };
- // | ~~~~^~~~~
- // In file included from /usr/include/c++/9.2.0/functional:59,
- // from containers.hpp:4,
- // from main.cpp:1:
- // /usr/include/c++/9.2.0/bits/std_function.h:669:7: error: ‘std::function<_Res(_ArgTypes ...)>::function(_Functor) [with _Functor = containers::List<T>::create_compare() [with T = containers::Stack<int>]::<lambda(const containers::Stack<int>&, const containers::Stack<int>&)>; <template-parameter-2-2> = void; <template-parameter-2-3> = void; _Res = bool; _ArgTypes = {const containers::Stack<int>&, const containers::Stack<int>&}]’, declared using local type ‘containers::List<T>::create_compare() [with T = containers::Stack<int>]::<lambda(const containers::Stack<int>&, const containers::Stack<int>&)>’, is used but never defined [-fpermissive]
- // 669 | function<_Res(_ArgTypes...)>::
- // | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
- //
- template <typename T>
- class List : public Container<T>
- {
- using Container<T>::head;
- static const std::function<bool(const T&, const T&)> create_compare()
- {
- static auto c = [](const T &lhs, const T &rhs) -> bool { return lhs > rhs; };
- return c;
- }
- const std::function<bool(const T&, const T&)> compare = create_compare();
- void deepcopy(Node<T> *n)
- {
- if(n) {
- push(n->value);
- deepcopy(n->next);
- }
- }
- public:
- List() : Container<T>{} {}
- List(std::function<bool(const T&, const T&)> compare_) : Container<T>{} , compare{compare_} {}
- template <typename ... Args>
- List(T i, Args ... args) : Container<T>{}
- {
- push(i);
- push(args...);
- }
- List(const List &other) : Container<T>{}
- {
- deepcopy(other.head);
- }
- List& operator=(const List &other) = default;
- template <typename ... Args>
- void push(T i, Args ... args)
- {
- push(i);
- push(args...);
- }
- void push(T i)
- {
- if (this->empty() || !compare(i, head->value)) {
- head = new Node<T>{i, head};
- } else {
- Node<T> *cur = head;
- while (cur->next && compare(i, cur->next->value)) cur = cur->next;
- cur->next = new Node<T>{i, cur->next};
- }
- }
- T pop()
- {
- return pop(1);
- }
- /// \Brief Return element at position pos; index starts from 1.
- T pop(int pos)
- {
- if (this->empty()) return T{};
- if (pos == 1) {
- auto tmp = head;
- auto v = head->value;
- head = head->next;
- delete tmp;
- return v;
- } else {
- auto cur = head;
- for (int i = 2; i < pos && cur->next; ++i, cur = cur->next);
- if (!cur->next) return T{};
- auto tmp = cur->next;
- auto v = cur->next->value;
- cur->next = cur->next->next;
- delete tmp;
- return v;
- }
- }
- /// \Brief Delete element from list
- void erase(int v)
- {
- int index = 1;
- for (auto i = head; i; i = i->next, ++index)
- if (i->value == v)
- pop(index);
- }
- };
- } // namespace containers
- #endif /* CONTAINERS_HPP_ */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement