Initial revision
This commit is contained in:
parent
218ca90543
commit
2186d5f3f9
572 changed files with 2 additions and 29666 deletions
871
src/win95/list_tem.hpp
Normal file
871
src/win95/list_tem.hpp
Normal file
|
@ -0,0 +1,871 @@
|
|||
// Doubly linked list class.
|
||||
//
|
||||
// Inserts new entries at the *end* of the list -- so add_entry()
|
||||
// followed by delete_last_entry() will do nothing.
|
||||
//
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// List<Thing> l; creates an empty list.
|
||||
// Thing a; List<Thing> l(a); creates a list containing a.
|
||||
//
|
||||
// void l.add_entry(Thing a); adds an entry.
|
||||
// void l.delete_entry(Thing a); removes `a' from the list if it's there,
|
||||
// aborts if it's not.
|
||||
// void l.delete_{first,last}_entry deletes the first/last entry.
|
||||
// Thing l.{first,last}_entry returns the first/last entry.
|
||||
// bool l.contains(Thing a) is a in the list?
|
||||
#ifndef list_template_hpp
|
||||
#define list_template_hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef _CPPRTTI // run time type information available
|
||||
#include <typeinfo.h>
|
||||
#define LIST_TEM_TYPEID_THIS typeid(*this).name()
|
||||
#else
|
||||
#define LIST_TEM_TYPEID_THIS "?"
|
||||
#endif
|
||||
|
||||
#if defined(engine)
|
||||
// Not all preprocessors do lazy evaluation. DW
|
||||
#if engine
|
||||
#include "mem3dc.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define fail if (0)
|
||||
#define list_fail_get_data_from_sentinel NULL
|
||||
#define list_fail_add_entry_after NULL
|
||||
#define list_fail_add_entry_before NULL
|
||||
#define list_fail_delete_entry NULL
|
||||
#define list_fail_delete_entry_by_pointer NULL
|
||||
#define list_fail_alter_entry NULL
|
||||
#define list_fail_next_entry_nonexist NULL
|
||||
#define list_fail_next_entry_sentinel NULL
|
||||
#define list_fail_prev_entry_nonexist NULL
|
||||
#define list_fail_prev_entry_sentinel NULL
|
||||
#define list_fail_last_entry NULL
|
||||
#define list_fail_first_entry NULL
|
||||
#define list_fail_similar_entry NULL
|
||||
#define list_fail_delete_last_entry NULL
|
||||
#define list_fail_delete_first_entry NULL
|
||||
#define list_fail_operator NULL
|
||||
#define lit_fail_next NULL
|
||||
#define lit_fail_operator NULL
|
||||
#define lit_fail_delete_current NULL
|
||||
#define lit_fail_change_current NULL
|
||||
#else
|
||||
#include "fail.h"
|
||||
extern char const * list_fail_get_data_from_sentinel;
|
||||
extern char const * list_fail_add_entry_after;
|
||||
extern char const * list_fail_add_entry_before;
|
||||
extern char const * list_fail_delete_entry;
|
||||
extern char const * list_fail_delete_entry_by_pointer;
|
||||
extern char const * list_fail_alter_entry;
|
||||
extern char const * list_fail_next_entry_nonexist;
|
||||
extern char const * list_fail_next_entry_sentinel;
|
||||
extern char const * list_fail_prev_entry_nonexist;
|
||||
extern char const * list_fail_prev_entry_sentinel;
|
||||
extern char const * list_fail_last_entry;
|
||||
extern char const * list_fail_first_entry;
|
||||
extern char const * list_fail_similar_entry;
|
||||
extern char const * list_fail_delete_last_entry;
|
||||
extern char const * list_fail_delete_first_entry;
|
||||
extern char const * list_fail_operator;
|
||||
extern char const * lit_fail_next;
|
||||
extern char const * lit_fail_operator;
|
||||
extern char const * lit_fail_delete_current;
|
||||
extern char const * lit_fail_change_current;
|
||||
#endif
|
||||
|
||||
// The first declaration of these class templates was previously as friends
|
||||
// of List. However, Visual C++ 5 can't parse them unless we give a
|
||||
// forward declaration first - I think this is a compiler bug - Garry.
|
||||
template<class T>
|
||||
class List_Iterator_Forward;
|
||||
template<class T>
|
||||
class ConstList_Iterator_Forward;
|
||||
template<class T>
|
||||
class List_Iterator_Backward;
|
||||
template<class T>
|
||||
class ConstList_Iterator_Backward;
|
||||
template<class T>
|
||||
class List_Iterator_Loop;
|
||||
|
||||
template<class T>
|
||||
struct List_Member;
|
||||
|
||||
template<class T>
|
||||
struct List_Member_Base
|
||||
{
|
||||
union
|
||||
{
|
||||
List_Member_Base<T> *prev;
|
||||
#ifndef __WATCOMC__
|
||||
List_Member<T> *prev_debug; // encourage the debugger to display the list members data
|
||||
#endif // hopefully casting from base to derived class would not
|
||||
// cause the actual value of the ptr to change, so the debugger
|
||||
// will display the information correctly, and this union
|
||||
// won't cause any kind of performance hit
|
||||
|
||||
//watcom doesn't appear to like this, unfortunately.
|
||||
|
||||
|
||||
|
||||
};
|
||||
union
|
||||
{
|
||||
List_Member_Base<T> *next;
|
||||
#ifndef __WATCOMC__
|
||||
List_Member<T> *next_debug;
|
||||
#endif
|
||||
};
|
||||
virtual ~List_Member_Base() {}
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct List_Member : public List_Member_Base<T>
|
||||
{
|
||||
T data;
|
||||
List_Member<T>(const T& n) : data(n) {}
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class List {
|
||||
private:
|
||||
List_Member_Base<T> *sentinel;
|
||||
int n_entries;
|
||||
mutable T **entry_pointers;
|
||||
mutable bool calculated_indices;
|
||||
|
||||
T& data(List_Member_Base<T>* e) const
|
||||
{
|
||||
if (e == sentinel)
|
||||
fail(list_fail_get_data_from_sentinel,LIST_TEM_TYPEID_THIS);
|
||||
return ((List_Member<T>*)e)->data;
|
||||
}
|
||||
|
||||
public:
|
||||
List() {
|
||||
sentinel = new List_Member_Base<T>;
|
||||
|
||||
sentinel->next = sentinel;
|
||||
sentinel->prev = sentinel;
|
||||
|
||||
n_entries = 0;
|
||||
entry_pointers = 0;
|
||||
calculated_indices = false;
|
||||
}
|
||||
|
||||
List(const T& n) {
|
||||
sentinel = new List_Member_Base<T>;
|
||||
sentinel->next = sentinel;
|
||||
sentinel->prev = sentinel;
|
||||
n_entries = 0;
|
||||
entry_pointers = 0;
|
||||
calculated_indices = false;
|
||||
|
||||
add_entry(n);
|
||||
}
|
||||
|
||||
List(const List<T>& l) {
|
||||
sentinel = new List_Member_Base<T>;
|
||||
|
||||
sentinel->next = sentinel;
|
||||
sentinel->prev = sentinel;
|
||||
n_entries = 0;
|
||||
|
||||
entry_pointers = 0;
|
||||
calculated_indices = false;
|
||||
|
||||
List_Member_Base<T>* m = l.sentinel->next;
|
||||
while (m != l.sentinel) {
|
||||
add_entry(data(m));
|
||||
m = m->next;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
List<T>& operator= (const List<T>& l) {
|
||||
while(n_entries != 0) delete_last_entry();
|
||||
if (entry_pointers != 0)
|
||||
delete[] entry_pointers;
|
||||
|
||||
List_Member_Base<T>* m = l.sentinel->next;
|
||||
while (m != l.sentinel) {
|
||||
add_entry(data(m));
|
||||
m = m->next;
|
||||
}
|
||||
calculated_indices = false;
|
||||
entry_pointers = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
~List() {
|
||||
while (n_entries != 0) delete_last_entry();
|
||||
delete sentinel;
|
||||
delete[] entry_pointers;
|
||||
}
|
||||
|
||||
void add_entry(const T& n) {
|
||||
add_entry_end(n);
|
||||
}
|
||||
|
||||
void add_entry_end(const T& n) {
|
||||
List_Member<T> *e = new List_Member<T>(n);
|
||||
e->next = sentinel;
|
||||
e->prev = sentinel->prev;
|
||||
sentinel->prev->next = e;
|
||||
sentinel->prev = e;
|
||||
n_entries++;
|
||||
cleanup();
|
||||
}
|
||||
|
||||
void add_entry_start(const T& n) {
|
||||
List_Member<T> *e = new List_Member<T>(n);
|
||||
e->prev = sentinel;
|
||||
e->next = sentinel->next;
|
||||
sentinel->next->prev = e;
|
||||
sentinel->next = e;
|
||||
n_entries++;
|
||||
cleanup();
|
||||
}
|
||||
|
||||
void add_entry_after(const T& n, const T& d) {
|
||||
List_Member_Base<T> *f = sentinel->next;
|
||||
while (f != sentinel && data(f) != d) {
|
||||
f = f->next;
|
||||
}
|
||||
if (f == sentinel) {
|
||||
fail(list_fail_add_entry_after,LIST_TEM_TYPEID_THIS);
|
||||
} else {
|
||||
List_Member<T> *e = new List_Member<T>(n);
|
||||
e->next = f->next;
|
||||
e->prev = f;
|
||||
e->next->prev = e;
|
||||
f->next = e;
|
||||
n_entries++;
|
||||
}
|
||||
cleanup();
|
||||
}
|
||||
|
||||
void add_entry_before(const T& n, const T& d) {
|
||||
List_Member_Base<T> *f = sentinel->next;
|
||||
while (f != sentinel && data(f) != d) {
|
||||
f = f->next;
|
||||
}
|
||||
if (f == sentinel) {
|
||||
fail(list_fail_add_entry_before,LIST_TEM_TYPEID_THIS);
|
||||
} else {
|
||||
List_Member<T> *e = new List_Member<T>(n);
|
||||
e->prev = f->prev;
|
||||
e->next = f;
|
||||
e->prev->next = e;
|
||||
f->prev = e;
|
||||
n_entries++;
|
||||
}
|
||||
cleanup();
|
||||
}
|
||||
|
||||
void delete_entry(const T& d) {
|
||||
List_Member_Base<T> *e = sentinel->next;
|
||||
while (e != sentinel && data(e) != d && e != sentinel) {
|
||||
e = e->next;
|
||||
}
|
||||
if (e == sentinel) {
|
||||
fail(list_fail_delete_entry,LIST_TEM_TYPEID_THIS);
|
||||
} else {
|
||||
e->prev->next = e->next;
|
||||
e->next->prev = e->prev;
|
||||
delete e;
|
||||
}
|
||||
n_entries--;
|
||||
cleanup();
|
||||
}
|
||||
|
||||
void delete_entry_backward(const T& d) {
|
||||
List_Member_Base<T> *e = sentinel->prev;
|
||||
while (e != sentinel && data(e) != d && e != sentinel) {
|
||||
e = e->prev;
|
||||
}
|
||||
if (e == sentinel) {
|
||||
fail(list_fail_delete_entry,LIST_TEM_TYPEID_THIS);
|
||||
} else {
|
||||
e->prev->next = e->next;
|
||||
e->next->prev = e->prev;
|
||||
delete e;
|
||||
}
|
||||
n_entries--;
|
||||
cleanup();
|
||||
}
|
||||
|
||||
void delete_entry_by_pointer(List_Member_Base<T>* l) {
|
||||
if (l == sentinel)
|
||||
fail(list_fail_delete_entry_by_pointer,LIST_TEM_TYPEID_THIS);
|
||||
l->next->prev = l->prev;
|
||||
l->prev->next = l->next;
|
||||
delete l;
|
||||
l = 0; // so we get a seg if we try and reuse it
|
||||
n_entries--;
|
||||
cleanup();
|
||||
}
|
||||
|
||||
void alter_entry(const T& od, const T& nd) {
|
||||
List_Member_Base<T> *e = sentinel->next;
|
||||
while (e != sentinel && data(e) != od) {
|
||||
e = e->next;
|
||||
}
|
||||
if (e == sentinel) {
|
||||
fail(list_fail_alter_entry,LIST_TEM_TYPEID_THIS);
|
||||
} else {
|
||||
// Remove this entry, and put a new one in it's place. We can't
|
||||
// just do e->data = nd, because that's assignment, and we don't
|
||||
// want to require an assignment operator to be defined for
|
||||
// every thing that we put on a list.
|
||||
List_Member<T> * n = new List_Member<T>(nd);
|
||||
e->prev->next = n;
|
||||
e->next->prev = n;
|
||||
n->next = e->next;
|
||||
n->prev = e->prev;
|
||||
delete e;
|
||||
}
|
||||
cleanup();
|
||||
}
|
||||
|
||||
T next_entry(const T& d) const {
|
||||
List_Member_Base<T> *e = sentinel->next;
|
||||
while (e != sentinel && data(e) != d && e != sentinel) {
|
||||
e = e->next;
|
||||
}
|
||||
if (e == sentinel) {
|
||||
fail(list_fail_next_entry_nonexist,LIST_TEM_TYPEID_THIS);
|
||||
} else {
|
||||
if (e->next == sentinel)
|
||||
fail(list_fail_next_entry_sentinel,LIST_TEM_TYPEID_THIS);
|
||||
return data(e->next);
|
||||
}
|
||||
return data(e->next);
|
||||
}
|
||||
|
||||
T prev_entry(const T& d) const {
|
||||
List_Member_Base<T> *e = sentinel->next;
|
||||
while (e!= sentinel && data(e) != d) {
|
||||
e = e->next;
|
||||
}
|
||||
if (e == sentinel) {
|
||||
fail(list_fail_prev_entry_nonexist,LIST_TEM_TYPEID_THIS);
|
||||
} else {
|
||||
if (e->prev == sentinel)
|
||||
fail(list_fail_prev_entry_sentinel,LIST_TEM_TYPEID_THIS);
|
||||
return data(e->prev);
|
||||
}
|
||||
return data(e->prev);
|
||||
}
|
||||
|
||||
T const & similar_entry(T const& d) const
|
||||
{
|
||||
List_Member_Base<T> *e = sentinel->next;
|
||||
while (e != sentinel)
|
||||
{
|
||||
if (data(e) == d)
|
||||
break;
|
||||
e = e->next;
|
||||
|
||||
}
|
||||
if (e == sentinel)
|
||||
{
|
||||
fail(list_fail_similar_entry,LIST_TEM_TYPEID_THIS);
|
||||
}
|
||||
return data(e);
|
||||
}
|
||||
|
||||
bool contains(const T& d) {
|
||||
List_Member_Base<T> *e = sentinel->next;
|
||||
while (e != sentinel && data(e) != d) {
|
||||
e = e->next;
|
||||
}
|
||||
if (e == sentinel) return false;
|
||||
else return true;
|
||||
}
|
||||
|
||||
void delete_last_entry() {
|
||||
if (sentinel->prev == sentinel) {
|
||||
fail(list_fail_delete_last_entry,LIST_TEM_TYPEID_THIS);
|
||||
} else {
|
||||
// aiee. These lines work, but are a bit hairy.
|
||||
|
||||
sentinel->prev = sentinel->prev->prev;
|
||||
delete sentinel->prev->next;
|
||||
sentinel->prev->next = sentinel;
|
||||
n_entries--;
|
||||
}
|
||||
cleanup();
|
||||
}
|
||||
|
||||
void delete_first_entry() {
|
||||
if (sentinel->next == sentinel) {
|
||||
fail(list_fail_delete_last_entry,LIST_TEM_TYPEID_THIS);
|
||||
} else {
|
||||
sentinel->next = sentinel->next->next;
|
||||
delete sentinel->next->prev;
|
||||
sentinel->next->prev = sentinel;
|
||||
n_entries--;
|
||||
}
|
||||
cleanup();
|
||||
}
|
||||
|
||||
T const & operator[](int i) const {
|
||||
if (i < 0 || i >= n_entries)
|
||||
fail(list_fail_operator,LIST_TEM_TYPEID_THIS, i+1, n_entries);
|
||||
|
||||
if (!calculated_indices) {
|
||||
if (entry_pointers != 0)
|
||||
delete[] entry_pointers;
|
||||
entry_pointers = new T*[n_entries+1];
|
||||
List_Member_Base<T>*e = sentinel->next;
|
||||
int j = 0;
|
||||
while (e != sentinel) {
|
||||
entry_pointers[j] = &data(e);
|
||||
e = e->next;
|
||||
j++;
|
||||
}
|
||||
calculated_indices = true;
|
||||
}
|
||||
return *entry_pointers[i];
|
||||
}
|
||||
|
||||
T & last_entry()
|
||||
{
|
||||
if (n_entries == 0)
|
||||
fail(list_fail_last_entry,LIST_TEM_TYPEID_THIS);
|
||||
return data(sentinel->prev);
|
||||
}
|
||||
|
||||
T const & last_entry() const
|
||||
{
|
||||
if (n_entries == 0)
|
||||
fail(list_fail_last_entry,LIST_TEM_TYPEID_THIS);
|
||||
return data(sentinel->prev);
|
||||
}
|
||||
|
||||
T & first_entry()
|
||||
{
|
||||
if (n_entries == 0)
|
||||
fail(list_fail_first_entry,LIST_TEM_TYPEID_THIS);
|
||||
return data(sentinel->next);
|
||||
}
|
||||
|
||||
T const & first_entry() const
|
||||
{
|
||||
if (n_entries == 0)
|
||||
fail(list_fail_first_entry,LIST_TEM_TYPEID_THIS);
|
||||
return data(sentinel->next);
|
||||
}
|
||||
|
||||
int size() const { return n_entries; }
|
||||
|
||||
void cleanup() { calculated_indices = false; if (entry_pointers != 0) delete[] entry_pointers; entry_pointers = 0;}
|
||||
|
||||
bool operator==(const List <T> &l1) const
|
||||
{
|
||||
if (n_entries != l1.n_entries) return false;
|
||||
for (List_Member_Base<T> * e = sentinel->next, *e1 = l1.sentinel->next; e != sentinel; e = e->next, e1 = e1->next)
|
||||
{
|
||||
if (((List_Member<T> *)e)->data != ((List_Member<T> *)e1)->data) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator!=(const List <T> &l1) const
|
||||
{
|
||||
if (n_entries != l1.n_entries) return true;
|
||||
for (List_Member_Base<T> * e = sentinel->next, *e1 = l1.sentinel->next; e != sentinel; e = e->next, e1 = e1->next)
|
||||
{
|
||||
if (((List_Member<T> *)e)->data != ((List_Member<T> *)e1)->data) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
friend class List_Iterator_Forward<T>;
|
||||
friend class ConstList_Iterator_Forward<T>;
|
||||
friend class List_Iterator_Backward<T>;
|
||||
friend class ConstList_Iterator_Backward<T>;
|
||||
friend class List_Iterator_Loop<T>;
|
||||
};
|
||||
|
||||
// Use List_Iterator_{Forward,Backward} as follows:
|
||||
//
|
||||
// for(List_Iterator_Forward<T*> oi(&(List_of_T*)); // a _pointer_
|
||||
// // to the list.
|
||||
// !oi.done();
|
||||
// oi.next() ) {
|
||||
// do_something( oi() ) ;
|
||||
// }
|
||||
//
|
||||
// First entry is the one past the sentinel, and next() and
|
||||
// operator() fail if you try and iterate too far; check if it's
|
||||
// done() before doing anything else, basically.
|
||||
//
|
||||
// As it's a doubly-linked list, we can go backwards and
|
||||
// forwards. next() takes us to the entry that the type of iterator
|
||||
// suggests; un_next() takes us in the other direction. un_next() is
|
||||
// an ugly name, but next() and prev() are too suggestive of a
|
||||
// particular direction.
|
||||
|
||||
template<class T>
|
||||
class List_Iterator_Forward
|
||||
{
|
||||
private:
|
||||
union
|
||||
{
|
||||
List_Member_Base<T> *m;
|
||||
List_Member<T> *m_debug; // encourage the debugger to display the list members data
|
||||
// hopefully casting from base to derived class would not
|
||||
// cause the actual value of the ptr to change, so the debugger
|
||||
// will display the information correctly, and this union
|
||||
// won't cause any kind of performance hit
|
||||
};
|
||||
List<T> *l;
|
||||
|
||||
public:
|
||||
List_Iterator_Forward() {}
|
||||
List_Iterator_Forward(List<T> *list) { l = list; m = l->sentinel->next; }
|
||||
|
||||
void next() {
|
||||
if (m != l->sentinel) {
|
||||
m = m->next;
|
||||
} else
|
||||
fail(lit_fail_next,LIST_TEM_TYPEID_THIS);
|
||||
}
|
||||
|
||||
void un_next() {
|
||||
if (m != l->sentinel) {
|
||||
m = m->prev;
|
||||
} else
|
||||
fail(lit_fail_next,LIST_TEM_TYPEID_THIS);
|
||||
}
|
||||
|
||||
T & operator() () const {
|
||||
if (m == l->sentinel)
|
||||
fail(lit_fail_operator,LIST_TEM_TYPEID_THIS);
|
||||
return l->data(m);
|
||||
}
|
||||
|
||||
void delete_current() {
|
||||
if (m != l->sentinel) {
|
||||
m = m->next;
|
||||
l->delete_entry_by_pointer(m->prev);
|
||||
} else
|
||||
fail(lit_fail_delete_current,LIST_TEM_TYPEID_THIS);
|
||||
}
|
||||
|
||||
void change_current(T const &new_val) const {
|
||||
if (m != l->sentinel) {
|
||||
// Delete the current member out of the list, put a new one in.
|
||||
|
||||
List_Member<T> * n = new List_Member<T>(new_val);
|
||||
m->prev->next = n;
|
||||
m->next->prev = n;
|
||||
n->next = m->next;
|
||||
n->prev = m->prev;
|
||||
delete m;
|
||||
*(List_Member_Base<T> **)&m =n; // or we're pointing at the thing we just deleted.
|
||||
l->cleanup(); // because it's changed, but the List doesn't know that.
|
||||
} else
|
||||
fail(lit_fail_change_current,LIST_TEM_TYPEID_THIS);
|
||||
}
|
||||
|
||||
bool done() { if (m == l->sentinel) return true; else return false; }
|
||||
void restart() { m = l->sentinel->next; }
|
||||
// Go to the end of the list.
|
||||
void end() { m = l->sentinel->prev; }
|
||||
};
|
||||
|
||||
#define LIF List_Iterator_Forward
|
||||
|
||||
template<class T>
|
||||
class ConstList_Iterator_Forward
|
||||
{
|
||||
private:
|
||||
union
|
||||
{
|
||||
List_Member_Base<T> *m;
|
||||
List_Member<T> *m_debug; // encourage the debugger to display the list members data
|
||||
};
|
||||
List<T> const *l;
|
||||
|
||||
public:
|
||||
ConstList_Iterator_Forward(List<T> const *list) { l = list; m = l->sentinel->next; }
|
||||
ConstList_Iterator_Forward(){}
|
||||
|
||||
void next() {
|
||||
if (m == l->sentinel) {
|
||||
fail(lit_fail_next,LIST_TEM_TYPEID_THIS);
|
||||
}
|
||||
m = m->next;
|
||||
}
|
||||
|
||||
void un_next() {
|
||||
if (m == l->sentinel) {
|
||||
fail(lit_fail_next,LIST_TEM_TYPEID_THIS);
|
||||
}
|
||||
m = m->prev;
|
||||
}
|
||||
|
||||
T const & operator() () const {
|
||||
if (m == l->sentinel)
|
||||
fail(lit_fail_operator,LIST_TEM_TYPEID_THIS);
|
||||
return l->data(m);
|
||||
}
|
||||
|
||||
#if 0 // shouldn't really be available on a const list
|
||||
void change_current(T const & new_val) const {
|
||||
if (m != l->sentinel) {
|
||||
m->data = new_val;
|
||||
} else
|
||||
fail(lit_fail_change_current,LIST_TEM_TYPEID_THIS);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool done() const { if (m == l->sentinel) return true; else return false; }
|
||||
void restart() { m = l->sentinel->next; }
|
||||
// Go to the end of the list.
|
||||
void end() { m = l->sentinel->prev; }
|
||||
};
|
||||
|
||||
#define CLIF ConstList_Iterator_Forward
|
||||
|
||||
template<class T>
|
||||
class List_Iterator_Backward
|
||||
{
|
||||
private:
|
||||
union
|
||||
{
|
||||
List_Member_Base<T> *m;
|
||||
List_Member<T> *m_debug; // encourage the debugger to display the list members data
|
||||
};
|
||||
List<T> *l;
|
||||
|
||||
public:
|
||||
List_Iterator_Backward() {}
|
||||
List_Iterator_Backward(List<T> *list) { l = list; m = l->sentinel->prev; }
|
||||
|
||||
void next() {
|
||||
if (m != l->sentinel) {
|
||||
m = m->prev;
|
||||
} else
|
||||
fail(lit_fail_next,LIST_TEM_TYPEID_THIS);
|
||||
}
|
||||
|
||||
void un_next() {
|
||||
if (m != l->sentinel) {
|
||||
m = m->next;
|
||||
} else
|
||||
fail(lit_fail_next,LIST_TEM_TYPEID_THIS);
|
||||
}
|
||||
|
||||
T & operator() () const {
|
||||
if (m == l->sentinel)
|
||||
fail(lit_fail_operator,LIST_TEM_TYPEID_THIS);
|
||||
return l->data(m);
|
||||
}
|
||||
|
||||
void delete_current() {
|
||||
if (m != l->sentinel) {
|
||||
m = m->prev;
|
||||
l->delete_entry_by_pointer(m->next);
|
||||
} else
|
||||
fail(lit_fail_delete_current,LIST_TEM_TYPEID_THIS);
|
||||
}
|
||||
|
||||
void change_current(T const & new_val) {
|
||||
if (m != l->sentinel) {
|
||||
// Delete the current member out of the list, put a new one in.
|
||||
|
||||
List_Member<T> * n = new List_Member<T>(new_val);
|
||||
m->prev->next = n;
|
||||
m->next->prev = n;
|
||||
n->next = m->next;
|
||||
n->prev = m->prev;
|
||||
delete m;
|
||||
m = n; // or we're pointing at the thing we just deleted.
|
||||
l->cleanup(); // because it's changed, but the List doesn't know that.
|
||||
} else
|
||||
fail(lit_fail_change_current,LIST_TEM_TYPEID_THIS);
|
||||
}
|
||||
|
||||
bool done() { if (m == l->sentinel) return true; else return false; }
|
||||
void restart() { m = l->sentinel->prev; }
|
||||
// Go to the end of the list.
|
||||
void end() { m = l->sentinel->prev; }
|
||||
};
|
||||
|
||||
#define LIB List_Iterator_Backward
|
||||
|
||||
template<class T>
|
||||
class ConstList_Iterator_Backward
|
||||
{
|
||||
private:
|
||||
union
|
||||
{
|
||||
List_Member_Base<T> *m;
|
||||
List_Member<T> *m_debug; // encourage the debugger to display the list members data
|
||||
};
|
||||
List<T> const *l;
|
||||
|
||||
public:
|
||||
ConstList_Iterator_Backward(List<T> const *list) { l = list; m = l->sentinel->prev; }
|
||||
ConstList_Iterator_Backward(){}
|
||||
|
||||
void next() {
|
||||
if (m == l->sentinel) {
|
||||
fail(lit_fail_next,LIST_TEM_TYPEID_THIS);
|
||||
}
|
||||
m = m->prev;
|
||||
}
|
||||
|
||||
void un_next() {
|
||||
if (m == l->sentinel) {
|
||||
fail(lit_fail_next,LIST_TEM_TYPEID_THIS);
|
||||
}
|
||||
m = m->next;
|
||||
}
|
||||
|
||||
T const & operator() () const {
|
||||
if (m == l->sentinel)
|
||||
fail(lit_fail_operator,LIST_TEM_TYPEID_THIS);
|
||||
return l->data(m);
|
||||
}
|
||||
|
||||
#if 0 // shouldn't really be available on a const list
|
||||
void change_current(T const & new_val) const {
|
||||
if (m != l->sentinel) {
|
||||
m->data = new_val;
|
||||
} else
|
||||
fail(lit_fail_change_current,LIST_TEM_TYPEID_THIS);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool done() const { if (m == l->sentinel) return true; else return false; }
|
||||
void restart() { m = l->sentinel->prev; }
|
||||
// Go to the end of the list.
|
||||
void end() { m = l->sentinel->prev; }
|
||||
};
|
||||
|
||||
#define CLIB ConstList_Iterator_Backward
|
||||
|
||||
/*
|
||||
A looping list iterator class :
|
||||
next from the last member will go to the first
|
||||
previous from the first member will go to the last
|
||||
*/
|
||||
|
||||
template<class T>
|
||||
class List_Iterator_Loop
|
||||
{
|
||||
private:
|
||||
union
|
||||
{
|
||||
List_Member_Base<T> *m;
|
||||
List_Member<T> *m_debug; // encourage the debugger to display the list members data
|
||||
};
|
||||
List<T> *l;
|
||||
|
||||
public:
|
||||
List_Iterator_Loop(List<T> *list) { l = list; m = l->sentinel->next; }
|
||||
|
||||
void next() {
|
||||
m=m->next;
|
||||
if (m == l->sentinel) {
|
||||
m = m->next;
|
||||
}
|
||||
}
|
||||
|
||||
void previous() {
|
||||
m=m->prev;
|
||||
if (m == l->sentinel) {
|
||||
m = m->prev;
|
||||
}
|
||||
}
|
||||
|
||||
T const & operator() () {
|
||||
if (m == l->sentinel)
|
||||
{
|
||||
m=m->next;//needed in case iterator was created before anything was added to the list
|
||||
if (m == l->sentinel)
|
||||
{
|
||||
fail(lit_fail_operator,LIST_TEM_TYPEID_THIS);
|
||||
}
|
||||
}
|
||||
return l->data(m);
|
||||
}
|
||||
|
||||
void delete_current() {
|
||||
if (m == l->sentinel)
|
||||
{
|
||||
m=m->next;//needed in case iterator was created before anything was added to the list
|
||||
if (m == l->sentinel)
|
||||
{
|
||||
fail(lit_fail_delete_current,LIST_TEM_TYPEID_THIS);
|
||||
}
|
||||
}
|
||||
m = m->next;
|
||||
l->delete_entry_by_pointer(m->prev);
|
||||
}
|
||||
|
||||
|
||||
void change_current(T const & new_val)
|
||||
{
|
||||
if (m == l->sentinel)
|
||||
m=m->next;//needed in case iterator was created before anything was added to the list
|
||||
|
||||
if (m != l->sentinel)
|
||||
{
|
||||
// Delete the current member out of the list, put a new one in.
|
||||
List_Member<T> * n = new List_Member<T>(new_val);
|
||||
m->prev->next = n;
|
||||
m->next->prev = n;
|
||||
n->next = m->next;
|
||||
n->prev = m->prev;
|
||||
delete m;
|
||||
m = n; // or we're pointing at the thing we just deleted.
|
||||
l->cleanup(); // because it's changed, but the List doesn't know that.
|
||||
}
|
||||
else
|
||||
fail(lit_fail_change_current,LIST_TEM_TYPEID_THIS);
|
||||
}
|
||||
|
||||
// Go to the start of the list.
|
||||
void restart() { m = l->sentinel->next; }
|
||||
|
||||
// Go to the end of the list.
|
||||
void end() { m = l->sentinel->prev; }
|
||||
|
||||
// Is it on the last entry.
|
||||
bool at_last() const { if (m == l->sentinel->prev) return true; else return false; }
|
||||
|
||||
// Get the next entry but done move the pointer.
|
||||
T const & get_next() {
|
||||
if (m->next == l->sentinel)
|
||||
{
|
||||
if (m->next->next == l->sentinel)
|
||||
{
|
||||
fail(lit_fail_operator,LIST_TEM_TYPEID_THIS);
|
||||
}
|
||||
return l->data(m->next->next);
|
||||
}
|
||||
return l->data(m->next);
|
||||
}
|
||||
};
|
||||
|
||||
#define LIL List_Iterator_Loop
|
||||
|
||||
#ifdef NDEBUG
|
||||
#undef fail // allow other code to have local variables called or differently scoped 'fail'
|
||||
#endif
|
||||
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue