aboutsummaryrefslogtreecommitdiff
path: root/src/backend/nodes/multibitmapset.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/nodes/multibitmapset.c')
-rw-r--r--src/backend/nodes/multibitmapset.c162
1 files changed, 162 insertions, 0 deletions
diff --git a/src/backend/nodes/multibitmapset.c b/src/backend/nodes/multibitmapset.c
new file mode 100644
index 00000000000..924225c68fc
--- /dev/null
+++ b/src/backend/nodes/multibitmapset.c
@@ -0,0 +1,162 @@
+/*-------------------------------------------------------------------------
+ *
+ * multibitmapset.c
+ * Lists of Bitmapsets
+ *
+ * A multibitmapset is useful in situations where members of a set can
+ * be identified by two small integers; for example, varno and varattno
+ * of a group of Vars within a query. The implementation is a List of
+ * Bitmapsets, so that the empty set can be represented by NIL. (But,
+ * as with Bitmapsets, that's not the only allowed representation.)
+ * The zero-based index of a List element is the first identifying value,
+ * and the (also zero-based) index of a bit within that Bitmapset is
+ * the second identifying value. There is no expectation that the
+ * Bitmapsets should all be the same size.
+ *
+ * The available operations on multibitmapsets are intended to parallel
+ * those on bitmapsets, for example union and intersection. So far only
+ * a small fraction of that has been built out; we'll add more as needed.
+ *
+ *
+ * Copyright (c) 2022, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ * src/backend/nodes/multibitmapset.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "nodes/multibitmapset.h"
+
+
+/*
+ * mbms_add_member
+ * Add a new member to a multibitmapset.
+ *
+ * The new member is identified by "listidx", the zero-based index of the
+ * List element it should go into, and "bitidx", which specifies the bit
+ * number to be set therein.
+ *
+ * This is like bms_add_member, but for multibitmapsets.
+ */
+List *
+mbms_add_member(List *a, int listidx, int bitidx)
+{
+ Bitmapset *bms;
+ ListCell *lc;
+
+ if (listidx < 0 || bitidx < 0)
+ elog(ERROR, "negative multibitmapset member index not allowed");
+ /* Add empty elements as needed */
+ while (list_length(a) <= listidx)
+ a = lappend(a, NULL);
+ /* Update the target element */
+ lc = list_nth_cell(a, listidx);
+ bms = lfirst_node(Bitmapset, lc);
+ bms = bms_add_member(bms, bitidx);
+ lfirst(lc) = bms;
+ return a;
+}
+
+/*
+ * mbms_add_members
+ * Add all members of set b to set a.
+ *
+ * This is a UNION operation, but the left input is modified in-place.
+ *
+ * This is like bms_add_members, but for multibitmapsets.
+ */
+List *
+mbms_add_members(List *a, const List *b)
+{
+ ListCell *lca,
+ *lcb;
+
+ /* Add empty elements to a, as needed */
+ while (list_length(a) < list_length(b))
+ a = lappend(a, NULL);
+ /* forboth will stop at the end of the shorter list, which is fine */
+ forboth(lca, a, lcb, b)
+ {
+ Bitmapset *bmsa = lfirst_node(Bitmapset, lca);
+ const Bitmapset *bmsb = lfirst_node(Bitmapset, lcb);
+
+ bmsa = bms_add_members(bmsa, bmsb);
+ lfirst(lca) = bmsa;
+ }
+ return a;
+}
+
+/*
+ * mbms_int_members
+ * Reduce set a to its intersection with set b.
+ *
+ * This is an INTERSECT operation, but the left input is modified in-place.
+ *
+ * This is like bms_int_members, but for multibitmapsets.
+ */
+List *
+mbms_int_members(List *a, const List *b)
+{
+ ListCell *lca,
+ *lcb;
+
+ /* Remove any elements of a that are no longer of use */
+ a = list_truncate(a, list_length(b));
+ /* forboth will stop at the end of the shorter list, which is fine */
+ forboth(lca, a, lcb, b)
+ {
+ Bitmapset *bmsa = lfirst_node(Bitmapset, lca);
+ const Bitmapset *bmsb = lfirst_node(Bitmapset, lcb);
+
+ bmsa = bms_int_members(bmsa, bmsb);
+ lfirst(lca) = bmsa;
+ }
+ return a;
+}
+
+/*
+ * mbms_is_member
+ * Is listidx/bitidx a member of A?
+ *
+ * This is like bms_is_member, but for multibitmapsets.
+ */
+bool
+mbms_is_member(int listidx, int bitidx, const List *a)
+{
+ const Bitmapset *bms;
+
+ /* XXX better to just return false for negative indexes? */
+ if (listidx < 0 || bitidx < 0)
+ elog(ERROR, "negative multibitmapset member index not allowed");
+ if (listidx >= list_length(a))
+ return false;
+ bms = list_nth_node(Bitmapset, a, listidx);
+ return bms_is_member(bitidx, bms);
+}
+
+/*
+ * mbms_overlap_sets
+ * Identify the bitmapsets having common members in a and b.
+ *
+ * The result is a bitmapset of the list indexes of bitmapsets that overlap.
+ */
+Bitmapset *
+mbms_overlap_sets(const List *a, const List *b)
+{
+ Bitmapset *result = NULL;
+ ListCell *lca,
+ *lcb;
+
+ /* forboth will stop at the end of the shorter list, which is fine */
+ forboth(lca, a, lcb, b)
+ {
+ const Bitmapset *bmsa = lfirst_node(Bitmapset, lca);
+ const Bitmapset *bmsb = lfirst_node(Bitmapset, lcb);
+
+ if (bms_overlap(bmsa, bmsb))
+ result = bms_add_member(result, foreach_current_index(lca));
+ }
+ return result;
+}