Files
x86_microcode/80386/disassembler/include/alfe/array.h
T
2026-05-23 11:01:52 +01:00

698 lines
21 KiB
C++

#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 T> class List : private Handle
{
class Body : public Handle::Body
{
class Node
{
public:
template<typename... Args> Node(Args&&... args)
: _value(std::forward<Args>(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<typename... Args> Body(Args&&... args)
: _first(std::forward<Args>(args)...), _last(&_first), _count(1) { }
~Body()
{
Node* n = _first.next();
while (n != 0) {
Node* nn = n->next();
delete n;
n = nn;
}
}
template<typename... Args> T* add(Args&&... args)
{
_last->setNext(new Node(std::forward<Args>(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<typename... Args> T* add(Args&&... args)
{
if (!valid()) {
*this = List(create<Body>(std::forward<Args>(args)...));
return &body()->_first._value;
}
return body()->add(std::forward<Args>(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<Body>(); }
const Body* body() const { return as<Body>(); }
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 T> class Array;
template<class T, class Base = typename Array<T>::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 T> class Array : private Handle
{
public:
// "allocate" is number of Ts to allocate space for.
// "construct" is number of Ts to actually construct.
template<class C = Handle, class H = Handle::Body> static
C create(int allocate, int construct)
{
return create<C, H>(allocate, construct, 0);
}
template<class C = Handle, class H = Handle::Body, typename... Args> static
C create(int allocate, int construct, int extraBytes, Args&&... args)
{
void* buffer = operator new(Body<H>::headSize() + allocate*sizeof(T) +
extraBytes);
Body<H>* b;
try {
b = new(buffer) Body<H>(std::forward<Args>(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 H = Handle::Body> 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<H>) - sizeof(T); }
T* pointer() { return &static_cast<HT<H>*>(this)->_t; }
const T* pointer() const
{
return &static_cast<const HT<H>*>(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<void*>(static_cast<const void*>(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<typename... Args> void constructT(Args&&... args)
{
new(static_cast<void*>(&(*this)[_size]))
T(std::forward<Args>(args)...);
++_size;
}
class Iterator
//: public std::iterator<std::random_access_iterator_tag, T>
{
public:
using difference_type = ptrdiff_t;
using value_type = T;
//typename std::iterator<std::random_access_iterator_tag, T>::
//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<std::random_access_iterator_tag, T>
{
using difference_type = ptrdiff_t;
using value_type = T;
//typename std::iterator<std::random_access_iterator_tag, T>::
//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<typename... Args> Body(Args&&... args)
: H(std::forward<Args>(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<class Key, class Value> friend class HashTable;
template<class Key> friend class Set;
friend class Array;
};
template<class H> class HT : public Body<H> { public: T _t; };
class AppendableBaseBody : public Handle::Body
{
public:
int _allocated;
};
Array() { }
Array(const List<T>& list)
{
int n = list.count();
if (n != 0) {
*this = Array(create<>(n, 0));
for (auto p : list)
body()->constructT(p);
}
}
Array(const AppendableArray<T>& 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<class B> bool operator==(const AppendableArray<T, B>& 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<class B> bool operator!=(const AppendableArray<T, B>& 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<Body<>>(); }
const Body<>* body() const { return as<Body<>>(); }
template<class U, class B> 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 T, class Base> class AppendableArray : private Handle
{
protected:
typedef typename Array<T>::template Body<Base> Body;
public:
AppendableArray() { }
AppendableArray(const Handle& other) : Handle(other) { }
AppendableArray(const List<T>& 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<T>::template create<Handle, Base>(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<T>& other)
{
if (other.count() > 0)
append(&other[0], other.count());
}
template<class B> void append(const AppendableArray<T, B>& 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<T>& 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<class B> bool operator==(const AppendableArray<T, B>& 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<T>& other) const { return !operator==(other); }
template<class B> bool operator!=(const AppendableArray<T, B>& 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<Body>(); }
const Body* body() const { return as<Body>(); }
// For access to body().
template<class Key, class Value> friend class HashTable;
template<class Key> friend class Set;
// For conversion to Handle
template<class U> friend class Array;
};
#endif // INCLUDED_ARRAY_H