diff --git a/lib/generic/array.h b/lib/generic/array.h
index 8fa93809fbe51e8f4a08d0972c98ba199b8112bb..96dcf19f0ffd8fa343a0e812e365db58b5fd5892 100644
--- a/lib/generic/array.h
+++ b/lib/generic/array.h
@@ -21,7 +21,7 @@
  * Be aware of that, as direct usage of the macros in the evaluating macros
  * may lead to different expectations, i.e.
  *
- *     MIN(array_push(arr, val))
+ *     MIN(array_push(arr, val), other)
  *
  *  May evaluate the code twice, leading to unexpected behaviour.
  *  This is a price to pay for absence of proper generics.
@@ -58,9 +58,40 @@
  */
 
 #pragma once
+#include <stdlib.h>
 
-/** @todo Implement mreserve over custom memory context. */
-#include <libknot/internal/mem.h>
+/** Simplified Qt containers growth strategy. */
+static inline size_t array_next_count(size_t want)
+{
+	if (want < 2048) {
+		return (want < 20) ? want + 4 : want * 2;
+	} else {
+		return want + 2048;
+	}
+}
+
+/** @internal Incremental memory reservation */
+static inline int array_std_reserve(void *baton, char **mem, size_t elm_size, size_t want, size_t *have)
+{
+	if (*have >= want) {
+		return 0;
+	}
+	/* Simplified Qt containers growth strategy */
+	size_t next_size = array_next_count(want);
+	void *mem_new = realloc(*mem, next_size * elm_size);
+	if (mem_new != NULL) {
+		*mem = mem_new;
+		*have = next_size;
+		return 0;
+	}
+	return -1;
+}
+
+/** @internal Wrapper for stdlib free. */
+static inline void array_std_free(void *baton, void *p)
+{
+	free(p);
+}
 
 /** Declare an array structure. */
 #define array_t(type) struct {type * at; size_t len; size_t cap; }
@@ -70,14 +101,20 @@
 
 /** Free and zero-initialize the array. */
 #define array_clear(array) \
-	free((array).at), array_init(array)
+	array_clear_mm(array, array_std_free, NULL)
+/** @internal Clear array with a callback. */
+#define array_clear_mm(array, free, baton) \
+	(free)((baton), (array).at), array_init(array)
 
 /**
  * Reserve capacity up to 'n' bytes.
  * @return >=0 if success
  */
 #define array_reserve(array, n) \
-	mreserve((char **) &(array).at, sizeof((array).at[0]), n, 0, &(array).cap)
+	array_reserve_mm(array, n, array_std_reserve, NULL)
+/** @internal Reserve capacity using callback. */
+#define array_reserve_mm(array, n, reserve, baton) \
+	(reserve)((baton), (char **) &(array).at, sizeof((array).at[0]), (n), &(array).cap)
 
 /**
  * Push value at the end of the array, resize it if necessary.
@@ -86,7 +123,7 @@
  */
 #define array_push(array, val) \
 	(array).len < (array).cap ? ((array).at[(array).len] = val, (array).len++) \
