git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 18/21] strbuf: allow "buf" to point to the middle of the allocated buffer

From
Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Date
Dec 15, 2010, 15:02 UTC
Message-ID
<1292425376-14550-19-git-send-email-pclouds@gmail.com>
In-Reply-To
<1292425376-14550-1-git-send-email-pclouds@gmail.com>

This allows offseting buf forward by neglen bytes. This patch makes sure that reallocation works even when buf is not at the top of allocated region.

Many functions are not aware that there could be data before buf. Use with care.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 strbuf.c |   36 ++++++++++++++++++++++++++----------
 strbuf.h |   10 ++++++----
 2 files changed, 32 insertions(+), 14 deletions(-)
diff --git a/strbuf.c b/strbuf.c
index bc3a080..12cda6f 100644
--- a/strbuf.c
+++ b/strbuf.c
@@ -28,8 +28,10 @@ char strbuf_slopbuf[1];
 
 void strbuf_init(struct strbuf *sb, size_t hint)
 {
-	sb->alloc = sb->len = 0;
-	sb->buf = strbuf_slopbuf;
+	sb->alloc  = 0;
+	sb->len	   = 0;
+	sb->neglen = 0;
+	sb->buf	   = strbuf_slopbuf;
 	if (hint)
 		strbuf_grow(sb, hint);
 }
@@ -37,7 +39,7 @@ void strbuf_init(struct strbuf *sb, size_t hint)
 void strbuf_release(struct strbuf *sb)
 {
 	if (sb->alloc) {
-		free(sb->buf);
+		free(sb->buf - sb->neglen);
 		strbuf_init(sb, 0);
 	}
 }
@@ -45,6 +47,8 @@ void strbuf_release(struct strbuf *sb)
 char *strbuf_detach(struct strbuf *sb, size_t *sz)
 {
 	char *res = sb->alloc ? sb->buf : NULL;
+	if (sb->neglen)
+		die("shift buf back before detaching");
 	if (sz)
 		*sz = sb->len;
 	strbuf_init(sb, 0);
@@ -54,20 +58,23 @@ char *strbuf_detach(struct strbuf *sb, size_t *sz)
 void strbuf_attach(struct strbuf *sb, void *buf, size_t len, size_t alloc)
 {
 	strbuf_release(sb);
-	sb->buf   = buf;
-	sb->len   = len;
-	sb->alloc = alloc;
+	sb->buf    = buf;
+	sb->len    = len;
+	sb->neglen = 0;
+	sb->alloc  = alloc;
 	strbuf_grow(sb, 0);
 	sb->buf[sb->len] = '\0';
 }
 
 void strbuf_grow(struct strbuf *sb, size_t extra)
 {
-	if (sb->len + extra + 1 <= sb->len)
+	char *buf = !sb->alloc ? NULL : sb->buf - sb->neglen;
+	int len = sb->neglen + sb->len;
+
+	if (len + extra + 1 <= len)
 		die("you want to use way too much memory");
-	if (!sb->alloc)
-		sb->buf = NULL;
-	ALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc);
+	ALLOC_GROW(buf, len + extra + 1, sb->alloc);
+	sb->buf = buf + sb->neglen;
 }
 
 void strbuf_trim(struct strbuf *sb)
@@ -402,3 +409,12 @@ int strbuf_check_branch_ref(struct strbuf *sb, const char *name)
 	strbuf_splice(sb, 0, 0, "refs/heads/", 11);
 	return check_ref_format(sb->buf);
 }
+
+void strbuf_offset(struct strbuf *sb, int offset)
+{
+	if (offset > sb->len || offset < sb->neglen)
+		die("you cannot offset out of allocated buffer");
+	sb->buf	   += offset;
+	sb->neglen += offset;
+	sb->len	   -= offset;
+}
diff --git a/strbuf.h b/strbuf.h
index fac2dbc..3c3b146 100644
--- a/strbuf.h
+++ b/strbuf.h
@@ -43,11 +43,11 @@
 extern char strbuf_slopbuf[];
 struct strbuf {
 	size_t alloc;
-	size_t len;
+	size_t len, neglen;
 	char *buf;
 };
 
-#define STRBUF_INIT  { 0, 0, strbuf_slopbuf }
+#define STRBUF_INIT  { 0, 0, 0, strbuf_slopbuf }
 
 /*----- strbuf life cycle -----*/
 extern void strbuf_init(struct strbuf *, size_t);
