1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2025-01-11 05:17:44 +03:00

Merge pull request #23453 from keszybz/strv-parsing

Add strv methods with externally-supplied size argument and speed up parsing of /etc/hosts
This commit is contained in:
Luca Boccassi 2022-05-21 15:00:51 +01:00 committed by GitHub
commit 6910d43af5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 1085 additions and 17 deletions

View File

@ -403,27 +403,33 @@ char* strv_join_full(char * const *l, const char *separator, const char *prefix,
return r;
}
int strv_push(char ***l, char *value) {
char **c;
size_t n;
int strv_push_with_size(char ***l, size_t *n, char *value) {
/* n is a pointer to a variable to store the size of l.
* If not given (i.e. n is NULL or *n is SIZE_MAX), size will be calculated using strv_length().
* If n is not NULL, the size after the push will be returned.
* If value is empty, no action is taken and *n is not set. */
if (!value)
return 0;
n = strv_length(*l);
size_t size = n ? *n : SIZE_MAX;
if (size == SIZE_MAX)
size = strv_length(*l);
/* Check for overflow */
if (n > SIZE_MAX-2)
if (size > SIZE_MAX-2)
return -ENOMEM;
c = reallocarray(*l, GREEDY_ALLOC_ROUND_UP(n + 2), sizeof(char*));
char **c = reallocarray(*l, GREEDY_ALLOC_ROUND_UP(size + 2), sizeof(char*));
if (!c)
return -ENOMEM;
c[n] = value;
c[n+1] = NULL;
c[size] = value;
c[size+1] = NULL;
*l = c;
if (n)
*n = size + 1;
return 0;
}
@ -484,10 +490,10 @@ int strv_insert(char ***l, size_t position, char *value) {
return free_and_replace(*l, c);
}
int strv_consume(char ***l, char *value) {
int strv_consume_with_size(char ***l, size_t *n, char *value) {
int r;
r = strv_push(l, value);
r = strv_push_with_size(l, n, value);
if (r < 0)
free(value);
@ -529,7 +535,7 @@ int strv_prepend(char ***l, const char *value) {
return strv_consume_prepend(l, v);
}
int strv_extend(char ***l, const char *value) {
int strv_extend_with_size(char ***l, size_t *n, const char *value) {
char *v;
if (!value)
@ -539,7 +545,7 @@ int strv_extend(char ***l, const char *value) {
if (!v)
return -ENOMEM;
return strv_consume(l, v);
return strv_consume_with_size(l, n, v);
}
int strv_extend_front(char ***l, const char *value) {

View File

@ -35,18 +35,36 @@ size_t strv_length(char * const *l) _pure_;
int strv_extend_strv(char ***a, char * const *b, bool filter_duplicates);
int strv_extend_strv_concat(char ***a, char * const *b, const char *suffix);
int strv_prepend(char ***l, const char *value);
int strv_extend(char ***l, const char *value);
/* _with_size() are lower-level functions where the size can be provided externally,
* which allows us to skip iterating over the strv to find the end, which saves
* a bit of time and reduces the complexity of appending from O(n²) to O(n). */
int strv_extend_with_size(char ***l, size_t *n, const char *value);
static inline int strv_extend(char ***l, const char *value) {
return strv_extend_with_size(l, NULL, value);
}
int strv_extendf(char ***l, const char *format, ...) _printf_(2,0);
int strv_extend_front(char ***l, const char *value);
int strv_push(char ***l, char *value);
int strv_push_with_size(char ***l, size_t *n, char *value);
static inline int strv_push(char ***l, char *value) {
return strv_push_with_size(l, NULL, value);
}
int strv_push_pair(char ***l, char *a, char *b);
int strv_insert(char ***l, size_t position, char *value);
static inline int strv_push_prepend(char ***l, char *value) {
return strv_insert(l, 0, value);
}
int strv_consume(char ***l, char *value);
int strv_consume_with_size(char ***l, size_t *n, char *value);
static inline int strv_consume(char ***l, char *value) {
return strv_consume_with_size(l, NULL, value);
}
int strv_consume_pair(char ***l, char *a, char *b);
int strv_consume_prepend(char ***l, char *value);

View File

@ -127,7 +127,7 @@ static int parse_line(EtcHosts *hosts, unsigned nr, const char *line) {
continue;
}
r = strv_extend(&item->names, name);
r = strv_extend_with_size(&item->names, &item->n_names, name);
if (r < 0)
return log_oom();
@ -391,7 +391,7 @@ int manager_etc_hosts_lookup(Manager *m, DnsQuestion* q, DnsAnswer **answer) {
}
if (found_ptr) {
r = dns_answer_reserve(answer, strv_length(item->names));
r = dns_answer_reserve(answer, item->n_names);
if (r < 0)
return r;

View File

@ -9,6 +9,7 @@ typedef struct EtcHostsItem {
struct in_addr_data address;
char **names;
size_t n_names;
} EtcHostsItem;
typedef struct EtcHostsItemByName {

View File

@ -601,6 +601,25 @@ TEST(strv_extend_strv) {
assert_se(strv_length(n) == 4);
}
TEST(strv_extend_with_size) {
_cleanup_strv_free_ char **a = NULL;
size_t n = SIZE_MAX;
a = strv_new("test", "test1");
assert_se(a);
assert_se(strv_extend_with_size(&a, &n, "test2") >= 0);
assert_se(n == 3);
assert_se(strv_extend_with_size(&a, &n, "test3") >= 0);
assert_se(n == 4);
assert_se(streq(a[0], "test"));
assert_se(streq(a[1], "test1"));
assert_se(streq(a[2], "test2"));
assert_se(streq(a[3], "test3"));
assert_se(a[4] == NULL);
}
TEST(strv_extend) {
_cleanup_strv_free_ char **a = NULL, **b = NULL;
@ -746,6 +765,30 @@ TEST(strv_push_prepend) {
assert_se(!a[5]);
}
TEST(strv_push_with_size) {
_cleanup_strv_free_ char **a = NULL;
size_t n = 0;
char *i, *j;
assert_se(i = strdup("foo"));
assert_se(strv_push_with_size(&a, &n, i) >= 0);
assert_se(n == 1);
assert_se(i = strdup("a"));
assert_se(j = strdup("b"));
assert_se(strv_push_with_size(&a, &n, i) >= 0);
assert_se(n == 2);
assert_se(strv_push_with_size(&a, &n, j) >= 0);
assert_se(n == 3);
assert_se(streq_ptr(a[0], "foo"));
assert_se(streq_ptr(a[1], "a"));
assert_se(streq_ptr(a[2], "b"));
assert_se(streq_ptr(a[3], NULL));
assert_se(n = strv_length(a));
}
TEST(strv_push) {
_cleanup_strv_free_ char **a = NULL;
char *i, *j;

File diff suppressed because it is too large Load Diff