#include "alfe/main.h" #ifndef INCLUDED_ARRAY_H #define INCLUDED_ARRAY_H #include "alfe/bitwise.h" // List is not quite a value type, since adding an element to a list will // affect copies of the list. template class List : private Handle { class Body : public Handle::Body { class Node { public: template Node(Args&&... args) : _value(std::forward(args)...), _next(0) { } Node* next() const { return _next; } void setNext(Node* next) { _next = next; } const T& value() const { return _value; } private: T _value; Node* _next; friend class Body; friend class List; }; public: template Body(Args&&... args) : _first(std::forward(args)...), _last(&_first), _count(1) { } ~Body() { Node* n = _first.next(); while (n != 0) { Node* nn = n->next(); delete n; n = nn; } } template T* add(Args&&... args) { _last->setNext(new Node(std::forward(args)...)); _last = _last->next(); ++_count; return &_last->_value; } int count() const { return _count; } const Node* start() const { return &_first; } private: Node _first; Node* _last; int _count; friend class List; friend class List::Iterator; }; public: List() { } template T* add(Args&&... args) { if (!valid()) { *this = List(create(std::forward(args)...)); return &body()->_first._value; } return body()->add(std::forward(args)...); } int count() const { if (valid()) return body()->count(); return 0; } bool operator==(List other) const { Iterator l = begin(); Iterator r = other.begin(); while (l != end() && r != other.end()) { if (*l != *r) return false; ++l; ++r; } return l == end() && r == other.end(); } private: List(const Handle& other) : Handle(other) { } Body* body() { return as(); } const Body* body() const { return as(); } public: class Iterator { public: const T& operator*() const { return _node->value(); } const T* operator->() const { return &_node->value(); } const Iterator& operator++() { _node = _node->next(); return *this; } bool operator==(const Iterator& other) { return _node == other._node; } bool operator!=(const Iterator& other) { return !operator==(other); } bool end() const { return _node == 0; } private: const typename Body::Node* _node; Iterator(const typename Body::Node* node) : _node(node) { } friend class List; }; Iterator begin() const { if (valid()) return Iterator(body()->start()); return end(); } Iterator end() const { return Iterator(0); } }; template class Array; template::AppendableBaseBody> class AppendableArray; // Array is not quite a value type, since changing an element in one array will // affect copies of the same array unless a deep copy is made with copy(). template class Array : private Handle { public: // "allocate" is number of Ts to allocate space for. // "construct" is number of Ts to actually construct. template static C create(int allocate, int construct) { return create(allocate, construct, 0); } template static C create(int allocate, int construct, int extraBytes, Args&&... args) { void* buffer = operator new(Body::headSize() + allocate*sizeof(T) + extraBytes); Body* b; try { b = new(buffer) Body(std::forward(args)...); try { b->constructTail(construct); } catch (...) { b->destruct(); throw; } } catch (...) { operator delete(buffer); throw; } return C(b, false); } // This class combines an H and an array of Ts in a single memory block. // Also known as the "struct hack". T must be default-constructable. template class Body : public H { // HT is never actually used directly - it's just used to figure out // the length and the address of the first T. // class HT : public Body { public: T _t; }; public: static int headSize() { return sizeof(HT) - sizeof(T); } T* pointer() { return &static_cast*>(this)->_t; } const T* pointer() const { return &static_cast*>(this)->_t; } T& operator[](int i) { return pointer()[i]; } const T& operator[](int i) const { return pointer()[i]; } void destroy() const { this->preDestroy(); destruct(); operator delete(const_cast(static_cast(this))); } int size() const { return _size; } // Be careful to avoid calling setSize() with a size argument greater // than the "allocate" size passed to create(). void setSize(int size) { if (size > _size) constructTail(size); else destructTail(size); } template void constructT(Args&&... args) { new(static_cast(&(*this)[_size])) T(std::forward(args)...); ++_size; } class Iterator //: public std::iterator { public: using difference_type = ptrdiff_t; using value_type = T; //typename std::iterator:: //difference_type; Iterator() : _p(0) { } T& operator[](difference_type n) const { return _p[n]; } T& operator*() const { return *_p; } T* operator->() { return _p; } const Iterator& operator++() { ++_p; return *this; } const Iterator& operator--() { --_p; return *this; } Iterator operator++(int) { Iterator r = *this; ++_p; return r; } Iterator operator--(int) { Iterator r = *this; --_p; return r; } const Iterator& operator+=(difference_type n) { _p += n; return *this; } const Iterator& operator-=(difference_type n) { _p -= n; return *this; } Iterator operator+(difference_type n) const { Iterator r = *this; r += n; return r; } Iterator operator-(difference_type n) const { Iterator r = *this; r -= n; return r; } friend inline Iterator operator+(difference_type n, const Iterator& a) { return a + n; } friend inline Iterator operator-(difference_type n, const Iterator& a) { return a - n; } bool operator==(const Iterator& other) const { return _p == other._p; } bool operator!=(const Iterator& other) const { return _p != other._p; } bool operator<(const Iterator& other) const { return _p < other._p; } bool operator>(const Iterator& other) const { return _p > other._p; } bool operator<=(const Iterator& other) const { return _p <= other._p; } bool operator>=(const Iterator& other) const { return _p >= other._p; } ptrdiff_t operator-(const Iterator& other) const { return _p - other._p; } private: T* _p; Iterator(T* p) : _p(p) { } friend class Body; }; class ConstIterator //: public std::iterator { using difference_type = ptrdiff_t; using value_type = T; //typename std::iterator:: //difference_type; public: ConstIterator() : _p(0) { } const T& operator[](difference_type n) const { return _p[n]; } const T& operator*() const { return *_p; } const T* operator->() const { return _p; } const ConstIterator& operator++() { ++_p; return *this; } const ConstIterator& operator--() { --_p; return *this; } ConstIterator operator++(int) { ConstIterator r = *this; ++_p; return r; } ConstIterator operator--(int) { ConstIterator r = *this; --_p; return r; } const ConstIterator& operator+=(difference_type n) { _p += n; return *this; } const ConstIterator& operator-=(difference_type n) { _p -= n; return *this; } const ConstIterator& operator+(difference_type n) const { ConstIterator r = *this; r += n; return r; } const ConstIterator& operator-(difference_type n) const { ConstIterator r = *this; r -= n; return r; } friend inline Iterator operator+(difference_type n, const ConstIterator& a) { return a + n; } friend inline Iterator operator-(difference_type n, const ConstIterator& a) { return a - n; } bool operator==(const ConstIterator& other) const { return _p == other._p; } bool operator!=(const ConstIterator& other) const { return _p != other._p; } bool operator<(const ConstIterator& other) const { return _p < other._p; } bool operator>(const ConstIterator& other) const { return _p > other._p; } bool operator<=(const ConstIterator& other) const { return _p <= other._p; } bool operator>=(const ConstIterator& other) const { return _p >= other._p; } ptrdiff_t operator-(const ConstIterator& other) const { return other._p - _p; } private: const T* _p; ConstIterator(const T* p) : _p(p) { } friend class Body; }; ConstIterator begin() const { return ConstIterator(&((*this)[0])); } ConstIterator end() const { return ConstIterator(&((*this)[size()])); } Iterator begin() { return Iterator(&((*this)[0])); } Iterator end() { return Iterator(&((*this)[size()])); } void justSetSize(int size) const { _size = size; } private: void constructTail(int size) { int oldSize = _size; try { while (_size < size) constructT(); } catch (...) { destructTail(oldSize); throw; } } void destructTail(int size) const { for (; _size > size; --_size) (&(*this)[_size - 1])->~T(); } void destruct() const { destructTail(0); this->~Body(); } mutable int _size; // Needs to be mutable so destroy() can be const. // Only constructor is private to prevent inheritance, composition and // stack allocation. All instances are constructed via the placement // new call in create(). template Body(Args&&... args) : H(std::forward(args)...), _size(0) { } // HashTable and Set keep all elements constructed, and use _size to // keep track of the number of actual entries in the table. template friend class HashTable; template friend class Set; friend class Array; }; template class HT : public Body { public: T _t; }; class AppendableBaseBody : public Handle::Body { public: int _allocated; }; Array() { } Array(const List& list) { int n = list.count(); if (n != 0) { *this = Array(create<>(n, 0)); for (auto p : list) body()->constructT(p); } } Array(const AppendableArray& a) { *this = Handle(a); } explicit Array(int n) { if (n != 0) *this = Array(create<>(n, n)); } void allocate(int n) { *this = Array(n); } void ensure(int n) { if (count() < n) allocate(n); } bool operator==(const Array& other) const { int n = count(); if (n != other.count()) return false; for (int i = 0; i < n; ++i) if ((*this)[i] != other[i]) return false; return true; } template bool operator==(const AppendableArray& other) const { int n = count(); if (n != other.count()) return false; for (int i = 0; i < n; ++i) if ((*this)[i] != other[i]) return false; return true; } bool operator!=(const Array& other) const { return !operator==(other); } template bool operator!=(const AppendableArray& other) const { return !operator==(other); } T& operator[](int i) { return (*body())[i]; } const T& operator[](int i) const { return (*body())[i]; } int count() const { return body() == 0 ? 0 : body()->size(); } Array copy() const { Array r(create<>(count(), 0)); for (int i = 0; i < count(); ++i) r.body()->constructT((*this)[i]); return r; } typedef typename Body<>::Iterator Iterator; typedef typename Body<>::ConstIterator ConstIterator; ConstIterator begin() const { if (body() != 0) return body()->begin(); return typename Body<>::ConstIterator(); } ConstIterator end() const { if (body() != 0) return body()->end(); return typename Body<>::ConstIterator(); } Iterator begin() { if (body() != 0) return body()->begin(); return typename Body<>::Iterator(); } Iterator end() { if (body() != 0) return body()->end(); return typename Body<>::Iterator(); } private: Array(const Handle& other) : Handle(other) { } Body<>* body() { return as>(); } const Body<>* body() const { return as>(); } template friend class AppendableArray; }; // AppendableArray is not quite a value type, since changing an element in one // array will affect copies of the same array unless a deep copy is made with // copy(). Appending to an array may cause it to become a deep copy, if more // storage space was needed. template class AppendableArray : private Handle { protected: typedef typename Array::template Body Body; public: AppendableArray() { } AppendableArray(const Handle& other) : Handle(other) { } AppendableArray(const List& list) : AppendableArray(list.count()) { for (auto p : list) body()->constructT(p); } explicit AppendableArray(int n) { // The 8 bytes is the observed malloc overhead on both GCC and VC, // 32-bit and 64-bit (though not VC with debug heap). The idea is that // we allocate actual memory blocks that are powers of 2 bytes to // minimize fragmentation, and allocate as many objects as we can in // that space so as to make the best use of it. int overhead = Body::headSize() + 8; int s = n*sizeof(T) + overhead; s = roundUpToPowerOf2(s) - overhead; int count = s/sizeof(T); int extra = s%sizeof(T); AppendableArray b = Array::template create(count, 0, extra); b.body()->_allocated = count; *this = b; } void allocate(int n) { if (allocated() < n) { AppendableArray a(n); if (count() > 0) a.addUnchecked(body()->pointer(), count()); *this = a; } } void append(const T& value) { append(&value, 1); } void append(const Array& other) { if (other.count() > 0) append(&other[0], other.count()); } template void append(const AppendableArray& other) { if (other.count() > 0) append(&other[0], other.count()); } void append(const T* data, int length) { if (allocated() < count() + length) { AppendableArray a(count() + length); if (count() > 0) a.addUnchecked(body()->pointer(), count()); a.addUnchecked(data, length); *this = a; } else { int oldCount = count(); try { addUnchecked(data, length); } catch (...) { body()->setSize(oldCount); throw; } } } void unappend(int elements = 1) { body()->setSize(count() - elements); } // Like append but with default construction instead of copying. void expand(int length) { if (allocated() < count() + length) { AppendableArray a(count() + length); if (count() > 0) a.addUnchecked(body()->pointer(), count()); a.expandUnchecked(length); *this = a; } else { int oldCount = count(); try { expandUnchecked(length); } catch (...) { body()->setSize(oldCount); throw; } } } void ensure(int n) { if (n > count()) expand(n - count()); } void clear() { if (count() > 0) body()->setSize(0); } bool operator==(const Array& other) const { int n = count(); if (n != other.count()) return false; for (int i = 0; i < n; ++i) if ((*this)[i] != other[i]) return false; return true; } template bool operator==(const AppendableArray& other) const { int n = count(); if (n != other.count()) return false; for (int i = 0; i < n; ++i) if ((*this)[i] != other[i]) return false; return true; } bool operator!=(const Array& other) const { return !operator==(other); } template bool operator!=(const AppendableArray& other) const { return !operator==(other); } T& operator[](int i) { return (*body())[i]; } const T& operator[](int i) const { return (*body())[i]; } int count() const { return body() == 0 ? 0 : body()->size(); } int allocated() const { return body() == 0 ? 0 : body()->_allocated; } AppendableArray copy() const { AppendableArray r(count()); r.addUnchecked(&(*this)[0], count()); return r; } typedef typename Body::Iterator Iterator; Iterator begin() const { if (body() != 0) return body()->begin(); return Body::Iterator(); } Iterator end() const { if (body() != 0) return body()->end(); return Body::Iterator(); } Iterator begin() { if (body() != 0) return body()->begin(); return Body::Iterator(); } Iterator end() { if (body() != 0) return body()->end(); return Body::Iterator(); } private: void addUnchecked(const T* start, int c) { for (int i = 0; i < c; ++i) { body()->constructT(*start); ++start; } } void expandUnchecked(int c) { for (int i = 0; i < c; ++i) body()->constructT(); } Body* body() { return as(); } const Body* body() const { return as(); } // For access to body(). template friend class HashTable; template friend class Set; // For conversion to Handle template friend class Array; }; #endif // INCLUDED_ARRAY_H