Convert attrs and diffs to use string pools

This converts the git attr related code (including ignores) and
the git diff related code (and implicitly the status code) to use
`git_pools` for storing strings.  This reduces the number of small
blocks allocated dramatically.
This commit is contained in:
Russell Belfer 2012-04-17 15:12:50 -07:00
parent 2bc8fa0227
commit 19fa2bc111
12 changed files with 216 additions and 153 deletions

View File

@ -167,6 +167,7 @@ int git_attr_add_macro(
{
int error;
git_attr_rule *macro = NULL;
git_pool *pool;
if (git_attr_cache__init(repo) < 0)
return -1;
@ -174,13 +175,15 @@ int git_attr_add_macro(
macro = git__calloc(1, sizeof(git_attr_rule));
GITERR_CHECK_ALLOC(macro);
macro->match.pattern = git__strdup(name);
pool = &git_repository_attr_cache(repo)->pool;
macro->match.pattern = git_pool_strdup(pool, name);
GITERR_CHECK_ALLOC(macro->match.pattern);
macro->match.length = strlen(macro->match.pattern);
macro->match.flags = GIT_ATTR_FNMATCH_MACRO;
error = git_attr_assignment__parse(repo, &macro->assigns, &values);
error = git_attr_assignment__parse(repo, pool, &macro->assigns, &values);
if (!error)
error = git_attr_cache__insert_macro(repo, macro);
@ -221,7 +224,7 @@ int git_attr_cache__lookup_or_create_file(
return 0;
}
if (git_attr_file__new(&file) < 0)
if (git_attr_file__new(&file, &cache->pool) < 0)
return -1;
if (loader)
@ -384,6 +387,10 @@ int git_attr_cache__init(git_repository *repo)
return -1;
}
/* allocate string pool */
if (git_pool_init(&cache->pool, 1, 0) < 0)
return -1;
cache->initialized = 1;
/* insert default macros */
@ -393,30 +400,33 @@ int git_attr_cache__init(git_repository *repo)
void git_attr_cache_flush(
git_repository *repo)
{
git_hashtable *table;
git_attr_cache *cache;
if (!repo)
return;
if ((table = git_repository_attr_cache(repo)->files) != NULL) {
cache = git_repository_attr_cache(repo);
if (cache->files != NULL) {
git_attr_file *file;
GIT_HASHTABLE_FOREACH_VALUE(table, file, git_attr_file__free(file));
git_hashtable_free(table);
git_repository_attr_cache(repo)->files = NULL;
GIT_HASHTABLE_FOREACH_VALUE(
cache->files, file, git_attr_file__free(file));
git_hashtable_free(cache->files);
cache->files = NULL;
}
if ((table = git_repository_attr_cache(repo)->macros) != NULL) {
if (cache->macros != NULL) {
git_attr_rule *rule;
GIT_HASHTABLE_FOREACH_VALUE(table, rule, git_attr_rule__free(rule));
git_hashtable_free(table);
git_repository_attr_cache(repo)->macros = NULL;
GIT_HASHTABLE_FOREACH_VALUE(
cache->macros, rule, git_attr_rule__free(rule));
git_hashtable_free(cache->macros);
cache->macros = NULL;
}
git_repository_attr_cache(repo)->initialized = 0;
git_pool_clear(&cache->pool);
cache->initialized = 0;
}
int git_attr_cache__insert_macro(git_repository *repo, git_attr_rule *macro)

View File

@ -14,6 +14,7 @@
typedef struct {
int initialized;
git_pool pool;
git_hashtable *files; /* hash path to git_attr_file of rules */
git_hashtable *macros; /* hash name to vector<git_attr_assignment> */
const char *cfg_attr_file; /* cached value of core.attributesfile */

View File

@ -9,21 +9,32 @@ const char *git_attr__false = "[internal]__FALSE__";
static int sort_by_hash_and_name(const void *a_raw, const void *b_raw);
static void git_attr_rule__clear(git_attr_rule *rule);
int git_attr_file__new(git_attr_file **attrs_ptr)
int git_attr_file__new(git_attr_file **attrs_ptr, git_pool *pool)
{
git_attr_file *attrs = NULL;
attrs = git__calloc(1, sizeof(git_attr_file));
GITERR_CHECK_ALLOC(attrs);
if (git_vector_init(&attrs->rules, 4, NULL) < 0) {
git__free(attrs);
attrs = NULL;
if (pool)
attrs->pool = pool;
else {
attrs->pool = git__calloc(1, sizeof(git_pool));
if (!attrs->pool || git_pool_init(attrs->pool, 1, 0) < 0)
goto fail;
attrs->pool_is_allocated = true;
}
*attrs_ptr = attrs;
if (git_vector_init(&attrs->rules, 4, NULL) < 0)
goto fail;
return attrs ? 0 : -1;
*attrs_ptr = attrs;
return 0;
fail:
git_attr_file__free(attrs);
attrs_ptr = NULL;
return -1;
}
int git_attr_file__set_path(
@ -76,8 +87,10 @@ int git_attr_file__from_buffer(
}
/* parse the next "pattern attr attr attr" line */
if (!(error = git_attr_fnmatch__parse(&rule->match, context, &scan)) &&
!(error = git_attr_assignment__parse(repo, &rule->assigns, &scan)))
if (!(error = git_attr_fnmatch__parse(
&rule->match, attrs->pool, context, &scan)) &&
!(error = git_attr_assignment__parse(
repo, attrs->pool, &rule->assigns, &scan)))
{
if (rule->match.flags & GIT_ATTR_FNMATCH_MACRO)
/* should generate error/warning if this is coming from any
@ -141,12 +154,18 @@ void git_attr_file__free(git_attr_file *file)
git__free(file->path);
file->path = NULL;
if (file->pool_is_allocated) {
git_pool_clear(file->pool);
git__free(file->pool);
}
file->pool = NULL;
git__free(file);
}
unsigned long git_attr_file__name_hash(const char *name)
uint32_t git_attr_file__name_hash(const char *name)
{
unsigned long h = 5381;
uint32_t h = 5381;
int c;
assert(name);
while ((c = (int)*name++) != 0)
@ -293,6 +312,7 @@ int git_attr_path__init(
*/
int git_attr_fnmatch__parse(
git_attr_fnmatch *spec,
git_pool *pool,
const char *source,
const char **base)
{
@ -358,7 +378,7 @@ int git_attr_fnmatch__parse(
/* given an unrooted fullpath match from a file inside a repo,
* prefix the pattern with the relative directory of the source file
*/
spec->pattern = git__malloc(sourcelen + spec->length + 1);
spec->pattern = git_pool_malloc(pool, sourcelen + spec->length + 1);
if (spec->pattern) {
memcpy(spec->pattern, source, sourcelen);
memcpy(spec->pattern + sourcelen, pattern, spec->length);
@ -366,7 +386,7 @@ int git_attr_fnmatch__parse(
spec->pattern[spec->length] = '\0';
}
} else {
spec->pattern = git__strndup(pattern, spec->length);
spec->pattern = git_pool_strndup(pool, pattern, spec->length);
}
if (!spec->pattern) {
@ -405,14 +425,11 @@ static int sort_by_hash_and_name(const void *a_raw, const void *b_raw)
static void git_attr_assignment__free(git_attr_assignment *assign)
{
git__free(assign->name);
/* name and value are stored in a git_pool associated with the
* git_attr_file, so they do not need to be freed here
*/
assign->name = NULL;
if (assign->is_allocated) {
git__free((void *)assign->value);
assign->value = NULL;
}
assign->value = NULL;
git__free(assign);
}
@ -428,6 +445,7 @@ static int merge_assignments(void **old_raw, void *new_raw)
int git_attr_assignment__parse(
git_repository *repo,
git_pool *pool,
git_vector *assigns,
const char **base)
{
@ -454,7 +472,6 @@ int git_attr_assignment__parse(
assign->name_hash = 5381;
assign->value = git_attr__true;
assign->is_allocated = 0;
/* look for magic name prefixes */
if (*scan == '-') {
@ -482,7 +499,7 @@ int git_attr_assignment__parse(
}
/* allocate permanent storage for name */
assign->name = git__strndup(name_start, scan - name_start);
assign->name = git_pool_strndup(pool, name_start, scan - name_start);
GITERR_CHECK_ALLOC(assign->name);
/* if there is an equals sign, find the value */
@ -491,9 +508,8 @@ int git_attr_assignment__parse(
/* if we found a value, allocate permanent storage for it */
if (scan > value_start) {
assign->value = git__strndup(value_start, scan - value_start);
assign->value = git_pool_strndup(pool, value_start, scan - value_start);
GITERR_CHECK_ALLOC(assign->value);
assign->is_allocated = 1;
}
}
@ -548,7 +564,7 @@ static void git_attr_rule__clear(git_attr_rule *rule)
git_vector_free(&rule->assigns);
}
git__free(rule->match.pattern);
/* match.pattern is stored in a git_pool, so no need to free */
rule->match.pattern = NULL;
rule->match.length = 0;
}

View File

@ -10,6 +10,7 @@
#include "git2/attr.h"
#include "vector.h"
#include "hashtable.h"
#include "pool.h"
#define GIT_ATTR_FILE ".gitattributes"
#define GIT_ATTR_FILE_INREPO "info/attributes"
@ -36,20 +37,21 @@ typedef struct {
typedef struct {
git_refcount unused;
const char *name;
unsigned long name_hash;
uint32_t name_hash;
} git_attr_name;
typedef struct {
git_refcount rc; /* for macros */
char *name;
unsigned long name_hash;
uint32_t name_hash;
const char *value;
int is_allocated;
} git_attr_assignment;
typedef struct {
char *path; /* cache the path this was loaded from */
git_vector rules; /* vector of <rule*> or <fnmatch*> */
git_pool *pool;
bool pool_is_allocated;
} git_attr_file;
typedef struct {
@ -62,7 +64,7 @@ typedef struct {
* git_attr_file API
*/
extern int git_attr_file__new(git_attr_file **attrs_ptr);
extern int git_attr_file__new(git_attr_file **attrs_ptr, git_pool *pool);
extern void git_attr_file__free(git_attr_file *file);
extern int git_attr_file__from_buffer(
@ -84,7 +86,7 @@ extern int git_attr_file__lookup_one(
git_vector_rforeach(&(file)->rules, (iter), (rule)) \
if (git_attr_rule__match((rule), (path)))
extern unsigned long git_attr_file__name_hash(const char *name);
extern uint32_t git_attr_file__name_hash(const char *name);
/*
@ -93,6 +95,7 @@ extern unsigned long git_attr_file__name_hash(const char *name);
extern int git_attr_fnmatch__parse(
git_attr_fnmatch *spec,
git_pool *pool,
const char *source,
const char **base);
@ -114,6 +117,7 @@ extern int git_attr_path__init(
extern int git_attr_assignment__parse(
git_repository *repo, /* needed to expand macros */
git_pool *pool,
git_vector *assigns,
const char **scan);

View File

@ -54,24 +54,6 @@ static bool diff_path_matches_pathspec(git_diff_list *diff, const char *path)
return false;
}
static void diff_delta__free(git_diff_delta *delta)
{
if (!delta)
return;
if (delta->new.flags & GIT_DIFF_FILE_FREE_PATH) {
git__free((char *)delta->new.path);
delta->new.path = NULL;
}
if (delta->old.flags & GIT_DIFF_FILE_FREE_PATH) {
git__free((char *)delta->old.path);
delta->old.path = NULL;
}
git__free(delta);
}
static git_diff_delta *diff_delta__alloc(
git_diff_list *diff,
git_delta_t status,
@ -81,12 +63,11 @@ static git_diff_delta *diff_delta__alloc(
if (!delta)
return NULL;
delta->old.path = git__strdup(path);
delta->old.path = git_pool_strdup(&diff->pool, path);
if (delta->old.path == NULL) {
git__free(delta);
return NULL;
}
delta->old.flags |= GIT_DIFF_FILE_FREE_PATH;
delta->new.path = delta->old.path;
if (diff->opts.flags & GIT_DIFF_REVERSE) {
@ -101,7 +82,8 @@ static git_diff_delta *diff_delta__alloc(
return delta;
}
static git_diff_delta *diff_delta__dup(const git_diff_delta *d)
static git_diff_delta *diff_delta__dup(
const git_diff_delta *d, git_pool *pool)
{
git_diff_delta *delta = git__malloc(sizeof(git_diff_delta));
if (!delta)
@ -109,33 +91,29 @@ static git_diff_delta *diff_delta__dup(const git_diff_delta *d)
memcpy(delta, d, sizeof(git_diff_delta));
delta->old.path = git__strdup(d->old.path);
if (delta->old.path == NULL) {
git__free(delta);
return NULL;
}
delta->old.flags |= GIT_DIFF_FILE_FREE_PATH;
delta->old.path = git_pool_strdup(pool, d->old.path);
if (delta->old.path == NULL)
goto fail;
if (d->new.path != d->old.path) {
delta->new.path = git__strdup(d->new.path);
if (delta->new.path == NULL) {
git__free(delta->old.path);
git__free(delta);
return NULL;
}
delta->new.flags |= GIT_DIFF_FILE_FREE_PATH;
delta->new.path = git_pool_strdup(pool, d->new.path);
if (delta->new.path == NULL)
goto fail;
} else {
delta->new.path = delta->old.path;
delta->new.flags &= ~GIT_DIFF_FILE_FREE_PATH;
}
return delta;
fail:
git__free(delta);
return NULL;
}
static git_diff_delta *diff_delta__merge_like_cgit(
const git_diff_delta *a, const git_diff_delta *b)
const git_diff_delta *a, const git_diff_delta *b, git_pool *pool)
{
git_diff_delta *dup = diff_delta__dup(a);
git_diff_delta *dup = diff_delta__dup(a, pool);
if (!dup)
return NULL;
@ -146,9 +124,7 @@ static git_diff_delta *diff_delta__merge_like_cgit(
dup->new.mode = b->new.mode;
dup->new.size = b->new.size;
dup->new.flags =
(dup->new.flags & GIT_DIFF_FILE_FREE_PATH) |
(b->new.flags & ~GIT_DIFF_FILE_FREE_PATH);
dup->new.flags = b->new.flags;
/* Emulate C git for merging two diffs (a la 'git diff <sha>').
*
@ -210,7 +186,7 @@ static int diff_delta__from_one(
delta->new.flags |= GIT_DIFF_FILE_VALID_OID;
if (git_vector_insert(&diff->deltas, delta) < 0) {
diff_delta__free(delta);
git__free(delta);
return -1;
}
@ -249,7 +225,7 @@ static int diff_delta__from_two(
delta->new.flags |= GIT_DIFF_FILE_VALID_OID;
if (git_vector_insert(&diff->deltas, delta) < 0) {
diff_delta__free(delta);
git__free(delta);
return -1;
}
@ -259,19 +235,15 @@ static int diff_delta__from_two(
#define DIFF_SRC_PREFIX_DEFAULT "a/"
#define DIFF_DST_PREFIX_DEFAULT "b/"
static char *diff_strdup_prefix(const char *prefix)
static char *diff_strdup_prefix(git_pool *pool, const char *prefix)
{
size_t len = strlen(prefix);
char *str = git__malloc(len + 2);
if (str != NULL) {
memcpy(str, prefix, len + 1);
/* append '/' at end if needed */
if (len > 0 && str[len - 1] != '/') {
str[len] = '/';
str[len + 1] = '\0';
}
}
return str;
/* append '/' at end if needed */
if (len > 0 && prefix[len - 1] != '/')
return git_pool_strcat(pool, prefix, "/");
else
return git_pool_strndup(pool, prefix, len + 1);
}
static int diff_delta__cmp(const void *a, const void *b)
@ -300,6 +272,10 @@ static git_diff_list *git_diff_list_alloc(
diff->repo = repo;
if (git_vector_init(&diff->deltas, 0, diff_delta__cmp) < 0 ||
git_pool_init(&diff->pool, 1, 0) < 0)
goto fail;
/* load config values that affect diff behavior */
if (git_repository_config__weakptr(&cfg, repo) < 0)
goto fail;
@ -319,9 +295,9 @@ static git_diff_list *git_diff_list_alloc(
memcpy(&diff->opts, opts, sizeof(git_diff_options));
memset(&diff->opts.pathspec, 0, sizeof(diff->opts.pathspec));
diff->opts.src_prefix = diff_strdup_prefix(
diff->opts.src_prefix = diff_strdup_prefix(&diff->pool,
opts->src_prefix ? opts->src_prefix : DIFF_SRC_PREFIX_DEFAULT);
diff->opts.dst_prefix = diff_strdup_prefix(
diff->opts.dst_prefix = diff_strdup_prefix(&diff->pool,
opts->dst_prefix ? opts->dst_prefix : DIFF_DST_PREFIX_DEFAULT);
if (!diff->opts.src_prefix || !diff->opts.dst_prefix)
@ -333,9 +309,6 @@ static git_diff_list *git_diff_list_alloc(
diff->opts.dst_prefix = swap;
}
if (git_vector_init(&diff->deltas, 0, diff_delta__cmp) < 0)
goto fail;
/* only copy pathspec if it is "interesting" so we can test
* diff->pathspec.length > 0 to know if it is worth calling
* fnmatch as we iterate.
@ -349,11 +322,10 @@ static git_diff_list *git_diff_list_alloc(
for (i = 0; i < opts->pathspec.count; ++i) {
int ret;
const char *pattern = opts->pathspec.strings[i];
git_attr_fnmatch *match =
git__calloc(1, sizeof(git_attr_fnmatch));
git_attr_fnmatch *match = git__calloc(1, sizeof(git_attr_fnmatch));
if (!match)
goto fail;
ret = git_attr_fnmatch__parse(match, NULL, &pattern);
ret = git_attr_fnmatch__parse(match, &diff->pool, NULL, &pattern);
if (ret == GIT_ENOTFOUND) {
git__free(match);
continue;
@ -381,23 +353,18 @@ void git_diff_list_free(git_diff_list *diff)
return;
git_vector_foreach(&diff->deltas, i, delta) {
diff_delta__free(delta);
git__free(delta);
diff->deltas.contents[i] = NULL;
}
git_vector_free(&diff->deltas);
git_vector_foreach(&diff->pathspec, i, match) {
if (match != NULL) {
git__free(match->pattern);
match->pattern = NULL;
git__free(match);
diff->pathspec.contents[i] = NULL;
}
git__free(match);
diff->pathspec.contents[i] = NULL;
}
git_vector_free(&diff->pathspec);
git__free(diff->opts.src_prefix);
git__free(diff->opts.dst_prefix);
git_pool_clear(&diff->pool);
git__free(diff);
}
@ -709,6 +676,7 @@ int git_diff_merge(
const git_diff_list *from)
{
int error = 0;
git_pool onto_pool;
git_vector onto_new;
git_diff_delta *delta;
unsigned int i, j;
@ -718,7 +686,8 @@ int git_diff_merge(
if (!from->deltas.length)
return 0;
if (git_vector_init(&onto_new, onto->deltas.length, diff_delta__cmp) < 0)
if (git_vector_init(&onto_new, onto->deltas.length, diff_delta__cmp) < 0 ||
git_pool_init(&onto_pool, 1, 0) < 0)
return -1;
for (i = 0, j = 0; i < onto->deltas.length || j < from->deltas.length; ) {
@ -727,13 +696,13 @@ int git_diff_merge(
int cmp = !f ? -1 : !o ? 1 : strcmp(o->old.path, f->old.path);
if (cmp < 0) {
delta = diff_delta__dup(o);
delta = diff_delta__dup(o, &onto_pool);
i++;
} else if (cmp > 0) {
delta = diff_delta__dup(f);
delta = diff_delta__dup(f, &onto_pool);
j++;
} else {
delta = diff_delta__merge_like_cgit(o, f);
delta = diff_delta__merge_like_cgit(o, f, &onto_pool);
i++;
j++;
}
@ -744,12 +713,14 @@ int git_diff_merge(
if (!error) {
git_vector_swap(&onto->deltas, &onto_new);
git_pool_swap(&onto->pool, &onto_pool);
onto->new_src = from->new_src;
}
git_vector_foreach(&onto_new, i, delta)
diff_delta__free(delta);
git__free(delta);
git_vector_free(&onto_new);
git_pool_clear(&onto_pool);
return error;
}

View File

@ -12,6 +12,7 @@
#include "buffer.h"
#include "iterator.h"
#include "repository.h"
#include "pool.h"
enum {
GIT_DIFFCAPS_HAS_SYMLINKS = (1 << 0), /* symlinks on platform? */
@ -26,6 +27,7 @@ struct git_diff_list {
git_diff_options opts;
git_vector pathspec;
git_vector deltas; /* vector of git_diff_file_delta */
git_pool pool;
git_iterator_type_t old_src;
git_iterator_type_t new_src;
uint32_t diffcaps;

View File

@ -35,7 +35,9 @@ static int load_ignore_file(
GITERR_CHECK_ALLOC(match);
}
if (!(error = git_attr_fnmatch__parse(match, context, &scan))) {
if (!(error = git_attr_fnmatch__parse(
match, ignores->pool, context, &scan)))
{
match->flags = match->flags | GIT_ATTR_FNMATCH_IGNORE;
scan = git__next_line(scan);
error = git_vector_insert(&ignores->rules, match);

View File

@ -13,7 +13,7 @@ struct git_pool_page {
#define GIT_POOL_MIN_USABLE 4
#define GIT_POOL_MIN_PAGESZ 2 * sizeof(void*)
static int pool_alloc_page(git_pool *pool, uint32_t size, void **ptr);
static void *pool_alloc_page(git_pool *pool, uint32_t size);
static void pool_insert_page(git_pool *pool, git_pool_page *page);
int git_pool_init(
@ -62,11 +62,25 @@ void git_pool_clear(git_pool *pool)
pool->free_list = NULL;
pool->items = 0;
pool->has_string_alloc = 0;
pool->has_multi_item_alloc = 0;
pool->has_large_page_alloc = 0;
}
void git_pool_swap(git_pool *a, git_pool *b)
{
git_pool temp;
if (a == b)
return;
memcpy(&temp, a, sizeof(temp));
memcpy(a, b, sizeof(temp));
memcpy(b, &temp, sizeof(temp));
}
static void pool_insert_page(git_pool *pool, git_pool_page *page)
{
git_pool_page *scan;
@ -88,8 +102,7 @@ static void pool_insert_page(git_pool *pool, git_pool_page *page)
scan->next = page;
}
static int pool_alloc_page(
git_pool *pool, uint32_t size, void **ptr)
static void *pool_alloc_page(git_pool *pool, uint32_t size)
{
git_pool_page *page;
uint32_t alloc_size;
@ -103,7 +116,7 @@ static int pool_alloc_page(
page = git__calloc(1, alloc_size + sizeof(git_pool_page));
if (!page)
return -1;
return NULL;
page->size = alloc_size;
page->avail = alloc_size - size;
@ -115,9 +128,9 @@ static int pool_alloc_page(
pool->full = page;
}
*ptr = page->data;
pool->items++;
return 0;
return page->data;
}
GIT_INLINE(void) pool_remove_page(
@ -129,22 +142,26 @@ GIT_INLINE(void) pool_remove_page(
prev->next = page->next;
}
int git_pool_malloc(git_pool *pool, uint32_t items, void **ptr)
void *git_pool_malloc(git_pool *pool, uint32_t items)
{
git_pool_page *scan = pool->open, *prev;
uint32_t size = items * pool->item_size;
void *ptr = NULL;
pool->has_string_alloc = 0;
if (items > 1)
pool->has_multi_item_alloc = 1;
else if (pool->free_list != NULL) {
*ptr = pool->free_list;
ptr = pool->free_list;
pool->free_list = *((void **)pool->free_list);
return ptr;
}
/* just add a block if there is no open one to accomodate this */
if (size >= pool->page_size || !scan || scan->avail < size)
return pool_alloc_page(pool, size, ptr);
return pool_alloc_page(pool, size);
pool->items++;
/* find smallest block in free list with space */
for (scan = pool->open, prev = NULL;
@ -152,7 +169,7 @@ int git_pool_malloc(git_pool *pool, uint32_t items, void **ptr)
prev = scan, scan = scan->next);
/* allocate space from the block */
*ptr = &scan->data[scan->size - scan->avail];
ptr = &scan->data[scan->size - scan->avail];
scan->avail -= size;
/* move to full list if there is almost no space left */
@ -167,7 +184,7 @@ int git_pool_malloc(git_pool *pool, uint32_t items, void **ptr)
pool_insert_page(pool, scan);
}
return 0;
return ptr;
}
char *git_pool_strndup(git_pool *pool, const char *str, size_t n)
@ -176,8 +193,10 @@ char *git_pool_strndup(git_pool *pool, const char *str, size_t n)
assert(pool && str && pool->item_size == sizeof(char));
if (!git_pool_malloc(pool, n, &ptr))
if ((ptr = git_pool_malloc(pool, n + 1)) != NULL) {
memcpy(ptr, str, n);
*(((char *)ptr) + n) = '\0';
}
pool->has_string_alloc = 1;
return ptr;
@ -187,7 +206,29 @@ char *git_pool_strdup(git_pool *pool, const char *str)
{
assert(pool && str && pool->item_size == sizeof(char));
return git_pool_strndup(pool, str, strlen(str) + 1);
return git_pool_strndup(pool, str, strlen(str));
}
char *git_pool_strcat(git_pool *pool, const char *a, const char *b)
{
void *ptr;
size_t len_a, len_b;
assert(pool && a && b && pool->item_size == sizeof(char));
len_a = a ? strlen(a) : 0;
len_b = b ? strlen(b) : 0;
if ((ptr = git_pool_malloc(pool, len_a + len_b + 1)) != NULL) {
if (len_a)
memcpy(ptr, a, len_a);
if (len_b)
memcpy(((char *)ptr) + len_a, b, len_b);
*(((char *)ptr) + len_a + len_b) = '\0';
}
pool->has_string_alloc = 1;
return ptr;
}
void git_pool_free(git_pool *pool, void *ptr)

View File

@ -33,11 +33,14 @@ typedef struct {
void *free_list; /* optional: list of freed blocks */
uint32_t item_size; /* size of single alloc unit in bytes */
uint32_t page_size; /* size of page in bytes */
uint32_t items;
unsigned has_string_alloc : 1; /* was the strdup function used */
unsigned has_multi_item_alloc : 1; /* was items ever > 1 in malloc */
unsigned has_large_page_alloc : 1; /* are any pages > page_size */
} git_pool;
#define GIT_POOL_INIT_STRINGPOOL { 0, 0, 0, 1, 4000, 0, 0, 0, 0 }
/**
* Initialize a pool.
*
@ -49,7 +52,7 @@ typedef struct {
* To allocate items of fixed size, use like this:
*
* git_pool_init(&pool, sizeof(item), 0);
* git_pool_malloc(&pool, 1, &my_item_ptr);
* my_item = git_pool_malloc(&pool, 1);
*
* Of course, you can use this in other ways, but those are the
* two most common patterns.
@ -62,10 +65,15 @@ extern int git_pool_init(
*/
extern void git_pool_clear(git_pool *pool);
/**
* Swap two pools with one another
*/
extern void git_pool_swap(git_pool *a, git_pool *b);
/**
* Allocate space for one or more items from a pool.
*/
extern int git_pool_malloc(git_pool *pool, uint32_t items, void **ptr);
extern void *git_pool_malloc(git_pool *pool, uint32_t items);
/**
* Allocate space and duplicate string data into it.
@ -81,6 +89,13 @@ extern char *git_pool_strndup(git_pool *pool, const char *str, size_t n);
*/
extern char *git_pool_strdup(git_pool *pool, const char *str);
/**
* Allocate space for the concatenation of two strings.
*
* This is allowed only for pools with item_size == sizeof(char)
*/
extern char *git_pool_strcat(git_pool *pool, const char *a, const char *b);
/**
* Push a block back onto the free list for the pool.
*

View File

@ -11,7 +11,7 @@ void test_attr_file__simple_read(void)
git_attr_assignment *assign;
git_attr_rule *rule;
cl_git_pass(git_attr_file__new(&file));
cl_git_pass(git_attr_file__new(&file, NULL));
cl_git_pass(git_attr_file__from_file(NULL, cl_fixture("attr/attr0"), file));
cl_assert_equal_s(cl_fixture("attr/attr0"), file->path);
cl_assert(file->rules.length == 1);
@ -27,7 +27,6 @@ void test_attr_file__simple_read(void)
cl_assert(assign != NULL);
cl_assert_equal_s("binary", assign->name);
cl_assert(GIT_ATTR_TRUE(assign->value));
cl_assert(!assign->is_allocated);
git_attr_file__free(file);
}
@ -38,7 +37,7 @@ void test_attr_file__match_variants(void)
git_attr_rule *rule;
git_attr_assignment *assign;
cl_git_pass(git_attr_file__new(&file));
cl_git_pass(git_attr_file__new(&file, NULL));
cl_git_pass(git_attr_file__from_file(NULL, cl_fixture("attr/attr1"), file));
cl_assert_equal_s(cl_fixture("attr/attr1"), file->path);
cl_assert(file->rules.length == 10);
@ -56,7 +55,6 @@ void test_attr_file__match_variants(void)
cl_assert_equal_s("attr0", assign->name);
cl_assert(assign->name_hash == git_attr_file__name_hash(assign->name));
cl_assert(GIT_ATTR_TRUE(assign->value));
cl_assert(!assign->is_allocated);
rule = get_rule(1);
cl_assert_equal_s("pat1", rule->match.pattern);
@ -125,7 +123,7 @@ void test_attr_file__assign_variants(void)
git_attr_rule *rule;
git_attr_assignment *assign;
cl_git_pass(git_attr_file__new(&file));
cl_git_pass(git_attr_file__new(&file, NULL));
cl_git_pass(git_attr_file__from_file(NULL, cl_fixture("attr/attr2"), file));
cl_assert_equal_s(cl_fixture("attr/attr2"), file->path);
cl_assert(file->rules.length == 11);
@ -191,7 +189,7 @@ void test_attr_file__check_attr_examples(void)
git_attr_rule *rule;
git_attr_assignment *assign;
cl_git_pass(git_attr_file__new(&file));
cl_git_pass(git_attr_file__new(&file, NULL));
cl_git_pass(git_attr_file__from_file(NULL, cl_fixture("attr/attr3"), file));
cl_assert_equal_s(cl_fixture("attr/attr3"), file->path);
cl_assert(file->rules.length == 3);

View File

@ -9,7 +9,7 @@ void test_attr_lookup__simple(void)
git_attr_path path;
const char *value = NULL;
cl_git_pass(git_attr_file__new(&file));
cl_git_pass(git_attr_file__new(&file, NULL));
cl_git_pass(git_attr_file__from_file(NULL, cl_fixture("attr/attr0"), file));
cl_assert_equal_s(cl_fixture("attr/attr0"), file->path);
cl_assert(file->rules.length == 1);
@ -127,7 +127,7 @@ void test_attr_lookup__match_variants(void)
{ NULL, NULL, 0, NULL }
};
cl_git_pass(git_attr_file__new(&file));
cl_git_pass(git_attr_file__new(&file, NULL));
cl_git_pass(git_attr_file__from_file(NULL, cl_fixture("attr/attr1"), file));
cl_assert_equal_s(cl_fixture("attr/attr1"), file->path);
cl_assert(file->rules.length == 10);
@ -144,6 +144,7 @@ void test_attr_lookup__match_variants(void)
void test_attr_lookup__assign_variants(void)
{
git_attr_file *file;
struct attr_expected cases[] = {
/* pat0 -> simple assign */
{ "pat0", "simple", EXPECT_TRUE, NULL },
@ -187,7 +188,7 @@ void test_attr_lookup__assign_variants(void)
{ NULL, NULL, 0, NULL }
};
cl_git_pass(git_attr_file__new(&file));
cl_git_pass(git_attr_file__new(&file, NULL));
cl_git_pass(git_attr_file__from_file(NULL, cl_fixture("attr/attr2"), file));
cl_assert(file->rules.length == 11);
@ -199,6 +200,7 @@ void test_attr_lookup__assign_variants(void)
void test_attr_lookup__check_attr_examples(void)
{
git_attr_file *file;
struct attr_expected cases[] = {
{ "foo.java", "diff", EXPECT_STRING, "java" },
{ "foo.java", "crlf", EXPECT_FALSE, NULL },
@ -222,7 +224,7 @@ void test_attr_lookup__check_attr_examples(void)
{ NULL, NULL, 0, NULL }
};
cl_git_pass(git_attr_file__new(&file));
cl_git_pass(git_attr_file__new(&file, NULL));
cl_git_pass(git_attr_file__from_file(NULL, cl_fixture("attr/attr3"), file));
cl_assert(file->rules.length == 3);
@ -234,6 +236,7 @@ void test_attr_lookup__check_attr_examples(void)
void test_attr_lookup__from_buffer(void)
{
git_attr_file *file;
struct attr_expected cases[] = {
{ "abc", "foo", EXPECT_TRUE, NULL },
{ "abc", "bar", EXPECT_TRUE, NULL },
@ -247,7 +250,7 @@ void test_attr_lookup__from_buffer(void)
{ NULL, NULL, 0, NULL }
};
cl_git_pass(git_attr_file__new(&file));
cl_git_pass(git_attr_file__new(&file, NULL));
cl_git_pass(git_attr_file__from_buffer(NULL, "a* foo\nabc bar\n* baz", file));
cl_assert(file->rules.length == 3);

View File

@ -11,9 +11,8 @@ void test_core_pool__0(void)
cl_git_pass(git_pool_init(&p, 1, 4000));
for (i = 1; i < 10000; i *= 2) {
cl_git_pass(git_pool_malloc(&p, i, &ptr));
ptr = git_pool_malloc(&p, i);
cl_assert(ptr != NULL);
cl_assert(git_pool__ptr_in_pool(&p, ptr));
cl_assert(!git_pool__ptr_in_pool(&p, &i));
}
@ -32,12 +31,11 @@ void test_core_pool__1(void)
{
int i;
git_pool p;
void *ptr;
cl_git_pass(git_pool_init(&p, 1, 4000));
for (i = 2010; i > 0; i--)
cl_git_pass(git_pool_malloc(&p, i, &ptr));
cl_assert(git_pool_malloc(&p, i) != NULL);
/* with fixed page size, allocation must end up with these values */
cl_assert(git_pool__open_pages(&p) == 1);
@ -48,7 +46,7 @@ void test_core_pool__1(void)
cl_git_pass(git_pool_init(&p, 1, 4100));
for (i = 2010; i > 0; i--)
cl_git_pass(git_pool_malloc(&p, i, &ptr));
cl_assert(git_pool_malloc(&p, i) != NULL);
/* with fixed page size, allocation must end up with these values */
cl_assert(git_pool__open_pages(&p) == 1);
@ -71,7 +69,9 @@ void test_core_pool__2(void)
cl_git_pass(git_pool_init(&p, sizeof(git_oid), 100));
for (i = 1000; i < 10000; i++) {
cl_git_pass(git_pool_malloc(&p, 1, (void **)&oid));
oid = git_pool_malloc(&p, 1);
cl_assert(oid != NULL);
for (j = 0; j < 8; j++)
oid_hex[j] = to_hex[(i >> (4 * j)) & 0x0f];
cl_git_pass(git_oid_fromstr(oid, oid_hex));