Split function now takes slices as input, performs no allocs

pull/2319/head
David Garcia Quintas 10 years ago
parent 14f1c27192
commit 074e2247eb
  1. 56
      src/core/support/string.c
  2. 5
      src/core/support/string.h
  3. 49
      test/core/support/string_test.c

@ -188,25 +188,51 @@ char *gpr_strjoin_sep(const char **strs, size_t nstrs, const char *sep,
return out;
}
static void do_nothing(void *ignored) {}
gpr_slice_buffer *gpr_strsplit(const char *str, const char *sep) {
const size_t sep_len = strlen(sep);
const char *splitpoint = str;
gpr_slice_buffer *parts;
/** 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 gpr_slice 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 gpr_uint8 *sep_ptr = GPR_SLICE_START_PTR(sep);
const size_t str_len = GPR_SLICE_LENGTH(str) - read_offset;
const size_t sep_len = GPR_SLICE_LENGTH(sep);
if (str_len < sep_len) {
return 0;
}
GPR_ASSERT(sep_len > 0);
for (i = 0; i <= str_len - sep_len; i++) {
if (memcmp(str_ptr + i, sep_ptr, sep_len) == 0) {
*begin = read_offset;
*end = read_offset + i;
return 1;
}
}
return 0;
}
parts = gpr_malloc(sizeof(gpr_slice_buffer));
gpr_slice_buffer_init(parts);
void gpr_slice_split(gpr_slice str, gpr_slice sep, gpr_slice_buffer *dst) {
const size_t sep_len = GPR_SLICE_LENGTH(sep);
size_t begin, end;
GPR_ASSERT(sep_len > 0);
for (; (splitpoint = strstr(str, sep)) != NULL; splitpoint += sep_len) {
gpr_slice_buffer_add(
parts, gpr_slice_new((void *)str, splitpoint - str, do_nothing));
str += (splitpoint - str + sep_len);
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));
}
gpr_slice_buffer_add(parts,
gpr_slice_new((void *)str, strlen(str), do_nothing));
return parts;
}
void gpr_strvec_init(gpr_strvec *sv) {

@ -79,8 +79,9 @@ char *gpr_strjoin(const char **strs, size_t nstrs, size_t *total_length);
char *gpr_strjoin_sep(const char **strs, size_t nstrs, const char *sep,
size_t *total_length);
/** Split \a str at separator \a sep. */
gpr_slice_buffer *gpr_strsplit(const char *str, const char *sep);
/** 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, gpr_slice sep, gpr_slice_buffer *dst);
/* A vector of strings... for building up a final string one piece at a time */
typedef struct {

@ -194,52 +194,69 @@ static void test_strjoin_sep(void) {
static void test_strsplit(void) {
gpr_slice_buffer* parts;
gpr_slice str;
gpr_slice sep;
LOG_TEST_NAME("test_strsplit");
parts = gpr_strsplit("one, two, three, four", ", ");
parts = gpr_malloc(sizeof(gpr_slice_buffer));
gpr_slice_buffer_init(parts);
str = gpr_slice_from_copied_string("one, two, three, four");
sep = gpr_slice_from_copied_string(", ");
gpr_slice_split(str, sep, 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_destroy(parts);
gpr_free(parts);
gpr_slice_buffer_reset_and_unref(parts);
gpr_slice_unref(str);
/* separator not present in string */
parts = gpr_strsplit("one two three four", ", ");
str = gpr_slice_from_copied_string("one two three four");
gpr_slice_split(str, sep, parts);
GPR_ASSERT(1 == parts->count);
GPR_ASSERT(0 == gpr_slice_str_cmp(parts->slices[0], "one two three four"));
gpr_slice_buffer_destroy(parts);
gpr_free(parts);
gpr_slice_buffer_reset_and_unref(parts);
gpr_slice_unref(str);
/* separator at the end */
parts = gpr_strsplit("foo,", ",");
str = gpr_slice_from_copied_string("foo, ");
gpr_slice_split(str, sep, 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_destroy(parts);
gpr_free(parts);
gpr_slice_buffer_reset_and_unref(parts);
gpr_slice_unref(str);
/* separator at the beginning */
parts = gpr_strsplit(",foo", ",");
str = gpr_slice_from_copied_string(", foo");
gpr_slice_split(str, sep, 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_destroy(parts);
gpr_free(parts);
gpr_slice_buffer_reset_and_unref(parts);
gpr_slice_unref(str);
/* standalone separator */
parts = gpr_strsplit(",", ",");
str = gpr_slice_from_copied_string(", ");
gpr_slice_split(str, sep, 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_destroy(parts);
gpr_free(parts);
gpr_slice_buffer_reset_and_unref(parts);
gpr_slice_unref(str);
/* empty input */
parts = gpr_strsplit("", ",");
str = gpr_slice_from_copied_string("");
gpr_slice_split(str, sep, 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_unref(sep);
gpr_slice_buffer_destroy(parts);
gpr_free(parts);
}

Loading…
Cancel
Save