
18 changed files with 262 additions and 39 deletions
-
1CHANGES
-
4GNUmakefile
-
7array/array_allocate.c
-
7array/array_get.c
-
7array/array_truncate.c
-
31array/iarray_allocate.3
-
47array/iarray_allocate.c
-
16array/iarray_free.3
-
9array/iarray_free.c
-
25array/iarray_get.3
-
12array/iarray_get.c
-
19array/iarray_init.3
-
16array/iarray_init.c
-
29iarray.h
-
13likely.h
-
29t.c
-
20test/buffer_tosa.c
-
9test/fmt_strm_alloca.c
@ -0,0 +1,31 @@ |
|||
.TH iarray_allocate 3 |
|||
.SH NAME |
|||
iarray_allocate \- get pointer to nth element in iarray |
|||
.SH SYNTAX |
|||
.B #include <iarray.h> |
|||
|
|||
void* \fBiarray_allocate\fP(iarray* \fIx\fR, size_t \fIpos\fR); |
|||
|
|||
iarray \fIx\fR; |
|||
size_t \fIpos\fR; |
|||
\fIt\fR* p = iarray_allocate(&\fIx\fR,\fIpos\fR); |
|||
|
|||
.SH DESCRIPTION |
|||
iarray_allocate is similar to iarray_get, but if the requested element |
|||
is not in the array, the array will be resized. If the resize fails, |
|||
iarray_allocate returns NULL and leaves the array untouched. |
|||
|
|||
This function is safe to use in environments with multiple threads, but |
|||
it can block for indeterminate time if other threads are reallocating |
|||
the array at the same time. |
|||
|
|||
Note that it is safe to use iarray_allocate where you would otherwise |
|||
use iarray_get. The only reason to use iarray_get over iarray_allocate |
|||
would be optimization. |
|||
|
|||
.SH "RETURN VALUE" |
|||
Return a pointer to the requested element. If there was a memory |
|||
allocation failure, returns NULL. |
|||
|
|||
.SH "SEE ALSO" |
|||
iarray_init(3), iarray_get(3), iarray_free(3) |
@ -0,0 +1,47 @@ |
|||
#include "likely.h" |
|||
#include <stdlib.h> |
|||
#include "iarray.h" |
|||
|
|||
void* iarray_allocate(iarray* ia,size_t pos) { |
|||
size_t y; |
|||
/* first the easy case without locking */ |
|||
if (__likely((y=pos/ia->elemperpage) < ia->pagefence && ia->pages[y])) |
|||
return ia->pages[y]+(pos%ia->elemperpage)*ia->elemsize; |
|||
/* the case where ia->pages == NULL is implicit */ |
|||
|
|||
pthread_mutex_lock(&ia->m); |
|||
|
|||
if (__unlikely(y >= ia->pagefence)) { |
|||
char** np; |
|||
/* The data structure is an array of pointer to pages. |
|||
* Each page holds at least one element of the array. |
|||
* Here we realloc the array of pointers. Each element in this |
|||
* array is only 4 or 8 bytes, so we should allocate a few more than |
|||
* we need to cut down on future reallocs. */ |
|||
size_t z=(y+512)&-512; /* round up to multiple of 512 */ |
|||
/* It may seem as if there can be no integer overflow in the |
|||
* indirect index, because then the array would not fit into the |
|||
* address space in the first place, but remember that this is a |
|||
* sparse array. Someone might just pass in an unreasonable large |
|||
* index and have large elements, too */ |
|||
if (z==0) goto unlockandfail; /* integer overflow */ |
|||
np=realloc(ia->pages,z*ia->bytesperpage); |
|||
if (!np) goto unlockandfail; |
|||
ia->pagefence=z; |
|||
ia->pages=np; |
|||
} |
|||
|
|||
/* at this point we know the slot exists */ |
|||
/* through a race between the early-out above and the |
|||
* pthread_mutex_lock, the page pointer to it could be non-NULL, |
|||
* however */ |
|||
if (__unlikely(ia->pages[y]==0 && (ia->pages[y]=malloc(ia->bytesperpage))==0)) { |
|||
unlockandfail: |
|||
pthread_mutex_unlock(&ia->m); |
|||
return 0; |
|||
} |
|||
|
|||
pthread_mutex_unlock(&ia->m); |
|||
|
|||
return ia->pages[y] + (pos%ia->elemperpage)*ia->elemsize; |
|||
} |
@ -0,0 +1,16 @@ |
|||
.TH iarray_free 3 |
|||
.SH NAME |
|||
iarray_free \- free iarray data structure |
|||
.SH SYNTAX |
|||
.B #include <iarray.h> |
|||
|
|||
void \fBiarray_free\fP(iarray* \fIx\fR); |
|||
|
|||
.SH DESCRIPTION |
|||
iarray_free frees the iarray and all elements in it. |
|||
|
|||
Using the array during or after iarray_free results in undefined |
|||
behavior. |
|||
|
|||
.SH "SEE ALSO" |
|||
iarray_allocate(3), iarray_get(3), iarray_allocate(3) |
@ -0,0 +1,9 @@ |
|||
#include <stdlib.h> |
|||
#include "iarray.h" |
|||
|
|||
void iarray_free(iarray* ia) { |
|||
size_t i; |
|||
for (i=0; i<ia->pagefence; ++i) |
|||
if (ia->pages[i]) free(ia->pages[i]); |
|||
free(ia->pages); |
|||
} |
@ -0,0 +1,25 @@ |
|||
.TH iarray_get 3 |
|||
.SH NAME |
|||
iarray_get \- get pointer to nth element in iarray |
|||
.SH SYNTAX |
|||
.B #include <iarray.h> |
|||
|
|||
void* \fBiarray_get\fP(iarray* \fIx\fR, size_t \fIpos\fR); |
|||
|
|||
iarray \fIx\fR; |
|||
size_t \fIpos\fR; |
|||
\fIt\fR* p = iarray_get(&\fIx\fR,\fIpos\fR); |
|||
|
|||
.SH DESCRIPTION |
|||
iarray_get is similar to iarray_allocate, but it only works if the |
|||
element has previously been allocated. If the element in the iarray |
|||
is not there, this function will fail instead of manipulating the |
|||
iarray. This also guarantees that there will be no locks, so this |
|||
function returns in a deterministic time. |
|||
|
|||
.SH "RETURN VALUE" |
|||
Return a pointer to the requested element. If there is no such element |
|||
in the array, returns NULL. |
|||
|
|||
.SH "SEE ALSO" |
|||
iarray_init(3), iarray_allocate(3), iarray_free(3) |
@ -0,0 +1,12 @@ |
|||
#include "iarray.h" |
|||
|
|||
void* iarray_get(iarray* ia,size_t pos) { |
|||
char* x; |
|||
size_t y; |
|||
if (!ia->pages) return 0; |
|||
y=pos/ia->elemperpage; |
|||
if (y>=ia->pagefence) return 0; |
|||
x=ia->pages[y]; |
|||
if (!x) return 0; |
|||
return x+(pos%ia->elemperpage)*ia->elemsize; |
|||
} |
@ -0,0 +1,19 @@ |
|||
.TH iarray_init 3 |
|||
.SH NAME |
|||
iarray_init \- initialize iarray data structure |
|||
.SH SYNTAX |
|||
.B #include <iarray.h> |
|||
|
|||
void \fBiarray_init\fP(array* \fIx\fR, size_t \fIelemsize\fR); |
|||
|
|||
iarray \fIx\fR; |
|||
int64 \fIpos\fR; |
|||
\fIt\fR* p = iarray_init(&\fIx\fR,sizeof(\fIelement\fR)); |
|||
|
|||
.SH DESCRIPTION |
|||
iarray_init initializes an iarray so that it can hold elements of size |
|||
\fIelemsize\fR. iarray_init does not actually allocate anything, so it |
|||
can not fail. |
|||
|
|||
.SH "SEE ALSO" |
|||
iarray_allocate(3), iarray_get(3), iarray_free(3) |
@ -0,0 +1,16 @@ |
|||
#include "iarray.h" |
|||
|
|||
void iarray_init(iarray* ia,size_t elemsize) { |
|||
ia->elemsize=elemsize; |
|||
ia->pages=0; |
|||
ia->pagefence=0; |
|||
if (elemsize<1024) |
|||
ia->bytesperpage=4096; |
|||
else if (elemsize<8192) |
|||
ia->bytesperpage=65536; |
|||
else |
|||
ia->bytesperpage=elemsize; |
|||
ia->elemperpage=ia->bytesperpage/elemsize; |
|||
pthread_mutex_init(&ia->m,NULL); |
|||
} |
|||
|
@ -0,0 +1,29 @@ |
|||
#ifndef IARRAY_H |
|||
#define IARRAY_H |
|||
|
|||
#include "uint64.h" |
|||
#include <stddef.h> |
|||
#include <pthread.h> |
|||
|
|||
/* this is an indirect array; it only reallocs the indirect index, not |
|||
* the whole array. The actual data does not move. So there is no need |
|||
* to lock the array for read accesses. */ |
|||
|
|||
typedef struct { |
|||
char** pages; |
|||
size_t elemsize,pagefence,elemperpage,bytesperpage; |
|||
/* pagefence is the number of pages + 1, |
|||
* i.e. the first out of bounds index in "pages" */ |
|||
pthread_mutex_t m; |
|||
} iarray; |
|||
|
|||
void iarray_init(iarray* ia,size_t elemsize); |
|||
void* iarray_get(iarray* ia,size_t pos); |
|||
void* iarray_allocate(iarray* ia,size_t pos); |
|||
|
|||
/* WARNING: do not use the array during or after iarray_free, make sure |
|||
* no threads are potentially doing anything with the iarray while it is |
|||
* being freed! */ |
|||
void iarray_free(iarray* ia); |
|||
|
|||
#endif |
@ -0,0 +1,13 @@ |
|||
#ifdef __dietlibc__ |
|||
#include <sys/cdefs.h> |
|||
#else |
|||
|
|||
#if __GNUC__ < 3 |
|||
#define __expect(foo,bar) (foo) |
|||
#else |
|||
#define __expect(foo,bar) __builtin_expect((long)(foo),bar) |
|||
#endif |
|||
#define __likely(foo) __expect((foo),1) |
|||
#define __unlikely(foo) __expect((foo),0) |
|||
|
|||
#endif |
@ -0,0 +1,20 @@ |
|||
#include "byte.h" |
|||
#include "stralloc.h" |
|||
#include "buffer.h" |
|||
#include <assert.h> |
|||
|
|||
int main() { |
|||
stralloc a; |
|||
buffer b; |
|||
int i; |
|||
stralloc_init(&a); |
|||
buffer_tosa(&b,&a); |
|||
|
|||
for (i=0; i<100; ++i) |
|||
buffer_puts(&b,"foo bar baz!\n"); |
|||
buffer_flush(&b); |
|||
assert(a.len==100*sizeof("foo bar baz!")); |
|||
for (i=0; i<100; ++i) |
|||
assert(byte_equal(a.s+i*sizeof("foo bar baz!"),sizeof("foo bar baz!"),"foo bar baz!\n")); |
|||
return 0; |
|||
} |
@ -0,0 +1,9 @@ |
|||
#include <stdlib.h> |
|||
#include "fmt.h" |
|||
#include "byte.h" |
|||
#include <assert.h> |
|||
|
|||
int main() { |
|||
char* c=fmt_strm_alloca("foo"," bar","\n"); |
|||
assert(byte_equal(c,sizeof("foo bar\n"),"foo bar\n")); |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue