From d2ea8d719f1981937f3205150b0870d38499fabc Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@enterprisedb.com>
Date: Thu, 10 Aug 2017 15:40:30 +1200
Subject: [PATCH] Teach Bitmapset to skip leading zeroes in some cases.

Some of the algorithms in bitmapset.c can avoid scanning most of their words
in the not-uncommon case of singleton or fortunately organized sparse sets,
if we keep track of the first occupied word.

* Quick hack, not for commit! *

Author: Thomas Munro
---
 src/backend/nodes/bitmapset.c | 22 ++++++++++++++++------
 src/include/nodes/bitmapset.h |  1 +
 2 files changed, 17 insertions(+), 6 deletions(-)

diff --git a/src/backend/nodes/bitmapset.c b/src/backend/nodes/bitmapset.c
index bf8545d4378..8bf8271f88f 100644
--- a/src/backend/nodes/bitmapset.c
+++ b/src/backend/nodes/bitmapset.c
@@ -187,6 +187,7 @@ bms_make_singleton(int x)
 	wordnum = WORDNUM(x);
 	bitnum = BITNUM(x);
 	result = (Bitmapset *) palloc0(BITMAPSET_SIZE(wordnum + 1));
+	result->first_non_empty_wordnum = wordnum;
 	result->nwords = wordnum + 1;
 	result->words[wordnum] = ((bitmapword) 1 << bitnum);
 	return result;
@@ -310,6 +311,7 @@ bms_is_subset(const Bitmapset *a, const Bitmapset *b)
 	int			shortlen;
 	int			longlen;
 	int			i;
+	int			start;
 
 	/* Handle cases where either input is NULL */
 	if (a == NULL)
@@ -318,7 +320,8 @@ bms_is_subset(const Bitmapset *a, const Bitmapset *b)
 		return bms_is_empty(a);
 	/* Check common words */
 	shortlen = Min(a->nwords, b->nwords);
-	for (i = 0; i < shortlen; i++)
+	start = Min(a->first_non_empty_wordnum, b->first_non_empty_wordnum);
+	for (i = start; i < shortlen; i++)
 	{
 		if ((a->words[i] & ~b->words[i]) != 0)
 			return false;
@@ -444,13 +447,15 @@ bms_overlap(const Bitmapset *a, const Bitmapset *b)
 {
 	int			shortlen;
 	int			i;
+	int			start;
 
 	/* Handle cases where either input is NULL */
 	if (a == NULL || b == NULL)
 		return false;
 	/* Check words in common */
 	shortlen = Min(a->nwords, b->nwords);
-	for (i = 0; i < shortlen; i++)
+	start = Max(a->first_non_empty_wordnum, b->first_non_empty_wordnum);
+	for (i = start; i < shortlen; i++)
 	{
 		if ((a->words[i] & b->words[i]) != 0)
 			return true;
@@ -611,7 +616,7 @@ bms_num_members(const Bitmapset *a)
 	if (a == NULL)
 		return 0;
 	nwords = a->nwords;
-	for (wordnum = 0; wordnum < nwords; wordnum++)
+	for (wordnum = a->first_non_empty_wordnum; wordnum < nwords; wordnum++)
 	{
 		bitmapword	w = a->words[wordnum];
 
@@ -640,7 +645,7 @@ bms_membership(const Bitmapset *a)
 	if (a == NULL)
 		return BMS_EMPTY_SET;
 	nwords = a->nwords;
-	for (wordnum = 0; wordnum < nwords; wordnum++)
+	for (wordnum = a->first_non_empty_wordnum; wordnum < nwords; wordnum++)
 	{
 		bitmapword	w = a->words[wordnum];
 
@@ -668,7 +673,7 @@ bms_is_empty(const Bitmapset *a)
 	if (a == NULL)
 		return true;
 	nwords = a->nwords;
-	for (wordnum = 0; wordnum < nwords; wordnum++)
+	for (wordnum = a->first_non_empty_wordnum; wordnum < nwords; wordnum++)
 	{
 		bitmapword	w = a->words[wordnum];
 
@@ -707,6 +712,9 @@ bms_add_member(Bitmapset *a, int x)
 	wordnum = WORDNUM(x);
 	bitnum = BITNUM(x);
 
+	if (wordnum < a->first_non_empty_wordnum)
+		a->first_non_empty_wordnum = wordnum;
+
 	/* enlarge the set if necessary */
 	if (wordnum >= a->nwords)
 	{
@@ -779,6 +787,8 @@ bms_add_members(Bitmapset *a, const Bitmapset *b)
 	otherlen = other->nwords;
 	for (i = 0; i < otherlen; i++)
 		result->words[i] |= other->words[i];
+	result->first_non_empty_wordnum =
+		Min(result->first_non_empty_wordnum, other->first_non_empty_wordnum);
 	if (result != a)
 		pfree(a);
 	return result;
@@ -890,7 +900,7 @@ bms_first_member(Bitmapset *a)
 	if (a == NULL)
 		return -1;
 	nwords = a->nwords;
-	for (wordnum = 0; wordnum < nwords; wordnum++)
+	for (wordnum = a->first_non_empty_wordnum; wordnum < nwords; wordnum++)
 	{
 		bitmapword	w = a->words[wordnum];
 
diff --git a/src/include/nodes/bitmapset.h b/src/include/nodes/bitmapset.h
index aa3fb253c27..fd2ed729de5 100644
--- a/src/include/nodes/bitmapset.h
+++ b/src/include/nodes/bitmapset.h
@@ -37,6 +37,7 @@ typedef int32 signedbitmapword; /* must be the matching signed type */
 typedef struct Bitmapset
 {
 	int			nwords;			/* number of words in array */
+	int			first_non_empty_wordnum;		/* first non-zero word */
 	bitmapword	words[FLEXIBLE_ARRAY_MEMBER];	/* really [nwords] */
 } Bitmapset;
 
-- 
2.13.2

