Commit 18234b14 by Russell Belfer

Add efficient git_buf join3 API

There are a few places where we need to join three strings to
assemble a path.  This adds a simple join3 function to avoid the
comparatively expensive join_n (which calls strlen on each string
twice).
parent 2450d4c6
......@@ -467,6 +467,59 @@ int git_buf_join(
return 0;
}
int git_buf_join3(
git_buf *buf,
char separator,
const char *str_a,
const char *str_b,
const char *str_c)
{
size_t len_a = strlen(str_a), len_b = strlen(str_b), len_c = strlen(str_c);
int sep_a = 0, sep_b = 0;
char *tgt;
/* for this function, disallow pointers into the existing buffer */
assert(str_a < buf->ptr || str_a >= buf->ptr + buf->size);
assert(str_b < buf->ptr || str_b >= buf->ptr + buf->size);
assert(str_c < buf->ptr || str_c >= buf->ptr + buf->size);
if (separator) {
if (len_a > 0) {
while (*str_b == separator) { str_b++; len_b--; }
sep_a = (str_a[len_a - 1] != separator);
}
if (len_a > 0 || len_b > 0)
while (*str_c == separator) { str_c++; len_c--; }
if (len_b > 0)
sep_b = (str_b[len_b - 1] != separator);
}
if (git_buf_grow(buf, len_a + sep_a + len_b + sep_b + len_c + 1) < 0)
return -1;
tgt = buf->ptr;
if (len_a) {
memcpy(tgt, str_a, len_a);
tgt += len_a;
}
if (sep_a)
*tgt++ = separator;
if (len_b) {
memcpy(tgt, str_b, len_b);
tgt += len_b;
}
if (sep_b)
*tgt++ = separator;
if (len_c)
memcpy(tgt, str_c, len_c);
buf->size = len_a + sep_a + len_b + sep_b + len_c;
buf->ptr[buf->size] = '\0';
return 0;
}
void git_buf_rtrim(git_buf *buf)
{
while (buf->size > 0) {
......
......@@ -98,8 +98,12 @@ void git_buf_truncate(git_buf *buf, size_t len);
void git_buf_shorten(git_buf *buf, size_t amount);
void git_buf_rtruncate_at_char(git_buf *path, char separator);
/** General join with separator */
int git_buf_join_n(git_buf *buf, char separator, int nbuf, ...);
/** Fast join of two strings - first may legally point into `buf` data */
int git_buf_join(git_buf *buf, char separator, const char *str_a, const char *str_b);
/** Fast join of three strings - cannot reference `buf` data */
int git_buf_join3(git_buf *buf, char separator, const char *str_a, const char *str_b, const char *str_c);
/**
* Join two strings as paths, inserting a slash between as needed.
......
......@@ -1432,7 +1432,7 @@ static int create_new_reflog_file(const char *filepath)
GIT_INLINE(int) retrieve_reflog_path(git_buf *path, git_repository *repo, const char *name)
{
return git_buf_join_n(path, '/', 3, repo->path_repository, GIT_REFLOG_DIR, name);
return git_buf_join3(path, '/', repo->path_repository, GIT_REFLOG_DIR, name);
}
static int refdb_reflog_fs__ensure_log(git_refdb_backend *_backend, const char *name)
......
......@@ -168,10 +168,11 @@ int git_submodule_lookup(
if (git_repository_workdir(repo)) {
git_buf path = GIT_BUF_INIT;
if (git_buf_joinpath(&path, git_repository_workdir(repo), name) < 0)
if (git_buf_join3(&path,
'/', git_repository_workdir(repo), name, DOT_GIT) < 0)
return -1;
if (git_path_contains(&path, DOT_GIT))
if (git_path_exists(path.ptr))
error = GIT_EEXISTS;
git_buf_free(&path);
......@@ -328,8 +329,8 @@ int git_submodule_add_setup(
else if (use_gitlink) {
git_buf repodir = GIT_BUF_INIT;
error = git_buf_join_n(
&repodir, '/', 3, git_repository_path(repo), "modules", path);
error = git_buf_join3(
&repodir, '/', git_repository_path(repo), "modules", path);
if (error < 0)
goto cleanup;
......
......@@ -599,6 +599,38 @@ void test_core_buffer__10(void)
git_buf_free(&a);
}
void test_core_buffer__join3(void)
{
git_buf a = GIT_BUF_INIT;
cl_git_pass(git_buf_join3(&a, '/', "test", "string", "join"));
cl_assert_equal_s("test/string/join", a.ptr);
cl_git_pass(git_buf_join3(&a, '/', "test/", "string", "join"));
cl_assert_equal_s("test/string/join", a.ptr);
cl_git_pass(git_buf_join3(&a, '/', "test/", "/string", "join"));
cl_assert_equal_s("test/string/join", a.ptr);
cl_git_pass(git_buf_join3(&a, '/', "test/", "/string/", "join"));
cl_assert_equal_s("test/string/join", a.ptr);
cl_git_pass(git_buf_join3(&a, '/', "test/", "/string/", "/join"));
cl_assert_equal_s("test/string/join", a.ptr);
cl_git_pass(git_buf_join3(&a, '/', "", "string", "join"));
cl_assert_equal_s("string/join", a.ptr);
cl_git_pass(git_buf_join3(&a, '/', "", "string/", "join"));
cl_assert_equal_s("string/join", a.ptr);
cl_git_pass(git_buf_join3(&a, '/', "", "string/", "/join"));
cl_assert_equal_s("string/join", a.ptr);
cl_git_pass(git_buf_join3(&a, '/', "string", "", "join"));
cl_assert_equal_s("string/join", a.ptr);
cl_git_pass(git_buf_join3(&a, '/', "string/", "", "join"));
cl_assert_equal_s("string/join", a.ptr);
cl_git_pass(git_buf_join3(&a, '/', "string/", "", "/join"));
cl_assert_equal_s("string/join", a.ptr);
git_buf_free(&a);
}
void test_core_buffer__11(void)
{
git_buf a = GIT_BUF_INIT;
......
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