Here is v6 of cube penalty patch.
There was a warning about unused edge function under systems without
__STDC_IEC_559__ defined, this patch fixes it.
Regards, Andrey Borodin.
diff --git a/contrib/cube/cube.c b/contrib/cube/cube.c
index 3feddef..ad868ac 100644
--- a/contrib/cube/cube.c
+++ b/contrib/cube/cube.c
@@ -18,6 +18,7 @@
#include "cubedata.h"
+
PG_MODULE_MAGIC;
/*
@@ -27,6 +28,15 @@ PG_MODULE_MAGIC;
#define ARRNELEMS(x) ArrayGetNItems( ARR_NDIM(x), ARR_DIMS(x))
/*
+ * If IEEE754 floats are fully supported we use advanced penalty
+ * which takes into account cube volume, perimeter and tend to favor
+ * small nodes over big ones. For more info see g_cube_penalty implementation
+ */
+#ifdef __STDC_IEC_559__
+#define ADVANCED_PENALTY
+#endif
+
+/*
** Input/Output routines
*/
PG_FUNCTION_INFO_V1(cube_in);
@@ -91,14 +101,18 @@ PG_FUNCTION_INFO_V1(cube_enlarge);
/*
** For internal use only
*/
-int32 cube_cmp_v0(NDBOX *a, NDBOX *b);
-bool cube_contains_v0(NDBOX *a, NDBOX *b);
-bool cube_overlap_v0(NDBOX *a, NDBOX *b);
-NDBOX *cube_union_v0(NDBOX *a, NDBOX *b);
-void rt_cube_size(NDBOX *a, double *sz);
-NDBOX *g_cube_binary_union(NDBOX *r1, NDBOX *r2, int *sizep);
-bool g_cube_leaf_consistent(NDBOX *key, NDBOX *query, StrategyNumber
strategy);
-bool g_cube_internal_consistent(NDBOX *key, NDBOX *query,
StrategyNumber strategy);
+static int32 cube_cmp_v0(NDBOX *a, NDBOX *b);
+static bool cube_contains_v0(NDBOX *a, NDBOX *b);
+static bool cube_overlap_v0(NDBOX *a, NDBOX *b);
+static NDBOX *cube_union_v0(NDBOX *a, NDBOX *b);
+#ifdef ADVANCED_PENALTY
+static float pack_float(float value, int realm);
+static void rt_cube_edge(NDBOX *a, double *sz);
+#endif
+static void rt_cube_size(NDBOX *a, double *sz);
+static NDBOX *g_cube_binary_union(NDBOX *r1, NDBOX *r2, int *sizep);
+static bool g_cube_leaf_consistent(NDBOX *key, NDBOX *query,
StrategyNumber strategy);
+static bool g_cube_internal_consistent(NDBOX *key, NDBOX *query,
StrategyNumber strategy);
/*
** Auxiliary funxtions
@@ -419,7 +433,36 @@ g_cube_decompress(PG_FUNCTION_ARGS)
}
PG_RETURN_POINTER(entry);
}
+/*
+ * Function to pack floats of different realms
+ * This function serves to pack bit flags inside float type
+ * Resulted value represent can be from four different "realms"
+ * Every value from realm 3 is greater than any value from realms 2,1 and 0.
+ * Every value from realm 2 is less than every value from realm 3 and greater
+ * than any value from realm 1 and 0, and so on. Values from the same realm
+ * loose two bits of precision. This technique is possible due to floating
+ * point numbers specification according to IEEE 754: exponent bits are highest
+ * (excluding sign bits, but here penalty is always positive). If float a is
+ * greater than float b, integer A with same bit representation as a is greater
+ * than integer B with same bits as b.
+ */
+#ifdef ADVANCED_PENALTY
+static float
+pack_float(const float value, const int realm)
+{
+ union {
+ float f;
+ struct { unsigned value:31, sign:1; } vbits;
+ struct { unsigned value:29, realm:2, sign:1; } rbits;
+ } a;
+
+ a.f = value;
+ a.rbits.value = a.vbits.value >> 2;
+ a.rbits.realm = realm;
+ return a.f;
+}
+#endif
/*
** The GiST Penalty method for boxes
@@ -441,9 +484,42 @@ g_cube_penalty(PG_FUNCTION_ARGS)
rt_cube_size(DatumGetNDBOX(origentry->key), &tmp2);
*result = (float) (tmp1 - tmp2);
- /*
- * fprintf(stderr, "penalty\n"); fprintf(stderr, "\t%g\n", *result);
- */
+#ifdef ADVANCED_PENALTY
+ /* Realm tricks are used only in case of IEEE754 support(IEC 60559) */
+
+ /* REALM 0: No extension is required, volume is zero, return edge
*/
+ /* REALM 1: No extension is required, return nonzero volume
*/
+ /* REALM 2: Volume extension is zero, return nonzero edge extension
*/
+ /* REALM 3: Volume extension is nonzero, return it
*/
+
+ if( *result == 0 )
+ {
+ double tmp3 = tmp1; /* remember entry volume */
+ rt_cube_edge(ud, &tmp1);
+ rt_cube_edge(DatumGetNDBOX(origentry->key), &tmp2);
+ *result = (float) (tmp1 - tmp2);
+ if( *result == 0 )
+ {
+ if( tmp3 != 0 )
+ {
+ *result = pack_float(tmp3, 1); /* REALM 1 */
+ }
+ else
+ {
+ *result = pack_float(tmp1, 0); /* REALM 0 */
+ }
+ }
+ else
+ {
+ *result = pack_float(*result, 2); /* REALM 2 */
+ }
+ }
+ else
+ {
+ *result = pack_float(*result, 3); /* REALM 3 */
+ }
+#endif
+
PG_RETURN_FLOAT8(*result);
}
@@ -626,7 +702,7 @@ g_cube_same(PG_FUNCTION_ARGS)
/*
** SUPPORT ROUTINES
*/
-bool
+static bool
g_cube_leaf_consistent(NDBOX *key,
NDBOX *query,
StrategyNumber strategy)
@@ -658,7 +734,7 @@ g_cube_leaf_consistent(NDBOX *key,
return (retval);
}
-bool
+static bool
g_cube_internal_consistent(NDBOX *key,
NDBOX *query,
StrategyNumber strategy)
@@ -688,7 +764,7 @@ g_cube_internal_consistent(NDBOX *key,
return (retval);
}
-NDBOX *
+static NDBOX *
g_cube_binary_union(NDBOX *r1, NDBOX *r2, int *sizep)
{
NDBOX *retval;
@@ -701,7 +777,7 @@ g_cube_binary_union(NDBOX *r1, NDBOX *r2, int *sizep)
/* cube_union_v0 */
-NDBOX *
+static NDBOX *
cube_union_v0(NDBOX *a, NDBOX *b)
{
int i;
@@ -875,25 +951,42 @@ cube_size(PG_FUNCTION_ARGS)
PG_RETURN_FLOAT8(result);
}
-void
+static void
rt_cube_size(NDBOX *a, double *size)
{
int i;
+ double result = 0;
- if (a == (NDBOX *) NULL)
- *size = 0.0;
- else
+ if (a != (NDBOX *) NULL)
{
- *size = 1.0;
+ result = 1.0;
for (i = 0; i < DIM(a); i++)
- *size = (*size) * Abs(UR_COORD(a, i) - LL_COORD(a, i));
+ result *= UR_COORD(a, i) - LL_COORD(a, i);
}
+ *size = Abs(result);
return;
}
+#ifdef ADVANCED_PENALTY
+static void
+rt_cube_edge(NDBOX *a, double *size)
+{
+ int i;
+ double result = 0;
+
+ if (a != (NDBOX *) NULL)
+ {
+ for (i = 0; i < DIM(a); i++)
+ result += Abs(UR_COORD(a, i) - LL_COORD(a, i));
+ }
+ *size = result;
+ return;
+}
+#endif
+
/* make up a metric in which one box will be 'lower' than the other
-- this can be useful for sorting and to determine uniqueness */
-int32
+static int32
cube_cmp_v0(NDBOX *a, NDBOX *b)
{
int i;
@@ -1080,7 +1173,7 @@ cube_ge(PG_FUNCTION_ARGS)
/* Contains */
/* Box(A) CONTAINS Box(B) IFF pt(A) < pt(B) */
-bool
+static bool
cube_contains_v0(NDBOX *a, NDBOX *b)
{
int i;
@@ -1150,7 +1243,7 @@ cube_contained(PG_FUNCTION_ARGS)
/* Overlap */
/* Box(A) Overlap Box(B) IFF (pt(a)LL < pt(B)UR) && (pt(b)LL < pt(a)UR) */
-bool
+static bool
cube_overlap_v0(NDBOX *a, NDBOX *b)
{
int i;
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers