#ifndef STAR_LIST_HPP #define STAR_LIST_HPP #include #include #include #include "StarException.hpp" #include "StarStaticVector.hpp" #include "StarSmallVector.hpp" #include "StarPythonic.hpp" #include "StarMaybe.hpp" #include "StarFormat.hpp" namespace Star { template class ListMixin : public BaseList { public: typedef BaseList Base; typedef typename Base::iterator iterator; typedef typename Base::const_iterator const_iterator; typedef typename Base::value_type value_type; typedef typename Base::reference reference; typedef typename Base::const_reference const_reference; ListMixin(); ListMixin(Base const& list); ListMixin(Base&& list); ListMixin(value_type const* p, size_t count); template ListMixin(InputIterator beg, InputIterator end); explicit ListMixin(size_t len, const_reference s1 = value_type()); ListMixin(initializer_list list); void append(value_type e); template void appendAll(Container&& list); template reference emplaceAppend(Args&&... args); reference first(); const_reference first() const; reference last(); const_reference last() const; Maybe maybeFirst(); Maybe maybeLast(); void removeLast(); value_type takeLast(); Maybe maybeTakeLast(); // Limit the size of the list by removing elements from the back until the // size is the maximumSize or less. void limitSizeBack(size_t maximumSize); size_t count() const; bool contains(const_reference e) const; // Remove all equal to element, returns number removed. size_t remove(const_reference e); template void filter(Filter&& filter); template void insertSorted(value_type e, Comparator&& comparator); void insertSorted(value_type e); // Returns true if this *sorted* list contains the given element. template bool containsSorted(value_type const& e, Comparator&& comparator); bool containsSorted(value_type e); template void exec(Function&& function); template void exec(Function&& function) const; template void transform(Function&& function); template bool any(Function&& function) const; bool any() const; template bool all(Function&& function) const; bool all() const; }; template class ListHasher { public: size_t operator()(List const& l) const; private: hash elemHasher; }; template class RandomAccessListMixin : public BaseList { public: typedef BaseList Base; typedef typename Base::iterator iterator; typedef typename Base::const_iterator const_iterator; typedef typename Base::value_type value_type; typedef typename Base::reference reference; typedef typename Base::const_reference const_reference; using Base::Base; template void sort(Comparator&& comparator); void sort(); void reverse(); // Returns first index of given element, NPos if not found. size_t indexOf(const_reference e, size_t from = 0) const; // Returns last index of given element, NPos if not found. size_t lastIndexOf(const_reference e, size_t til = NPos) const; const_reference at(size_t n) const; reference at(size_t n); const_reference operator[](size_t n) const; reference operator[](size_t n); // Does not throw if n is beyond end of list, instead returns def value_type get(size_t n, value_type def = value_type()) const; value_type takeAt(size_t i); // Same as at, but wraps around back to the beginning // (throws if list is empty) const_reference wrap(size_t n) const; reference wrap(size_t n); // Does not throw if list is empty value_type wrap(size_t n, value_type def) const; void eraseAt(size_t index); // Erases region from begin to end, not including end. void eraseAt(size_t begin, size_t end); void insertAt(size_t pos, value_type e); template void insertAllAt(size_t pos, Container const& l); // Ensures that list is large enough to hold pos elements. void set(size_t pos, value_type e); void swap(size_t i, size_t j); // same as insert(to, takeAt(from)) void move(size_t from, size_t to); }; template class FrontModifyingListMixin : public BaseList { public: typedef BaseList Base; typedef typename Base::iterator iterator; typedef typename Base::const_iterator const_iterator; typedef typename Base::value_type value_type; typedef typename Base::reference reference; typedef typename Base::const_reference const_reference; using Base::Base; void prepend(value_type e); template void prependAll(Container&& list); template reference emplacePrepend(Args&&... args); void removeFirst(); value_type takeFirst(); // Limit the size of the list by removing elements from the front until the // size is the maximumSize or less. void limitSizeFront(size_t maximumSize); }; template > class List : public RandomAccessListMixin>> { public: typedef RandomAccessListMixin>> Base; typedef typename Base::iterator iterator; typedef typename Base::const_iterator const_iterator; typedef typename Base::value_type value_type; typedef typename Base::reference reference; typedef typename Base::const_reference const_reference; template static List from(Container const& c); using Base::Base; // Pointer to contiguous storage, returns nullptr if empty value_type* ptr(); value_type const* ptr() const; List slice(SliceIndex a = SliceIndex(), SliceIndex b = SliceIndex(), int i = 1) const; template List filtered(Filter&& filter) const; template List sorted(Comparator&& comparator) const; List sorted() const; template auto transformed(Function&& function); template auto transformed(Function&& function) const; }; template struct hash> : public ListHasher> {}; template class StaticList : public RandomAccessListMixin>> { public: typedef RandomAccessListMixin>> Base; typedef typename Base::iterator iterator; typedef typename Base::const_iterator const_iterator; typedef typename Base::value_type value_type; typedef typename Base::reference reference; typedef typename Base::const_reference const_reference; template static StaticList from(Container const& c); using Base::Base; StaticList slice(SliceIndex a = SliceIndex(), SliceIndex b = SliceIndex(), int i = 1) const; template StaticList filtered(Filter&& filter) const; template StaticList sorted(Comparator&& comparator) const; StaticList sorted() const; template auto transformed(Function&& function); template auto transformed(Function&& function) const; }; template struct hash> : public ListHasher> {}; template class SmallList : public RandomAccessListMixin>> { public: typedef RandomAccessListMixin>> Base; typedef typename Base::iterator iterator; typedef typename Base::const_iterator const_iterator; typedef typename Base::value_type value_type; typedef typename Base::reference reference; typedef typename Base::const_reference const_reference; template static SmallList from(Container const& c); using Base::Base; SmallList slice(SliceIndex a = SliceIndex(), SliceIndex b = SliceIndex(), int i = 1) const; template SmallList filtered(Filter&& filter) const; template SmallList sorted(Comparator&& comparator) const; SmallList sorted() const; template auto transformed(Function&& function); template auto transformed(Function&& function) const; }; template struct hash> : public ListHasher> {}; template > class Deque : public FrontModifyingListMixin>>> { public: typedef FrontModifyingListMixin>>> Base; typedef typename Base::iterator iterator; typedef typename Base::const_iterator const_iterator; typedef typename Base::value_type value_type; typedef typename Base::reference reference; typedef typename Base::const_reference const_reference; template static Deque from(Container const& c); using Base::Base; Deque slice(SliceIndex a = SliceIndex(), SliceIndex b = SliceIndex(), int i = 1) const; template Deque filtered(Filter&& filter) const; template Deque sorted(Comparator&& comparator) const; Deque sorted() const; template auto transformed(Function&& function); template auto transformed(Function&& function) const; }; template struct hash> : public ListHasher> {}; template > class LinkedList : public FrontModifyingListMixin>> { public: typedef FrontModifyingListMixin>> Base; typedef typename Base::iterator iterator; typedef typename Base::const_iterator const_iterator; typedef typename Base::value_type value_type; typedef typename Base::reference reference; typedef typename Base::const_reference const_reference; template static LinkedList from(Container const& c); using Base::Base; void appendAll(LinkedList list); void prependAll(LinkedList list); template void appendAll(Container&& list); template void prependAll(Container&& list); template LinkedList filtered(Filter&& filter) const; template LinkedList sorted(Comparator&& comparator) const; LinkedList sorted() const; template auto transformed(Function&& function); template auto transformed(Function&& function) const; }; template struct hash> : public ListHasher> {}; template std::ostream& operator<<(std::ostream& os, ListMixin const& list); template struct ListZipTypes { typedef tuple::type::value_type...> Tuple; typedef List Result; }; template typename ListZipTypes::Result zip(Containers&&... args); template struct ListEnumerateTypes { typedef pair::type::value_type, size_t> Pair; typedef List Result; }; template typename ListEnumerateTypes::Result enumerate(Container&& container); template ListMixin::ListMixin() : Base() {} template ListMixin::ListMixin(Base const& list) : Base(list) {} template ListMixin::ListMixin(Base&& list) : Base(std::move(list)) {} template ListMixin::ListMixin(size_t len, const_reference s1) : Base(len, s1) {} template ListMixin::ListMixin(value_type const* p, size_t count) : Base(p, p + count) {} template template ListMixin::ListMixin(InputIterator beg, InputIterator end) : Base(beg, end) {} template ListMixin::ListMixin(initializer_list list) { // In case underlying class type doesn't support initializer_list for (auto& e : list) append(std::move(e)); } template void ListMixin::append(value_type e) { Base::push_back(std::move(e)); } template template void ListMixin::appendAll(Container&& list) { for (auto& e : list) { if (std::is_rvalue_reference::value) Base::push_back(std::move(e)); else Base::push_back(e); } } template template auto ListMixin::emplaceAppend(Args&&... args) -> reference { Base::emplace_back(forward(args)...); return *prev(Base::end()); } template auto ListMixin::first() -> reference { if (Base::empty()) throw OutOfRangeException("first() called on empty list"); return *Base::begin(); } template auto ListMixin::first() const -> const_reference { if (Base::empty()) throw OutOfRangeException("first() called on empty list"); return *Base::begin(); } template auto ListMixin::last() -> reference { if (Base::empty()) throw OutOfRangeException("last() called on empty list"); return *prev(Base::end()); } template auto ListMixin::last() const -> const_reference { if (Base::empty()) throw OutOfRangeException("last() called on empty list"); return *prev(Base::end()); } template auto ListMixin::maybeFirst() -> Maybe { if (Base::empty()) return {}; return *Base::begin(); } template auto ListMixin::maybeLast() -> Maybe { if (Base::empty()) return {}; return *prev(Base::end()); } template void ListMixin::removeLast() { if (Base::empty()) throw OutOfRangeException("removeLast() called on empty list"); Base::pop_back(); } template auto ListMixin::takeLast() -> value_type { value_type e = std::move(last()); Base::pop_back(); return e; } template auto ListMixin::maybeTakeLast() -> Maybe { if (Base::empty()) return {}; value_type e = std::move(last()); Base::pop_back(); return e; } template void ListMixin::limitSizeBack(size_t maximumSize) { while (Base::size() > maximumSize) Base::pop_back(); } template size_t ListMixin::count() const { return Base::size(); } template bool ListMixin::contains(const_reference e) const { for (auto const& r : *this) { if (r == e) return true; } return false; } template size_t ListMixin::remove(const_reference e) { size_t removed = 0; auto i = Base::begin(); while (i != Base::end()) { if (*i == e) { ++removed; i = Base::erase(i); } else { ++i; } } return removed; } template template void ListMixin::filter(Filter&& filter) { Star::filter(*this, forward(filter)); } template template void ListMixin::insertSorted(value_type e, Comparator&& comparator) { auto i = std::upper_bound(Base::begin(), Base::end(), e, forward(comparator)); Base::insert(i, std::move(e)); } template void ListMixin::insertSorted(value_type e) { auto i = std::upper_bound(Base::begin(), Base::end(), e); Base::insert(i, std::move(e)); } template template bool ListMixin::containsSorted(value_type const& e, Comparator&& comparator) { auto range = std::equal_range(Base::begin(), Base::end(), e, forward(comparator)); return range.first != range.second; } template bool ListMixin::containsSorted(value_type e) { auto range = std::equal_range(Base::begin(), Base::end(), e); return range.first != range.second; } template template void ListMixin::exec(Function&& function) { for (auto& e : *this) function(e); } template template void ListMixin::exec(Function&& function) const { for (auto const& e : *this) function(e); } template template void ListMixin::transform(Function&& function) { for (auto& e : *this) e = function(e); } template template bool ListMixin::any(Function&& function) const { return Star::any(*this, forward(function)); } template bool ListMixin::any() const { return Star::any(*this); } template template bool ListMixin::all(Function&& function) const { return Star::all(*this, forward(function)); } template bool ListMixin::all() const { return Star::all(*this); } template template void RandomAccessListMixin::sort(Comparator&& comparator) { Star::sort(*this, forward(comparator)); } template void RandomAccessListMixin::sort() { Star::sort(*this); } template void RandomAccessListMixin::reverse() { Star::reverse(*this); } template size_t RandomAccessListMixin::indexOf(const_reference e, size_t from) const { for (size_t i = from; i < Base::size(); ++i) if (operator[](i) == e) return i; return NPos; } template size_t RandomAccessListMixin::lastIndexOf(const_reference e, size_t til) const { size_t index = NPos; size_t end = std::min(Base::size(), til); for (size_t i = 0; i < end; ++i) { if (operator[](i) == e) index = i; } return index; } template auto RandomAccessListMixin::at(size_t n) const -> const_reference { if (n >= Base::size()) throw OutOfRangeException(strf("out of range list::at(%s)", n)); return operator[](n); } template auto RandomAccessListMixin::at(size_t n) -> reference { if (n >= Base::size()) throw OutOfRangeException(strf("out of range list::at(%s)", n)); return operator[](n); } template auto RandomAccessListMixin::operator[](size_t n) const -> const_reference { starAssert(n < Base::size()); return Base::operator[](n); } template auto RandomAccessListMixin::operator[](size_t n) -> reference { starAssert(n < Base::size()); return Base::operator[](n); } template auto RandomAccessListMixin::get(size_t n, value_type def) const -> value_type { if (n >= BaseList::size()) return def; return operator[](n); } template auto RandomAccessListMixin::takeAt(size_t i) -> value_type { value_type e = at(i); Base::erase(Base::begin() + i); return e; } template auto RandomAccessListMixin::wrap(size_t n) const -> const_reference { if (BaseList::empty()) throw OutOfRangeException(); else return operator[](n % BaseList::size()); } template auto RandomAccessListMixin::wrap(size_t n) -> reference { if (BaseList::empty()) throw OutOfRangeException(); else return operator[](n % BaseList::size()); } template auto RandomAccessListMixin::wrap(size_t n, value_type def) const -> value_type { if (BaseList::empty()) return def; else return operator[](n % BaseList::size()); } template void RandomAccessListMixin::eraseAt(size_t i) { starAssert(i < Base::size()); Base::erase(Base::begin() + i); } template void RandomAccessListMixin::eraseAt(size_t b, size_t e) { starAssert(b < Base::size() && e <= Base::size()); Base::erase(Base::begin() + b, Base::begin() + e); } template void RandomAccessListMixin::insertAt(size_t pos, value_type e) { starAssert(pos <= Base::size()); Base::insert(Base::begin() + pos, std::move(e)); } template template void RandomAccessListMixin::insertAllAt(size_t pos, Container const& l) { starAssert(pos <= Base::size()); Base::insert(Base::begin() + pos, l.begin(), l.end()); } template void RandomAccessListMixin::set(size_t pos, value_type e) { if (pos >= Base::size()) Base::resize(pos + 1); operator[](pos) = std::move(e); } template void RandomAccessListMixin::swap(size_t i, size_t j) { std::swap(operator[](i), operator[](j)); } template void RandomAccessListMixin::move(size_t from, size_t to) { Base::insert(to, takeAt(from)); } template void FrontModifyingListMixin::prepend(value_type e) { Base::push_front(std::move(e)); } template template void FrontModifyingListMixin::prependAll(Container&& list) { for (auto i = std::rbegin(list); i != std::rend(list); ++i) { if (std::is_rvalue_reference::value) Base::push_front(std::move(*i)); else Base::push_front(*i); } } template template auto FrontModifyingListMixin::emplacePrepend(Args&&... args) -> reference { Base::emplace_front(forward(args)...); return *Base::begin(); } template void FrontModifyingListMixin::removeFirst() { if (Base::empty()) throw OutOfRangeException("removeFirst() called on empty list"); Base::pop_front(); } template auto FrontModifyingListMixin::takeFirst() -> value_type { value_type e = std::move(Base::first()); Base::pop_front(); return e; } template void FrontModifyingListMixin::limitSizeFront(size_t maximumSize) { while (Base::size() > maximumSize) Base::pop_front(); } template template List List::from(Container const& c) { return List(c.begin(), c.end()); } template auto List::ptr() -> value_type * { return Base::data(); } template auto List::ptr() const -> value_type const * { return Base::data(); } template auto List::slice(SliceIndex a, SliceIndex b, int i) const -> List { return Star::slice(*this, a, b, i); } template template auto List::filtered(Filter&& filter) const -> List { List list(*this); list.filter(forward(filter)); return list; } template template auto List::sorted(Comparator&& comparator) const -> List { List list(*this); list.sort(forward(comparator)); return list; } template List List::sorted() const { List list(*this); list.sort(); return list; } template template auto List::transformed(Function&& function) { List()(std::declval()))>::type> res; res.reserve(Base::size()); transformInto(res, *this, forward(function)); return res; } template template auto List::transformed(Function&& function) const { List()(std::declval()))>::type> res; res.reserve(Base::size()); transformInto(res, *this, forward(function)); return res; } template template StaticList StaticList::from(Container const& c) { return StaticList(c.begin(), c.end()); } template auto StaticList::slice(SliceIndex a, SliceIndex b, int i) const -> StaticList { return Star::slice(*this, a, b, i); } template template auto StaticList::filtered(Filter&& filter) const -> StaticList { StaticList list(*this); list.filter(forward(filter)); return list; } template template auto StaticList::sorted(Comparator&& comparator) const -> StaticList { StaticList list(*this); list.sort(forward(comparator)); return list; } template StaticList StaticList::sorted() const { StaticList list(*this); list.sort(); return list; } template template auto StaticList::transformed(Function&& function) { StaticList()(std::declval()))>::type, MaxSize> res; transformInto(res, *this, forward(function)); return res; } template template auto StaticList::transformed(Function&& function) const { StaticList()(std::declval()))>::type, MaxSize> res; transformInto(res, *this, forward(function)); return res; } template template SmallList SmallList::from(Container const& c) { return SmallList(c.begin(), c.end()); } template auto SmallList::slice(SliceIndex a, SliceIndex b, int i) const -> SmallList { return Star::slice(*this, a, b, i); } template template auto SmallList::filtered(Filter&& filter) const -> SmallList { SmallList list(*this); list.filter(forward(filter)); return list; } template template auto SmallList::sorted(Comparator&& comparator) const -> SmallList { SmallList list(*this); list.sort(forward(comparator)); return list; } template SmallList SmallList::sorted() const { SmallList list(*this); list.sort(); return list; } template template auto SmallList::transformed(Function&& function) { SmallList()(std::declval()))>::type, MaxStackSize> res; transformInto(res, *this, forward(function)); return res; } template template auto SmallList::transformed(Function&& function) const { SmallList()(std::declval()))>::type, MaxStackSize> res; transformInto(res, *this, forward(function)); return res; } template template Deque Deque::from(Container const& c) { return Deque(c.begin(), c.end()); } template Deque Deque::slice(SliceIndex a, SliceIndex b, int i) const { return Star::slice(*this, a, b, i); } template template Deque Deque::filtered(Filter&& filter) const { Deque l(*this); l.filter(forward(filter)); return l; } template template Deque Deque::sorted(Comparator&& comparator) const { Deque l(*this); l.sort(forward(comparator)); return l; } template Deque Deque::sorted() const { Deque l(*this); l.sort(); return l; } template template auto Deque::transformed(Function&& function) { return Star::transform()(std::declval()))>>(*this, forward(function)); } template template auto Deque::transformed(Function&& function) const { return Star::transform()(std::declval()))>>(*this, forward(function)); } template template LinkedList LinkedList::from(Container const& c) { return LinkedList(c.begin(), c.end()); } template void LinkedList::appendAll(LinkedList list) { Base::splice(Base::end(), list); } template void LinkedList::prependAll(LinkedList list) { Base::splice(Base::begin(), list); } template template void LinkedList::appendAll(Container&& list) { for (auto& e : list) { if (std::is_rvalue_reference::value) Base::push_back(std::move(e)); else Base::push_back(e); } } template template void LinkedList::prependAll(Container&& list) { for (auto i = std::rbegin(list); i != std::rend(list); ++i) { if (std::is_rvalue_reference::value) Base::push_front(std::move(*i)); else Base::push_front(*i); } } template template LinkedList LinkedList::filtered(Filter&& filter) const { LinkedList list(*this); list.filter(forward(filter)); return list; } template template LinkedList LinkedList::sorted(Comparator&& comparator) const { LinkedList l(*this); l.sort(forward(comparator)); return l; } template LinkedList LinkedList::sorted() const { LinkedList l(*this); l.sort(); return l; } template template auto LinkedList::transformed(Function&& function) { return Star::transform()(std::declval()))>>(*this, forward(function)); } template template auto LinkedList::transformed(Function&& function) const { return Star::transform()(std::declval()))>>(*this, forward(function)); } template std::ostream& operator<<(std::ostream& os, ListMixin const& list) { os << "("; for (auto i = list.begin(); i != list.end(); ++i) { if (i != list.begin()) os << ", "; os << *i; } os << ")"; return os; } template size_t ListHasher::operator()(List const& l) const { size_t h = 0; for (auto const& e : l) hashCombine(h, elemHasher(e)); return h; } template typename ListZipTypes::Result zip(Containers&&... args) { typename ListZipTypes::Result res; for (auto el : zipIterator(args...)) res.push_back(std::move(el)); return res; } template typename ListEnumerateTypes::Result enumerate(Container&& container) { typename ListEnumerateTypes::Result res; for (auto el : enumerateIterator(container)) res.push_back(std::move(el)); return res; } } #endif