From 3bfa164e69fd5a7dfad6a1dd31b2ffb9d6f5575f Mon Sep 17 00:00:00 2001
From: Evgeny Voropaev <evorop@gmail.com>
Date: Mon, 13 Apr 2026 20:12:55 +0800
Subject: [PATCH v11 1/5] Implement vect and uniqsortvect containers and
 bitpack algorithms.

The vect container stores arrays of integers and provides a set of
algorithms implementing essential operations on the contained array,
such as initialization, appending, inserting, and clearing.

The uniqsortvect container is based on the vect type but assumes that
its elements are sorted and unique. In addition to the algorithms
provided by vect, uniqsortvect implements binary search and the
specialized insertion routine.

The containers support both external memory provided by a caller and
automatically managed memory using malloc, Postgres's palloc, or similar
allocation functions. A container's strategy regarding memory management
must be set at container initialization, and all subsequent operations
honor this configuration. For example, a caller can place a buffer on
the stack to avoid heap allocation and pass the buffer to a vector
instance, which results in the vector performs no dynamic allocation.

This commit also introduces the bitpack unit, which provides algorithms
for dense bit-level packing and unpacking. The bitpack unit does not
use dynamic memory.

Each unit (vect, bitpack) is implemented as a set of templates that
allows developers to generate specialized solutions for any integer type
(uint8, int8, uint16, int16, and so on). The units bitpack_u16 and
vect_u16 supporting the uint16_t type are also provided by this commit.

Author: Evgeny Voropaev <evgeny.voropaev@tantorlabs.com> <evorop@gmail.com>
Reviewed by: Andrey Borodin <x4mmm@yandex-team.ru>
---
 src/backend/lib/Makefile               |   5 +
 src/backend/lib/Makefile.dfor          |   5 +
 src/backend/lib/bitpack_templ.c        | 156 +++++++++++++
 src/backend/lib/bitpack_u16.c          |   8 +
 src/backend/lib/meson.build            |   7 +
 src/backend/lib/vect_templ.c           | 301 +++++++++++++++++++++++++
 src/backend/lib/vect_u16.c             |   8 +
 src/include/c.h                        |   4 +
 src/include/lib/bitpack_staple_templ.h |  57 +++++
 src/include/lib/bitpack_templ.h        |  14 ++
 src/include/lib/bitpack_templ_undef.h  |   5 +
 src/include/lib/bitpack_u16.h          |  12 +
 src/include/lib/bitpack_u16_config.h   |   6 +
 src/include/lib/vect_templ.h           |  27 +++
 src/include/lib/vect_templ_staple.h    | 140 ++++++++++++
 src/include/lib/vect_templ_undef.h     |  25 ++
 src/include/lib/vect_u16.h             |  34 +++
 src/include/lib/vect_u16_config.h      |  10 +
 18 files changed, 824 insertions(+)
 create mode 100644 src/backend/lib/Makefile.dfor
 create mode 100644 src/backend/lib/bitpack_templ.c
 create mode 100644 src/backend/lib/bitpack_u16.c
 create mode 100644 src/backend/lib/vect_templ.c
 create mode 100644 src/backend/lib/vect_u16.c
 create mode 100644 src/include/lib/bitpack_staple_templ.h
 create mode 100644 src/include/lib/bitpack_templ.h
 create mode 100644 src/include/lib/bitpack_templ_undef.h
 create mode 100644 src/include/lib/bitpack_u16.h
 create mode 100644 src/include/lib/bitpack_u16_config.h
 create mode 100644 src/include/lib/vect_templ.h
 create mode 100644 src/include/lib/vect_templ_staple.h
 create mode 100644 src/include/lib/vect_templ_undef.h
 create mode 100644 src/include/lib/vect_u16.h
 create mode 100644 src/include/lib/vect_u16_config.h

diff --git a/src/backend/lib/Makefile b/src/backend/lib/Makefile
index b6cefd9cca0..74167bc9e4c 100644
--- a/src/backend/lib/Makefile
+++ b/src/backend/lib/Makefile
@@ -12,6 +12,8 @@ subdir = src/backend/lib
 top_builddir = ../../..
 include $(top_builddir)/src/Makefile.global
 
+include Makefile.dfor
+
 OBJS = \
 	bipartite_match.o \
 	bloomfilter.o \
@@ -22,5 +24,8 @@ OBJS = \
 	knapsack.o \
 	pairingheap.o \
 	rbtree.o \
