#ifndef Array_H #define Array_H #include #include #include "Errors.h" #include "ReferenceCounter.h" #include "Stream.h" #include "Supplier.h" #include "Text.h" namespace Framework { template //! Ein Eintrag in einer Linked List struct ArrayEintrag { TYP var; bool set; ArrayEintrag* next; ArrayEintrag() : var(), set(0), next(0) {} //! Setzt den Eintrag auf die Werte des anderen Eintrages ArrayEintrag& operator=(ArrayEintrag& r) { var = r.var; set = r.set; next = r.next; return *this; } //! Gibt den aktuell gespeicherten Wert zurück operator TYP() { if (!set) { Text err = "Index out of Range Exception File: "; err += __FILE__; err += " Line: "; err += __LINE__; throw std::out_of_range(err); } return var; } //! inkrementiert durch die Linked List durch ArrayEintrag& operator++() //! prefix { if (!next) { ArrayEintrag tmp; tmp.set = 0; tmp.next = 0; *this = tmp; return *this; } *this = *next; return *next; } //! inkrementiert durch die Linked List durch ArrayEintrag& operator++(int) //! postfix { if (!next) { ArrayEintrag tmp; tmp.set = 0; tmp.next = 0; *this = tmp; return *this; } *this = *next; return *next; } #ifdef WIN32 # pragma warning(once : 26495) }; #else }; #endif template class ArrayIterator : public Iterator> { private: ArrayEintrag* current; std::function*(ArrayEintrag* removed)> onRemove; public: ArrayIterator(ArrayEintrag* start, std::function*(ArrayEintrag* removed)> onRemove) { this->onRemove = onRemove; current = start; while (current && !current->set) { current = current->next; } } ArrayIterator(const ArrayIterator& it) { onRemove = it.onRemove; current = it.current; } virtual ~ArrayIterator() { current = 0; } ArrayIterator& operator=(ArrayIterator r) { onRemove = r.onRemove; current = r.current; return *this; } bool hasNext() override { ArrayEintrag* next = current->next; while (next && !next->set) { next = next->next; } return next != 0; } ArrayIterator next() override { if (!current) { Text err = "Index out of Range Exception File: "; err += __FILE__; err += " Line: "; err += __LINE__; throw std::out_of_range(err); } return ArrayIterator(current->next, onRemove); } operator bool() override { return current != 0; } ArrayIterator& operator++() override //! prefix { do { if (current) current = current->next; } while (current && !current->set); return *this; } ArrayIterator operator++(int) override //! postfix { ArrayIterator temp(*this); do { if (current) current = current->next; } while (current && !current->set); return temp; } TYP val() override { if (!current || !current->set) { Text err = "Index out of Range Exception File: "; err += __FILE__; err += " Line: "; err += __LINE__; throw std::out_of_range(err); } return current->var; } void set(TYP val) override { if (current) { current->var = val; current->set = true; } else { Text err = "Index out of Range Exception File: "; err += __FILE__; err += " Line: "; err += __LINE__; throw std::out_of_range(err); } } bool operator!=(ArrayIterator& r) { return current != r.current; } void remove() override { current = onRemove(current); } }; #define _ val() template //! Eine Linked List von Klassen, die kein Reference Counting berteiben class Array : public virtual ReferenceCounter { private: ArrayEintrag* entries; ArrayEintrag* last; int count; std::function*(ArrayEintrag* removed)> onRemove; public: //! Erstellt eine neue Linked List Array() noexcept : ReferenceCounter() { entries = new ArrayEintrag(); entries->set = 0; entries->next = 0; last = entries; count = 0; onRemove = [this](ArrayEintrag* entry) { if (!entry) return (ArrayEintrag*)0; if (entry->next) { entry->var = entry->next->var; entry->set = entry->next->set; } else entry->set = 0; ArrayEintrag* del = entry->next; if (entry->next) entry->next = entry->next->next; else entry->next = 0; if (del) { del->set = 0; del->next = 0; if (last == del) last = entry; delete del; } count--; return entry->set ? entry : 0; }; } //! Kopiert eine Linked list //! Array(const Array& arr) : Array() { int anz = arr.getEintragAnzahl(); for (int i = 0; i < anz; i++) add(arr.get(i)); } //! Leert und löscht die Linked List ~Array() { leeren(); delete entries; } //! Hängt ein Element ans Ende der Liste an //! \param t Das neue Element void add(TYP t) { if (!last->set) { last->var = t; last->set = 1; count++; return; } last->next = new ArrayEintrag(); last = last->next; last->set = 1; last->var = t; count++; } //! Fügt ein Element bei einer bestimmten Position in die Liste ein //! \param t das neue Element //! \param i Die Position, wo das Element eingefügt wird (danach der //! Index des neuen Elementes) void add(TYP t, int i) { if (i < 0 || i > count) throwOutOfRange(__FILE__, __LINE__, i, count); if (i == count) { add(t); return; } ArrayEintrag* e = entries; for (int a = 0; a < i; ++a) e = e->next; ArrayEintrag* ne = new ArrayEintrag(); ne->var = e->var; ne->set = e->set; ne->next = e->next; e->next = ne; e->var = t; e->set = 1; if (last->next) last = last->next; count++; } //! Setzt den Wert des i-ten Eintrags //! \param t der Neue Wert //! \param i Der Index des Eintrages der gesetzt werden soll void set(TYP t, int i) { if (i < 0 || i >= count) throwOutOfRange(__FILE__, __LINE__, i, count); ArrayEintrag* e = entries; for (int a = 0; a < i; ++a) e = e->next; e->var = t; e->set = 1; } //! Verändert die Position des i-ten Elementes in der Liste //! \param i Der Index des Elementes, welches verschoben werden soll //! \param p Die Zielposition des Elementes (danach der neue Index des //! Elementes) void setPosition(int i, int p) { if (i == p) return; if (i < 0 || p < 0 || i >= count || p >= count) throwOutOfRange(__FILE__, __LINE__, i, count); TYP t = get(i); remove(i); add(t, p); } //! Löscht ein Bestimmtes Element //! \param i Der Index des Elementes das gelöscht werden soll void remove(int i) { if (i < 0 || i >= count) throwOutOfRange(__FILE__, __LINE__, i, count); ArrayEintrag* e = entries; for (int a = 0; a < i; ++a) e = e->next; onRemove(e); } //! Löscht ein Bestimmtes Element //! \param i Der Index des Elementes das gelöscht werden soll void removeValue(TYP value) { ArrayEintrag* e = entries; while (e->var != value) { if (!e->next) return; e = e->next; } if (!e) return; if (e->next) { e->var = e->next->var; e->set = e->next->set; } else e->set = 0; ArrayEintrag* del = e->next; if (e->next) e->next = e->next->next; else e->next = 0; if (del) { del->set = 0; del->next = 0; if (last == del) last = e; delete del; } count--; } //! Vertauscht zwei Elemente in der Liste //! \param vi Der Index des ersten Elementes //! \param ni Der Index des zweiten Elementes void tausch(int vi, int ni) { TYP tmp = get(ni); set(get(vi), ni); set(tmp, vi); } //! Löscht alle Elemente der Liste void leeren() { ArrayEintrag* e2 = 0; for (ArrayEintrag* e = entries; e; e = e->next) { delete e2; e2 = e; } delete e2; entries = new ArrayEintrag(); entries->set = 0; entries->next = 0; last = entries; count = 0; } //! Gibt einen Iterator zurück. //! Mit ++ kann durch die Liste iteriert werden ArrayIterator begin() const { return ArrayIterator(entries, onRemove); } ArrayIterator end() const { return ArrayIterator(0, onRemove); } //! Gibt zurück, wie viele Elemente in der Liste sind int getEintragAnzahl() const { return count; } //! Gibt den Wert des i-ten Elementes zurück //! \param i Der index des gesuchten Elementes //! throws: //! \param std:out_of_range wenn i < 0 oder i >= getEintragAnzahl() TYP get(int i) const { if (i < 0 || i >= count) throwOutOfRange(__FILE__, __LINE__, i, count); ArrayEintrag* e = entries; for (int a = 0; a < i && e; ++a) e = e->next; return e->var; } //! Überprüft, ob ein Element in der Liste enthalten ist //! \param i Der Index des gesuchten Elementes //! \return (true), wenn der Index vorhanden ist. (false) sonnst bool hat(int i) const { return i >= 0 && i < count; } //! Gibt den Index eines Wertes zurück //! \param t Der Wert, nach dem gesucht werden soll int getWertIndex(TYP t) const { int ret = 0; for (ArrayEintrag* e = entries; e; e = e->next) { if (e->set && e->var == t) return ret; ++ret; } return -1; } bool anyMatch(std::function predicate) const { for (TYP t : *this) { if (predicate(t)) return 1; } return 0; } bool allMatch(std::function predicate) const { for (TYP t : *this) { if (!predicate(t)) return 0; } return 1; } int findIndex(std::function predicate) const { int index = 0; for (TYP t : *this) { if (predicate(t)) return index; index++; } return -1; } Array& operator=(const Array& arr) { leeren(); int anz = arr.getEintragAnzahl(); for (int i = 0; i < anz; i++) add(arr.get(i)); return *this; } Stream stream() { return Stream(new IteratorSupplier( new ArrayIterator(entries, onRemove))); } }; template //! Eine Linked List von Zeigern auf Zeichnunge, die Reference Counting //! berteiben class RCArray : public virtual ReferenceCounter { private: ArrayEintrag* entries; ArrayEintrag* last; int count; std::function*(ArrayEintrag* removed)> onRemove; public: //! Erstellt eine neue Linked List RCArray() noexcept : ReferenceCounter() { entries = new ArrayEintrag(); entries->var = 0; entries->set = 0; entries->next = 0; last = entries; count = 0; onRemove = [this](ArrayEintrag* entry) { if (!entry) return (ArrayEintrag*)0; if (entry->next) { if (entry->set && entry->var) entry->var->release(); entry->var = entry->next->var; entry->set = entry->next->set; } else { if (entry->set && entry->var) entry->var->release(); entry->set = 0; } ArrayEintrag* del = entry->next; if (entry->next) entry->next = entry->next->next; else entry->next = 0; if (del) { del->var = 0; del->set = 0; del->next = 0; if (last == del) last = entry; delete del; } count--; return entry->set ? entry : 0; }; } //! Kopiert eine Linked list RCArray(const RCArray& arr) : RCArray() { int anz = arr.getEintragAnzahl(); for (int i = 0; i < anz; i++) add(arr.get(i)); } //! Leert und löscht die Linked List ~RCArray() { leeren(); delete entries; } //! Hängt ein Element ans Ende der Liste an //! \param t Das neue Element void add(TYP* t) { count++; if (!last->set) { last->var = t; last->set = 1; return; } last->next = new ArrayEintrag(); last = last->next; last->var = t; last->set = 1; } //! Fügt ein Element bei einer bestimmten Position in die Liste ein //! \param t das neue Element //! \param i Die Position, wo das Element eingefügt wird (danach der //! Index des neuen Elementes) void add(TYP* t, int i) { if (i < 0 || i > count) throwOutOfRange(__FILE__, __LINE__, i, count); if (i == count) { add(t); return; } ArrayEintrag* e = entries; for (int a = 0; a < i; ++a) e = e->next; ArrayEintrag* ne = new ArrayEintrag(); ne->var = e->var; ne->set = e->set; ne->next = e->next; e->next = ne; e->var = t; e->set = 1; if (last->next) last = last->next; count++; } //! Setzt den Wert des i-ten Eintrags //! \param t der Neue Wert //! \param i Der Index des Eintrages der gesetzt werden soll void set(TYP* t, int i) { if (i < 0 || i >= count) throwOutOfRange(__FILE__, __LINE__, i, count); ArrayEintrag* e = entries; for (int a = 0; a < i; ++a) e = e->next; if (e->set && e->var) e->var->release(); e->var = t; e->set = 1; } //! Verändert die Position des i-ten Elementes in der Liste //! \param i Der Index des Elementes, welches verschoben werden soll //! \param p Die Zielposition des Elementes (danach der neue Index des //! Elementes) void setPosition(int i, int p) { if (i == p) return; if (i < 0 || p < 0 || i >= count || p >= count) throwOutOfRange(__FILE__, __LINE__, i, count); TYP* t = get(i); remove(i); add(t, p); } //! Löscht ein Bestimmtes Element //! \param i Der Index des Elementes das gelöscht werden soll void remove(int i) { if (i < 0 || i >= count) throwOutOfRange(__FILE__, __LINE__, i, count); ArrayEintrag* e = entries; for (int a = 0; a < i; ++a) e = e->next; if (e->next) { if (e->set && e->var) e->var->release(); e->var = e->next->var; e->set = e->next->set; } else { if (e->set && e->var) e->var->release(); e->set = 0; } ArrayEintrag* del = e->next; if (e->next) e->next = e->next->next; else e->next = 0; if (del) { del->set = 0; del->next = 0; if (last == del) last = e; delete del; } count--; } //! Vertauscht zwei Elemente in der Liste //! \param vi Der Index des ersten Elementes //! \param ni Der Index des zweiten Elementes void tausch(int vi, int ni) { if (vi < 0 || ni < 0) return; TYP* tmp = get(ni); set(get(vi), ni); set(tmp, vi); } //! Löscht alle Elemente der Liste void leeren() { for (ArrayEintrag* e = entries; e;) { if (e && e->var && e->set) e->var->release(); auto tmp = e->next; delete e; e = tmp; } entries = new ArrayEintrag(); entries->set = 0; entries->next = 0; last = entries; count = 0; } //! Gibt einen Iterator zurück. //! Mit ++ kann durch die Liste iteriert werden ArrayIterator begin() const { return ArrayIterator(entries, onRemove); } ArrayIterator end() const { return ArrayIterator(0, onRemove); } //! Gibt zurück, wie viele Elemente in der Liste sind int getEintragAnzahl() const { return count; } int getLastIndex() const { return count - 1; } //! Gibt den Wert des i-ten Elementes zurück mit erhöhtem Reference //! Counter \param i Der index des gesuchten Elementes, (0) wenn der //! Index nicht existiert TYP* get(int i) const { if (i < 0 || i >= count) throwOutOfRange(__FILE__, __LINE__, i, count); ArrayEintrag* e = entries; for (int a = 0; a < i && e; ++a) e = e->next; if (e && e->set && e->var) return dynamic_cast(e->var->getThis()); return (TYP*)0; } //! Gibt den Wert des i-ten Elementes zurück ohne erhöhten Reference //! Counter \param i Der index des gesuchten Elementes, (0) wenn der //! Index nicht existiert TYP* z(int i) const //! gibt den index - ten T zurück { if (i < 0 || i >= count) throwOutOfRange(__FILE__, __LINE__, i, count); ArrayEintrag* e = entries; for (int a = 0; a < i && e; ++a) e = e->next; if (e && e->set && e->var) return (TYP*)e->var; return (TYP*)0; } //! Überprüft, ob ein Element in der Liste enthalten ist //! \param i Der Index des gesuchten Elementes //! \return (true), wenn der Index vorhanden ist. (false) sonnst bool hat(int i) const { return i >= 0 && i < count; } //! returns the index of the first element that matches zT or -1 if not //! found int indexOf(TYP* zT) const { int i = 0; for (TYP* t : *this) { if (t == zT) return i; ++i; } return -1; } bool anyMatch(std::function predicate) const { for (TYP* t : *this) { if (predicate(t)) return 1; } return 0; } bool allMatch(std::function predicate) const { for (TYP* t : *this) { if (!predicate(t)) return 0; } return 1; } int findIndex(std::function predicate) const { int index = 0; for (TYP* t : *this) { if (predicate(t)) return index; index++; } return -1; } RCArray& operator=(const RCArray& arr) { leeren(); int anz = arr.getEintragAnzahl(); for (int i = 0; i < anz; i++) add(arr.get(i)); return *this; } Stream stream() { return Stream(new IteratorSupplier( new ArrayIterator(entries, onRemove))); } }; } // namespace Framework #endif