mirror of
				https://gitlab.gnome.org/GNOME/glib.git
				synced 2025-10-31 16:32:18 +01:00 
			
		
		
		
	Merge branch 'feature' into 'main'
remove quadratic behavior in g_string_replace See merge request GNOME/glib!4313
This commit is contained in:
		| @@ -1023,38 +1023,112 @@ g_string_replace (GString     *string, | |||||||
|                   const gchar *replace, |                   const gchar *replace, | ||||||
|                   guint        limit) |                   guint        limit) | ||||||
| { | { | ||||||
|   gsize f_len, r_len, pos; |   GString *new_string = NULL; | ||||||
|   gchar *cur, *next; |   gsize f_len, r_len, new_len; | ||||||
|   guint n = 0; |   gchar *cur, *next, *first, *dst; | ||||||
|  |   guint n; | ||||||
|  |  | ||||||
|   g_return_val_if_fail (string != NULL, 0); |   g_return_val_if_fail (string != NULL, 0); | ||||||
|   g_return_val_if_fail (find != NULL, 0); |   g_return_val_if_fail (find != NULL, 0); | ||||||
|   g_return_val_if_fail (replace != NULL, 0); |   g_return_val_if_fail (replace != NULL, 0); | ||||||
|  |  | ||||||
|  |   first = strstr (string->str, find); | ||||||
|  |  | ||||||
|  |   if (first == NULL) | ||||||
|  |     return 0; | ||||||
|  |  | ||||||
|  |   new_len = string->len; | ||||||
|   f_len = strlen (find); |   f_len = strlen (find); | ||||||
|   r_len = strlen (replace); |   r_len = strlen (replace); | ||||||
|   cur = string->str; |  | ||||||
|  |  | ||||||
|  |   /* Potentially do two passes: the first to calculate the length of the new string, | ||||||
|  |    * new_len, if it’s going to be longer than the original string; and the second to | ||||||
|  |    * do the replacements. The first pass is skipped if the new string is going to be | ||||||
|  |    * no longer than the original. */ | ||||||
|  |   do | ||||||
|  |     { | ||||||
|  |       dst = first; | ||||||
|  |       cur = first; | ||||||
|  |       n = 0; | ||||||
|       while ((next = strstr (cur, find)) != NULL) |       while ((next = strstr (cur, find)) != NULL) | ||||||
|         { |         { | ||||||
|       pos = next - string->str; |  | ||||||
|       g_string_erase (string, pos, f_len); |  | ||||||
|       g_string_insert (string, pos, replace); |  | ||||||
|       cur = string->str + pos + r_len; |  | ||||||
|           n++; |           n++; | ||||||
|  |           if G_UNLIKELY (f_len == 0) | ||||||
|  |             { | ||||||
|  |               g_string_insert_len (string, next - string->str, replace, r_len); | ||||||
|  |               cur = next + r_len; | ||||||
|               /* Only match the empty string once at any given position, to |               /* Only match the empty string once at any given position, to | ||||||
|                * avoid infinite loops */ |                * avoid infinite loops */ | ||||||
|       if (f_len == 0) |  | ||||||
|         { |  | ||||||
|               if (cur[0] == '\0') |               if (cur[0] == '\0') | ||||||
|                 break; |                 break; | ||||||
|               else |               else | ||||||
|                 cur++; |                 cur++; | ||||||
|             } |             } | ||||||
|  |           else | ||||||
|  |             { | ||||||
|  |               if (r_len <= f_len) | ||||||
|  |                 { | ||||||
|  |                   memmove (dst, cur, next - cur); | ||||||
|  |                   dst += next - cur; | ||||||
|  |                   memcpy (dst, replace, r_len); | ||||||
|  |                   dst += r_len; | ||||||
|  |                 } | ||||||
|  |               else | ||||||
|  |                 { | ||||||
|  |                   if (new_string == NULL) | ||||||
|  |                     { | ||||||
|  |                       new_len += r_len - f_len; | ||||||
|  |                     } | ||||||
|  |                   else | ||||||
|  |                     { | ||||||
|  |                       g_string_append_len (new_string, cur, next - cur); | ||||||
|  |                       g_string_append_len (new_string, replace, r_len); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |               cur = next + f_len; | ||||||
|  |             } | ||||||
|           if (n == limit) |           if (n == limit) | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |       /* @find is an empty string. */ | ||||||
|  |       if (f_len == 0) | ||||||
|  |         break; | ||||||
|  |  | ||||||
|  |       /* Append the trailing characters from after the final instance of @find | ||||||
|  |        * in the input string. */ | ||||||
|  |       if (r_len <= f_len) | ||||||
|  |         { | ||||||
|  |           /* First pass skipped. */ | ||||||
|  |           gchar *end = string->str + string->len; | ||||||
|  |           memmove (dst, cur, end - cur); | ||||||
|  |           end = dst + (end - cur); | ||||||
|  |           *end = 0; | ||||||
|  |           string->len = end - string->str; | ||||||
|  |           break; | ||||||
|  |         } | ||||||
|  |       else | ||||||
|  |         { | ||||||
|  |           if (new_string == NULL) | ||||||
|  |             { | ||||||
|  |               /* First pass. */ | ||||||
|  |               new_string = g_string_sized_new (new_len); | ||||||
|  |               g_string_append_len (new_string, string->str, first - string->str); | ||||||
|  |             } | ||||||
|  |           else | ||||||
|  |             { | ||||||
|  |               /* Second pass. */ | ||||||
|  |               g_string_append_len (new_string, cur, (string->str + string->len) - cur); | ||||||
|  |               g_free (string->str); | ||||||
|  |               string->allocated_len = new_string->allocated_len; | ||||||
|  |               string->len = new_string->len; | ||||||
|  |               string->str = g_string_free_and_steal (g_steal_pointer (&new_string)); | ||||||
|  |               break; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |   while (1); | ||||||
|  |  | ||||||
|   return n; |   return n; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user