1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
|
//Author: Max Howell <[email protected]>, (C) 2004
//Copyright: See COPYING file that comes with this distribution
#ifndef FILETREE_H
#define FILETREE_H
#include <qcstring.h> //qstrdup
#include <qfile.h> //decodeName()
#include <stdlib.h>
//TODO these are pointlessly general purpose now, make them incredibly specific
typedef unsigned long int FileSize;
typedef unsigned long int Dirsize; //**** currently unused
template <class T> class Iterator;
template <class T> class ConstIterator;
template <class T> class Chain;
template <class T>
class Link
{
public:
Link( T* const t ) : prev( this ), next( this ), data( t ) {}
Link() : prev( this ), next( this ), data( 0 ) {}
//TODO unlinking is slow and you don't use it very much in this context.
// ** Perhaps you can make a faster deletion system that doesn't bother tidying up first
// ** and then you MUST call some kind of detach() function when you remove elements otherwise
~Link() { delete data; unlink(); }
friend class Iterator<T>;
friend class ConstIterator<T>;
friend class Chain<T>;
private:
void unlink() { prev->next = next; next->prev = prev; prev = next = this; }
Link<T>* prev;
Link<T>* next;
T* data; //ensure only iterators have access to this
};
template <class T>
class Iterator
{
public:
Iterator() : link( 0 ) { } //**** remove this, remove this REMOVE THIS!!! dangerous as your implementation doesn't test for null links, always assumes they can be derefenced
Iterator( Link<T> *p ) : link( p ) { }
bool operator==( const Iterator<T>& it ) const { return link == it.link; }
bool operator!=( const Iterator<T>& it ) const { return link != it.link; }
bool operator!=( const Link<T> *p ) const { return p != link; }
//here we have a choice, really I should make two classes one const the other not
const T* operator*() const { return link->data; }
T* operator*() { return link->data; }
Iterator<T>& operator++() { link = link->next; return *this; } //**** does it waste time returning in places where we don't use the retval?
bool isNull() const { return (link == 0); } //REMOVE WITH ABOVE REMOVAL you don't want null iterators to be possible
void transferTo( Chain<T> &chain )
{
chain.append( remove() );
}
T* const remove() //remove from list, delete Link, data is returned NOT deleted
{
T* const d = link->data;
Link<T>* const p = link->prev;
link->data = 0;
delete link;
link = p; //make iterator point to previous element, YOU must check this points to an element
return d;
}
private:
Link<T> *link;
};
template <class T>
class ConstIterator
{
public:
ConstIterator( Link<T> *p ) : link( p ) { }
bool operator==( const Iterator<T>& it ) const { return link == it.link; }
bool operator!=( const Iterator<T>& it ) const { return link != it.link; }
bool operator!=( const Link<T> *p ) const { return p != link; }
const T* operator*() const { return link->data; }
ConstIterator<T>& operator++() { link = link->next; return *this; }
private:
const Link<T> *link;
};
template <class T>
class Chain
{
public:
virtual ~Chain() { empty(); }
void append( T* const data )
{
Link<T>* const link = new Link<T>( data );
link->prev = head.prev;
link->next = &head;
head.prev->next = link;
head.prev = link;
}
void transferTo( Chain &c )
{
if( isEmpty() ) return;
Link<T>* const first = head.next;
Link<T>* const last = head.prev;
head.unlink();
first->prev = c.head.prev;
c.head.prev->next = first;
last->next = &c.head;
c.head.prev = last;
}
void empty() { while( head.next != &head ) { delete head.next; } }
Iterator<T> iterator() const { return Iterator<T>( head.next ); }
ConstIterator<T> constIterator() const { return ConstIterator<T>( head.next ); }
const Link<T> *end() const { return &head; }
bool isEmpty() const { return head.next == &head; }
private:
Link<T> head;
void operator=( const Chain& );
};
class Directory;
class QString;
class File
{
public:
friend class Directory;
enum UnitPrefix { kilo, mega, giga, tera };
static const uint DENOMINATOR[4];
public:
File( const char *name, FileSize size ) : m_parent( 0 ), m_name( qstrdup( name ) ), m_size( size ) {}
virtual ~File() { delete [] m_name; }
const Directory *parent() const { return m_parent; }
const char *name8Bit() const { return m_name; }
const FileSize size() const { return m_size; }
QString name() const { return QFile::decodeName( m_name ); }
virtual bool isDirectory() const { return false; }
QString fullPath( const Directory* = 0 ) const;
QString humanReadableSize( UnitPrefix key = mega ) const;
public:
static QString humanReadableSize( uint size, UnitPrefix Key = mega );
protected:
File( const char *name, FileSize size, Directory *parent ) : m_parent( parent ), m_name( qstrdup( name ) ), m_size( size ) {}
Directory *m_parent; //0 if this is treeRoot
char *m_name;
FileSize m_size; //in units of KiB
private:
File( const File& );
void operator=( const File& );
};
class Directory : public Chain<File>, public File
{
public:
Directory( const char *name ) : File( name, 0 ), m_children( 0 ) {} //DON'T pass the full path!
uint children() const { return m_children; }
virtual bool isDirectory() const { return true; }
///appends a Directory
void append( Directory *d, const char *name=0 )
{
if( name ) {
delete [] d->m_name;
d->m_name = qstrdup( name ); } //directories that had a fullpath copy just their names this way
m_children += d->children(); //doesn't include the dir itself
d->m_parent = this;
append( (File*)d ); //will add 1 to filecount for the dir itself
}
///appends a File
void append( const char *name, FileSize size )
{
append( new File( name, size, this ) );
}
private:
void append( File *p )
{
m_children++;
m_size += p->size();
Chain<File>::append( p );
}
uint m_children;
private:
Directory( const Directory& ); //undefined
void operator=( const Directory& ); //undefined
};
#endif
|