Merge branch 'dev'

This commit is contained in:
Nils O. Selåsdal
2013-12-05 17:45:01 +01:00
10 changed files with 866 additions and 15 deletions
+162
View File
@@ -0,0 +1,162 @@
#ifndef UC_DSTR_H_
#define UC_DSTR_H_
#include <stddef.h>
#include <stdarg.h>
#ifdef __cplusplus
extern "C" {
#endif
/** A managed C-string, using dynalically allocated memory for the string.
*
* The .str member might not always be nul terminated,
* Normally, use uc_dstr_str() to retreive the managed string
* instead of accessing ->str directly.
*
* Normally, let the DSTR manage the nul terminator as manually adding
* a nul byte and potintially adding more data to the DStr would append
* it after that nul terminator.
*/
struct DStr {
/** Length of the managed string.*/
size_t len;
//internal fields:
size_t allocated;
char *str;
};
#define UC_DSTR_STATIC_INIT {0, 0, NULL}
/** Initialize a DStr.
* Note that str->str will be NULL after initialization.
*
*/
void uc_dstr_init(struct DStr *str);
/** Destroy/free the string.
* (Frees str->str, not str itself)
*/
void uc_dstr_destroy(struct DStr *str);
/** Copy a DStr
*
* @param dest destination string to copy to, must not contain an existing string
* @param src DStr to copy
*
* @return 0 if success, != 0 if allocation fails
*/
int uc_dstr_copy(struct DStr *dest, const struct DStr *src);
/**
* @return the available/unused tail bytes in the string.
*/
size_t uc_dstr_available(const struct DStr *str);
/** Ensure the DStr have room for least 'len' bytes,
* allocating room if needed.
*
* This includes the length of the existing string,
* to ensure e.g an additional 10 bytes can be appended,
* one would do uc_dstr_ensure(str, str->len + 10)
*
* @return 0 on success (!= 0 if an allocation fail)
*/
int uc_dstr_ensure(struct DStr *str, size_t total);
/** Reset the DStr, setting its length to 0
*/
void uc_dstr_reset(struct DStr *str);
/** nul terminate the DStr */
void uc_dstr_terminate(struct DStr *str);
/** Retreive the managed string, the returned string
* is always nul terminated. The DStr will still be managing
* the returned char *.
*/
char *uc_dstr_str(struct DStr *str);
/** Reserve len bytes for appending to the dstr
* you must fill in a string in the 0-len range of
* the returned pointer.
*
* @param len bytes to reseve
* @return poiinter to the start of the data to append
*/
char *uc_dstr_put(struct DStr *str, size_t len);
/** Append a string, filtering out characters.
* e.g. pass in the ctype.h isdigit as the is_x function
* to append only the digits in the supplied string.
*
* @param s string to append
* @param is_x ctype.h compatible function to use as a filter.
* @return number of chars appended
*/
size_t uc_dstr_put_str_filter(struct DStr *str, const char *s, int (*is_x)(int c));
/* Append a string of the give size.
* (The nul terminator is not appended)
*
* @param s string to append
* @param len bytes to append (not including the nul terminator)
* @return 0 on success (!= 0 if an allocation fail)
*/
int uc_dstr_put_str_sz(struct DStr *str, const char *s, size_t len);
/* Append a string.
* (The nul terminator is not appended)
*
* @return 0 on success (!= 0 if an allocation fail)
*/
int uc_dstr_put_str(struct DStr *str, const char *s);
/* Append a single char.
*
* @return 0 on success (!= 0 if an allocation fail)
*/
int uc_dstr_put_char(struct DStr *str, char c);
/* Make the DStr take ownership of the given dynamically allocated string.
* Any existing string in the DStr is freed.
*/
void uc_dstr_own(struct DStr *str, char *s);
/** Release the managed string.
* The caller is now responsible for managing/free'ing the returned string.
* The DStr is considered empty afterwards.
*
* @return The dynamically allocated string that was managed.
*/
char *uc_dstr_steal(struct DStr *str);
/** Swap the A and B DStr */
void uc_str_swap(struct DStr *a, struct DStr *b);
/** Replace all occurences in the DStr
* (This may be used to replace any embedded nul bytes too)
*
* @param f char to find
* @param r char to replace with
*/
size_t uc_dstr_replace(struct DStr *str, char f, char r);
/** Remove leading and trailing spaces in the DStr
* Spaces are the ascii ones: " \t\r\v\t\n"
*/
void uc_dstr_trim(struct DStr *str);
/** Append formatted string (just as sprintf)*/
int uc_dstr_sprintf(struct DStr *str, const char *fmt, ...) __attribute__((format(printf,2,3)));
/** va_list variant */
int uc_dstr_vsprintf(struct DStr *str, const char *fmt, va_list ap_)__attribute__((format(printf,2,0)));
#ifdef __cplusplus
}
#endif
#endif
+30
View File
@@ -0,0 +1,30 @@
#ifndef UC_HEAPSORT_H_
#define UC_HEAPSORT_H_
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
///compare function. Needs only to return < 0 if
//a is less tan b
typedef int (*uc_hs_cmp)(const void *a, const void *b, void *cookie);
//swap function, must swap around element a and b
typedef void (*uc_hs_swp)(void *a, void *b);
/** Sort an array.
* @param base start of array
* @param count number of elements in array
* @param width size of each element
* @param cmp compare function
* @param swap swap function
* @param cookie user pointer passed back to compare function
*/
void uc_heapsort(void *base, size_t count, size_t width,
uc_hs_cmp cmp, uc_hs_swp swap, void *cookie);
#ifdef __cplusplus
}
#endif
#endif
+6 -6
View File
@@ -14,15 +14,15 @@
//MAX of a and b //MAX of a and b
#define UC_MAX(a,b) \ #define UC_MAX(a,b) \
({ __typeof__ (a) _a = (a); \ ({ __typeof__ (a) _amx = (a); \
__typeof__ (b) _b = (b); \ __typeof__ (b) _bmx = (b); \
_a > _b ? _a : _b; }) _amx > _bmx ? _amx : _bmx; })
//min of a and b //min of a and b
#define UC_MIN(a,b) \ #define UC_MIN(a,b) \
({ __typeof__ (a) _a = (a); \ ({ __typeof__ (a) _amn = (a); \
__typeof__ (b) _b = (b); \ __typeof__ (b) _bmn = (b); \
_a < _b ? _a : _b; }) _amn < _bmn ? _amn : _bmn; })
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*a)) #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*a))
+2 -1
View File
@@ -3,6 +3,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdarg.h> #include <stdarg.h>
#include "ucore/buffer.h" #include "ucore/buffer.h"
#include "ucore/utils.h"
GBuf* GBuf*
uc_new_gbuf(size_t initsz) uc_new_gbuf(size_t initsz)
@@ -48,7 +49,7 @@ uc_gbuf_append(GBuf *buf,const void *data,size_t len)
unsigned char *gbuf; unsigned char *gbuf;
if (buf->len - buf->used < len) if (buf->len - buf->used < len)
if (uc_gbuf_grow(buf, len + len/2)) if (uc_gbuf_grow(buf, len + UC_MAX(UC_MIN(8U,len/2),256U)))
return -1; return -1;
gbuf = buf->buf; gbuf = buf->buf;
+281
View File
@@ -0,0 +1,281 @@
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include "ucore/dstr.h"
#include "ucore/utils.h"
void uc_dstr_init(struct DStr *str)
{
str->len = 0;
str->allocated = 0;
str->str = NULL;
}
void uc_dstr_destroy(struct DStr *str)
{
free(str->str);
}
int uc_dstr_copy(struct DStr *dest, const struct DStr *src)
{
char *s;
uc_dstr_init(dest);
if (src->allocated == 0) {
return 0;
}
s = uc_dstr_put(dest, src->len);
if (s == NULL) {
return -1;
}
//+1 to copy a potential nul terminator, uc_dstr_put
//guarantees we have room for it.
memcpy(s, src->str, UC_MIN(src->len + 1, src->allocated));
return 0;
}
size_t uc_dstr_available(const struct DStr *str)
{
return str->allocated - str->len;
}
int uc_dstr_ensure(struct DStr *str, size_t total)
{
if (str->allocated < total) {
//allocate a minimum no. of bytes, and one
//additional for the common case of nul terminating
//the string
size_t new_len = UC_MAX(7U, total) + 1;
char *new_str = realloc(str->str, new_len);
if (new_str == NULL) {
return -1;
}
str->str = new_str;
str->allocated = new_len;
}
return 0;
}
void uc_dstr_reset(struct DStr *str)
{
str->len = 0;
if (str->str) {
str->str[0] = 0;
}
}
void uc_dstr_terminate(struct DStr *str)
{
uc_dstr_ensure(str, str->len + 1);
str->str[str->len] = 0;
}
char *uc_dstr_str(struct DStr *str)
{
uc_dstr_terminate(str);
return str->str;
}
char *uc_dstr_put(struct DStr *str, size_t len)
{
char *start;
if (uc_dstr_ensure(str, str->len + len) != 0) {
return NULL;
}
start = str->str + str->len;
str->len += len;
return start;
}
size_t uc_dstr_put_str_filter(struct DStr *str, const char *s, int (*is_x)(int c))
{
size_t len = strlen(s);
size_t i;
size_t idx = 0;
if (uc_dstr_ensure(str, str->len + len) != 0) {
return 0;
}
for (i = 0; i < len; i++) {
if (is_x(s[i])) {
str->str[str->len + idx]= s[i];
idx++;
}
}
str->len += idx;
return idx;
}
int uc_dstr_put_str_sz(struct DStr *str, const char *s, size_t len)
{
char *start = uc_dstr_put(str, len);
if (start == NULL) {
return -1;
}
memcpy(start, s, len);
return 0;
}
int uc_dstr_put_str(struct DStr *str, const char *s)
{
size_t len = strlen(s);
return uc_dstr_put_str_sz(str, s ,len);
}
int uc_dstr_put_char(struct DStr *str, char c)
{
char *start = uc_dstr_put(str, 1);
if (start == NULL) {
return -1;
}
*start = c;
return 0;
}
void uc_dstr_own(struct DStr *str, char *s)
{
size_t len = strlen(s);
if (str->str) {
free(str);
}
str->len = len;
str->allocated = len + 1;
str->str = s;
}
char *uc_dstr_steal(struct DStr *str)
{
char *s = str->str;
uc_dstr_init(str);
return s;
}
void uc_str_swap(struct DStr *a, struct DStr *b)
{
struct DStr tmp;
tmp = *a;
*a = *b;
*b = tmp;
}
size_t uc_dstr_replace(struct DStr *str, char f, char r)
{
size_t i;
size_t count = 0;
if (str->len == 0) {
return 0;
}
for (i = 0; i < str->len; i++) {
if (str->str[i] == f) {
str->str[i] = r;
count++;
}
}
return count;
}
void uc_dstr_trim(struct DStr *str)
{
size_t spaces;
uc_dstr_terminate(str);
//spaces at the start
spaces = strspn(str->str, " \t\n\v\f\r");
if (spaces > 0) {
memmove(str->str, str->str + spaces, str->len - spaces);
str->len -= spaces;
}
//spaces at the end
if (str->len > 0) {
size_t idx = str->len - 1;
do {
if (strchr(" \t\n\v\f\r", str->str[idx]) == NULL) {
break;
} else {
str->len--;
idx--;
}
} while (idx != 0);
}
}
int uc_dstr_sprintf(struct DStr *str, const char *fmt, ...)
{
va_list ap;
int rc;
va_start(ap, fmt);
rc = uc_dstr_vsprintf(str, fmt, ap);
va_end(ap);
return rc;
}
int uc_dstr_vsprintf(struct DStr *str, const char *fmt, va_list ap_)
{
va_list ap;
int rc;
int available;
int needed;
rc = uc_dstr_ensure(str, str->len + 1);
if (rc != 0) {
return -1;
}
available = uc_dstr_available(str);
va_copy(ap, ap_);
needed = vsnprintf(str->str + str->len, available, fmt, ap);
va_end(ap);
if (needed <= 0) {
return needed;
}
if (needed >= available) {
rc = uc_dstr_ensure(str, str->len + needed);
if (rc != 0) {
return -1;
}
available = uc_dstr_available(str);
va_copy(ap, ap_);
needed = vsnprintf(str->str + str->len, available, fmt, ap);
va_end(ap);
}
str->len += needed;
return needed;
}
+1 -7
View File
@@ -89,14 +89,8 @@ int uc_set_ip_dscp(int fd, unsigned int dscp)
int val; int val;
//only 6 bits for dscp //only 6 bits for dscp
if (dscp > 63) { val = (dscp & 0x3f) << 2;
errno = EINVAL;
return -1;
}
val = dscp << 2;
return setsockopt(fd, IPPROTO_IP, IP_TOS, &val, sizeof val); return setsockopt(fd, IPPROTO_IP, IP_TOS, &val, sizeof val);
} }
+53
View File
@@ -0,0 +1,53 @@
#include <string.h>
#include "ucore/heapsort.h"
static void
uc_sift(unsigned char *base, size_t start, size_t count, size_t width,
uc_hs_cmp cmp, uc_hs_swp swap, void *cookie)
{
size_t root = start, child;
while ((root * 2 + 1) < count) {
child = root * 2 + 1;
if (child < (count - 1)) {
int rc = cmp(&base[child * width], &base[(child + 1) * width], cookie);
if (rc < 0) {
child++;
}
}
if (cmp(&base[root * width], &base[child * width], cookie) < 0) {
swap(base + root * width, base + child * width);
root = child;
} else {
return;
}
}
}
void
uc_heapsort(void *base_, size_t count, size_t width,
uc_hs_cmp cmp, uc_hs_swp swap, void *cookie)
{
long start;
long end;
unsigned char *base = base_;
if (count == 0 || width == 0) {
return;
}
start = count / 2 - 1,
end = count - 1;
while (start >= 0) {
uc_sift(base, start, count, width, cmp, swap, cookie);
start--;
}
while (end > 0) {
swap(base + end * width, base);
uc_sift(base, 0, end, width, cmp, swap, cookie);
end--;
}
}
+186
View File
@@ -0,0 +1,186 @@
#include <check.h>
#include <ctype.h>
#include <ucore/dstr.h>
#include <ucore/utils.h>
START_TEST (test_dstr_basics)
struct DStr str;
int rc;
char *s;
uc_dstr_init(&str);
rc = uc_dstr_put_str(&str, "Hello");
ck_assert_int_eq(rc, 0);
ck_assert_int_eq(str.len, 5);
ck_assert_str_eq(uc_dstr_str(&str), "Hello");
rc = uc_dstr_put_char(&str, '!');
ck_assert_int_eq(rc, 0);
ck_assert_int_eq(str.len, 6);
ck_assert_str_eq(uc_dstr_str(&str), "Hello!");
rc = uc_dstr_put_str_sz(&str, " World 12345678", 13);
ck_assert_int_eq(rc, 0);
ck_assert_int_eq(str.len, 19);
ck_assert_str_eq(uc_dstr_str(&str), "Hello! World 123456");
uc_dstr_reset(&str);
ck_assert_int_eq(str.len, 0);
ck_assert_str_eq(uc_dstr_str(&str), "");
uc_dstr_reset(&str);
ck_assert_int_gt(uc_dstr_available(&str), 0);
s = uc_dstr_put(&str, 2);
fail_if(s == NULL);
s[0] = '1';
s[1] = '2';
ck_assert_str_eq(uc_dstr_str(&str), "12");
uc_dstr_destroy(&str);
//just test that this doesn't crash:
uc_dstr_init(&str);
uc_dstr_destroy(&str);
END_TEST
START_TEST (test_dstr_own_steal)
struct DStr str;
char *s;
uc_dstr_init(&str);
uc_dstr_own(&str, strdup("Hello !"));
ck_assert_int_eq(str.len, 7);
ck_assert_str_eq(uc_dstr_str(&str), "Hello !");
s = uc_dstr_steal(&str);
ck_assert_str_eq(s, "Hello !");
ck_assert_int_eq(str.len, 0);
ck_assert_str_eq(uc_dstr_str(&str), "");
free(s);
uc_dstr_destroy(&str);
END_TEST
START_TEST (test_dstr_trim)
struct DStr str = UC_DSTR_STATIC_INIT;
uc_dstr_put_str(&str, " \t \nHello !\r\n");
uc_dstr_trim(&str);
ck_assert_str_eq(uc_dstr_str(&str), "Hello !");
uc_dstr_destroy(&str);
uc_dstr_init(&str);
uc_dstr_put_str(&str, " ");
uc_dstr_trim(&str);
ck_assert_str_eq(uc_dstr_str(&str), "");
uc_dstr_destroy(&str);
uc_dstr_init(&str);
uc_dstr_trim(&str);
ck_assert_str_eq(uc_dstr_str(&str), "");
uc_dstr_destroy(&str);
END_TEST
START_TEST (test_dstr_replace)
struct DStr str;
size_t rc;
uc_dstr_init(&str);
uc_dstr_put_str(&str, "-1-2-3-4-5-");
rc = uc_dstr_replace(&str, '-',' ');
ck_assert_int_eq(rc, 6);
ck_assert_str_eq(uc_dstr_str(&str), " 1 2 3 4 5 ");
rc = uc_dstr_replace(&str, 'X','2');
ck_assert_int_eq(rc, 0);
ck_assert_str_eq(uc_dstr_str(&str), " 1 2 3 4 5 ");
uc_dstr_destroy(&str);
END_TEST
START_TEST (test_dstr_filter)
struct DStr str;
size_t rc;
uc_dstr_init(&str);
uc_dstr_put_str(&str, "AB:");
rc = uc_dstr_put_str_filter(&str, "1:2,3 4 ", isdigit);
ck_assert_int_eq(rc, 4);
ck_assert_str_eq(uc_dstr_str(&str), "AB:1234");
uc_dstr_destroy(&str);
END_TEST
START_TEST (test_dstr_sprintf)
struct DStr str;
size_t rc;
uc_dstr_init(&str);
rc = uc_dstr_sprintf(&str, "%d-%d-%d", 1, 2, 3);
ck_assert_int_gt(rc, 0);
ck_assert_str_eq(uc_dstr_str(&str), "1-2-3");
rc = uc_dstr_sprintf(&str, " Another, bigger %s.", "string");
ck_assert_int_gt(rc, 0);
ck_assert_str_eq(uc_dstr_str(&str), "1-2-3 Another, bigger string.");
uc_dstr_destroy(&str);
END_TEST
START_TEST (test_dstr_copy)
struct DStr str;
struct DStr copy;
size_t rc;
uc_dstr_init(&str);
rc = uc_dstr_put_str(&str, "123");
ck_assert_int_eq(rc, 0);
rc = uc_dstr_copy(&copy, &str);
ck_assert_int_eq(rc, 0);
ck_assert_str_eq(uc_dstr_str(&copy), uc_dstr_str(&str));
uc_dstr_destroy(&str);
uc_dstr_destroy(&copy);
uc_dstr_init(&str);
uc_dstr_init(&copy);
rc = uc_dstr_copy(&copy, &str);
ck_assert_int_eq(rc, 0);
ck_assert_str_eq(uc_dstr_str(&copy), "");
uc_dstr_destroy(&str);
uc_dstr_destroy(&copy);
END_TEST
Suite *dstr_suite(void)
{
Suite *s = suite_create("dstr");
TCase *tc = tcase_create("dstr tests");
tcase_add_test(tc, test_dstr_basics);
tcase_add_test(tc, test_dstr_own_steal);
tcase_add_test(tc, test_dstr_trim);
tcase_add_test(tc, test_dstr_replace);
tcase_add_test(tc, test_dstr_filter);
tcase_add_test(tc, test_dstr_sprintf);
tcase_add_test(tc, test_dstr_copy);
suite_add_tcase(s, tc);
return s;
}
+140
View File
@@ -0,0 +1,140 @@
#include <check.h>
#include <ucore/utils.h>
#include <ucore/heapsort.h>
struct Stuff {
char text[11];
int order;
};
static void swap_stuff(void *a_, void *b_)
{
struct Stuff *a = a_;
struct Stuff *b = b_;
struct Stuff tmp;
tmp = *a;
*a = *b;
*b = tmp;
}
static int cmp_stuff(const void *a_, const void *b_, void *cookie)
{
const struct Stuff *a = a_;
const struct Stuff *b = b_;
(void)cookie;
if (a->order < b->order)
return -1;
return 1;
}
void print_stuff(const struct Stuff *s, size_t len)
{
size_t i;
for(i = 0; i < len; i++) {
printf("%s:%d\n", s[i].text, s[i].order);
}
}
static int cmp_stuff_array(const struct Stuff *a, const struct Stuff *b, size_t len)
{
size_t i;
for (i = 0; i < len; i++) {
if (strcmp(a[i].text, b[i].text) != 0)
return -1;
if (a[i].order != b[i].order)
return -1;
}
return 0;
}
START_TEST (test_heapsort_odd)
struct Stuff unordered[] = {
{"2", 2},
{"1", 1},
{"4", 4},
{"5", 5},
{"3", 3},
};
struct Stuff ordered[] = {
{"1", 1},
{"2", 2},
{"3", 3},
{"4", 4},
{"5", 5},
};
uc_heapsort(unordered, ARRAY_SIZE(unordered), sizeof(struct Stuff),
cmp_stuff, swap_stuff, NULL);
print_stuff(unordered, ARRAY_SIZE(unordered));
fail_if(cmp_stuff_array(unordered, ordered, ARRAY_SIZE(unordered)) != 0);
END_TEST
START_TEST (test_heapsort_even)
struct Stuff unordered[] = {
{"1", 1},
{"7", 7},
{"3", 3},
{"4", 4},
{"6", 6},
{"2", 2},
};
struct Stuff ordered[] = {
{"1", 1},
{"2", 2},
{"3", 3},
{"4", 4},
{"6", 6},
{"7", 7},
};
uc_heapsort(unordered, ARRAY_SIZE(unordered), sizeof(struct Stuff),
cmp_stuff, swap_stuff, NULL);
fail_if(cmp_stuff_array(unordered, ordered, ARRAY_SIZE(unordered)) != 0);
END_TEST
START_TEST (test_heapsort_zero)
struct Stuff unordered[] = {
{"1", 1},
{"7", 7},
{"3", 3},
{"4", 4},
{"6", 6},
{"2", 2},
};
struct Stuff same[] = {
{"1", 1},
{"7", 7},
{"3", 3},
{"4", 4},
{"6", 6},
{"2", 2},
};
uc_heapsort(unordered, 0, sizeof(struct Stuff),
cmp_stuff, swap_stuff, NULL);
fail_if(cmp_stuff_array(unordered, same, ARRAY_SIZE(unordered)) != 0);
uc_heapsort(unordered, ARRAY_SIZE(unordered), 0,
cmp_stuff, swap_stuff, NULL);
fail_if(cmp_stuff_array(unordered, same, ARRAY_SIZE(unordered)) != 0);
END_TEST
Suite *heapsort_suite(void)
{
Suite *s = suite_create("heapsort");
TCase *tc = tcase_create("heapsort tests");
tcase_add_test(tc, test_heapsort_odd);
tcase_add_test(tc, test_heapsort_even);
tcase_add_test(tc, test_heapsort_zero);
suite_add_tcase(s, tc);
return s;
}
+5 -1
View File
@@ -27,6 +27,8 @@ extern Suite *sprintb_suite(void);
extern Suite *strv_suite(void); extern Suite *strv_suite(void);
extern Suite *ratelimit_suite(void); extern Suite *ratelimit_suite(void);
extern Suite *htable_suite(void); extern Suite *htable_suite(void);
extern Suite *heapsort_suite(void);
extern Suite *dstr_suite(void);
static suite_func suites[] = { static suite_func suites[] = {
bitvec_suite, bitvec_suite,
@@ -48,7 +50,9 @@ static suite_func suites[] = {
ratelimit_suite, ratelimit_suite,
htable_suite, htable_suite,
clock_suite, clock_suite,
threadqueue_suite threadqueue_suite,
heapsort_suite,
dstr_suite
}; };
int int