mirror of
https://github.com/profanity-im/profanity.git
synced 2024-12-04 14:46:46 -05:00
Less allocations in str_replace()
If `n` is the number of `substr` replace operations, the old implementation did `n+1` allocations and always first copied start, then replacement, then the remaining (unsearched) part of the original string. Now calculate the number of occurences of `substr` before allocating the resulting string. Change the algorithm to parse through the original string and only copy the parts that must be kept into the resulting string plus the replacements where they belong at. Now we also only have to go through the original string twice plus we only do a single allocation. Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
This commit is contained in:
parent
b36562c6b6
commit
d3b6ebb1d7
53
src/common.c
53
src/common.c
@ -174,9 +174,12 @@ char*
|
|||||||
str_replace(const char* string, const char* substr,
|
str_replace(const char* string, const char* substr,
|
||||||
const char* replacement)
|
const char* replacement)
|
||||||
{
|
{
|
||||||
char* tok = NULL;
|
const char* head = NULL;
|
||||||
|
const char* tok = NULL;
|
||||||
char* newstr = NULL;
|
char* newstr = NULL;
|
||||||
char* head = NULL;
|
char* wr = NULL;
|
||||||
|
size_t num_substr = 0;
|
||||||
|
size_t len_string, len_substr, len_replacement, len_string_remains, len_newstr;
|
||||||
|
|
||||||
if (string == NULL)
|
if (string == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -184,26 +187,40 @@ str_replace(const char* string, const char* substr,
|
|||||||
if (substr == NULL || replacement == NULL || (strcmp(substr, "") == 0))
|
if (substr == NULL || replacement == NULL || (strcmp(substr, "") == 0))
|
||||||
return strdup(string);
|
return strdup(string);
|
||||||
|
|
||||||
newstr = strdup(string);
|
tok = string;
|
||||||
head = newstr;
|
while ((tok = strstr(tok, substr))) {
|
||||||
|
num_substr++;
|
||||||
|
tok++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num_substr == 0)
|
||||||
|
return strdup(string);
|
||||||
|
|
||||||
|
len_string = strlen(string);
|
||||||
|
len_substr = strlen(substr);
|
||||||
|
len_replacement = strlen(replacement);
|
||||||
|
len_newstr = len_string - (num_substr * len_substr) + (num_substr * len_replacement);
|
||||||
|
newstr = malloc(len_newstr + 1);
|
||||||
|
if (newstr == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
len_string_remains = len_string;
|
||||||
|
|
||||||
|
head = string;
|
||||||
|
wr = newstr;
|
||||||
|
|
||||||
while ((tok = strstr(head, substr))) {
|
while ((tok = strstr(head, substr))) {
|
||||||
auto_char char* oldstr = newstr;
|
size_t l = tok - head;
|
||||||
newstr = malloc(strlen(oldstr) - strlen(substr) + strlen(replacement) + 1);
|
memcpy(wr, head, l);
|
||||||
|
wr += l;
|
||||||
|
memcpy(wr, replacement, len_replacement);
|
||||||
|
wr += len_replacement;
|
||||||
|
len_string_remains -= len_substr + l;
|
||||||
|
|
||||||
if (newstr == NULL) {
|
head = tok + len_substr;
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(newstr, oldstr, tok - oldstr);
|
|
||||||
memcpy(newstr + (tok - oldstr), replacement, strlen(replacement));
|
|
||||||
memcpy(newstr + (tok - oldstr) + strlen(replacement),
|
|
||||||
tok + strlen(substr),
|
|
||||||
strlen(oldstr) - strlen(substr) - (tok - oldstr));
|
|
||||||
memset(newstr + strlen(oldstr) - strlen(substr) + strlen(replacement), 0, 1);
|
|
||||||
|
|
||||||
head = newstr + (tok - oldstr) + strlen(replacement);
|
|
||||||
}
|
}
|
||||||
|
memcpy(wr, head, len_string_remains);
|
||||||
|
newstr[len_newstr] = '\0';
|
||||||
|
|
||||||
return newstr;
|
return newstr;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user