PostGIS  2.4.9dev-r@@SVN_REVISION@@

◆ gserialized_cmp()

int gserialized_cmp ( const GSERIALIZED g1,
const GSERIALIZED g2 
)

Return -1 if g1 is "less than" g2, 1 if g1 is "greater than" g2 and 0 if g1 and g2 are the "same".

Equality is evaluated with a memcmp and size check. So it is possible that two identical objects where one lacks a bounding box could be evaluated as non-equal initially. Greater and less than are evaluated by calculating a sortable key from the center point of the object bounds.

Definition at line 294 of file g_serialized.c.

References GSERIALIZED::data, floatuint::f, GSERIALIZED::flags, FLAGS_GET_BBOX, FLAGS_GET_GEODETIC, gbox_get_sortable_hash(), gserialized_cmp_srid(), gserialized_get_gbox_p(), gserialized_get_type(), gserialized_header_size(), LW_FAILURE, POINTTYPE, GSERIALIZED::size, SIZE_GET, floatuint::u, uint32_interleave_2(), GBOX::xmax, GBOX::xmin, GBOX::ymax, and GBOX::ymin.

Referenced by geography_cmp(), geography_eq(), geography_ge(), geography_gt(), geography_le(), geography_lt(), lwgeom_cmp(), lwgeom_eq(), lwgeom_ge(), lwgeom_gt(), lwgeom_le(), and lwgeom_lt().

