[Mesa-dev] [PATCH 1/2] util: add stringbuf library

Nicolai Hähnle nhaehnle at gmail.com
Sat Aug 26 14:11:47 UTC 2017


From: Nicolai Hähnle <nicolai.haehnle at amd.com>

For building long strings by successive append operations.
---
 src/util/Makefile.sources |   2 +
 src/util/stringbuf.c      | 185 ++++++++++++++++++++++++++++++++++++++++++++++
 src/util/stringbuf.h      |  97 ++++++++++++++++++++++++
 3 files changed, 284 insertions(+)
 create mode 100644 src/util/stringbuf.c
 create mode 100644 src/util/stringbuf.h

diff --git a/src/util/Makefile.sources b/src/util/Makefile.sources
index 3315285f05e..b7744fe8cb0 100644
--- a/src/util/Makefile.sources
+++ b/src/util/Makefile.sources
@@ -32,20 +32,22 @@ MESA_UTIL_FILES := \
 	rgtc.c \
 	rgtc.h \
 	rounding.h \
 	set.c \
 	set.h \
 	simple_list.h \
 	slab.c \
 	slab.h \
 	string_to_uint_map.cpp \
 	string_to_uint_map.h \
+	stringbuf.c \
+	stringbuf.h \
 	strndup.h \
 	strtod.c \
 	strtod.h \
 	texcompress_rgtc_tmp.h \
 	u_atomic.c \
 	u_atomic.h \
 	u_dynarray.h \
 	u_endian.h \
 	u_queue.c \
 	u_queue.h \
