287 lines
5.4 KiB
C++
Executable File
287 lines
5.4 KiB
C++
Executable File
#include <stdlib.h>
|
|
|
|
#include <array.h>
|
|
|
|
#include "cg3.h"
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// TList
|
|
///////////////////////////////////////////////////////////
|
|
|
|
class TList : public TContainer
|
|
{
|
|
enum { MAX_SKIP = 8192 };
|
|
|
|
struct TList_object : public TObject
|
|
{
|
|
TObject* _obj;
|
|
TList_object* _next;
|
|
TList_object* _prev;
|
|
};
|
|
|
|
TList_object** _skip;
|
|
long _items, _current;
|
|
long _step, _last_skip;
|
|
|
|
protected:
|
|
// @cmember Ritorna un puntatore al primo oggetto del contenitore
|
|
virtual TObject* first_item( );
|
|
// @cmember Ritorna un puntatore all'ultimo oggetto del contenitore
|
|
virtual TObject* last_item( );
|
|
// @cmember Ritorna un puntatore all'oggetto successivo all'oggetto corrente
|
|
virtual TObject* succ_item( );
|
|
// @cmember Ritorna un puntatore all'oggetto che precede l'oggetto corrente
|
|
virtual TObject* pred_item( );
|
|
// @cmember Ritorna il numero di oggetti nel contenitore
|
|
virtual long objects( );
|
|
|
|
protected:
|
|
TList_object* detach_lstobj(long index);
|
|
TList_object* lstobjptr(long index);
|
|
void change_step(long step);
|
|
|
|
public:
|
|
|
|
TObject* TList::objptr(long index);
|
|
|
|
void destroy();
|
|
long insert(TObject* obj, long pos);
|
|
long add(TObject* obj, long pos = -1);
|
|
|
|
TObject* detach(long pos);
|
|
bool remove(long pos);
|
|
|
|
TList(long expected_size);
|
|
virtual ~TList();
|
|
};
|
|
|
|
TList::TList(long expected_size)
|
|
: _items(0), _current(0)
|
|
{
|
|
_step = expected_size / MAX_SKIP + 1;
|
|
_last_skip = 0;
|
|
|
|
_skip = new TList_object*[MAX_SKIP];
|
|
_skip[0] = NULL;
|
|
}
|
|
|
|
TList::~TList()
|
|
{
|
|
destroy();
|
|
delete [] _skip;
|
|
}
|
|
|
|
long TList::objects( )
|
|
{
|
|
return _items;
|
|
}
|
|
|
|
TObject* TList::first_item()
|
|
{
|
|
return objptr(_current = 0);
|
|
}
|
|
|
|
TObject* TList::succ_item()
|
|
{
|
|
return objptr(++_current);
|
|
}
|
|
|
|
TObject* TList::pred_item()
|
|
{
|
|
return objptr(_current++);
|
|
}
|
|
|
|
TObject* TList::last_item()
|
|
{
|
|
return objptr(_current = _items-1);
|
|
}
|
|
|
|
void TList::destroy()
|
|
{
|
|
TList_object* head = _skip[0];
|
|
while (head)
|
|
{
|
|
TList_object* next = head->_next;
|
|
if (head->_obj)
|
|
delete head->_obj;
|
|
delete head;
|
|
head = next;
|
|
}
|
|
_items = _current = _last_skip = 0;
|
|
_skip[0] = NULL;
|
|
}
|
|
|
|
TList::TList_object* TList::lstobjptr(long index)
|
|
{
|
|
TList_object* lstobj = NULL;
|
|
const ldiv_t p = ldiv(index, _step);
|
|
if (p.quot >= 0 && p.quot < _last_skip)
|
|
{
|
|
TList_object* lo = _skip[p.quot];
|
|
for (long s = p.rem; lo && s > 0; s--)
|
|
lo = lo->_next;
|
|
|
|
lstobj = lo;
|
|
}
|
|
return lstobj;
|
|
}
|
|
|
|
TObject* TList::objptr(long index)
|
|
{
|
|
TList_object* lo = lstobjptr(index);
|
|
return lo ? lo->_obj : NULL;
|
|
}
|
|
|
|
void TList::change_step(long step)
|
|
{
|
|
CHECKD(step > 0 && step <= 16384, "Bad list step ", step);
|
|
_step = step;
|
|
_last_skip = 0;
|
|
|
|
step = 0;
|
|
for (TList_object* lo = _skip[0]; lo; lo = lo->_next, step--)
|
|
{
|
|
if (step == 0)
|
|
{
|
|
CHECK(_last_skip < MAX_SKIP, "Too many items");
|
|
_skip[_last_skip++] = lo;
|
|
step = _step;
|
|
}
|
|
}
|
|
}
|
|
|
|
long TList::insert(TObject* obj, long index)
|
|
{
|
|
if (index < 0)
|
|
index = 0;
|
|
else
|
|
{
|
|
if (index > _items)
|
|
index = _items;
|
|
}
|
|
const long pred = index-1;
|
|
|
|
TList_object* newobj = new TList_object;
|
|
newobj->_obj = obj;
|
|
|
|
if (pred < 0)
|
|
{
|
|
newobj->_prev = NULL;
|
|
newobj->_next = _skip[0];
|
|
if (_skip[0])
|
|
_skip[0]->_prev = newobj;
|
|
}
|
|
else
|
|
{
|
|
TList_object* lo = lstobjptr(pred);
|
|
CHECK(lo, "NULL insertion point");
|
|
newobj->_next = lo->_next;
|
|
newobj->_prev = lo;
|
|
if (lo->_next)
|
|
lo->_next->_prev = newobj;
|
|
lo->_next = newobj;
|
|
}
|
|
_items++;
|
|
|
|
ldiv_t p = ldiv(index, _step);
|
|
if (p.rem == 0 && p.quot < MAX_SKIP) // Cambia il capolista
|
|
_skip[p.quot] = newobj;
|
|
|
|
for (long i = p.quot + 1; i < _last_skip; i++)
|
|
_skip[i] = _skip[i]->_prev; // Aggiorna capilista successivi
|
|
|
|
// Siamo andati oltre l'ultimo skip
|
|
const long s = (_items - 1) / _step + 1;
|
|
if (s > _last_skip)
|
|
{
|
|
if (s > MAX_SKIP)
|
|
change_step(_step+1);
|
|
else
|
|
_last_skip++;
|
|
}
|
|
|
|
return index;
|
|
}
|
|
|
|
long TList::add(TObject* obj, long index)
|
|
{
|
|
if (index < 0 || index >= _items)
|
|
{
|
|
index = insert(obj, _items);
|
|
}
|
|
else
|
|
{
|
|
TList_object* lo = lstobjptr(index);
|
|
CHECK(lo, "NULL list object");
|
|
delete lo->_obj;
|
|
lo->_obj = obj;
|
|
}
|
|
return index;
|
|
}
|
|
|
|
TList::TList_object* TList::detach_lstobj(long index)
|
|
{
|
|
TList_object* lo = lstobjptr(index);
|
|
if (lo)
|
|
{
|
|
if (lo->_prev)
|
|
lo->_prev->_next = lo->_next;
|
|
if (lo->_next)
|
|
lo->_next->_prev = lo->_prev;
|
|
ldiv_t res = ldiv(index, _step);
|
|
if (res.rem == 0)
|
|
_skip[res.quot] = lo->_next;
|
|
long p;
|
|
for (p = res.quot + 1; p < _last_skip; p++)
|
|
_skip[p] = _skip[p]->_next;
|
|
|
|
_items--;
|
|
|
|
p = (_items - 1) / _step + 1;
|
|
if (p < _last_skip)
|
|
{
|
|
_last_skip--;
|
|
_skip[_last_skip] = NULL;
|
|
}
|
|
}
|
|
|
|
return lo;
|
|
}
|
|
|
|
TObject* TList::detach(long index)
|
|
{
|
|
TList_object* lo = detach_lstobj(index);
|
|
TObject* obj;
|
|
if (lo)
|
|
{
|
|
obj = lo->_obj;
|
|
delete lo;
|
|
}
|
|
else
|
|
obj = NULL;
|
|
return obj;
|
|
}
|
|
|
|
bool TList::remove(long index)
|
|
{
|
|
TObject* o = detach(index);
|
|
if (o)
|
|
delete o;
|
|
return o != NULL;
|
|
}
|
|
|
|
#include <time.h>
|
|
|
|
int cg3600(int argc, char* argv[])
|
|
{
|
|
long max = 100000L;
|
|
TList l(max);
|
|
const clock_t start = clock();
|
|
|
|
for (long i = 0; i < max; i++)
|
|
l.add(NULL);
|
|
|
|
const clock_t end = clock()-start;
|
|
|
|
return 0;
|
|
} |