+	$(OBJS_DFOR) \
+
+CPPFLAGS := -I$(top_srcdir)/src/backend/lib $(CPPFLAGS)
 
 include $(top_srcdir)/src/backend/common.mk
diff --git a/src/backend/lib/Makefile.dfor b/src/backend/lib/Makefile.dfor
new file mode 100644
index 00000000000..b93c6e78644
--- /dev/null
+++ b/src/backend/lib/Makefile.dfor
@@ -0,0 +1,5 @@
+# Makefile.dfor
+
+OBJS_DFOR := \
+	bitpack_u16.o \
+	vect_u16.o
diff --git a/src/backend/lib/bitpack_templ.c b/src/backend/lib/bitpack_templ.c
new file mode 100644
index 00000000000..5f721ea1ebc
--- /dev/null
+++ b/src/backend/lib/bitpack_templ.c
@@ -0,0 +1,156 @@
+/*
+ * bitpack_templ.c
+ *
+ * The BITPACK unit implements routines pertaining to bit-packing. The bitpack
+ * unit allow higher-level functions to create high-density arrays packed
+ * bit-by-bit. In general, width of each item in a bitpacked array can vary and
+ * have not to be of fixed size, items can have different length.
+ */
+
+#include "lib/bitpack_staple_templ.h"
+
+item_t width_from_val(item_t val);
+item_t width_to_mask(size_t width);
+size_t bitpack_pack(uint8_t *pack, size_t caret, item_t item,
+					size_t szItemWidth);
+item_t bitpack_unpack(const uint8_t *pack, size_t *caret, size_t szItemWidth);
+
+/*
+ * Since width of item_t cannot be more than length of item_t
+ * lg(MAX(item_t))+1, we use the item_t type for returned value
+ */
+item_t
+width_from_val(item_t val)
+{
+	item_t width = 0;
+
+	while (val) {
+		width++;
+		val = val >> 1;
+	}
+
+	return width == 0 ? 1 : width;
+}
+
+item_t
+width_to_mask(size_t width)
+{
+	size_t mask = 0;
+
+	Assert(width != 0);
+	Assert(width <= sizeof(item_t) * 8);
+
+	if (likely(width < sizeof(size_t)))
+		mask = (1 << width) - 1;
+	else
+		while (width--)
+			mask = (mask << 1) | 1;
+
+	return (item_t)mask;
+}
+
+size_t
+bitpack_pack(uint8_t *pack, size_t caret, item_t item, size_t szItemWidth)
+{
+	size_t szItemWidthToGo = szItemWidth;
+	item_t itmMaskToGo = width_to_mask(szItemWidth);
+
+	while (szItemWidthToGo > 0) {
+		size_t cntSavedBits;
+		size_t byte = caret / 8;
+		size_t off = caret % 8;
+		uint8_t ubChunk = (uint8_t)item << off;
+		item_t itmChunkMask = itmMaskToGo << off;
+		/*
+		 * Applying chunk using the mask. Setting bits to one and resetting bits
+		 * to zero is only in scopes defined by the mask. Zeroing of bits
+		 * according to a mask, we can use even a pack not been nulled in
+		 * advance.
+		 */
+		pack[byte] |= (ubChunk & itmChunkMask);
+		pack[byte] &= (ubChunk | ~itmChunkMask);
+		cntSavedBits = (8 - off > szItemWidthToGo) ?
+			szItemWidthToGo :
+			8 - off; // number of saved bits
+		szItemWidthToGo -= cntSavedBits;
+		caret += cntSavedBits;
+		item = item >> cntSavedBits;
+		itmMaskToGo = itmMaskToGo >> cntSavedBits;
+	}
+	return caret;
+}
+
+item_t
+bitpack_unpack(const uint8_t *pack, size_t *caret, size_t widItem)
+{
+	size_t szItemCaret;
+	size_t szItemWidthToGo;
+	uint8_t item[sizeof(item_t)]; /* size of item array */
+
+	size_t szPackByte;
+	size_t szPackOff;
+	size_t szItemByte;
+	size_t szItemOff;
+	uint8_t ubChunk;
+
+	szItemCaret = 0;
+	szItemWidthToGo = widItem;
+	memset(item, 0, sizeof(item_t));
+
+	while (szItemWidthToGo > 0) {
+		size_t szChunkSize;
+		size_t szChunkLowSize, szChunkHighSize;
+
+		szPackByte = *caret / 8;
+		szPackOff = *caret % 8;
+		szItemByte = szItemCaret / 8;
+		szItemOff = szItemCaret % 8;
+
+		ubChunk = pack[szPackByte] >> szPackOff;
+
+		szChunkSize = 8 - szPackOff;
+		if (szItemWidthToGo < szChunkSize) {
+			szChunkSize = szItemWidthToGo;
+			ubChunk = ubChunk & (uint8_t)width_to_mask(szItemWidthToGo);
+		}
+
+		if (szChunkSize > (8 - szItemOff)) /* Free space of item[szItemByte] */
+		{
+			szChunkLowSize = 8 - szItemOff;
+			szChunkHighSize = szChunkSize - szChunkLowSize;
+		} else {
+			szChunkLowSize = szChunkSize;
+			szChunkHighSize = 0;
+		}
+
+		item[szItemByte] |= ubChunk << szItemOff; /* chunk_low */
+
+		if (szChunkHighSize != 0) {
+			Assert((szItemByte + 1) < sizeof(item_t)); /* size of item array */
+			item[szItemByte + 1] |= ubChunk >> szChunkLowSize; /* chunk_high */
+		}
+
+		*caret += szChunkSize;
+		szItemCaret += szChunkSize;
+		szItemWidthToGo -= szChunkSize;
+	}
+
+	/*
+	 * Reordering bytes in accordance with endianness of the system.
+	 *
+	 * Here for a Little-endian system we can avoid reordering, but in such a
+	 * case we need to keep the item array aligned with item_t type, but we do
+	 * not keep.
+	 */
+	{
+		size_t j = 1;
+		item_t val = item[sizeof(item_t) - j];
+		while (++j <= sizeof(item_t)) {
+			val = val << 8;
+			val |= item[sizeof(item_t) - j];
+		}
+		return val;
+	}
+}
+
+#include "lib/bitpack_templ_undef.h"
diff --git a/src/backend/lib/bitpack_u16.c b/src/backend/lib/bitpack_u16.c
new file mode 100644
index 00000000000..ae2ee6d6bb2
--- /dev/null
+++ b/src/backend/lib/bitpack_u16.c
@@ -0,0 +1,8 @@
+/*
+ * File: bitpack_u16.c
+ */
+
+/* clang-format off */
+#include "lib/bitpack_u16_config.h"
+#include "bitpack_templ.c"
+/* clang-format on */
diff --git a/src/backend/lib/meson.build b/src/backend/lib/meson.build
index 8e38fb20f17..0984bd0e3f6 100644
--- a/src/backend/lib/meson.build
+++ b/src/backend/lib/meson.build
@@ -1,5 +1,10 @@
 # Copyright (c) 2022-2026, PostgreSQL Global Development Group
 