@@ -62,7 +62,7 @@ static inline void strbuf_swap(struct strbuf *a, struct strbuf *b) {
 
 /*----- strbuf size related -----*/
 static inline size_t strbuf_avail(const struct strbuf *sb) {
-	return sb->alloc ? sb->alloc - sb->len - 1 : 0;
+	return sb->alloc ? sb->alloc - sb->len - sb->neglen - 1 : 0;
 }
 
 extern void strbuf_grow(struct strbuf *, size_t);
@@ -70,7 +70,7 @@ extern void strbuf_grow(struct strbuf *, size_t);
 static inline void strbuf_setlen(struct strbuf *sb, size_t len) {
 	if (!sb->alloc)
 		strbuf_grow(sb, 0);
-	assert(len < sb->alloc);
+	assert(sb->neglen + len < sb->alloc);
 	sb->len = len;
 	sb->buf[len] = '\0';
 }
@@ -136,4 +136,6 @@ extern int launch_editor(const char *path, struct strbuf *buffer, const char *co
 extern int strbuf_branchname(struct strbuf *sb, const char *name);
 extern int strbuf_check_branch_ref(struct strbuf *sb, const char *name);
 
+extern void strbuf_offset(struct strbuf *sb, int offset);
+
 #endif /* STRBUF_H */
-- 
1.7.3.3.476.g10a82
Previous: Nguyễn Thái Ngọc DuyNext: Nguyễn Thái Ngọc Duy
Message 37 of 44 in “nd/struct-pathspec v2”
  1. 00/21 nd/struct-pathspec v2Nguyễn Thái Ngọc Duy, Dec 15, 2010
  2. 01/21 Add struct pathspecNguyễn Thái Ngọc Duy, Dec 15, 2010
  3. 02/21 diff-no-index: use diff_tree_setup_paths()Nguyễn Thái Ngọc Duy, Dec 15, 2010
  4. 03/21 Convert struct diff_options to use struct pathspecNguyễn Thái Ngọc Duy, Dec 15, 2010
  5. 04/21 tree_entry_interesting(): remove dependency on struct diff_optionsNguyễn Thái Ngọc Duy, Dec 15, 2010
  6. 05/21 Move tree_entry_interesting() to tree-walk.c and export itNguyễn Thái Ngọc Duy, Dec 15, 2010
  7. 06/21 glossary: define pathspecNguyễn Thái Ngọc Duy, Dec 15, 2010
  8. 07/21 diff-tree: convert base+baselen to writable strbufNguyễn Thái Ngọc Duy, Dec 15, 2010
  9. 08/21 tree_entry_interesting(): refactor into separate smaller functionsNguyễn Thái Ngọc Duy, Dec 15, 2010
  10. 09/21 tree_entry_interesting(): support depth limitNguyễn Thái Ngọc Duy, Dec 15, 2010
  11. Junio C HamanoJan 28, 2011
  12. Nguyen Thai Ngoc DuyJan 29, 2011
  13. tree_entry_interesting(): with no pathspecs, everything will matchJunio C Hamano, Jan 31, 2011
  14. 10/21 tree_entry_interesting(): fix depth limit with overlapping pathspecsNguyễn Thái Ngọc Duy, Dec 15, 2010
  15. Junio C HamanoDec 16, 2010
  16. Nguyen Thai Ngoc DuyDec 17, 2010
  17. Junio C HamanoDec 17, 2010
  18. Nguyen Thai Ngoc DuyDec 18, 2010
  19. 11/21 tree_entry_interesting(): support wildcard matchingNguyễn Thái Ngọc Duy, Dec 15, 2010
  20. diff-tree doc: correct & remove wrong documentationÆvar Arnfjörð Bjarmason, Feb 4, 2019
  21. Duy NguyenFeb 4, 2019
  22. Junio C HamanoFeb 4, 2019
  23. Ævar Arnfjörð BjarmasonFeb 4, 2019
  24. 12/21 tree_entry_interesting(): optimize wildcard matching when base is matchedNguyễn Thái Ngọc Duy, Dec 15, 2010
  25. 13/21 pathspec: add match_pathspec_depth()Nguyễn Thái Ngọc Duy, Dec 15, 2010
  26. 14/21 Convert ce_path_match() to use struct pathspecNguyễn Thái Ngọc Duy, Dec 15, 2010
  27. Junio C HamanoDec 17, 2010
  28. Nguyen Thai Ngoc DuyDec 17, 2010
  29. 14/21 struct rev_info: convert prune_data to struct pathspecNguyễn Thái Ngọc Duy, Dec 17, 2010
  30. 15/21 Convert ce_path_match() to use struct pathspecNguyễn Thái Ngọc Duy, Dec 17, 2010
  31. Junio C HamanoDec 17, 2010
  32. Nguyen Thai Ngoc DuyDec 17, 2010
  33. Junio C HamanoDec 17, 2010
  34. 15/21 Convert ce_path_match() to use match_pathspec_depth()Nguyễn Thái Ngọc Duy, Dec 15, 2010
  35. 16/21 grep: convert to use struct pathspecNguyễn Thái Ngọc Duy, Dec 15, 2010
  36. 17/21 grep: use match_pathspec_depth() for cache/worktree greppingNguyễn Thái Ngọc Duy, Dec 15, 2010
  37. 18/21 strbuf: allow "buf" to point to the middle of the allocated bufferNguyễn Thái Ngọc Duy, Dec 15, 2010
  38. 19/21 grep: use writable strbuf from caller in grep_tree()Nguyễn Thái Ngọc Duy, Dec 15, 2010
  39. Junio C HamanoDec 17, 2010
  40. Nguyen Thai Ngoc DuyDec 17, 2010
  41. 19/21 grep: use writable strbuf from caller for grep_tree()Nguyễn Thái Ngọc Duy, Dec 17, 2010
  42. 20/21 grep: drop pathspec_matches() in favor of tree_entry_interesting()Nguyễn Thái Ngọc Duy, Dec 15, 2010
  43. 20/21 grep: drop pathspec_matches() in favor of tree_entry_interesting()Nguyễn Thái Ngọc Duy, Dec 17, 2010
  44. 21/21 t7810: overlapping pathspecs and depth limitNguyễn Thái Ngọc Duy, Dec 15, 2010

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.