Added quicklist, a linked list with better cache characteristics.

This commit is contained in:
Enno Rehling 2011-02-23 22:18:58 -08:00
parent 0adf7899dd
commit 1cae5e2283
5 changed files with 159 additions and 0 deletions

View File

@ -19,6 +19,7 @@
#include <util/goodies.c>
#include <util/language.c>
#include <util/lists.c>
#include <util/quicklist.c>
#include <util/log.c>
#include <util/message.c>
#include <util/nrmessage.c>

View File

@ -109,6 +109,7 @@
<ClInclude Include="util\nrmessage_struct.h" />
<ClInclude Include="util\parser.h" />
<ClInclude Include="util\patricia.h" />
<ClInclude Include="util\quicklist.h" />
<ClInclude Include="util\rand.h" />
<ClInclude Include="util\resolve.h" />
<ClInclude Include="util\rng.h" />
@ -145,6 +146,7 @@
<ClCompile Include="util\nrmessage.c" />
<ClCompile Include="util\parser.c" />
<ClCompile Include="util\patricia.c" />
<ClCompile Include="util\quicklist.c" />
<ClCompile Include="util\rand.c" />
<ClCompile Include="util\resolve.c" />
<ClCompile Include="util\sql.c" />

View File

@ -107,6 +107,9 @@
<ClInclude Include="util\xml.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="util\quicklist.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="util\argstack.c">
@ -199,5 +202,8 @@
<ClCompile Include="util\xml.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="util\quicklist.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

115
src/util/quicklist.c Normal file
View File

@ -0,0 +1,115 @@
/*
Copyright (c) 2010-2011, Enno Rehling <enno@eressea.de>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
**/
#include "quicklist.h"
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#define QL_MAXSIZE 14 /* total struct is 64 bytes */
#define QL_LIMIT 8
typedef struct quicklist {
struct quicklist * next;
int num_elements;
void * elements[QL_MAXSIZE];
} quicklist;
void * ql_get(quicklist * ql, int index) {
return (ql && index<ql->num_elements)?ql->elements[index]:ql_get(ql->next, index-ql->num_elements);
}
int ql_length(const quicklist * ql) {
return ql?ql->num_elements+ql_length(ql->next):0;
}
void ql_push(quicklist ** qlp, void * data) {
quicklist * ql = 0;
while(*qlp && ((*qlp)->next || (*qlp)->num_elements==QL_MAXSIZE)) {
qlp = &(*qlp)->next;
}
if (!*qlp) {
ql = malloc(sizeof(quicklist));
ql->num_elements = 0;
ql->next = 0;
*qlp = ql;
} else {
ql = *qlp;
}
ql->elements[ql->num_elements++] = data;
}
int ql_delete(quicklist ** qlp, int index) {
quicklist * ql = *qlp;
if (index<0) return EINVAL;
if (ql && index>=ql->num_elements) {
return ql_delete(&ql->next, index-ql->num_elements);
} else if (ql) {
if (index+1<ql->num_elements) {
memmove(ql->elements+index, ql->elements+index+1, (ql->num_elements-index-1)*sizeof(void*));
}
--ql->num_elements;
if (ql->num_elements==0) {
*qlp = ql->next;
free(ql);
} else if (ql->next && ql->num_elements<QL_LIMIT) {
quicklist * qn = ql->next;
if (ql->num_elements+qn->num_elements>QL_MAXSIZE) {
memcpy(ql->elements+ql->num_elements, qn->elements, sizeof(void*));
--qn->num_elements;
++ql->num_elements;
memmove(qn->elements, qn->elements+1, qn->num_elements*sizeof(void*));
} else {
memcpy(ql->elements+ql->num_elements, qn->elements, qn->num_elements*sizeof(void*));
ql->num_elements += qn->num_elements;
ql->next = qn->next;
free(qn);
}
}
}
return 0;
}
int ql_insert(quicklist ** qlp, int index, void * data) {
quicklist * ql = *qlp;
if (ql) {
if (index>=QL_MAXSIZE) {
return ql_insert(&ql->next, index-ql->num_elements, data);
} else if (ql->num_elements<QL_MAXSIZE) {
memmove(ql->elements+index+1, ql->elements+index, (ql->num_elements-index)*sizeof(void*));
ql->elements[index]=data;
++ql->num_elements;
} else {
quicklist * qn = malloc(sizeof(quicklist));
qn->next = ql->next;
ql->next = qn;
qn->num_elements = QL_LIMIT;
ql->num_elements -= QL_LIMIT;
memcpy(qn->elements, ql->elements+ql->num_elements-QL_LIMIT, QL_LIMIT*sizeof(void*));
if (index<=ql->num_elements) {
return ql_insert(qlp, index, data);
} else {
return ql_insert(&ql->next, index-ql->num_elements, data);
}
}
} else if (index==0) {
ql_push(qlp, data);
} else {
return EINVAL;
}
return 0;
}

35
src/util/quicklist.h Normal file
View File

@ -0,0 +1,35 @@
/*
Copyright (c) 2010-2011, Enno Rehling <enno@eressea.de>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
**/
#ifndef _QUICKLIST_H
#define _QUICKLIST_H
#ifdef __cplusplus
extern "C" {
#endif
/* see http://en.wikipedia.org/wiki/Unrolled_linked_list */
struct quicklist;
void * ql_get(struct quicklist * ql, int index);
int ql_length(const struct quicklist * ql);
void ql_push(struct quicklist ** qlp, void * data);
int ql_delete(struct quicklist ** qlp, int index);
int ql_insert(struct quicklist ** qlp, int index, void * data);
#ifdef __cplusplus
}
#endif
#endif