/*------------------------------------------------------------------------- * * 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-2023, 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; }