Merge pull request #2319 from dgquintas/str_join_with_sep

Added convenience functions gpr_strjoin_sep and grp_strsplit
pull/2491/head
Nicolas Noble 10 years ago
commit d82d0b295b
  1. 62
      src/core/support/string.c
  2. 11
      src/core/support/string.h
  3. 116
      test/core/support/string_test.c

@ -38,6 +38,7 @@
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/port_platform.h>
#include <grpc/support/useful.h>
@ -174,6 +175,12 @@ int gpr_ltoa(long value, char *string) {
}
char *gpr_strjoin(const char **strs, size_t nstrs, size_t *final_length) {
return gpr_strjoin_sep(strs, nstrs, "", final_length);
}
char *gpr_strjoin_sep(const char **strs, size_t nstrs, const char *sep,
size_t *final_length) {
const size_t sep_len = strlen(sep);
size_t out_length = 0;
size_t i;
char *out;
@ -181,10 +188,17 @@ char *gpr_strjoin(const char **strs, size_t nstrs, size_t *final_length) {
out_length += strlen(strs[i]);
}
out_length += 1; /* null terminator */
if (nstrs > 0) {
out_length += sep_len * (nstrs - 1); /* separators */
}
out = gpr_malloc(out_length);
out_length = 0;
for (i = 0; i < nstrs; i++) {
size_t slen = strlen(strs[i]);
const size_t slen = strlen(strs[i]);
if (i != 0) {
memcpy(out + out_length, sep, sep_len);
out_length += sep_len;
}
memcpy(out + out_length, strs[i], slen);
out_length += slen;
}
@ -195,6 +209,52 @@ char *gpr_strjoin(const char **strs, size_t nstrs, size_t *final_length) {
return out;
}
/** Finds the initial (\a begin) and final (\a end) offsets of the next
* substring from \a str + \a read_offset until the next \a sep or the end of \a
* str.
*
* Returns 1 and updates \a begin and \a end. Returns 0 otherwise. */
static int slice_find_separator_offset(const gpr_slice str,
const char *sep,
const size_t read_offset,
size_t *begin,
size_t *end) {
size_t i;
const gpr_uint8 *str_ptr = GPR_SLICE_START_PTR(str) + read_offset;
const size_t str_len = GPR_SLICE_LENGTH(str) - read_offset;
const size_t sep_len = strlen(sep);
if (str_len < sep_len) {
return 0;
}
for (i = 0; i <= str_len - sep_len; i++) {
if (memcmp(str_ptr + i, sep, sep_len) == 0) {
*begin = read_offset;
*end = read_offset + i;
return 1;
}
}
return 0;
}
void gpr_slice_split(gpr_slice str, const char *sep, gpr_slice_buffer *dst) {
const size_t sep_len = strlen(sep);
size_t begin, end;
GPR_ASSERT(sep_len > 0);
if (slice_find_separator_offset(str, sep, 0, &begin, &end) != 0) {
do {
gpr_slice_buffer_add_indexed(dst, gpr_slice_sub(str, begin, end));
} while (slice_find_separator_offset(str, sep, end + sep_len, &begin,
&end) != 0);
gpr_slice_buffer_add_indexed(
dst, gpr_slice_sub(str, end + sep_len, GPR_SLICE_LENGTH(str)));
} else { /* no sep found, add whole input */
gpr_slice_buffer_add_indexed(dst, gpr_slice_ref(str));
}
}
void gpr_strvec_init(gpr_strvec *sv) {
memset(sv, 0, sizeof(*sv));
}

@ -37,6 +37,7 @@
#include <stddef.h>
#include <grpc/support/port_platform.h>
#include <grpc/support/slice_buffer.h>
#include <grpc/support/slice.h>
#ifdef __cplusplus
@ -77,6 +78,16 @@ void gpr_reverse_bytes(char *str, int len);
if it is non-null. */
char *gpr_strjoin(const char **strs, size_t nstrs, size_t *total_length);
/* Join a set of strings using a separator, returning the resulting string.
Total combined length (excluding null terminator) is returned in total_length
if it is non-null. */
char *gpr_strjoin_sep(const char **strs, size_t nstrs, const char *sep,
size_t *total_length);
/** Split \a str by the separator \a sep. Results are stored in \a dst, which
* should be a properly initialized instance. */
void gpr_slice_split(gpr_slice str, const char *sep, gpr_slice_buffer *dst);
/* A vector of strings... for building up a final string one piece at a time */
typedef struct {
char **strs;

@ -173,6 +173,119 @@ static void test_asprintf(void) {
}
}
static void test_strjoin(void) {
const char *parts[4] = {"one", "two", "three", "four"};
size_t joined_len;
char *joined;
LOG_TEST_NAME("test_strjoin");
joined = gpr_strjoin(parts, 4, &joined_len);
GPR_ASSERT(0 == strcmp("onetwothreefour", joined));
gpr_free(joined);
joined = gpr_strjoin(parts, 0, &joined_len);
GPR_ASSERT(0 == strcmp("", joined));
gpr_free(joined);
joined = gpr_strjoin(parts, 1, &joined_len);
GPR_ASSERT(0 == strcmp("one", joined));
gpr_free(joined);
}
static void test_strjoin_sep(void) {
const char *parts[4] = {"one", "two", "three", "four"};
size_t joined_len;
char *joined;
LOG_TEST_NAME("test_strjoin_sep");
joined = gpr_strjoin_sep(parts, 4, ", ", &joined_len);
GPR_ASSERT(0 == strcmp("one, two, three, four", joined));
gpr_free(joined);
/* empty separator */
joined = gpr_strjoin_sep(parts, 4, "", &joined_len);
GPR_ASSERT(0 == strcmp("onetwothreefour", joined));
gpr_free(joined);
/* degenerated case specifying zero input parts */
joined = gpr_strjoin_sep(parts, 0, ", ", &joined_len);
GPR_ASSERT(0 == strcmp("", joined));
gpr_free(joined);
/* single part should have no separator */
joined = gpr_strjoin_sep(parts, 1, ", ", &joined_len);
GPR_ASSERT(0 == strcmp("one", joined));
gpr_free(joined);
}
static void test_strsplit(void) {
gpr_slice_buffer* parts;
gpr_slice str;
LOG_TEST_NAME("test_strsplit");
parts = gpr_malloc(sizeof(gpr_slice_buffer));
gpr_slice_buffer_init(parts);
str = gpr_slice_from_copied_string("one, two, three, four");
gpr_slice_split(str, ", ", parts);
GPR_ASSERT(4 == parts->count);
GPR_ASSERT(0 == gpr_slice_str_cmp(parts->slices[0], "one"));
GPR_ASSERT(0 == gpr_slice_str_cmp(parts->slices[1], "two"));
GPR_ASSERT(0 == gpr_slice_str_cmp(parts->slices[2], "three"));
GPR_ASSERT(0 == gpr_slice_str_cmp(parts->slices[3], "four"));
gpr_slice_buffer_reset_and_unref(parts);
gpr_slice_unref(str);
/* separator not present in string */
str = gpr_slice_from_copied_string("one two three four");
gpr_slice_split(str, ", ", parts);
GPR_ASSERT(1 == parts->count);
GPR_ASSERT(0 == gpr_slice_str_cmp(parts->slices[0], "one two three four"));
gpr_slice_buffer_reset_and_unref(parts);
gpr_slice_unref(str);
/* separator at the end */
str = gpr_slice_from_copied_string("foo,");
gpr_slice_split(str, ",", parts);
GPR_ASSERT(2 == parts->count);
GPR_ASSERT(0 == gpr_slice_str_cmp(parts->slices[0], "foo"));
GPR_ASSERT(0 == gpr_slice_str_cmp(parts->slices[1], ""));
gpr_slice_buffer_reset_and_unref(parts);
gpr_slice_unref(str);
/* separator at the beginning */
str = gpr_slice_from_copied_string(",foo");
gpr_slice_split(str, ",", parts);
GPR_ASSERT(2 == parts->count);
GPR_ASSERT(0 == gpr_slice_str_cmp(parts->slices[0], ""));
GPR_ASSERT(0 == gpr_slice_str_cmp(parts->slices[1], "foo"));
gpr_slice_buffer_reset_and_unref(parts);
gpr_slice_unref(str);
/* standalone separator */
str = gpr_slice_from_copied_string(",");
gpr_slice_split(str, ",", parts);
GPR_ASSERT(2 == parts->count);
GPR_ASSERT(0 == gpr_slice_str_cmp(parts->slices[0], ""));
GPR_ASSERT(0 == gpr_slice_str_cmp(parts->slices[1], ""));
gpr_slice_buffer_reset_and_unref(parts);
gpr_slice_unref(str);
/* empty input */
str = gpr_slice_from_copied_string("");
gpr_slice_split(str, ", ", parts);
GPR_ASSERT(1 == parts->count);
GPR_ASSERT(0 == gpr_slice_str_cmp(parts->slices[0], ""));
gpr_slice_buffer_reset_and_unref(parts);
gpr_slice_unref(str);
gpr_slice_buffer_destroy(parts);
gpr_free(parts);
}
int main(int argc, char **argv) {
grpc_test_init(argc, argv);
test_strdup();
@ -180,5 +293,8 @@ int main(int argc, char **argv) {
test_dump_slice();
test_parse_uint32();
test_asprintf();
test_strjoin();
test_strjoin_sep();
test_strsplit();
return 0;
}

Loading…
Cancel
Save