diff --git a/src/util/stringbuf.c b/src/util/stringbuf.c
new file mode 100644
index 00000000000..b9a2a624fb5
--- /dev/null
+++ b/src/util/stringbuf.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2017 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "stringbuf.h"
+
+#include <limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "ralloc.h"
+#include "u_string.h"
+
+struct stringbuf_chunk {
+   struct stringbuf_chunk *next;
+   unsigned len, max;
+   char buf[];
+};
+
+struct stringbuf {
+   struct stringbuf_chunk *head;
+   struct stringbuf_chunk *tail;
+   unsigned size;
+   bool error;
+};
+
+
+struct stringbuf *
+stringbuf_new(void *parent)
+{
+   static const unsigned initial_max = 512;
+   struct stringbuf *sb = rzalloc_size(parent, sizeof(*sb));
+   if (!sb)
+      return NULL;
+
+   sb->head = sb->tail = ralloc_size(sb, sizeof(*sb->head) + initial_max);
+   if (!sb->head) {
+      ralloc_free(sb);
+      return NULL;
+   }
+   sb->head->next = NULL;
+   sb->head->len = 0;
+   sb->head->max = initial_max;
+   return sb;
+}
+
+char *
+stringbuf_build(struct stringbuf *sb)
+{
+   if (sb->error)
+      return NULL;
+
+   char *result = ralloc_size(ralloc_parent(sb), sb->size + 1);
+   char *p = result;
+
+   for (struct stringbuf_chunk *chunk = sb->head; chunk; chunk = chunk->next) {
+      memcpy(p, chunk->buf, chunk->len);
+      p += chunk->len;
+   }
+   assert(p - result == sb->size);
+   *p = 0;
+
+   return result;
+}
+
+bool
+stringbuf_error(struct stringbuf *sb)
+{
+   return sb->error;
+}
+
+static struct stringbuf_chunk *
+stringbuf_new_chunk(struct stringbuf *sb, size_t min_size)
+{
+   size_t size = MAX3(min_size, sb->tail->max, sb->size / 4);
+   if (UINT_MAX - sb->size < size) {
+      sb->error = true;
+      return NULL;
+   }
+
+   struct stringbuf_chunk *chunk = ralloc_size(sb, sizeof(*chunk) + size);
+   if (!chunk) {
+      sb->error = true;
+      return NULL;
+   }
+
+   chunk->next = NULL;
+   chunk->len = 0;
+   chunk->max = size;
+
+   sb->tail->next = chunk;
+   sb->tail = chunk;
+   return chunk;
+}
+
+bool
+stringbuf_append(struct stringbuf *sb, const char *str, size_t str_size)
+{
+   struct stringbuf_chunk *chunk = sb->tail;
+
+   if (chunk->max - chunk->len < str_size) {
+      chunk = stringbuf_new_chunk(sb, str_size);
+      if (!chunk)
+         return false;
+   }
+
+   memcpy(chunk->buf + chunk->len, str, str_size);
+   chunk->len += str_size;
+   sb->size += str_size;
+   return true;
+}
+
+bool
+stringbuf_vprintf(struct stringbuf *sb, const char *fmt, va_list va)
+{
+   struct stringbuf_chunk *chunk = sb->tail;
+   va_list va_copy;
+   int ret, ret_retry;
+
+   va_copy(va_copy, va);
+
+   ret = util_vsnprintf(chunk->buf + chunk->len, chunk->max - chunk->len, fmt, va);
+   if (ret < 0) {
+      sb->error = true;
+      return false;
+   }
+
+   if (ret <= chunk->max - chunk->len) {
+      chunk->len += ret;
+      sb->size += ret;
+      return true;
+   }
+
+   chunk = stringbuf_new_chunk(sb, ret + 1);
+   if (!chunk)
+      return false;
+
+   assert(chunk->len == 0);
+   ret_retry = vsnprintf(chunk->buf, chunk->max, fmt, va_copy);
+   if (ret_retry < 0) {
+      sb->error = true;
+      return false;
+   }
+
+   assert(ret_retry == ret);
+   assert(ret_retry < chunk->max);
+
+   chunk->len = ret_retry;
+   sb->size += ret_retry;
+   return true;
+}
+
+bool
+stringbuf_printf(struct stringbuf *sb, const char *fmt, ...)
+{
+   va_list va;
+   bool ret;
+
+   va_start(va, fmt);
+   ret = stringbuf_vprintf(sb, fmt, va);
+   va_end(va);
+
+   return ret;
+}
+
diff --git a/src/util/stringbuf.h b/src/util/stringbuf.h
new file mode 100644
index 00000000000..ca11234d0ec
--- /dev/null
+++ b/src/util/stringbuf.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2017 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef STRINGBUF_H
+#define STRINGBUF_H
+
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+#include "macros.h"
+
+/**
+ * \file stringbuf.h
+ *
+ * ralloc-based sring buffer suitable for building large strings by appending.
+ */
+
+struct stringbuf;
+
+/**
+ * Create a new string buffer with the given ralloc parent.
+ *
+ * All internal allocations will be children of the main stringbuf object,
+ * so you can use \ref ralloc_free to free a stringbuf.
+ */
+struct stringbuf *stringbuf_new(void *parent) MALLOCLIKE;
+
+/**
+ * Concatenate all the pieces that were appended to the string buffer into
+ * one big string.
+ *
+ * This will fail if a memory allocation error occurred during any append
+ * operation on \p sb. On the other hand, if memory allocation fails during
+ * the concatenation, the error flag of \p sb is \em not set.
+ *
+ * \return A NUL-terminated, newly allocated copy of the final string. Its
+ * ralloc parent will be the parent of \p sb.
+ */
+char *stringbuf_build(struct stringbuf *sb) MALLOCLIKE;
+
+/**
+ * Check whether a memory allocation error occurred during any operation on
+ * \p sb (except for \ref stringbuf_build).
+ *
+ * Basically, this yields one summary error flag that can be checked after all
+ * append operations instead of checking the return value of each individual
+ * append operation.
+ *
+ * \return True if any memory allocation failed during appending to \p sb.
+ */
+bool stringbuf_error(struct stringbuf *sb);
+
+/**
+ * Append \p str_size bytes of \p str to \p sb.
+ *
+ * No strlen calls are made.
+ *
+ * \return True unless memory allocation failed.
+ */
+bool stringbuf_append(struct stringbuf *sb, const char *str, size_t str_size);
+
+/**
+ * Append a formatted string to \p sb.
+ *
+ * \return True unless memory allocation failed.
+ */
+bool stringbuf_vprintf(struct stringbuf *sb, const char *fmt, va_list va);
+
+/**
+ * Append a formatted string to \p sb.
+ *
+ * \return True unless memory allocation failed.
+ */
+bool stringbuf_printf(struct stringbuf *sb, const char *fmt, ...) PRINTFLIKE(2, 3);
+
+#endif /* STRINGBUF_H */
-- 
2.11.0



More information about the mesa-dev mailing list