Changed directory listings to a doubly linked list
This significantly improves the performance when browsing large directories. It is somewhat costly on the memory usage, though. :-(
Этот коммит содержится в:
родитель
c84e70b627
Коммит
eed949d48d
19
src/calc.c
19
src/calc.c
@ -172,6 +172,8 @@ int calc_item(struct dir *par, char *name) {
|
||||
d->parent = par;
|
||||
d->next = par->sub;
|
||||
par->sub = d;
|
||||
if(d->next)
|
||||
d->next->prev = d;
|
||||
d->name = malloc(strlen(name)+1);
|
||||
strcpy(d->name, name);
|
||||
|
||||
@ -496,15 +498,14 @@ int calc_process() {
|
||||
/* update references and free original item */
|
||||
if(orig) {
|
||||
root->next = orig->next;
|
||||
if(orig->parent) {
|
||||
t = orig->parent->sub;
|
||||
if(t == orig)
|
||||
orig->parent->sub = root;
|
||||
else if(t != NULL)
|
||||
for(; t->next!=NULL; t=t->next)
|
||||
if(t->next == orig)
|
||||
t->next = root;
|
||||
}
|
||||
root->prev = orig->prev;
|
||||
if(root->parent && root->parent->sub == orig)
|
||||
root->parent->sub = root;
|
||||
if(root->prev)
|
||||
root->prev->next = root;
|
||||
if(root->next)
|
||||
root->next->prev = root;
|
||||
orig->next = orig->prev = NULL;
|
||||
freedir(orig);
|
||||
}
|
||||
browse_init(root->sub);
|
||||
|
@ -122,6 +122,7 @@ struct dir *dirlist_sort(struct dir *list) {
|
||||
}
|
||||
if(tail) tail->next = e;
|
||||
else list = e;
|
||||
e->prev = tail;
|
||||
tail = e;
|
||||
}
|
||||
p = q;
|
||||
@ -225,10 +226,22 @@ struct dir *dirlist_next(struct dir *d) {
|
||||
}
|
||||
|
||||
|
||||
struct dir *dirlist_prev(struct dir *d) {
|
||||
if(!head || !d)
|
||||
return NULL;
|
||||
while((d = d->prev)) {
|
||||
if(!ISHIDDEN(d))
|
||||
return d;
|
||||
}
|
||||
if(dirlist_parent)
|
||||
return dirlist_parent;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* this function assumes that 'selected' is valid and points to a visible item */
|
||||
struct dir *dirlist_get(int i) {
|
||||
struct dir *t = selected, *d;
|
||||
int j;
|
||||
|
||||
if(!head)
|
||||
return NULL;
|
||||
@ -247,15 +260,15 @@ struct dir *dirlist_get(int i) {
|
||||
return t;
|
||||
}
|
||||
|
||||
/* negative number? start from beginning to get the index of the selected
|
||||
* item, and then start all over to get the requested item before that.
|
||||
* XXX: This can obviously be optimized by using a doubly linked list. */
|
||||
for(j=0,t=NULL; (t=dirlist_next(t)); j++)
|
||||
if(t == selected)
|
||||
break;
|
||||
for(t=NULL,j+=i; (t=dirlist_next(t))&&j>0; j--)
|
||||
;
|
||||
return t;
|
||||
/* otherwise, backward */
|
||||
while(1) {
|
||||
d = dirlist_prev(t);
|
||||
if(!d)
|
||||
return t;
|
||||
t = d;
|
||||
if(!++i)
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -52,7 +52,7 @@
|
||||
* XXX: probably a good idea to get rid of the custom _t types and use
|
||||
* fixed-size integers instead, which are much more predictable */
|
||||
struct dir {
|
||||
struct dir *parent, *next, *sub, *hlnk;
|
||||
struct dir *parent, *next, *prev, *sub, *hlnk;
|
||||
char *name;
|
||||
off_t size, asize;
|
||||
unsigned long items;
|
||||
|
16
src/util.c
16
src/util.c
@ -226,16 +226,12 @@ void freedir(struct dir *dr) {
|
||||
freedir_rec(dr->sub);
|
||||
|
||||
/* update references */
|
||||
if(dr->parent) {
|
||||
/* item is at the top of the dir, refer to next item */
|
||||
if(dr->parent->sub == dr)
|
||||
dr->parent->sub = dr->next;
|
||||
/* else, get the previous item and update it's "next"-reference */
|
||||
else
|
||||
for(tmp = dr->parent->sub; tmp != NULL; tmp = tmp->next)
|
||||
if(tmp->next == dr)
|
||||
tmp->next = dr->next;
|
||||
}
|
||||
if(dr->parent && dr->parent->sub == dr)
|
||||
dr->parent->sub = dr->next;
|
||||
if(dr->prev)
|
||||
dr->prev->next = dr->next;
|
||||
if(dr->next)
|
||||
dr->next->prev = dr->prev;
|
||||
|
||||
freedir_hlnk(dr);
|
||||
|
||||
|
Загрузка…
x
Ссылка в новой задаче
Block a user