Commit 8a4e3181 by Vicent Martí

Merge pull request #504 from arrbee/git-buf-fast-join

Optimized implementation of git_buf_join
parents f5f04826 969d588d
...@@ -282,58 +282,24 @@ void git_buf_join( ...@@ -282,58 +282,24 @@ void git_buf_join(
const char *str_a, const char *str_a,
const char *str_b) const char *str_b)
{ {
size_t add_size = 0; size_t strlen_a = strlen(str_a);
size_t sep_a = 0; size_t strlen_b = strlen(str_b);
size_t strlen_a = 0; int need_sep = 0;
size_t sep_b = 0;
size_t strlen_b = 0; /* figure out if we need to insert a separator */
char *ptr; if (separator && strlen_a) {
while (*str_b == separator) { str_b++; strlen_b--; }
/* calculate string lengths and need for added separators */ if (str_a[strlen_a - 1] != separator)
if (str_a) { need_sep = 1;
while (*str_a == separator) { sep_a = 1; str_a++; }
strlen_a = strlen(str_a);
} }
if (str_b) {
while (*str_b == separator) { sep_b = 1; str_b++; }
strlen_b = strlen(str_b);
}
if (buf->size > 0) {
if (buf->ptr[buf->size - 1] == separator) {
sep_a = 0;
if (!strlen_a) sep_b = 0;
} else if (!strlen_a)
sep_b = (str_b != NULL);
}
if (strlen_a > 0) {
if (str_a[strlen_a - 1] == separator)
sep_b = 0;
else if (str_b)
sep_b = 1;
}
add_size = sep_a + strlen_a + sep_b + strlen_b;
if (!add_size) return; ENSURE_SIZE(buf, strlen_a + strlen_b + need_sep + 1);
ENSURE_SIZE(buf, buf->size + add_size + 1); memmove(buf->ptr, str_a, strlen_a);
if (need_sep)
buf->ptr[strlen_a] = separator;
memmove(buf->ptr + strlen_a + need_sep, str_b, strlen_b);
/* concatenate strings */ buf->size = strlen_a + strlen_b + need_sep;
ptr = buf->ptr + buf->size;
if (sep_a)
*ptr++ = separator;
if (strlen_a) {
memmove(ptr, str_a, strlen_a);
ptr += strlen_a;
}
if (sep_b)
*ptr++ = separator;
if (strlen_b) {
memmove(ptr, str_b, strlen_b);
ptr += strlen_b;
}
/* set size based on num characters actually written */
buf->size = ptr - buf->ptr;
buf->ptr[buf->size] = '\0'; buf->ptr[buf->size] = '\0';
} }
...@@ -92,6 +92,7 @@ extern void test_core_buffer__5(void); ...@@ -92,6 +92,7 @@ extern void test_core_buffer__5(void);
extern void test_core_buffer__6(void); extern void test_core_buffer__6(void);
extern void test_core_buffer__7(void); extern void test_core_buffer__7(void);
extern void test_core_buffer__8(void); extern void test_core_buffer__8(void);
extern void test_core_buffer__9(void);
extern void test_core_dirent__dont_traverse_dot(void); extern void test_core_dirent__dont_traverse_dot(void);
extern void test_core_dirent__dont_traverse_empty_folders(void); extern void test_core_dirent__dont_traverse_empty_folders(void);
extern void test_core_dirent__traverse_slash_terminated_folder(void); extern void test_core_dirent__traverse_slash_terminated_folder(void);
......
...@@ -29,15 +29,16 @@ ...@@ -29,15 +29,16 @@
* Wrapper for string comparison that knows about nulls. * Wrapper for string comparison that knows about nulls.
*/ */
#define cl_assert_strequal(a,b) \ #define cl_assert_strequal(a,b) \
cl_assert_strequal_internal(a,b,__FILE__,__LINE__) cl_assert_strequal_internal(a,b,__FILE__,__LINE__,"string mismatch: " #a " != " #b)
GIT_INLINE(void) cl_assert_strequal_internal(const char *a, const char *b, const char *file, int line) GIT_INLINE(void) cl_assert_strequal_internal(
const char *a, const char *b, const char *file, int line, const char *err)
{ {
int match = (a == NULL || b == NULL) ? (a == b) : (strcmp(a, b) == 0); int match = (a == NULL || b == NULL) ? (a == b) : (strcmp(a, b) == 0);
if (!match) { if (!match) {
char buf[4096]; char buf[4096];
snprintf(buf, 4096, "'%s' != '%s'", a, b); snprintf(buf, 4096, "'%s' != '%s'", a, b);
clay__assert(0, file, line, buf, "Strings do not match", 1); clay__assert(0, file, line, buf, err, 1);
} }
} }
......
...@@ -145,7 +145,8 @@ static const struct clay_func _clay_cb_core_buffer[] = { ...@@ -145,7 +145,8 @@ static const struct clay_func _clay_cb_core_buffer[] = {
{"5", &test_core_buffer__5}, {"5", &test_core_buffer__5},
{"6", &test_core_buffer__6}, {"6", &test_core_buffer__6},
{"7", &test_core_buffer__7}, {"7", &test_core_buffer__7},
{"8", &test_core_buffer__8} {"8", &test_core_buffer__8},
{"9", &test_core_buffer__9}
}; };
static const struct clay_func _clay_cb_core_dirent[] = { static const struct clay_func _clay_cb_core_dirent[] = {
{"dont_traverse_dot", &test_core_dirent__dont_traverse_dot}, {"dont_traverse_dot", &test_core_dirent__dont_traverse_dot},
...@@ -326,7 +327,7 @@ static const struct clay_suite _clay_suites[] = { ...@@ -326,7 +327,7 @@ static const struct clay_suite _clay_suites[] = {
"core::buffer", "core::buffer",
{NULL, NULL}, {NULL, NULL},
{NULL, NULL}, {NULL, NULL},
_clay_cb_core_buffer, 9 _clay_cb_core_buffer, 10
}, },
{ {
"core::dirent", "core::dirent",
...@@ -493,7 +494,7 @@ static const struct clay_suite _clay_suites[] = { ...@@ -493,7 +494,7 @@ static const struct clay_suite _clay_suites[] = {
}; };
static size_t _clay_suite_count = 34; static size_t _clay_suite_count = 34;
static size_t _clay_callback_count = 112; static size_t _clay_callback_count = 113;
/* Core test functions */ /* Core test functions */
static void static void
......
...@@ -374,20 +374,10 @@ check_joinbuf_2( ...@@ -374,20 +374,10 @@ check_joinbuf_2(
char sep = '/'; char sep = '/';
git_buf buf = GIT_BUF_INIT; git_buf buf = GIT_BUF_INIT;
/* first validate join from nothing */
git_buf_join(&buf, sep, a, b); git_buf_join(&buf, sep, a, b);
cl_assert(git_buf_oom(&buf) == 0); cl_assert(git_buf_oom(&buf) == 0);
cl_assert_strequal(expected, git_buf_cstr(&buf)); cl_assert_strequal(expected, git_buf_cstr(&buf));
git_buf_free(&buf); git_buf_free(&buf);
/* next validate join-append */
git_buf_sets(&buf, a);
cl_assert(git_buf_oom(&buf) == 0);
git_buf_join(&buf, sep, NULL, b);
cl_assert(git_buf_oom(&buf) == 0);
cl_assert_strequal(expected, git_buf_cstr(&buf));
git_buf_free(&buf);
} }
static void static void
...@@ -490,3 +480,45 @@ void test_core_buffer__8(void) ...@@ -490,3 +480,45 @@ void test_core_buffer__8(void)
check_joinbuf_n_4(";abcd;", ";efgh;", ";ijkl;", ";mnop;", ";abcd;efgh;ijkl;mnop;"); check_joinbuf_n_4(";abcd;", ";efgh;", ";ijkl;", ";mnop;", ";abcd;efgh;ijkl;mnop;");
} }
void test_core_buffer__9(void)
{
git_buf buf = GIT_BUF_INIT;
/* just some exhaustive tests of various separator placement */
char *a[] = { "", "-", "a-", "-a", "-a-" };
char *b[] = { "", "-", "b-", "-b", "-b-" };
char sep[] = { 0, '-', '/' };
char *expect_null[] = { "", "-", "a-", "-a", "-a-",
"-", "--", "a--", "-a-", "-a--",
"b-", "-b-", "a-b-", "-ab-", "-a-b-",
"-b", "--b", "a--b", "-a-b", "-a--b",
"-b-", "--b-", "a--b-", "-a-b-", "-a--b-" };
char *expect_dash[] = { "", "-", "a-", "-a-", "-a-",
"-", "-", "a-", "-a-", "-a-",
"b-", "-b-", "a-b-", "-a-b-", "-a-b-",
"-b", "-b", "a-b", "-a-b", "-a-b",
"-b-", "-b-", "a-b-", "-a-b-", "-a-b-" };
char *expect_slas[] = { "", "-/", "a-/", "-a/", "-a-/",
"-", "-/-", "a-/-", "-a/-", "-a-/-",
"b-", "-/b-", "a-/b-", "-a/b-", "-a-/b-",
"-b", "-/-b", "a-/-b", "-a/-b", "-a-/-b",
"-b-", "-/-b-", "a-/-b-", "-a/-b-", "-a-/-b-" };
char **expect_values[] = { expect_null, expect_dash, expect_slas };
char separator, **expect;
unsigned int s, i, j;
for (s = 0; s < sizeof(sep) / sizeof(char); ++s) {
separator = sep[s];
expect = expect_values[s];
for (j = 0; j < sizeof(b) / sizeof(char*); ++j) {
for (i = 0; i < sizeof(a) / sizeof(char*); ++i) {
git_buf_join(&buf, separator, a[i], b[j]);
cl_assert_strequal(*expect, buf.ptr);
expect++;
}
}
}
git_buf_free(&buf);
}
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