-		: (array_reserve(array, ((array).cap + 1) * 2) < 0 ? -1 \
+		: (array_reserve(array, ((array).cap + 1)) < 0 ? -1 \
 			: ((array).at[(array).len] = val, (array).len++))
 
 /**
diff --git a/lib/generic/map.c b/lib/generic/map.c
index 683db284658a8f0e090fe0cccf4546c0c8507132..86c2b19aa4deb26b662c9a7f0a3495309e895a92 100644
--- a/lib/generic/map.c
+++ b/lib/generic/map.c
@@ -53,12 +53,12 @@ static inline cb_node_t *ref_get_internal(uint8_t *p)
 }
 
 /* Standard memory allocation functions */
-static void *malloc_std(size_t size, void *baton) {
+static void *malloc_std(void *baton, size_t size) {
 	(void)baton; /* Prevent compiler warnings */
 	return malloc(size);
 }
 
-static void free_std(void *ptr, void *baton) {
+static void free_std(void *baton, void *ptr) {
 	(void)baton; /* Prevent compiler warnings */
 	free(ptr);
 }
@@ -71,9 +71,9 @@ static void cbt_traverse_delete(map_t *map, void *top)
 		cb_node_t *q = ref_get_internal(p);
 		cbt_traverse_delete(map, q->child[0]);
 		cbt_traverse_delete(map, q->child[1]);
-		map->free(q, map->baton);
+		map->free(map->baton, q);
 	} else {
-		map->free(p, map->baton);
+		map->free(map->baton, p);
 	}
 }
 
@@ -103,7 +103,7 @@ static int cbt_traverse_prefixed(void *top,
 
 static cb_data_t *cbt_make_data(map_t *map, const uint8_t *str, size_t len, void *value)
 {
-	cb_data_t *x = map->malloc(sizeof(cb_data_t) + len, map->baton);
+	cb_data_t *x = map->malloc(map->baton, sizeof(cb_data_t) + len);
 	if (x != NULL) {
 		x->value = value;
 		memcpy(x->key, str, len);
@@ -215,14 +215,14 @@ different_byte_found:
 	c = data->key[newbyte];
 	newdirection = (1 + (newotherbits | c)) >> 8;
 
-	newnode = map->malloc(sizeof(cb_node_t), map->baton);
+	newnode = map->malloc(map->baton, sizeof(cb_node_t));
 	if (newnode == NULL) {
 		return ENOMEM;
 	}
 
 	x = (uint8_t *)cbt_make_data(map, ubytes, ulen + 1, value);
 	if (x == NULL) {
-		map->free(newnode, map->baton);
+		map->free(map->baton, newnode);
 		return ENOMEM;
 	}
 
@@ -293,7 +293,7 @@ int map_del(map_t *map, const char *str)
 	if (strcmp(str, (const char *)data->key) != 0) {
 		return 1;
 	}
-	map->free(p, map->baton);
+	map->free(map->baton, p);
 
 	if (!whereq) {
 		map->root = NULL;
@@ -301,7 +301,7 @@ int map_del(map_t *map, const char *str)
 	}
 
 	*whereq = q->child[1 - direction];
-	map->free(q, map->baton);
+	map->free(map->baton, q);
 	return 0;
 }
 
diff --git a/lib/generic/map.h b/lib/generic/map.h
index 25258d198f34c4a38b8656ed1828b4cba1a41386..96ce01714709a8b9b783d80f9e6a73d2a944ef39 100644
--- a/lib/generic/map.h
+++ b/lib/generic/map.h
@@ -58,8 +58,8 @@ extern "C" {
 /*! Main data structure */
 typedef struct {
 	void *root;
-	void *(*malloc)(size_t size, void *baton);
-	void (*free)(void *ptr, void *baton);
+	void *(*malloc)(void *baton, size_t size);
+	void (*free)(void *baton, void *ptr);
 	void *baton; /*! Passed to malloc() and free() */
 } map_t;
 
diff --git a/lib/generic/pack.h b/lib/generic/pack.h
new file mode 100644
index 0000000000000000000000000000000000000000..171b7f1d3ca6286a40c2c043f88e0e9173798899
--- /dev/null
+++ b/lib/generic/pack.h
@@ -0,0 +1,118 @@
+/*  Copyright (C) 2015 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/>.
+ */
+
+/**
+ * Generics - array of lenght-prefixed packed objects
+ * 
+ * Each object is prefixed by item length, unlike array this structure 
+ * permits variable-length data. It is also equivallent to forward-only list
+ * backed by an array.
+ *
+ * @note Maximum object size is 2^16 bytes, @see pack_objlen_t
+ *
+ *  Example usage:
+ *
+ *     pack_t pack;
+ *     pack_init(pack);
+ *
+ *     // Reserve 2 objects, 6 bytes total
+ *     pack_reserve(pack, 2, 4 + 2);
+ *
+ *     // Push 2 objects
+ *     pack_obj_push(pack, U8("jedi"), 4)
+ *     pack_obj_push(pack, U8("\xbe\xef"), 2);
+ *
+ *     // Iterate length-value pairs
+ *     uint8_t *it = pack_head(pack);
+ *     while (it != pack_tail(pack)) {
+ *         uint8_t *val = pack_obj_val(it);
+ *         it = pack_obj_next(it);
+ *     }
+ *
+ *     pack_clear(pack);
+ *
+ * \addtogroup generics
+ * @{
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include "array.h"
+
+/** Packed object length type. */
+typedef uint16_t pack_objlen_t;
+
+/** Pack is defined as an array of bytes */
+typedef array_t(uint8_t) pack_t;
+
+/** Zero-initialize the pack. */
+#define pack_init(pack) \
+	array_init(pack)
+/** Free and the pack. */
+#define pack_clear(pack) \
+	array_clear(pack)
+/** @internal Clear pack with a callback. */
+#define pack_clear_mm(pack, free, baton) \
+	array_clear_mm(pack, array_std_free, baton)
+/** Incrementally reserve objects in the pack. */
+#define pack_reserve(pack, objs_count, objs_len) \
+	pack_reserve_mm((pack), (objs_count), (objs_len), array_std_reserve, NULL)
+/** @internal Reservation with a callback. */
+#define pack_reserve_mm(pack, objs_count, objs_len, reserve, baton) \
+	array_reserve_mm((pack), (pack).len + (sizeof(pack_objlen_t)*(objs_count) + (objs_len)), (reserve), (baton))
+/** Return pointer to first packed object. */
+#define pack_head(pack) \
+	&((pack).at[0])
+/** Return pack end pointer. */
+#define pack_tail(pack) \
+	&((pack).at[(pack).len])
+
+/** Return packed object length. */
+static inline pack_objlen_t pack_obj_len(uint8_t *it)
+{
+	pack_objlen_t len = 0;
+	memcpy(&len, it, sizeof(len));
+	return len;
+}
+
+/** Return packed object value. */
+static inline uint8_t *pack_obj_val(uint8_t *it)
+{
+	return it + sizeof(pack_objlen_t);
+}
+
+/** Return pointer to next packed object. */
+static inline uint8_t *pack_obj_next(uint8_t *it)
+{
+	return pack_obj_val(it) + pack_obj_len(it);
+}
+
+/** Push object to the end of the pack
+  * @return 0 on success, negative number on failure
+  */
+static inline int pack_obj_push(pack_t *pack, const uint8_t *obj, pack_objlen_t len)
+{
+	uint8_t *endp = pack_tail(*pack);
+	size_t packed_len = len + sizeof(len);
+	if (pack == NULL || (pack->len + packed_len) > pack->cap) {
+		return -1;
+	}
+
+	memcpy(endp, (char *)&len, sizeof(len));
+	memcpy(endp + sizeof(len), obj, len);
+	pack->len += packed_len;
+	return 0;
+}
\ No newline at end of file
diff --git a/tests/test_pack.c b/tests/test_pack.c
new file mode 100644
index 0000000000000000000000000000000000000000..27c09bffdea585b62964162bd58b67e9869fa4b9
--- /dev/null
+++ b/tests/test_pack.c
@@ -0,0 +1,64 @@
+/*  Copyright (C) 2015 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/>.
+ */
+
+#include "tests/test.h"
+#include "lib/generic/pack.h"
+
+#define U8(x) (const uint8_t *)(x)
+mm_ctx_t global_mm;
+
+static void test_pack_std(void **state)
+{
+	int ret = 0;
+	pack_t pack;
+	pack_init(pack);
+	assert_int_equal(pack.len, 0);
+
+	/* Push without reservation. */
+	assert_int_not_equal(pack_obj_push(&pack, U8(""), 1), 0);
+
+	/* Reserve capacity and fill. */
+	assert_true(pack_reserve(pack, 10, 10 * 2) >= 0);
+	for (unsigned i = 0; i < 10; ++i) {
+		ret = pack_obj_push(&pack, U8("de"), 2);
+		assert_true(ret >= 0);
+	}
+
+	/* Iterate */
+	uint8_t *it = pack_head(pack);
+	assert_non_null(it);
+	unsigned count = 0;
+	while (it != pack_tail(pack)) {
+		assert_int_equal(pack_obj_len(it), 2);
+		assert_true(memcmp(pack_obj_val(it), "de", 2) == 0);
+		it = pack_obj_next(it);
+		count += 1;
+	}
+
+
+	pack_clear(pack);
+}
+
+int main(void)
+{
+	test_mm_ctx_init(&global_mm);
+
+	const UnitTest tests[] = {
+		unit_test(test_pack_std),
+	};
+
+	return run_tests(tests);
+}
diff --git a/tests/unit.mk b/tests/unit.mk
index d6e09da09444103998632b8e76d408dc06408b65..d8ac592e79ef0095b506df2c1d4e16c12efdcefe 100644
--- a/tests/unit.mk
+++ b/tests/unit.mk
@@ -6,6 +6,7 @@ tests_BIN := \
 	test_set \
 	test_map \
 	test_array \
+	test_pack \
 	test_utils \
 	test_module \
 	test_rplan \