295 {
296  int g1_is_empty, g2_is_empty, cmp;
297  GBOX box1, box2;
298  uint64_t hash1, hash2;
299  size_t sz1 = SIZE_GET(g1->size);
300  size_t sz2 = SIZE_GET(g2->size);
301  union floatuint x, y;
302 
303  /*
304  * For two non-same planar points, we can skip a lot of machinery.
305  */
306  if (
307  sz1 > 16 && // 16 is size of EMPTY, if it's larger - it has coordinates
308  sz2 > 16 &&
309  *(uint32_t*)(g1->data) == POINTTYPE &&
310  *(uint32_t*)(g2->data) == POINTTYPE &&
311  !FLAGS_GET_BBOX(g1->flags) &&
312  !FLAGS_GET_GEODETIC(g1->flags) &&
313  !FLAGS_GET_BBOX(g2->flags) &&
315  )
316  {
317  double *dptr = (double*)(g1->data);
318  x.f = 2.0 * dptr[1];
319  y.f = 2.0 * dptr[2];
320  hash1 = uint32_interleave_2(x.u, y.u);
321 
322  dptr = (double*)(g2->data);
323  x.f = 2.0 * dptr[1];
324  y.f = 2.0 * dptr[2];
325  hash2 = uint32_interleave_2(x.u, y.u);
326 
327  if ( hash1 > hash2 )
328  return 1;
329  if ( hash1 < hash2 )
330  return -1;
331 
332  // if hashes happen to be the same, go to full compare.
333  }
334 
335  size_t hsz1 = gserialized_header_size(g1);
336  size_t hsz2 = gserialized_header_size(g2);
337 
338  uint8_t *b1 = (uint8_t*)g1 + hsz1;
339  uint8_t *b2 = (uint8_t*)g2 + hsz2;
340  size_t bsz1 = sz1 - hsz1;
341  size_t bsz2 = sz2 - hsz2;
342  size_t bsz = bsz1 < bsz2 ? bsz1 : bsz2;
343 
344  int cmp_srid = gserialized_cmp_srid(g1, g2);
345 
346  g1_is_empty = (gserialized_get_gbox_p(g1, &box1) == LW_FAILURE);
347  g2_is_empty = (gserialized_get_gbox_p(g2, &box2) == LW_FAILURE);
348 
349  /* Empty == Empty */
350  if (g1_is_empty && g2_is_empty)
351  {
352  /* POINT EMPTY == POINT EMPTY */
353  /* POINT EMPTY < LINESTRING EMPTY */
356  return t1 == t2 ? 0 : (t1 < t2 ? -1 : 1);
357  }
358 
359  /* Empty < Non-empty */
360  if (g1_is_empty)
361  return -1;
362 
363  /* Non-empty > Empty */
364  if (g2_is_empty)
365  return 1;
366 
367  /* Return equality for perfect equality only */
368  cmp = memcmp(b1, b2, bsz);
369  if ( bsz1 == bsz2 && cmp_srid == 0 && cmp == 0 )
370  return 0;
371 
372  /* Using the centroids, calculate somewhat sortable */
373  /* hash key. The key doesn't provide good locality over */
374  /* the +/- boundary, but otherwise is pretty OK */
375  hash1 = gbox_get_sortable_hash(&box1);
376  hash2 = gbox_get_sortable_hash(&box2);
377 
378  if ( hash1 > hash2 )
379  return 1;
380  else if ( hash1 < hash2 )
381  return -1;
382 
383  /* What, the hashes are equal? OK... sort on the */
384  /* box minima */
385  if (box1.xmin < box2.xmin)
386  return -1;
387  else if (box1.xmin > box2.xmin)
388  return 1;
389 
390  if (box1.ymin < box2.ymin)
391  return -1;
392  else if (box1.ymin > box2.ymin)
393  return 1;
394 
395  /* Still equal? OK... sort on the box maxima */
396  if (box1.xmax < box2.xmax)
397  return -1;
398  else if (box1.xmax > box2.xmax)
399  return 1;
400 
401  if (box1.ymax < box2.ymax)
402  return -1;
403  else if (box1.ymax > box2.ymax)
404  return 1;
405 
406  /* Geeze! How about object size? Sort on that... */
407  if (hsz1 < hsz2)
408  return -1;
409  else if (hsz1 > hsz2)
410  return 1;
411 
412  /* OK fine, we'll sort on the memcmp just to be done with this */
413  return cmp == 0 ? 0 : (cmp > 0 ? 1 : -1);
414 }
int gserialized_get_gbox_p(const GSERIALIZED *g, GBOX *box)
Read the bounding box off a serialization and calculate one if it is not already there.
Definition: g_serialized.c:642
uint32_t gserialized_get_type(const GSERIALIZED *s)
Extract the geometry type from the serialized form (it hides in the anonymous data area...
Definition: g_serialized.c:86
uint8_t data[1]
Definition: liblwgeom.h:384
static int gserialized_cmp_srid(const GSERIALIZED *s1, const GSERIALIZED *s2)
Definition: g_serialized.c:133
#define FLAGS_GET_GEODETIC(flags)
Definition: liblwgeom.h:143
double xmax
Definition: liblwgeom.h:293
#define LW_FAILURE
Definition: liblwgeom.h:79
uint64_t gbox_get_sortable_hash(const GBOX *g)
Return a sortable key based on the center point of the GBOX.
Definition: g_serialized.c:259
unsigned int uint32_t
Definition: uthash.h:78
double ymin
Definition: liblwgeom.h:294
static uint64_t uint32_interleave_2(uint32_t u1, uint32_t u2)
Definition: g_serialized.c:228
double xmin
Definition: liblwgeom.h:292
#define FLAGS_GET_BBOX(flags)
Definition: liblwgeom.h:142
double ymax
Definition: liblwgeom.h:295
#define SIZE_GET(varsize)
Macro for reading the size from the GSERIALIZED size attribute.
uint32_t size
Definition: liblwgeom.h:381
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition: liblwgeom.h:85
uint32_t gserialized_header_size(const GSERIALIZED *gser)
Returns the size in bytes of the header, from the start of the object up to the type number...
Definition: g_serialized.c:76
unsigned char uint8_t
Definition: uthash.h:79
uint8_t flags
Definition: liblwgeom.h:383
Here is the call graph for this function:
Here is the caller graph for this function: