From fd2d87ad5c93342e07842fb46f46a09b19ec2473 Mon Sep 17 00:00:00 2001
From: Libor Peltan <libor.peltan@nic.cz>
Date: Mon, 16 Jan 2017 15:19:41 +0100
Subject: [PATCH] contrib: added dynamic array

---
 Knot.files             |  1 +
 src/Makefile.am        |  1 +
 src/contrib/dynarray.h | 92 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 94 insertions(+)
 create mode 100644 src/contrib/dynarray.h

diff --git a/Knot.files b/Knot.files
index 129b41dd8b..b2c9c77ba0 100644
--- a/Knot.files
+++ b/Knot.files
@@ -21,6 +21,7 @@ src/contrib/dnstap/reader.c
 src/contrib/dnstap/reader.h
 src/contrib/dnstap/writer.c
 src/contrib/dnstap/writer.h
+src/contrib/dynarray.h
 src/contrib/endian.h
 src/contrib/files.c
 src/contrib/files.h
diff --git a/src/Makefile.am b/src/Makefile.am
index 00b1f98951..46ad861dbc 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -40,6 +40,7 @@ libcontrib_la_SOURCES = 			\
 	contrib/base32hex.h			\
 	contrib/base64.c			\
 	contrib/base64.h			\
+	contrib/dynarray.h			\
 	contrib/endian.h			\
 	contrib/files.c				\
 	contrib/files.h				\
diff --git a/src/contrib/dynarray.h b/src/contrib/dynarray.h
new file mode 100644
index 0000000000..adb8aa144c
--- /dev/null
+++ b/src/contrib/dynarray.h
@@ -0,0 +1,92 @@
+/*  Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*!
+ * \brief Simple write-once allocation-optimal dynamic array.
+ *
+ * Include it into your .c file
+ *
+ * prefix - identifier prefix, e.g. ptr -> struct ptr_dynarray, ptr_dynarray_add(), ...
+ * ntype - data type to be stored. Let it be a number, pointer or small struct
+ * initial_capacity - how many data items will be allocated on stac and copied with assignment
+ *
+ * prefix_dynarray_add() - add a data item
+ * prefix_dynarray_fix() - call EVERYTIME the array is copied from some already invalid stack
+ * prefix_dynarray_free() - call EVERYTIME you dismiss all copies of the array
+ *
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+
+#pragma once
+
+#define dynarray_define(prefix, ntype, initial_capacity) \
+	\
+	struct prefix ## _dynarray { \
+		ssize_t capacity; \
+		ssize_t size; \
+		ntype init[initial_capacity]; \
+		ntype *arr; \
+	}; \
+	\
+	static void prefix ## _dynarray_free__(struct prefix ## _dynarray *dynarray) \
+	{ \
+		if (dynarray->capacity > initial_capacity) { \
+			free(dynarray->arr); \
+		} \
+	} \
+	\
+	__attribute__((unused)) \
+	static void prefix ## _dynarray_fix(struct prefix ## _dynarray *dynarray) \
+	{ \
+		assert(dynarray->size <= dynarray->capacity); \
+		if (dynarray->capacity <= initial_capacity) { \
+			dynarray->capacity = initial_capacity; \
+			dynarray->arr = dynarray->init; \
+		} \
+	} \
+	\
+	__attribute__((unused)) \
+	static void prefix ## _dynarray_add(struct prefix ## _dynarray *dynarray, \
+	                                    ntype const *to_add) \
+	{ \
+		prefix ## _dynarray_fix(dynarray); \
+		if (dynarray->size >= dynarray->capacity) { \
+			ssize_t new_capacity = dynarray->capacity * 2 + 1; \
+			ntype *new_arr = calloc(new_capacity, sizeof(ntype)); \
+			if (new_arr == NULL) { \
+				prefix ## _dynarray_free__(dynarray); \
+				dynarray->capacity = dynarray->size = -1; \
+				return; \
+			} \
+			if (dynarray->capacity > 0) { \
+				memcpy(new_arr, dynarray->arr, \
+				       dynarray->capacity * sizeof(ntype)); \
+			} \
+			prefix ## _dynarray_free__(dynarray); \
+			dynarray->arr = new_arr; \
+			dynarray->capacity = new_capacity; \
+		} \
+		dynarray->arr[dynarray->size++] = *to_add; \
+	} \
+	\
+	__attribute__((unused)) \
+	static void prefix ## _dynarray_free(struct prefix ## _dynarray *dynarray) \
+	{ \
+		prefix ## _dynarray_free__(dynarray); \
+		memset(dynarray, 0, sizeof(*dynarray)); \
+	}
-- 
GitLab