commit 124df174f78190c79ad0bffaeff238e585457f4c from: Omar Polo date: Sat Aug 11 22:10:03 2018 UTC Better memory management The completion are stored one after one instead of within a linked-list: since we know in advance the size this make sense. Before we allocate/deallocate the whole completion list on every `filter`, now we don't. commit - d29c160f7129fc8f3ecb23638648704792d42929 commit + 124df174f78190c79ad0bffaeff238e585457f4c blob - be5b28412e99f7a59d3a5659ebb5813336b09f97 blob + 70485948562d17a7171533ec4f1137a62ddad7e9 --- mymenu.c +++ mymenu.c @@ -131,65 +131,37 @@ struct rendering { #endif }; -// A simple linked list to store the completions. struct completion { char *completion; char *rcompletion; - struct completion *next; }; // Wrap the linked list of completions struct completions { struct completion *completions; - int selected; - int lenght; + ssize_t selected; + size_t lenght; }; // return a newly allocated (and empty) completion list -struct completions *compls_new() { +struct completions *compls_new(size_t lenght) { struct completions *cs = malloc(sizeof(struct completions)); if (cs == nil) return cs; - cs->completions = nil; + cs->completions = calloc(lenght, sizeof(struct completion)); cs->selected = -1; - cs->lenght = 0; + cs->lenght = lenght; return cs; } -// Return a newly allocated (and empty) completion -struct completion *compl_new() { - struct completion *c = malloc(sizeof(struct completion)); - if (c == nil) - return c; - - c->completion = nil; - c->rcompletion = nil; - c->next = nil; - return c; -} - -// delete ONLY the given completion (i.e. does not free c->next...) -void compl_delete(struct completion *c) { - free(c); -} - -// delete the current completion and the next (c->next) and so on... -void compl_delete_rec(struct completion *c) { - while (c != nil) { - struct completion *t = c->next; - free(c); - c = t; - } -} - // Delete the wrapper and the whole list void compls_delete(struct completions *cs) { if (cs == nil) return; - compl_delete_rec(cs->completions); + free(cs->completions); free(cs); } @@ -197,50 +169,32 @@ void compls_delete(struct completions *cs) { // completions (null terminated). Expects a non-null `cs'. lines and // vlines should have the same lenght OR vlines is null void filter(struct completions *cs, char *text, char **lines, char **vlines) { - struct completion *c = compl_new(); - if (c == nil) { - return; - } + size_t index = 0; + size_t matching = 0; - cs->completions = c; - - int index = 0; - int matching = 0; - if (vlines == nil) vlines = lines; while (true) { - char *l = vlines[index] ? vlines[index] : lines[index]; + char *l = vlines[index] != nil ? vlines[index] : lines[index]; if (l == nil) break; if (strcasestr(l, text) != nil) { + struct completion *c = &cs->completions[matching]; + c->completion = l; + c->rcompletion = lines[index]; matching++; - - c->next = compl_new(); - c = c->next; - if (c == nil) { - compls_delete(cs); - return; - } - c->completion = l; - c->rcompletion = lines[index]; } index++; } - - struct completion *f = cs->completions->next; - compl_delete(cs->completions); - cs->completions = f; cs->lenght = matching; cs->selected = -1; } // update the given completion, that is: clean the old cs & generate a new one. void update_completions(struct completions *cs, char *text, char **lines, char **vlines, bool first_selected) { - compl_delete_rec(cs->completions); filter(cs, text, lines, vlines); if (first_selected && cs->lenght > 0) cs->selected = 0; @@ -276,14 +230,8 @@ void complete(struct completions *cs, bool first_selec index = 0; index = cs->selected = (cs->lenght + (p ? index - 1 : index + 1)) % cs->lenght; - struct completion *n = cs->completions; + struct completion *n = &cs->completions[cs->selected]; - // find the selected item - while (index != 0) { - index--; - n = n->next; - } - free(*text); *text = strdup(n->completion); if (text == nil) { @@ -395,8 +343,8 @@ char *normalize_str(const char *str) { // `realloc(3)` to store more line. Return the number of lines // read. The last item will always be a NULL pointer. It ignore the // "null" (empty) lines -int readlines(char ***lns, int items) { - int n = 0; +size_t readlines(char ***lns, size_t items) { + size_t n = 0; char **lines = *lns; while (true) { size_t linelen = 0; @@ -438,9 +386,6 @@ int text_extents(char *str, int len, struct rendering #ifdef USE_XFT XGlyphInfo gi; XftTextExtentsUtf8(r->d, r->font, str, len, &gi); - /* height = gi.height; */ - /* height = (gi.height + (r->font->ascent - r->font->descent)/2) / 2; */ - /* height = (r->font->ascent - r->font->descent)/2 + gi.height*2; */ height = r->font->ascent - r->font->descent; width = gi.width - gi.x; #else @@ -515,11 +460,12 @@ void draw_horizontally(struct rendering *r, char *text XFillRectangle(r->d, r->w, r->completion_bg, start_at, r->y_zero, r->width, inner_height(r)); - struct completion *c = cs->completions; - for (int i = 0; c != nil; ++i) { - enum text_type tt = cs->selected == i ? COMPL_HIGH : COMPL; - GC h = cs->selected == i ? r->completion_highlighted_bg : r->completion_bg; + for (size_t i = 0; i < cs->lenght; ++i) { + struct completion *c = &cs->completions[i]; + enum text_type tt = cs->selected == (ssize_t)i ? COMPL_HIGH : COMPL; + GC h = cs->selected == (ssize_t)i ? r->completion_highlighted_bg : r->completion_bg; + int len = strlen(c->completion); int text_width = text_extents(c->completion, len, r, nil, nil); @@ -531,8 +477,6 @@ void draw_horizontally(struct rendering *r, char *text if (start_at > inner_width(r)) break; // don't draw completion if the space isn't enough - - c = c->next; } } @@ -558,10 +502,10 @@ void draw_vertically(struct rendering *r, char *text, start_at += r->y_zero; - struct completion *c = cs->completions; - for (int i = 0; c != nil; ++i){ - enum text_type tt = cs->selected == i ? COMPL_HIGH : COMPL; - GC h = cs->selected == i ? r->completion_highlighted_bg : r->completion_bg; + for (size_t i = 0; i < cs->lenght; ++i){ + struct completion *c = &cs->completions[i]; + enum text_type tt = cs->selected == (ssize_t)i ? COMPL_HIGH : COMPL; + GC h = cs->selected == (ssize_t)i ? r->completion_highlighted_bg : r->completion_bg; int len = strlen(c->completion); text_extents(c->completion, len, r, &width, &height); @@ -572,8 +516,6 @@ void draw_vertically(struct rendering *r, char *text, if (start_at > inner_height(r)) break; // don't draw completion if the space isn't enough - - c = c->next; } } @@ -916,7 +858,7 @@ int main(int argc, char **argv) { // read the lines from stdin char **lines = calloc(INITIAL_ITEMS, sizeof(char*)); check_allocation(lines); - int nlines = readlines(&lines, INITIAL_ITEMS); + size_t nlines = readlines(&lines, INITIAL_ITEMS); char **vlines = nil; if (sep != nil) { int l = strlen(sep); @@ -971,7 +913,7 @@ int main(int argc, char **argv) { check_allocation(text); /* struct completions *cs = filter(text, lines); */ - struct completions *cs = compls_new(); + struct completions *cs = compls_new(nlines); check_allocation(cs); // start talking to xorg @@ -1493,7 +1435,7 @@ int main(int argc, char **argv) { while (true) { if (index == 0) break; - c = c->next; + c++; index--; } char *t = c->rcompletion;