+dfor_sources = files(
+  'bitpack_u16.c',
+  'vect_u16.c'
+)
+
 backend_sources += files(
   'bipartite_match.c',
   'bloomfilter.c',
@@ -11,3 +16,5 @@ backend_sources += files(
   'pairingheap.c',
   'rbtree.c',
 )
+
+backend_sources += dfor_sources
diff --git a/src/backend/lib/vect_templ.c b/src/backend/lib/vect_templ.c
new file mode 100644
index 00000000000..52713c39d3b
--- /dev/null
+++ b/src/backend/lib/vect_templ.c
@@ -0,0 +1,301 @@
+/*
+ * File: vect_templ.c
+ */
+
+#include "lib/vect_templ_staple.h"
+
+/*
+ * Vector's functions
+ * Keep this section equal to the same section in vect_templ.h
+ */
+/*
+ * Caller has to control whether vector use outer memory provided by caller or
+ * manage memory allocation automatically, which defines whether vect_insert,
+ * vect_append and other functions of the vector container automatically mange
+ * dynamic memory allocation or not.
+ */
+
+int vect_init(vect_t *v, size_t cap, item_t outer_mem[]);
+int vect_fill(vect_t *v, size_t cnt, const item_t in[]);
+int vect_reserve(vect_t *v, size_t szNewCap);
+int vect_append(vect_t *vect, item_t val);
+void vect_print(const vect_t *a);
+int vect_compare(const vect_t *a, const vect_t *b);
+int vect_insert(vect_t *v, size_t pos, item_t val);
+void vect_clear(vect_t *v);
+
+/*
+ * Unique sorted vector's functions
+ * Keep this section equal to the same section in vect_templ.h
+ */
+usv_ins_res_t usv_insert(uniqsortvect_t *a, item_t val);
+usv_srch_res_t usv_search(const uniqsortvect_t *usv, item_t val);
+
+int
+vect_init(vect_t *v, size_t cap, item_t outer_mem[])
+{
+	if (v == NULL)
+		goto vect_init_error;
+
+	v->cap = cap;
+	v->cnt = 0;
+
+	if (outer_mem != NULL)
+	{
+		v->mem_is_outer = true;
+		v->m = outer_mem;
+	}
+	else
+	{
+		v->mem_is_outer = false;
+		if (cap == 0)
+			v->m = NULL;
+		else
+		{
+			v->m = (item_t *)VECT_MALLOC(cap * sizeof(item_t));
+			if (v->m == NULL)
+				goto vect_init_error;
+		}
+	}
+
+	/* vect_init_ok: */
+	return 0;
+vect_init_error:
+	memset(v, 0, sizeof(vect_t));
+	return -1;
+}
+
+int
+vect_fill(vect_t *v, size_t cnt, const item_t in[])
+{
+	if (v == NULL)
+		return -1;
+
+	if (cnt == 0)
+	{
+		vect_clear(v);
+		return 0;
+	}
+
+	for (size_t j = 0; j < cnt; j++)
+	{
+		if (vect_append(v, in[j]) != 0)
+		{
+			vect_clear(v);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+int
+vect_reserve(vect_t *v, size_t szNewCap)
+{
+	item_t *mNew;
+
+	if (v == NULL)
+		return -1;
+
+	if (v->mem_is_outer)
+		return -1;
+
+	if (szNewCap <= v->cap)
+		return 0;
+
+	mNew = (item_t *) VECT_MALLOC(sizeof(item_t) * szNewCap);
+
+	if (mNew == NULL)
+		return -1;
+
+	if(v->m == NULL && v->cnt != 0)
+		return -1;
+
+	if(v->m != NULL && v->cnt != 0)
+		memcpy(mNew, v->m, v->cnt * sizeof(item_t));
+
+	VECT_FREE(v->m);
+	v->m = mNew;
+	v->cap = szNewCap;
+	return 0;
+}
+
+int
+vect_append(vect_t *vect, item_t val)
+{
+	if (vect == NULL)
+		return -1;
+
+	if (vect->cnt + 1 > vect->cap)
+	{
+		if (vect->mem_is_outer)
+			return -1;
+		else
+			vect_reserve(vect, vect->cap + VECT_MEMALLOCSTEP);
+	}
+
+	vect->m[vect->cnt] = val;
+	vect->cnt++;
+	return 0;
+}
+
+void
+vect_print(const vect_t *a)
+{
+	for (size_t j = 0; j < a->cnt; j++)
+		printf("%" VECT_ITEM_FORMAT_SPECIFIER " ", a->m[j]);
+
+	printf("\n");
+}
+
+int
+vect_compare(const vect_t *a, const vect_t *b)
+{
+	if (a == NULL || b == NULL)
+		return -1;
+
+	if (a->cnt != b->cnt)
+		return -1;
+
+	for (size_t j = 0; j < a->cnt; j++)
+		if (a->m[j] != b->m[j])
+			return -1;
+
+	return 0;
+}
+
+int
+vect_insert(vect_t *v, size_t pos, item_t val)
+{
+	if (v->cap < v->cnt + 1 &&
+		(v->mem_is_outer || vect_reserve(v, v->cap + VECT_MEMALLOCSTEP) != 0))
+		return -1;
+
+	/*
+	 * If need, move right from pos including pos. Because
+	 * neither stdlib's nor POSIX's documentation defines the
+	 * behaviour of memmove in case of count=0, we check it by
+	 * ourselves.
+	 */
+	if (v->cnt - pos > 0)
+		memmove(&v->m[pos + 1], &v->m[pos], (v->cnt - pos) * sizeof(item_t));
+
+	v->m[pos] = val;
+	v->cnt++;
+	return 0;
+}
+
+void
+vect_clear(vect_t *v)
+{
+	if (v == NULL)
+		return;
+
+	if (!v->mem_is_outer)
+		VECT_FREE(v->m);
+
+	memset(v, 0, sizeof(vect_t));
+}
+
+usv_srch_res_t
+usv_search(const uniqsortvect_t *usv, item_t val)
+{
+	size_t i, l, g;
+	usv_srch_res_t res;
+
+	if (usv == NULL || (usv->m == NULL && ((usv->cnt != 0) || usv->cap != 0))) {
+		res.st = USV_SRCH_ERROR;
+		return res;
+	}
+
+	if (usv->cnt == 0) {
+		res.pos = 0;
+		res.st = USV_SRCH_EMPTY;
+		return res;
+	}
+
+	if (val < usv->m[0]) {
+		res.pos = 0;
+		res.st = USV_SRCH_NOT_FOUND_SMALLEST;
+		return res;
+	}
+
+	if (val > usv->m[usv->cnt - 1]) {
+		res.pos = usv->cnt - 1;
+		res.st = USV_SRCH_NOT_FOUND_LARGEST;
+		return res;
+	}
+
+	l = 0;
+	g = usv->cnt - 1;
+
+	while (g - l > 1) {
+		i = l + (g - l) / 2;
+		if (val == usv->m[i]) {
+			res.pos = i;
+			res.st = USV_SRCH_FOUND;
+			return res;
+		} else if (val > usv->m[i]) {
+			l = i;
+		} else // val <= usv->m[i]
+		{
+			g = i;
+		}
+	}
+	/*
+	 * When scopes l and g are neighbours (  g-l = 1)
+	 */
+	if (val == usv->m[g]) {
+		res.pos = g;
+		res.st = USV_SRCH_FOUND;
+		return res;
+	} else if (val == usv->m[l]) {
+		res.pos = l;
+		res.st = USV_SRCH_FOUND;
+		return res;
+	}
+
+	res.pos = g;
+	res.st = USV_SRCH_NOT_FOUND;
+	return res;
+}
+
+/*
+ * INSERT
+ * receives a value, checks whether an unique sorted values vector contains
+ * this value. If not, inserts new value, retaining sorted order.
+ */
+usv_ins_res_t
+usv_insert(uniqsortvect_t *a, item_t val)
+{
+	usv_srch_res_t search;
+	usv_ins_res_t insert;
+
+	Assert(a != NULL);
+
+	search = usv_search(a, val);
+	if (search.st == USV_SRCH_FOUND) {
+		insert.st = USV_INS_EXISTS;
+		insert.pos = search.pos;
+		return insert;
+	} else if (search.st == USV_SRCH_NOT_FOUND_SMALLEST ||
+			   search.st == USV_SRCH_NOT_FOUND) {
+		insert.pos = search.pos;
+	} else if (search.st == USV_SRCH_EMPTY ||
+			   search.st == USV_SRCH_NOT_FOUND_LARGEST) {
+		/* In case when value is more than largest: pos = a->cnt = search.g + 1.
+		 */
+		/* In case of empty vector: pos = a->cnt = 0. */
+		insert.pos = a->cnt;
+	} else /* USV_SRCH_ERROR or unknown result */
+	{
+		insert.st = USV_INS_ERROR;
+		return insert;
+	}
+
+	insert.st = vect_insert(a, insert.pos, val)
+	== 0 ? USV_INS_NEW : USV_INS_ERROR;
+
+	return insert;
+}
+
+#include "lib/vect_templ_undef.h"
diff --git a/src/backend/lib/vect_u16.c b/src/backend/lib/vect_u16.c
new file mode 100644
index 00000000000..0ab8e224c7a
--- /dev/null
+++ b/src/backend/lib/vect_u16.c
@@ -0,0 +1,8 @@
+/*
+ * File: vect_u16.c
+ */
+
+/* clang-format off */
+#include "lib/vect_u16_config.h"
+#include "vect_templ.c"
+/* clang-format on */
diff --git a/src/include/c.h b/src/include/c.h
index 88d13ec9993..1e48a52ae90 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -505,6 +505,10 @@ extern "C++"
 #define CppAsString(identifier) #identifier
 #define CppAsString2(x)			CppAsString(x)
 #define CppConcat(x, y)			x##y
+#define CppConcat2(x, y)		CppConcat(x, y)
+
+#define CppConcatTriple(x, y, z)	x##y##z
+#define CppConcatTriple2(a, b, c)	CppConcatTriple(a, b, c)
 
 /*
  * VA_ARGS_NARGS
diff --git a/src/include/lib/bitpack_staple_templ.h b/src/include/lib/bitpack_staple_templ.h
new file mode 100644
index 00000000000..5c9972e08cb
--- /dev/null
+++ b/src/include/lib/bitpack_staple_templ.h
@@ -0,0 +1,57 @@
+/*
+ * File: bitpack_staple_templ.h.h
+ */
+
+#include "c.h"
+
+/******************************************************************************
+ * NONREUSABLE CODE, allowed to be included only once
+ *
+ * This code should appear only once in a file (or in a chain of files)
+ * including this header with #include. So, we protect it from duplicates by
+ * means of macro
+ *
+ *****************************************************************************/
+#ifndef _BITPACK_STAPLE_TEMPL_H_UNIQUE_CODE_
+#define _BITPACK_STAPLE_TEMPL_H_UNIQUE_CODE_
+
+/* No code here yet */
+
+#endif /* _BITPACK_STAPLE_TEMPL_H_UNIQUE_CODE_ */
+
+/******************************************************************************
+ * End of Code, allowed to be included only once
+ *****************************************************************************/
+
+/******************************************************************************
+ * REUSABLE CODE
+ *
+ * This code can be reused with #include directive in a file if BITPACK_MARKER
+ * redefined. This allow creation of several types of vectors with different
+ * types of members.
+ *
+ *****************************************************************************/
+
+#ifndef BITPACK_ITEM_TYPE
+#error "BITPACK_ITEM_TYPE macro is indefined."
+#endif
+#ifndef BITPACK_MARKER
+#error "BITPACK_MARKER macro is indefined."
+#endif
+
+#define item_t		   BITPACK_ITEM_TYPE
+#define width_from_val CppConcatTriple2(width_, BITPACK_MARKER, _from_val)
+#define width_to_mask  CppConcatTriple2(width_, BITPACK_MARKER, _to_mask)
+#define bitpack_pack   CppConcatTriple2(bitpack_, BITPACK_MARKER, _pack)
+#define bitpack_unpack CppConcatTriple2(bitpack_, BITPACK_MARKER, _unpack)
+
+/******************************************************************************
+ * End of Reusable Code
+ *****************************************************************************/
+
+/*
+ * Don't forget to include this code in your file that uses this header
+ *
+ * #include "lib/bitpack_templ_undef.h"
+ *
+ */
diff --git a/src/include/lib/bitpack_templ.h b/src/include/lib/bitpack_templ.h
new file mode 100644
index 00000000000..b3a6e06c328
--- /dev/null
+++ b/src/include/lib/bitpack_templ.h
@@ -0,0 +1,14 @@
+/*
+ * bitpack_templ.h
+ *
+ */
+
+#include "bitpack_staple_templ.h"
+
+extern item_t width_from_val(item_t val);
+extern item_t width_to_mask(size_t width);
+extern size_t bitpack_pack(uint8_t *pack, size_t caret, item_t item,
+						   size_t szItemWidth);
+extern item_t bitpack_unpack(const uint8_t *pack, size_t *caret, size_t szItemWidth);
+
+#include "bitpack_templ_undef.h"
diff --git a/src/include/lib/bitpack_templ_undef.h b/src/include/lib/bitpack_templ_undef.h
new file mode 100644
index 00000000000..5bf864ffa15
--- /dev/null
+++ b/src/include/lib/bitpack_templ_undef.h
@@ -0,0 +1,5 @@
+#undef item_t
+#undef width_from_val
+#undef width_to_mask
+#undef bitpack_pack
+#undef bitpack_unpack
diff --git a/src/include/lib/bitpack_u16.h b/src/include/lib/bitpack_u16.h
new file mode 100644
index 00000000000..45fb6c4b17b
--- /dev/null
+++ b/src/include/lib/bitpack_u16.h
@@ -0,0 +1,12 @@
+/*
+ * bitpack.h
+ */
+#ifndef _BITPACK_U16_H_
+#define _BITPACK_U16_H_
+
+/* clang-format off */
+#include "bitpack_u16_config.h"
+#include "bitpack_templ.h"
+/* clang-format on */
+
+#endif /* _BITPACK_U16_H_ */
diff --git a/src/include/lib/bitpack_u16_config.h b/src/include/lib/bitpack_u16_config.h
new file mode 100644
index 00000000000..9e6c64d4fee
--- /dev/null
+++ b/src/include/lib/bitpack_u16_config.h
@@ -0,0 +1,6 @@
+/*
+ * File: vect_u16_config.h
+ */
+
+#define BITPACK_ITEM_TYPE uint16_t
+#define BITPACK_MARKER	  u16
diff --git a/src/include/lib/vect_templ.h b/src/include/lib/vect_templ.h
new file mode 100644
index 00000000000..8eec6f064b3
--- /dev/null
+++ b/src/include/lib/vect_templ.h
@@ -0,0 +1,27 @@
+/*
+ * File: vect_templ.h
+ */
+
+#include "vect_templ_staple.h"
+
+/*
+ * Vector's functions
+ * Keep this section equal to the same section in vect_templ.c
+ */
+extern int vect_init(vect_t *v, size_t cap, item_t external_memory[]);
+extern int vect_fill(vect_t *v, size_t cnt, const item_t *in);
+extern int vect_reserve(vect_t *v, size_t szNewCap);
+extern int vect_append(vect_t *vect, item_t val);
+extern void vect_print(const vect_t *a);
+extern int vect_compare(const vect_t *a, const vect_t *b);
+extern int vect_insert(vect_t *v, size_t pos, item_t val);
+extern void vect_clear(vect_t *v);
+
+/*
+ * Unique sorted vector's functions
+ * Keep this section equal to the same section in vect_templ.c
+ */
+extern usv_ins_res_t usv_insert(uniqsortvect_t *a, item_t val);
+extern usv_srch_res_t usv_search(const uniqsortvect_t *usv, item_t val);
+
+#include "vect_templ_undef.h"
\ No newline at end of file
diff --git a/src/include/lib/vect_templ_staple.h b/src/include/lib/vect_templ_staple.h
new file mode 100644
index 00000000000..b192c6d82a3
--- /dev/null
+++ b/src/include/lib/vect_templ_staple.h
@@ -0,0 +1,140 @@
+/*
+ * File: vect_staple_templ.h
+ */
+
+#include "c.h"
+
+/******************************************************************************
+ * NONREUSABLE CODE, allowed to be included only once
+ *
+ * This code should appear only once in a file (or in a chain of files)
+ * including this header with #include. So, we protect it from duplicates by
+ * means of macro
+ *
+ *****************************************************************************/
+#ifndef _VECT_STAPLE_TEMPL_H_UNIQUE_CODE_
+#define _VECT_STAPLE_TEMPL_H_UNIQUE_CODE_
+
+/*
+ * SEARCH in Vector of Unique Sorted members
+ */
+typedef enum
+{
+	USV_SRCH_ERROR = -1,
+	USV_SRCH_FOUND = 0,
+	USV_SRCH_EMPTY,
+	USV_SRCH_NOT_FOUND,
+	USV_SRCH_NOT_FOUND_SMALLEST,
+	USV_SRCH_NOT_FOUND_LARGEST
+} usv_srch_stat_t;
+
+typedef struct
+{
+	usv_srch_stat_t st;
+	size_t pos; /* position (index) of a member that is equal to searched value
+				 * or that is nearest greater member */
+} usv_srch_res_t;
+
+/*
+ * INSERT  in Vector of Unique Sorted members
+ */
+typedef enum
+{
+	USV_INS_ERROR = -1,
+	USV_INS_EXISTS = 0,
+	USV_INS_NEW
+} usv_ins_stat_t;
+
+typedef struct
+{
+	usv_ins_stat_t st;
+	size_t pos; /* position (index) of a member that was inserted or that proved
+				 * to be equal to inserted value
+				 */
+} usv_ins_res_t;
+
+#endif /* _VECT_STAPLE_TEMPL_H_UNIQUE_CODE_ */
+
+/******************************************************************************
+ * End of Code, allowed to be included only once
+ *****************************************************************************/
+
+/******************************************************************************
+ * REUSABLE CODE
+ *
+ * This code can be reused with #include directive in a file if VECT_MARKER
+ * redefined. This allow creation of several types of vectors with different
+ * types of members.
+ *
+ *****************************************************************************/
+
+#ifndef VECT_ITEM_TYPE
+#error "VECT_ITEM_TYPE macro is indefined."
+#endif
+
+#ifndef VECT_ITEM_FORMAT_SPECIFIER
+#error "VECT_ITEM_FORMAT_SPECIFIER macro is indefined."
+#endif
+
+#ifndef VECT_MARKER
+#error "VECT_MARKER macro is indefined."
+#endif
+
+#ifndef VECT_MEMALLOCSTEP
+#error "VECT_MEMALLOCSTEP macro is indefined."
+#endif
+
+#ifndef VECT_MALLOC
+#error "VECT_MALLOC macro is indefined."
+#endif
+
+#ifndef VECT_FREE
+#error "VECT_FREE macro is indefined."
+#endif
+
+/*
+ * The Vector type itself,
+ * The Vector of Unique Sorted Items type
+ * and the Item type
+ *
+ * In fact, vectors's names looks like vect_u16_t where:
+ *     vect_ - common prefix,
+ *     u16 - marker,
+ *     _t - suffix
+ */
+#define vect_t		   CppConcatTriple2(vect_, VECT_MARKER, _t)
+#define uniqsortvect_t CppConcatTriple2(uniqsortvect_, VECT_MARKER, _t)
+#define item_t		   VECT_ITEM_TYPE
+
+typedef struct
+{
+	size_t cnt;		   /* number of items */
+	size_t cap;		   /* capacity */
+	bool mem_is_outer; /* flag about an external memory is used */
+	item_t *m;		   /* items (members) */
+} vect_t;
+
+typedef vect_t uniqsortvect_t;
+
+#define vect_init		   CppConcatTriple2(vect_, VECT_MARKER, _init)
+#define vect_fill		   CppConcatTriple2(vect_, VECT_MARKER, _fill)
+#define vect_reserve	   CppConcatTriple2(vect_, VECT_MARKER, _reserve)
+#define vect_append		   CppConcatTriple2(vect_, VECT_MARKER, _append)
+#define vect_print		   CppConcatTriple2(vect_, VECT_MARKER, _print)
+#define vect_compare	   CppConcatTriple2(vect_, VECT_MARKER, _compare)
+#define vect_insert		   CppConcatTriple2(vect_, VECT_MARKER, _insert)
+#define vect_clear		   CppConcatTriple2(vect_, VECT_MARKER, _clear)
+
+#define usv_insert CppConcatTriple2(usv_, VECT_MARKER, _insert)
+#define usv_search CppConcatTriple2(usv_, VECT_MARKER, _search)
+
+/******************************************************************************
+ * End of Reusable Code
+ *****************************************************************************/
+
+/*
+ * Don't forget to include
+ * 		#include "vect_templ_undef.h"
+ * in your file that uses this header
+ *
+ */
diff --git a/src/include/lib/vect_templ_undef.h b/src/include/lib/vect_templ_undef.h
new file mode 100644
index 00000000000..59b69f18b99
--- /dev/null
+++ b/src/include/lib/vect_templ_undef.h
@@ -0,0 +1,25 @@
+/*
+ * File: vect_undef.h
+ */
+
+#undef vect_t
+#undef uniqsortvect_t
+#undef item_t
+
+#undef VECT_ITEM_TYPE
+#undef VECT_MARKER
+#undef VECT_CppConcatTriple2
+
+#undef vect_init
+#undef vect_fill
+#undef vect_reserve
+#undef vect_append
+#undef vect_print
+#undef vect_compare
+#undef vect_insert
+#undef vect_clear
+
+#undef usv_insert
+#undef usv_search
+
+#undef VECT_PRI_FORMAT_SPECIFIER
\ No newline at end of file
diff --git a/src/include/lib/vect_u16.h b/src/include/lib/vect_u16.h
new file mode 100644
index 00000000000..edf81a417f4
--- /dev/null
+++ b/src/include/lib/vect_u16.h
@@ -0,0 +1,34 @@
+/*
+ * File: vect_u16.h
+ */
+
+#ifndef _VECT_U16_H_
+#define _VECT_U16_H_
+
+/* clang-format off */
+#include "vect_u16_config.h"
+#include "vect_templ.h"
+/* clang-format on */
+
+/*
+ * Types are supposed to be created created by this file
+ *     vect_u16_t
+ *     item_u16_t
+ *     uniqsortvect_u16_t
+ */
+/*
+ * Functions are supposed to be created by this file
+ *     vect_u16_create
+ *     vect_u16_create_filled
+ *     vect_u16_reserve
+ *     vect_u16_append
+ *     vect_u16_destroy
+ *     vect_u16_print
+ *     vect_u16_compare
+ *     vect_u16_insert
+ *     vect_u16_clear
+ *     usv_u16_insert
+ *     usv_u16_search
+ */
+
+#endif //_VECT_U16_H_
diff --git a/src/include/lib/vect_u16_config.h b/src/include/lib/vect_u16_config.h
new file mode 100644
index 00000000000..13a93284e8f
--- /dev/null
+++ b/src/include/lib/vect_u16_config.h
@@ -0,0 +1,10 @@
+/*
+ * File: vect_u16_config.h
+ */
+
+#define VECT_ITEM_TYPE			   uint16_t
+#define VECT_ITEM_FORMAT_SPECIFIER PRIu16
+#define VECT_MARKER				   u16
+#define VECT_MEMALLOCSTEP		   5
+#define VECT_MALLOC				   malloc
+#define VECT_FREE				   free
-- 
2.53.0

