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