Commit c1daa044 authored by Rusty Russell's avatar Rusty Russell

From: Joseph Adams <joeyadams3.14159@gmail.com>

I have given my array module a makeover (see attached
array-0.1.tar.bz2 ).  Major changes are:

* All the macros have been renamed to flat array_* names.  Instead of
Array, AInit, AAppend, etc., it is now array, array_init,
array_append, etc..  This will obviously break any applications
already using the array module (if any); 'renames' is the list of sed
commands I used to make the name changes.
* array (by default) now uses talloc functions instead of regular
malloc/realloc/free.
* All of the array macros have tests now.
parent 09e4858b
#include <string.h> #include <string.h>
#include "config.h" #include "config.h"
#include "ccan/array/array.h"
/** /**
* array - A collection of macros for generic dynamic array management. * array - A collection of macros for generic dynamic array management.
* *
* The array module provides generic dynamic array functions via macros. It * The array module provides generic dynamic array functions via macros. It
* removes the tedium of managing realloc'd arrays with pointer, size, and * removes the tedium of managing realloc'd arrays with pointer, size, and
* allocated size. It also fits into structures quite well. * allocated size. It also fits into structures quite well. It uses the
* talloc library to allocate the memory.
* *
* NOTE: The API is currently unstable. It will likely change in the near future. * NOTE: The API should be fairly stable now, but do expect small changes
* over time.
* *
* Example: * Example:
* #include <ccan/array/array.h> * #include <ccan/array/array.h>
* #include <stdio.h> * #include <stdio.h>
* *
* int main(void) { * int main(void) {
* Array(int) numbers = NewArray(); * array(int) numbers = array_new(NULL);
* char buffer[32]; * char buffer[32];
* int add; * int add;
* *
* for (;;) { * for (;;) {
* AFor(i, numbers, printf("%d ", *i)) * array_for(i, numbers, printf("%d ", *i))
* if (numbers.size) puts(""); * if (numbers.size) puts("");
* *
* printf("array> "); * printf("array> ");
...@@ -29,14 +33,16 @@ ...@@ -29,14 +33,16 @@
* break; * break;
* add = atoi(buffer); * add = atoi(buffer);
* *
* AAppend(numbers, add); * array_append(numbers, add);
* } * }
* *
* AFree(numbers); * array_free(numbers);
* *
* return 0; * return 0;
* } * }
* *
* Author: Joey Adams
* Version: 0.1
* Licence: BSD * Licence: BSD
*/ */
int main(int argc, char *argv[]) int main(int argc, char *argv[])
...@@ -45,7 +51,11 @@ int main(int argc, char *argv[]) ...@@ -45,7 +51,11 @@ int main(int argc, char *argv[])
return 1; return 1;
if (strcmp(argv[1], "depends") == 0) if (strcmp(argv[1], "depends") == 0)
#ifndef ARRAY_USE_TALLOC
/* Nothing. */ /* Nothing. */
#else
printf("ccan/talloc\n");
#endif
return 0; return 0;
return 1; return 1;
......
#include "array.h"
#include <stdarg.h>
int array_alias_helper(const void *a, const void *b) {
(void)a, (void)b;
return 0;
}
//grows the allocated size to accomodate the size
void array_resize_helper(array_char *a, size_t itemSize) {
a->alloc = (a->size+63)&~63;
#ifndef ARRAY_USE_TALLOC
a->item = realloc(a->item, a->alloc*itemSize);
#else
a->item = talloc_realloc_size(NULL, a->item, a->alloc*itemSize +1);
#endif
}
void array_resize0_helper(array_char *a, size_t itemSize, size_t newSize) {
size_t oldSize = a->size;
a->size = newSize;
if (newSize > oldSize) {
if (newSize > a->alloc)
array_resize_helper(a, itemSize);
memset(a->item + oldSize*itemSize, 0, (newSize-oldSize)*itemSize);
}
}
void array_insert_items_helper(array_char *a, size_t itemSize, size_t pos, const void *items, size_t count, size_t tailSize) {
size_t oldSize = a->size;
size_t newSize = (a->size += count+tailSize);
if (newSize > a->alloc)
array_resize_helper(a, itemSize);
{
char *target = a->item + pos*itemSize;
count *= itemSize;
memmove(target+count, target, (oldSize-pos)*itemSize);
memcpy(target, items, count);
}
}
This diff is collapsed.
s/NewArray/array_new/g
s/ASetAllocSize/array_realloc/g
s/ArrayChar/array_char/g
s/Array/array/g
s/ARof/array_rof/g
s/AResize0_helper/array_resize0_helper/g
s/AResize_helper/array_resize_helper/g
s/AResize/array_resize/g
s/APush/array_push/g
s/APrependString/array_prepend_string/g
s/APrepends/array_prepends/g
s/APrependLit/array_prepend_lit/g
s/APrependItems/array_prepend_items/g
s/APrepend/array_prepend/g
s/APopS/array_pop/g
s/APop/array_pop_nocheck/g
s/AMakeRoom/array_make_room/g
s/allocSize/alloc/g
s/AInsertItems_helper/array_insert_items_helper/g
s/AInsertItems/array_insert_items/g
s/AInit/array_init/g
s/AGrowAllocSize/array_growalloc/g
s/AFromString/array_from_string/g
s/AFromLit/array_from_lit/g
s/AFromItems/array_from_items/g
s/AFromC/array_from_c/g
s/AFree/array_free/g
s/AFor/array_for/g
s/AAppendString/array_append_string/g
s/AAppends/array_appends/g
s/AAppendLit/array_append_lit/g
s/AAppendItems/array_append_items/g
s/AAppend/array_append/g
s/Aalias_helper/array_alias_helper/g
s/Aalias/array_alias/g
long lotsOfNumbers[] = { const unsigned long lotsOfNumbers[] = {
0x3BC1544A, 0xDED23357, 0xC7CA2233, 0x642EB9E8, 0x3BC1544A, 0xDED23357, 0xC7CA2233, 0x642EB9E8,
0x79AF03EF, 0x2BA52B1B, 0xA1D838D1, 0x3D658883, 0x79AF03EF, 0x2BA52B1B, 0xA1D838D1, 0x3D658883,
0xD8559EA3, 0x47DF11FE, 0x5A6F486E, 0x0E522BFD, 0xD8559EA3, 0x47DF11FE, 0x5A6F486E, 0x0E522BFD,
......
This diff is collapsed.
#include <stdio.h> #include <stdio.h>
#include <tap/tap.h> #include <tap/tap.h>
#include "array/array.h" #include "array/array.h"
#include "array/array.c"
#define countof(array...) (sizeof(array)/sizeof(*(array))) #define countof(array...) (sizeof(array)/sizeof(*(array)))
#include "lotsOfNumbers.h" #include "lotsOfNumbers.h"
#include "lotsOfStrings.h"
struct {
char *stringsF, *stringsB;
//items of lotsOfStrings glued together
size_t stringsSize; //total strlen of all strings combined
} amalgams;
static void generateAmalgams(void);
static void freeAmalgams(void);
static int isZeros(void *ptr, size_t size);
static void memtile(void *dest, size_t destWidth, const void *src, size_t srcWidth);
#if 0
#define testing(...) printf("Testing %s...\n", #__VA_ARGS__)
#define trace(...) do {printf(__VA_ARGS__); puts("");} while(0)
#else
#define testing(...) do {} while(0)
#define trace(...) do {} while(0)
#endif
#include "testLits.h"
int main(void) { int main(void) {
Array(long) array = NewArray(); #ifndef ARRAY_USE_TALLOC
array(long) arr = array_new();
array_char str = array_new();
#define reset(array) do {array_free(array); array_init(array);} while(0)
#else
array(long) arr = array_new(NULL);
array_char str = array_new(NULL);
#define reset(array) do {array_free(array); array_init(array, NULL);} while(0)
#endif
size_t i; size_t i;
plan_tests(3); trace("Generating amalgams (internal)");
generateAmalgams();
plan_tests(41);
testLits();
testing(array_push);
{ {
for (i=0; i<countof(lotsOfNumbers); i++) for (i=0; i<countof(lotsOfNumbers); i++)
AAppend(array, lotsOfNumbers[i]); array_push(arr, lotsOfNumbers[i]);
ok1(array.size == countof(lotsOfNumbers)); ok1(arr.size == countof(lotsOfNumbers));
ok1(array.allocSize >= array.size); ok1(arr.alloc >= arr.size);
ok1(!memcmp(array.item, lotsOfNumbers, sizeof(lotsOfNumbers))); ok1(!memcmp(arr.item, lotsOfNumbers, sizeof(lotsOfNumbers)));
}
reset(arr);
testing(array_prepend, array_pop_nocheck);
{
for (i=countof(lotsOfNumbers); i;)
array_prepend(arr, lotsOfNumbers[--i]);
ok1(arr.size == countof(lotsOfNumbers));
ok1(arr.alloc >= arr.size);
ok1(!memcmp(arr.item, lotsOfNumbers, sizeof(lotsOfNumbers)));
for (i=countof(lotsOfNumbers); i;) {
if (array_pop_nocheck(arr) != (long)lotsOfNumbers[--i]) {
i++;
break;
}
}
ok1(i==0);
ok1(arr.size == 0);
}
reset(arr);
testing(array_from_c, array_for, array_rof);
{
size_t i_correct, r_correct;
array_from_c(arr, lotsOfNumbers);
ok1(arr.size == countof(lotsOfNumbers));
ok1(arr.alloc >= arr.size);
ok1(!memcmp(arr.item, lotsOfNumbers, sizeof(lotsOfNumbers)));
i_correct = 0;
r_correct = countof(lotsOfNumbers)-1;
array_for(i, arr,
if (i_correct != _i)
break;
if (r_correct != _r)
break;
if (i != arr.item+_i)
break;
if (*i != (long)lotsOfNumbers[_i])
break;
i_correct++;
r_correct--;
);
ok1(i_correct == countof(lotsOfNumbers));
i_correct = countof(lotsOfNumbers)-1;
r_correct = 0;
array_rof(i, arr,
if (i_correct != _i)
break;
if (r_correct != _r)
break;
if (i != arr.item+_i)
break;
if (*i != (long)lotsOfNumbers[_i])
break;
i_correct--;
r_correct++;
);
ok1(r_correct == countof(lotsOfNumbers));
}
reset(arr);
testing(array_append_string);
{
for (i=0; i<countof(lotsOfStrings); i++)
array_append_string(str, lotsOfStrings[i]);
ok1(str.size == amalgams.stringsSize);
ok1(str.alloc > str.size);
ok1(str.item[str.size] == 0);
ok1(!strcmp(str.item, amalgams.stringsF));
}
reset(str);
testing(array_prepend_string);
{
for (i=0; i<countof(lotsOfStrings); i++)
array_prepend_string(str, lotsOfStrings[i]);
ok1(str.size == amalgams.stringsSize);
ok1(str.alloc > str.size);
ok1(str.item[str.size] == 0);
ok1(!strcmp(str.item, amalgams.stringsB));
}
reset(str);
testing(array_from_string);
{
for (i=0; i<countof(lotsOfStrings); i++) {
array_from_string(str, lotsOfStrings[i]);
if (str.size != strlen(lotsOfStrings[i]))
break;
if (str.alloc < strlen(lotsOfStrings[i])+1)
break;
if (strcmp(str.item, lotsOfStrings[i]))
break;
}
ok1(i == countof(lotsOfStrings));
}
reset(str);
testing(array_resize0);
{
size_t prevSize=0, size;
for (i=0; i<countof(lotsOfNumbers); i++, prevSize=size) {
size = lotsOfNumbers[i] & 0xFFFF;
array_resize0(arr, size);
if (arr.size != size)
break;
if (arr.alloc < size)
break;
if (size>prevSize) {
if (!isZeros(arr.item+prevSize, (size-prevSize)*sizeof(*arr.item)))
break;
}
//fill the array with lotsOfNumbers garbage
memtile(arr.item, arr.size*sizeof(*arr.item), lotsOfNumbers, sizeof(lotsOfNumbers));
}
ok1(i==countof(lotsOfNumbers));
}
reset(arr);
testing(array_realloc);
{
size_t s,a;
for (i=0; i<countof(lotsOfNumbers); i++) {
arr.size = (s = lotsOfNumbers[i] >> 16);
//give size a nonsense value to make sure array_realloc doesn't care about it
a = amalgams.stringsSize/sizeof(*arr.item)+2;
array_realloc(arr, a = lotsOfNumbers[i] % ((amalgams.stringsSize/sizeof(*arr.item))+1));
if (a*sizeof(*arr.item) > amalgams.stringsSize)
break;
if (arr.alloc != a)
break;
if (arr.size != s)
break;
memtile(arr.item, a*sizeof(*arr.item), amalgams.stringsF, a*sizeof(*arr.item));
if (memcmp(arr.item, amalgams.stringsF, a*sizeof(*arr.item)))
break;
}
ok1(i==countof(lotsOfNumbers));
} }
AFree(array); reset(arr);
AInit(array);
testing(array_growalloc);
{
size_t prevA, s, a;
for (i=0; i<countof(lotsOfNumbers); i++) {
arr.size = (s = lotsOfNumbers[i] >> 16);
//give size a nonsense value to make sure array_growalloc doesn't care about it
a = amalgams.stringsSize/sizeof(*arr.item)+2;
prevA = arr.alloc;
array_growalloc(arr, a = lotsOfNumbers[i] % ((amalgams.stringsSize/sizeof(*arr.item))+1));
if (a*sizeof(*arr.item) > amalgams.stringsSize)
break;
if (arr.alloc < a)
break;
if (arr.alloc < prevA)
break;
if (arr.size != s)
break;
memtile(arr.item, a*sizeof(*arr.item), amalgams.stringsF, a*sizeof(*arr.item));
if (memcmp(arr.item, amalgams.stringsF, a*sizeof(*arr.item)))
break;
//clear the array every now and then
if (!(lotsOfNumbers[i] & 15)) {
reset(arr);
}
}
ok1(i==countof(lotsOfNumbers));
}
reset(arr);
testing(array_make_room);
{
for (i=0; i<countof(lotsOfStrings); i++) {
char *dest = array_make_room(str, strlen(lotsOfStrings[i]));
if (str.alloc < str.size+strlen(lotsOfStrings[i]))
break;
if (dest != str.item+str.size)
break;
memcpy(dest, lotsOfStrings[i], strlen(lotsOfStrings[i]));
str.size += strlen(lotsOfStrings[i]);
}
ok1(i==countof(lotsOfStrings));
ok1(str.size == amalgams.stringsSize);
array_append(str, 0);
ok1(!strcmp(str.item, amalgams.stringsF));
}
reset(str);
testing(array_appends, array_prepends, array_pop);
{
#ifndef ARRAY_USE_TALLOC
array(const char*) array = array_new();
#else
array(const char*) array = array_new(NULL);
#endif
const char *n[9] = {"zero", "one", "two", "three", "four", "five", "six", "seven", "eight"};
array_appends(array, n[5], n[6], n[7], n[8]);
ok1(array.size==4 && array.alloc>=4);
array_prepends(array, n[0], n[1], n[2], n[3], n[4]);
ok1(array.size==9 && array.alloc>=9);
ok1(array.item[0]==n[0] &&
array.item[1]==n[1] &&
array.item[2]==n[2] &&
array.item[3]==n[3] &&
array.item[4]==n[4] &&
array.item[5]==n[5] &&
array.item[6]==n[6] &&
array.item[7]==n[7] &&
array.item[8]==n[8]);
ok1(array_pop(array)==n[8] &&
array_pop(array)==n[7] &&
array_pop(array)==n[6] &&
array_pop(array)==n[5] &&
array_pop(array)==n[4] &&
array_pop(array)==n[3] &&
array_pop(array)==n[2] &&
array_pop(array)==n[1] &&
array_pop(array)==n[0]);
ok1(array.size==0);
ok1(array_pop(array)==NULL && array_pop(array)==NULL && array_pop(array)==NULL);
array_free(array);
}
trace("Freeing amalgams (internal)");
freeAmalgams();
return 0; return 0;
} }
static void generateAmalgams(void) {
size_t i;
size_t lotsOfStringsLen = 0;
const char *src;
char *p;
for (i=0; i<countof(lotsOfStrings); i++)
lotsOfStringsLen += strlen(lotsOfStrings[i]);
amalgams.stringsSize = lotsOfStringsLen;
amalgams.stringsF = malloc(lotsOfStringsLen+1);
amalgams.stringsB = malloc(lotsOfStringsLen+1);
for (i=0,p=amalgams.stringsF; i<countof(lotsOfStrings); i++) {
size_t len = strlen(src=lotsOfStrings[i]);
memcpy(p, src, len);
p += len;
}
*p = 0;
ok1(p-amalgams.stringsF == (long)lotsOfStringsLen);
ok1(strlen(amalgams.stringsF) == lotsOfStringsLen);
for (i=countof(lotsOfStrings),p=amalgams.stringsB; i--;) {
size_t len = strlen(src=lotsOfStrings[i]);
memcpy(p, src, len);
p += len;
}
*p = 0;
ok1(p-amalgams.stringsB == (long)lotsOfStringsLen);
ok1(strlen(amalgams.stringsB) == lotsOfStringsLen);
}
static void freeAmalgams(void) {
free(amalgams.stringsF);
free(amalgams.stringsB);
}
static int isZeros(void *ptr, size_t size) {
unsigned char *pc = ptr;
size_t *pl;
if (size>8) {
//test one byte at a time until we have an aligned size_t pointer
while ((size_t)pc & (sizeof(size_t)-1))
if (*pc++)
return 0;
pl = (size_t*)pc;
size -= pc-(unsigned char*)ptr;
while (size >= sizeof(size_t)) {
size -= sizeof(size_t);
if (*pl++)
return 0;
}
pc = (unsigned char*)pl;
}
while (size--)
if (*pc++)
return 0;
return 1;
}
static void memtile(void *dest, size_t destWidth, const void *src, size_t srcWidth) {
char *d = dest;
while (destWidth > srcWidth) {
destWidth -= srcWidth;
memcpy(d, src, srcWidth);
d += srcWidth;
}
memcpy(d, src, destWidth);
}
This diff is collapsed.
static int testarray_from_lit(void);
static int testarray_append_lit(void);
static int testarray_prepend_lit(void);
static void testLits(void) {
testing(array_from_lit);
ok1(testarray_from_lit());
testing(testarray_append_lit);
ok1(testarray_append_lit());
testing(testarray_prepend_lit);
ok1(testarray_prepend_lit());
}
static int testarray_from_lit(void) {
#ifndef ARRAY_USE_TALLOC
array_char a = array_new();
#else
array_char a = array_new(NULL);
#endif
size_t testsPassed = 0;
size_t len = 0;
@forEachRandomString
/* Test @i */
array_from_lit(a, @str);
len = strlen(@str);
if (len != sizeof(@str)-1)
goto end;
if (a.size != len)
goto end;
if (a.size > a.alloc)
goto end;
if (strcmp(a.item, @str))
goto end;
array_free(a);
#ifndef ARRAY_USE_TALLOC
array_init(a);
#else
array_init(a, NULL);
#endif
testsPassed++;
@end
end:
array_free(a);
return testsPassed == @amount;
}
typedef struct {
char *item;
size_t size;
} testLits_string;
static int testarray_append_lit(void) {
#ifndef ARRAY_USE_TALLOC
array_char a = array_new();
array(testLits_string) strings = array_new();
#else
array_char a = array_new(NULL);
array(testLits_string) strings = array_new(NULL);
#endif
size_t testsPassed = 0;
size_t oldSize;
testLits_string append;
size_t offs = 0;
@forEachRandomString
/* Test @i */
append.size = sizeof(@str)-1;
oldSize = a.size;
array_append_lit(a, @str);
if (a.size != oldSize+append.size)
goto end;
if (a.size > a.alloc)
goto end;
if (a.item[a.size])
goto end;
if (memcmp(a.item+oldSize, @str, a.size-oldSize))
goto end;
append.item = strdup(@str);
array_append(strings, append);
testsPassed++;
@end
if (strings.size != @amount)
goto end;
array_for(i, strings,
if (a.size-offs < i->size)
goto end;
if (memcmp(a.item+offs, i->item, i->size))
goto end;
offs += i->size;
);
if (offs != a.size)
goto end;
if (a.item[offs])
goto end;
testsPassed++;
end:
array_free(a);
array_for(i, strings, free(i->item));
array_free(strings);
return testsPassed == @amount+1;
}
static int testarray_prepend_lit(void) {
#ifndef ARRAY_USE_TALLOC
array_char a = array_new();
array(testLits_string) strings = array_new();
#else
array_char a = array_new(NULL);
array(testLits_string) strings = array_new(NULL);
#endif
size_t testsPassed = 0;
size_t oldSize;
testLits_string append;
size_t offs;
@forEachRandomString
/* Test @i */
append.size = sizeof(@str)-1;
oldSize = a.size;
array_prepend_lit(a, @str);
if (a.size != oldSize+append.size)
goto end;
if (a.size > a.alloc)
goto end;
if (a.item[a.size])
goto end;
if (memcmp(a.item, @str, a.size-oldSize))
goto end;
append.item = strdup(@str);
array_append(strings, append);
testsPassed++;
@end
offs = a.size;
if (a.item[offs])
goto end;
if (strings.size != @amount)
goto end;
array_for(i, strings,
if (offs < i->size)
goto end;
offs -= i->size;
if (memcmp(a.item+offs, i->item, i->size))
goto end;
);
if (offs)
goto end;
testsPassed++;
end:
array_free(a);
array_for(i, strings, free(i->item));
array_free(strings);
return testsPassed == @amount+1;
}
#!/usr/bin/perl
use strict;
use warnings;
my $amount = 10;
my $maxLen = 509;
srand(0);
my $templateFile = 'testLits.h.template';
my $outFile = 'testLits.h';
open(TF, $templateFile);
open(OUT, '>'.$outFile);
select OUT;
my $inLoop = 0;
my $loopText = '';
foreach my $line (<TF>) {
$line =~ s/\@amount/$amount/g;
if (!$inLoop) {
if ($line =~ /\@forEachRandomString/) {
$inLoop = 1;
next;
}
print $line;
} elsif ($inLoop == 1) {
if ($line =~ /\@end/) {
$inLoop = 0;
#handle $loopText
for (my $i=0; $i<$amount; $i++) {
my $str = randomCString($maxLen);
my $lt = $loopText;
$lt =~ s/\@i/$i/g;
$lt =~ s/\@str/\"$str\"/g;
print "$lt\n";
}
$loopText = '';
next;
}
$loopText .= $line;
}
}
close(OUT);
close(TF);
#argument: maxLen
sub randomCString {
my $len = int(rand($_[0]+1));
my $lastWasHex = 0;
my $str = '';
for (my $i=0; $i<$len; $i++) {
my $cn = int(rand(255)) + 1;
my $c = chr($cn);
if ($lastWasHex && ($c =~ /[0-9A-Fa-f]/)) {
$lastWasHex = 1;
$str .= sprintf("\\x%02X", $cn);
} elsif ($c =~ /[\t\n\013\f\r]/) {
$lastWasHex = 0;
$c =~ tr/\t\n\013\f\r/tnvfr/;
$str .= '\\'.$c;
} elsif ($cn<32 || $cn>126) {
$lastWasHex = 1;
$str .= sprintf("\\x%02X", $cn);
} else {
$lastWasHex = 0;
if ($c =~ /[\"\\]/) {
$str .= '\\'.$c;
} else {
$str .= $c;
}
}
}
return $str;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment