Browse Source

libobs/util: Optimize strlist_* functions

When splitting a string in to a string list via stringlist_split, it
would previously allocate memory for each sub-string and again for the
list itself.  This optimizes that function to use a single contiguous
chunk of memory for the sake of access optimization and memory
allocation efficiency.
jp9000 8 years ago
parent
commit
97ec7166b7
1 changed files with 51 additions and 22 deletions
  1. 51 22
      libobs/util/dstr.c

+ 51 - 22
libobs/util/dstr.c

@@ -262,49 +262,78 @@ wchar_t *wcsdepad(wchar_t *str)
 
 char **strlist_split(const char *str, char split_ch, bool include_empty)
 {
-	const char    *cur_str = str;
-	const char    *next_str;
-	const char    *new_str;
-	DARRAY(char*) list;
-
-	da_init(list);
+	const char *cur_str = str;
+	const char *next_str;
+	char *      out = NULL;
+	size_t      count = 0;
+	size_t      total_size = 0;
 
 	if (str) {
+		char **table;
+		char *offset;
+		size_t cur_idx = 0;
+		size_t cur_pos = 0;
+
 		next_str = strchr(str, split_ch);
 
 		while (next_str) {
 			size_t size = next_str - cur_str;
 
 			if (size || include_empty) {
-				new_str = bstrdup_n(cur_str, size);
-				da_push_back(list, &new_str);
+				++count;
+				total_size += size + 1;
 			}
 
-			cur_str = next_str+1;
+			cur_str = next_str + 1;
 			next_str = strchr(cur_str, split_ch);
 		}
 
 		if (*cur_str || include_empty) {
-			new_str = bstrdup(cur_str);
-			da_push_back(list, &new_str);
+			++count;
+			total_size += strlen(cur_str) + 1;
 		}
-	}
 
-	new_str = NULL;
-	da_push_back(list, &new_str);
+		/* ------------------ */
+
+		cur_pos    = (count + 1) * sizeof(char *);
+		total_size += cur_pos;
+		out        = bmalloc(total_size);
+		offset     = out + cur_pos;
+		table      = (char **)out;
+
+		/* ------------------ */
+
+		next_str = strchr(str, split_ch);
+		cur_str  = str;
+
+		while (next_str) {
+			size_t size = next_str - cur_str;
+
+			if (size || include_empty) {
+				table[cur_idx++] = offset;
+				strncpy(offset, cur_str, size);
+				offset[size] = 0;
+				offset += size + 1;
+			}
+
+			cur_str = next_str + 1;
+			next_str = strchr(cur_str, split_ch);
+		}
+
+		if (*cur_str || include_empty) {
+			table[cur_idx++] = offset;
+			strcpy(offset, cur_str);
+		}
+
+		table[cur_idx] = NULL;
+	}
 
-	return list.array;
+	return (char**)out;
 }
 
 void strlist_free(char **strlist)
 {
-	if (strlist) {
-		char **temp = strlist;
-		while (*temp)
-			bfree(*(temp++));
-
-		bfree(strlist);
-	}
+	bfree(strlist);
 }
 
 void dstr_init_copy_strref(struct dstr *dst, const struct strref *src)