Age Owner TLA Line data Source code
1 : /*
2 : * contrib/seg/seg.c
3 : *
4 : ******************************************************************************
5 : This file contains routines that can be bound to a Postgres backend and
6 : called by the backend in the process of processing queries. The calling
7 : format for these routines is dictated by Postgres architecture.
8 : ******************************************************************************/
9 :
10 : #include "postgres.h"
11 :
12 : #include <float.h>
13 : #include <math.h>
14 :
15 : #include "access/gist.h"
16 : #include "access/stratnum.h"
17 : #include "fmgr.h"
18 :
19 : #include "segdata.h"
20 :
21 :
22 : #define DatumGetSegP(X) ((SEG *) DatumGetPointer(X))
23 : #define PG_GETARG_SEG_P(n) DatumGetSegP(PG_GETARG_DATUM(n))
24 :
25 :
26 : /*
27 : #define GIST_DEBUG
28 : #define GIST_QUERY_DEBUG
29 : */
30 :
6158 tgl 31 GIC 1 : PG_MODULE_MAGIC;
6158 tgl 32 ECB :
33 : /*
34 : * Auxiliary data structure for picksplit method.
35 : */
36 : typedef struct
37 : {
38 : float center;
39 : OffsetNumber index;
40 : SEG *data;
41 : } gseg_picksplit_item;
42 :
43 : /*
44 : ** Input/Output routines
45 : */
5469 alvherre 46 GIC 2 : PG_FUNCTION_INFO_V1(seg_in);
5469 alvherre 47 CBC 2 : PG_FUNCTION_INFO_V1(seg_out);
5468 tgl 48 1 : PG_FUNCTION_INFO_V1(seg_size);
5469 alvherre 49 2 : PG_FUNCTION_INFO_V1(seg_lower);
50 2 : PG_FUNCTION_INFO_V1(seg_upper);
51 2 : PG_FUNCTION_INFO_V1(seg_center);
5469 alvherre 52 ECB :
53 : /*
54 : ** GiST support methods
55 : */
2202 andres 56 GIC 2 : PG_FUNCTION_INFO_V1(gseg_consistent);
2202 andres 57 CBC 1 : PG_FUNCTION_INFO_V1(gseg_compress);
58 1 : PG_FUNCTION_INFO_V1(gseg_decompress);
59 2 : PG_FUNCTION_INFO_V1(gseg_picksplit);
60 2 : PG_FUNCTION_INFO_V1(gseg_penalty);
61 2 : PG_FUNCTION_INFO_V1(gseg_union);
62 2 : PG_FUNCTION_INFO_V1(gseg_same);
2202 andres 63 ECB : static Datum gseg_leaf_consistent(Datum key, Datum query, StrategyNumber strategy);
64 : static Datum gseg_internal_consistent(Datum key, Datum query, StrategyNumber strategy);
65 : static Datum gseg_binary_union(Datum r1, Datum r2, int *sizep);
66 :
67 :
68 : /*
69 : ** R-tree support functions
70 : */
2202 andres 71 GIC 2 : PG_FUNCTION_INFO_V1(seg_same);
2202 andres 72 CBC 2 : PG_FUNCTION_INFO_V1(seg_contains);
73 2 : PG_FUNCTION_INFO_V1(seg_contained);
74 2 : PG_FUNCTION_INFO_V1(seg_overlap);
75 2 : PG_FUNCTION_INFO_V1(seg_left);
76 2 : PG_FUNCTION_INFO_V1(seg_over_left);
77 2 : PG_FUNCTION_INFO_V1(seg_right);
78 2 : PG_FUNCTION_INFO_V1(seg_over_right);
79 1 : PG_FUNCTION_INFO_V1(seg_union);
80 1 : PG_FUNCTION_INFO_V1(seg_inter);
2202 andres 81 ECB : static void rt_seg_size(SEG *a, float *size);
82 :
83 : /*
84 : ** Various operators
85 : */
2202 andres 86 GIC 2 : PG_FUNCTION_INFO_V1(seg_cmp);
2202 andres 87 CBC 1 : PG_FUNCTION_INFO_V1(seg_lt);
88 1 : PG_FUNCTION_INFO_V1(seg_le);
89 1 : PG_FUNCTION_INFO_V1(seg_gt);
90 1 : PG_FUNCTION_INFO_V1(seg_ge);
91 2 : PG_FUNCTION_INFO_V1(seg_different);
8053 bruce 92 ECB :
93 : /*
94 : ** Auxiliary functions
95 : */
96 : static int restore(char *result, float val, int n);
97 :
98 :
99 : /*****************************************************************************
100 : * Input/Output functions
101 : *****************************************************************************/
102 :
103 : Datum
5469 alvherre 104 GIC 2823 : seg_in(PG_FUNCTION_ARGS)
8154 tgl 105 ECB : {
5469 alvherre 106 GIC 2823 : char *str = PG_GETARG_CSTRING(0);
8053 bruce 107 CBC 2823 : SEG *result = palloc(sizeof(SEG));
8053 bruce 108 ECB :
7147 tgl 109 GIC 2823 : seg_scanner_init(str);
8053 bruce 110 ECB :
107 andrew 111 GNC 2823 : if (seg_yyparse(result, fcinfo->context) != 0)
112 8 : seg_yyerror(result, fcinfo->context, "bogus input");
7147 tgl 113 ECB :
7147 tgl 114 GIC 2814 : seg_scanner_finish();
7147 tgl 115 ECB :
5469 alvherre 116 GIC 2814 : PG_RETURN_POINTER(result);
8154 tgl 117 ECB : }
118 :
119 : Datum
5469 alvherre 120 GIC 209 : seg_out(PG_FUNCTION_ARGS)
8154 tgl 121 ECB : {
2202 andres 122 GIC 209 : SEG *seg = PG_GETARG_SEG_P(0);
8053 bruce 123 ECB : char *result;
124 : char *p;
125 :
8053 bruce 126 GIC 209 : p = result = (char *) palloc(40);
8053 bruce 127 ECB :
8053 bruce 128 GIC 209 : if (seg->l_ext == '>' || seg->l_ext == '<' || seg->l_ext == '~')
8053 bruce 129 CBC 22 : p += sprintf(p, "%c", seg->l_ext);
8053 bruce 130 ECB :
8053 bruce 131 GIC 209 : if (seg->lower == seg->upper && seg->l_ext == seg->u_ext)
8053 bruce 132 ECB : {
133 : /*
134 : * indicates that this interval was built by seg_in off a single point
135 : */
8053 bruce 136 GIC 47 : p += restore(p, seg->lower, seg->l_sigd);
8053 bruce 137 ECB : }
138 : else
139 : {
8053 bruce 140 GIC 162 : if (seg->l_ext != '-')
8053 bruce 141 ECB : {
142 : /* print the lower boundary if exists */
8053 bruce 143 GIC 155 : p += restore(p, seg->lower, seg->l_sigd);
8053 bruce 144 CBC 155 : p += sprintf(p, " ");
8053 bruce 145 ECB : }
8053 bruce 146 GIC 162 : p += sprintf(p, "..");
8053 bruce 147 CBC 162 : if (seg->u_ext != '-')
8053 bruce 148 ECB : {
149 : /* print the upper boundary if exists */
8053 bruce 150 GIC 123 : p += sprintf(p, " ");
8053 bruce 151 CBC 123 : if (seg->u_ext == '>' || seg->u_ext == '<' || seg->l_ext == '~')
152 32 : p += sprintf(p, "%c", seg->u_ext);
153 123 : p += restore(p, seg->upper, seg->u_sigd);
8053 bruce 154 ECB : }
155 : }
156 :
5469 alvherre 157 GIC 209 : PG_RETURN_CSTRING(result);
8154 tgl 158 ECB : }
159 :
160 : Datum
5469 alvherre 161 GIC 143 : seg_center(PG_FUNCTION_ARGS)
8154 tgl 162 ECB : {
2202 andres 163 GIC 143 : SEG *seg = PG_GETARG_SEG_P(0);
5469 alvherre 164 ECB :
5469 alvherre 165 GIC 143 : PG_RETURN_FLOAT4(((float) seg->lower + (float) seg->upper) / 2.0);
8154 tgl 166 ECB : }
167 :
168 : Datum
5469 alvherre 169 GIC 143 : seg_lower(PG_FUNCTION_ARGS)
8154 tgl 170 ECB : {
2202 andres 171 GIC 143 : SEG *seg = PG_GETARG_SEG_P(0);
5469 alvherre 172 ECB :
5469 alvherre 173 GIC 143 : PG_RETURN_FLOAT4(seg->lower);
8154 tgl 174 ECB : }
175 :
176 : Datum
5469 alvherre 177 GIC 143 : seg_upper(PG_FUNCTION_ARGS)
8154 tgl 178 ECB : {
2202 andres 179 GIC 143 : SEG *seg = PG_GETARG_SEG_P(0);
5469 alvherre 180 ECB :
5469 alvherre 181 GIC 143 : PG_RETURN_FLOAT4(seg->upper);
8154 tgl 182 ECB : }
183 :
184 :
185 : /*****************************************************************************
186 : * GiST functions
187 : *****************************************************************************/
188 :
189 : /*
190 : ** The GiST Consistent method for segments
191 : ** Should return false if for all data items x below entry,
192 : ** the predicate x op query == false, where op is the oper
193 : ** corresponding to strategy in the pg_amop table.
194 : */
195 : Datum
2202 andres 196 GIC 5892 : gseg_consistent(PG_FUNCTION_ARGS)
8154 tgl 197 ECB : {
2202 andres 198 GIC 5892 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
2202 andres 199 CBC 5892 : Datum query = PG_GETARG_DATUM(1);
200 5892 : StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
2202 andres 201 ECB :
202 : /* Oid subtype = PG_GETARG_OID(3); */
2202 andres 203 GIC 5892 : bool *recheck = (bool *) PG_GETARG_POINTER(4);
2202 andres 204 ECB :
205 : /* All cases served by this function are exact */
5473 tgl 206 GIC 5892 : *recheck = false;
5473 tgl 207 ECB :
208 : /*
209 : * if entry is not leaf, use gseg_internal_consistent, else use
210 : * gseg_leaf_consistent
211 : */
8053 bruce 212 GIC 5892 : if (GIST_LEAF(entry))
2202 andres 213 CBC 5820 : return gseg_leaf_consistent(entry->key, query, strategy);
8053 bruce 214 ECB : else
2202 andres 215 GIC 72 : return gseg_internal_consistent(entry->key, query, strategy);
8154 tgl 216 ECB : }
217 :
218 : /*
219 : ** The GiST Union method for segments
220 : ** returns the minimal bounding seg that encloses all the entries in entryvec
221 : */
222 : Datum
2202 andres 223 GIC 2316 : gseg_union(PG_FUNCTION_ARGS)
8154 tgl 224 ECB : {
2202 andres 225 GIC 2316 : GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
2202 andres 226 CBC 2316 : int *sizep = (int *) PG_GETARG_POINTER(1);
8053 bruce 227 ECB : int numranges,
228 : i;
2202 andres 229 GIC 2316 : Datum out = 0;
2202 andres 230 ECB : Datum tmp;
231 :
232 : #ifdef GIST_DEBUG
233 : fprintf(stderr, "union\n");
234 : #endif
235 :
6949 teodor 236 GIC 2316 : numranges = entryvec->n;
2202 andres 237 CBC 2316 : tmp = entryvec->vector[0].key;
8053 bruce 238 2316 : *sizep = sizeof(SEG);
8154 tgl 239 ECB :
8053 bruce 240 GIC 4632 : for (i = 1; i < numranges; i++)
8053 bruce 241 ECB : {
2202 andres 242 GIC 2316 : out = gseg_binary_union(tmp, entryvec->vector[i].key, sizep);
8053 bruce 243 CBC 2316 : tmp = out;
8053 bruce 244 ECB : }
245 :
2202 andres 246 GIC 2316 : PG_RETURN_DATUM(out);
8154 tgl 247 ECB : }
248 :
249 : /*
250 : ** GiST Compress and Decompress methods for segments
251 : ** do not do anything.
252 : */
253 : Datum
2202 andres 254 UIC 0 : gseg_compress(PG_FUNCTION_ARGS)
8154 tgl 255 EUB : {
2202 andres 256 UIC 0 : PG_RETURN_POINTER(PG_GETARG_POINTER(0));
8154 tgl 257 EUB : }
258 :
259 : Datum
2202 andres 260 UIC 0 : gseg_decompress(PG_FUNCTION_ARGS)
8154 tgl 261 EUB : {
2202 andres 262 UIC 0 : PG_RETURN_POINTER(PG_GETARG_POINTER(0));
8154 tgl 263 EUB : }
264 :
265 : /*
266 : ** The GiST Penalty method for segments
267 : ** As in the R-tree paper, we use change in area as our penalty metric
268 : */
269 : Datum
2202 andres 270 GIC 5157 : gseg_penalty(PG_FUNCTION_ARGS)
8154 tgl 271 ECB : {
2202 andres 272 GIC 5157 : GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0);
2202 andres 273 CBC 5157 : GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
274 5157 : float *result = (float *) PG_GETARG_POINTER(2);
7983 tgl 275 ECB : SEG *ud;
276 : float tmp1,
277 : tmp2;
278 :
2202 andres 279 GIC 5157 : ud = DatumGetSegP(DirectFunctionCall2(seg_union,
2202 andres 280 ECB : origentry->key,
281 : newentry->key));
7983 tgl 282 GIC 5157 : rt_seg_size(ud, &tmp1);
2202 andres 283 CBC 5157 : rt_seg_size(DatumGetSegP(origentry->key), &tmp2);
8053 bruce 284 5157 : *result = tmp1 - tmp2;
8154 tgl 285 ECB :
286 : #ifdef GIST_DEBUG
287 : fprintf(stderr, "penalty\n");
288 : fprintf(stderr, "\t%g\n", *result);
289 : #endif
290 :
2202 andres 291 GIC 5157 : PG_RETURN_POINTER(result);
8154 tgl 292 ECB : }
293 :
294 : /*
295 : * Compare function for gseg_picksplit_item: sort by center.
296 : */
297 : static int
4498 tgl 298 GIC 29102 : gseg_picksplit_item_cmp(const void *a, const void *b)
4498 tgl 299 ECB : {
4498 tgl 300 GIC 29102 : const gseg_picksplit_item *i1 = (const gseg_picksplit_item *) a;
4498 tgl 301 CBC 29102 : const gseg_picksplit_item *i2 = (const gseg_picksplit_item *) b;
8154 tgl 302 ECB :
4498 tgl 303 GIC 29102 : if (i1->center < i2->center)
4498 tgl 304 CBC 11931 : return -1;
305 17171 : else if (i1->center == i2->center)
306 5238 : return 0;
4498 tgl 307 ECB : else
4498 tgl 308 GIC 11933 : return 1;
4498 tgl 309 ECB : }
310 :
311 : /*
312 : * The GiST PickSplit method for segments
313 : *
314 : * We used to use Guttman's split algorithm here, but since the data is 1-D
315 : * it's easier and more robust to just sort the segments by center-point and
316 : * split at the middle.
317 : */
318 : Datum
2202 andres 319 GIC 17 : gseg_picksplit(PG_FUNCTION_ARGS)
8154 tgl 320 ECB : {
2202 andres 321 GIC 17 : GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
2202 andres 322 CBC 17 : GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
4498 tgl 323 ECB : int i;
324 : SEG *seg,
325 : *seg_l,
326 : *seg_r;
327 : gseg_picksplit_item *sort_items;
328 : OffsetNumber *left,
329 : *right;
330 : OffsetNumber maxoff;
331 : OffsetNumber firstright;
332 :
333 : #ifdef GIST_DEBUG
334 : fprintf(stderr, "picksplit\n");
335 : #endif
336 :
337 : /* Valid items in entryvec->vector[] are indexed 1..maxoff */
4498 tgl 338 GIC 17 : maxoff = entryvec->n - 1;
8053 bruce 339 ECB :
340 : /*
341 : * Prepare the auxiliary array and sort it.
342 : */
343 : sort_items = (gseg_picksplit_item *)
4498 tgl 344 GIC 17 : palloc(maxoff * sizeof(gseg_picksplit_item));
4498 tgl 345 CBC 4471 : for (i = 1; i <= maxoff; i++)
8053 bruce 346 ECB : {
2202 andres 347 GIC 4454 : seg = DatumGetSegP(entryvec->vector[i].key);
4498 tgl 348 ECB : /* center calculation is done this way to avoid possible overflow */
4382 bruce 349 GIC 4454 : sort_items[i - 1].center = seg->lower * 0.5f + seg->upper * 0.5f;
4498 tgl 350 CBC 4454 : sort_items[i - 1].index = i;
351 4454 : sort_items[i - 1].data = seg;
8154 tgl 352 ECB : }
4498 tgl 353 GIC 17 : qsort(sort_items, maxoff, sizeof(gseg_picksplit_item),
4498 tgl 354 ECB : gseg_picksplit_item_cmp);
355 :
356 : /* sort items below "firstright" will go into the left side */
4498 tgl 357 GIC 17 : firstright = maxoff / 2;
8053 bruce 358 ECB :
4498 tgl 359 GIC 17 : v->spl_left = (OffsetNumber *) palloc(maxoff * sizeof(OffsetNumber));
4498 tgl 360 CBC 17 : v->spl_right = (OffsetNumber *) palloc(maxoff * sizeof(OffsetNumber));
8053 bruce 361 17 : left = v->spl_left;
362 17 : v->spl_nleft = 0;
363 17 : right = v->spl_right;
364 17 : v->spl_nright = 0;
8053 bruce 365 ECB :
366 : /*
367 : * Emit segments to the left output page, and compute its bounding box.
368 : */
2202 andres 369 GIC 17 : seg_l = (SEG *) palloc(sizeof(SEG));
2202 andres 370 CBC 17 : memcpy(seg_l, sort_items[0].data, sizeof(SEG));
4498 tgl 371 17 : *left++ = sort_items[0].index;
372 17 : v->spl_nleft++;
373 2227 : for (i = 1; i < firstright; i++)
8053 bruce 374 ECB : {
2202 andres 375 GIC 2210 : Datum sortitem = PointerGetDatum(sort_items[i].data);
2202 andres 376 ECB :
2202 andres 377 GIC 2210 : seg_l = DatumGetSegP(DirectFunctionCall2(seg_union,
2202 andres 378 ECB : PointerGetDatum(seg_l),
379 : sortitem));
4498 tgl 380 GIC 2210 : *left++ = sort_items[i].index;
4498 tgl 381 CBC 2210 : v->spl_nleft++;
4498 tgl 382 ECB : }
383 :
384 : /*
385 : * Likewise for the right page.
386 : */
2202 andres 387 GIC 17 : seg_r = (SEG *) palloc(sizeof(SEG));
2202 andres 388 CBC 17 : memcpy(seg_r, sort_items[firstright].data, sizeof(SEG));
4498 tgl 389 17 : *right++ = sort_items[firstright].index;
390 17 : v->spl_nright++;
391 2227 : for (i = firstright + 1; i < maxoff; i++)
4498 tgl 392 ECB : {
2202 andres 393 GIC 2210 : Datum sortitem = PointerGetDatum(sort_items[i].data);
2202 andres 394 ECB :
2202 andres 395 GIC 2210 : seg_r = DatumGetSegP(DirectFunctionCall2(seg_union,
2202 andres 396 ECB : PointerGetDatum(seg_r),
397 : sortitem));
4498 tgl 398 GIC 2210 : *right++ = sort_items[i].index;
4498 tgl 399 CBC 2210 : v->spl_nright++;
8154 tgl 400 ECB : }
401 :
2202 andres 402 GIC 17 : v->spl_ldatum = PointerGetDatum(seg_l);
2202 andres 403 CBC 17 : v->spl_rdatum = PointerGetDatum(seg_r);
8154 tgl 404 ECB :
2202 andres 405 GIC 17 : PG_RETURN_POINTER(v);
8154 tgl 406 ECB : }
407 :
408 : /*
409 : ** Equality methods
410 : */
411 : Datum
2202 andres 412 GIC 2315 : gseg_same(PG_FUNCTION_ARGS)
8154 tgl 413 ECB : {
2202 andres 414 GIC 2315 : bool *result = (bool *) PG_GETARG_POINTER(2);
2202 andres 415 ECB :
2202 andres 416 GIC 2315 : if (DirectFunctionCall2(seg_same, PG_GETARG_DATUM(0), PG_GETARG_DATUM(1)))
2062 peter_e 417 CBC 2286 : *result = true;
8053 bruce 418 ECB : else
2062 peter_e 419 GIC 29 : *result = false;
8154 tgl 420 ECB :
421 : #ifdef GIST_DEBUG
422 : fprintf(stderr, "same: %s\n", (*result ? "TRUE" : "FALSE"));
423 : #endif
424 :
2202 andres 425 GIC 2315 : PG_RETURN_POINTER(result);
8154 tgl 426 ECB : }
427 :
428 : /*
429 : ** SUPPORT ROUTINES
430 : */
431 : static Datum
2202 andres 432 GIC 5820 : gseg_leaf_consistent(Datum key, Datum query, StrategyNumber strategy)
8154 tgl 433 ECB : {
434 : Datum retval;
435 :
436 : #ifdef GIST_QUERY_DEBUG
437 : fprintf(stderr, "leaf_consistent, %d\n", strategy);
438 : #endif
439 :
8053 bruce 440 GIC 5820 : switch (strategy)
8053 bruce 441 ECB : {
8053 bruce 442 UIC 0 : case RTLeftStrategyNumber:
2202 andres 443 UBC 0 : retval = DirectFunctionCall2(seg_left, key, query);
8053 bruce 444 0 : break;
445 0 : case RTOverLeftStrategyNumber:
2202 andres 446 0 : retval = DirectFunctionCall2(seg_over_left, key, query);
8053 bruce 447 0 : break;
448 0 : case RTOverlapStrategyNumber:
2202 andres 449 0 : retval = DirectFunctionCall2(seg_overlap, key, query);
8053 bruce 450 0 : break;
451 0 : case RTOverRightStrategyNumber:
2202 andres 452 0 : retval = DirectFunctionCall2(seg_over_right, key, query);
8053 bruce 453 0 : break;
454 0 : case RTRightStrategyNumber:
2202 andres 455 0 : retval = DirectFunctionCall2(seg_right, key, query);
8053 bruce 456 0 : break;
457 0 : case RTSameStrategyNumber:
2202 andres 458 0 : retval = DirectFunctionCall2(seg_same, key, query);
8053 bruce 459 0 : break;
8053 bruce 460 GBC 5820 : case RTContainsStrategyNumber:
6055 tgl 461 ECB : case RTOldContainsStrategyNumber:
2202 andres 462 GIC 5820 : retval = DirectFunctionCall2(seg_contains, key, query);
8053 bruce 463 CBC 5820 : break;
8053 bruce 464 LBC 0 : case RTContainedByStrategyNumber:
6055 tgl 465 EUB : case RTOldContainedByStrategyNumber:
2202 andres 466 UIC 0 : retval = DirectFunctionCall2(seg_contained, key, query);
8053 bruce 467 UBC 0 : break;
468 0 : default:
2062 peter_e 469 0 : retval = false;
8053 bruce 470 EUB : }
471 :
2202 andres 472 GIC 5820 : PG_RETURN_DATUM(retval);
8154 tgl 473 ECB : }
474 :
475 : static Datum
2202 andres 476 GIC 72 : gseg_internal_consistent(Datum key, Datum query, StrategyNumber strategy)
8154 tgl 477 ECB : {
478 : bool retval;
479 :
480 : #ifdef GIST_QUERY_DEBUG
481 : fprintf(stderr, "internal_consistent, %d\n", strategy);
482 : #endif
483 :
8053 bruce 484 GIC 72 : switch (strategy)
8053 bruce 485 ECB : {
8053 bruce 486 UIC 0 : case RTLeftStrategyNumber:
2202 andres 487 UBC 0 : retval =
488 0 : !DatumGetBool(DirectFunctionCall2(seg_over_right, key, query));
6495 tgl 489 0 : break;
8053 bruce 490 0 : case RTOverLeftStrategyNumber:
2202 andres 491 0 : retval =
492 0 : !DatumGetBool(DirectFunctionCall2(seg_right, key, query));
8053 bruce 493 0 : break;
494 0 : case RTOverlapStrategyNumber:
2202 andres 495 EUB : retval =
2202 andres 496 UIC 0 : DatumGetBool(DirectFunctionCall2(seg_overlap, key, query));
8053 bruce 497 UBC 0 : break;
498 0 : case RTOverRightStrategyNumber:
2202 andres 499 0 : retval =
500 0 : !DatumGetBool(DirectFunctionCall2(seg_left, key, query));
6495 tgl 501 0 : break;
8053 bruce 502 0 : case RTRightStrategyNumber:
2202 andres 503 0 : retval =
504 0 : !DatumGetBool(DirectFunctionCall2(seg_over_left, key, query));
8053 bruce 505 0 : break;
8053 bruce 506 GBC 72 : case RTSameStrategyNumber:
8053 bruce 507 ECB : case RTContainsStrategyNumber:
508 : case RTOldContainsStrategyNumber:
509 : retval =
2202 andres 510 GIC 72 : DatumGetBool(DirectFunctionCall2(seg_contains, key, query));
8053 bruce 511 CBC 72 : break;
8053 bruce 512 LBC 0 : case RTContainedByStrategyNumber:
6055 tgl 513 EUB : case RTOldContainedByStrategyNumber:
514 : retval =
2202 andres 515 UIC 0 : DatumGetBool(DirectFunctionCall2(seg_overlap, key, query));
8053 bruce 516 UBC 0 : break;
517 0 : default:
2062 peter_e 518 0 : retval = false;
8053 bruce 519 EUB : }
520 :
2202 andres 521 GIC 72 : PG_RETURN_BOOL(retval);
8154 tgl 522 ECB : }
523 :
524 : static Datum
2202 andres 525 GIC 2316 : gseg_binary_union(Datum r1, Datum r2, int *sizep)
8154 tgl 526 ECB : {
527 : Datum retval;
528 :
2202 andres 529 GIC 2316 : retval = DirectFunctionCall2(seg_union, r1, r2);
8053 bruce 530 CBC 2316 : *sizep = sizeof(SEG);
8154 tgl 531 ECB :
2061 peter_e 532 GIC 2316 : return retval;
8154 tgl 533 ECB : }
534 :
535 :
536 : Datum
2202 andres 537 GIC 5907 : seg_contains(PG_FUNCTION_ARGS)
8154 tgl 538 ECB : {
2202 andres 539 GIC 5907 : SEG *a = PG_GETARG_SEG_P(0);
2202 andres 540 CBC 5907 : SEG *b = PG_GETARG_SEG_P(1);
2202 andres 541 ECB :
2202 andres 542 GIC 5907 : PG_RETURN_BOOL((a->lower <= b->lower) && (a->upper >= b->upper));
8154 tgl 543 ECB : }
544 :
545 : Datum
2202 andres 546 GIC 14 : seg_contained(PG_FUNCTION_ARGS)
8154 tgl 547 ECB : {
2202 andres 548 GIC 14 : Datum a = PG_GETARG_DATUM(0);
2202 andres 549 CBC 14 : Datum b = PG_GETARG_DATUM(1);
2202 andres 550 ECB :
2202 andres 551 GIC 14 : PG_RETURN_DATUM(DirectFunctionCall2(seg_contains, b, a));
8154 tgl 552 ECB : }
553 :
554 : /*****************************************************************************
555 : * Operator class for R-tree indexing
556 : *****************************************************************************/
557 :
558 : Datum
2202 andres 559 GIC 2459 : seg_same(PG_FUNCTION_ARGS)
8154 tgl 560 ECB : {
1165 alvherre 561 GIC 2459 : int cmp = DatumGetInt32(DirectFunctionCall2(seg_cmp,
1165 alvherre 562 ECB : PG_GETARG_DATUM(0),
563 : PG_GETARG_DATUM(1)));
564 :
2202 andres 565 GIC 2459 : PG_RETURN_BOOL(cmp == 0);
8154 tgl 566 ECB : }
567 :
568 : /* seg_overlap -- does a overlap b?
569 : */
570 : Datum
2202 andres 571 GIC 15 : seg_overlap(PG_FUNCTION_ARGS)
8154 tgl 572 ECB : {
2202 andres 573 GIC 15 : SEG *a = PG_GETARG_SEG_P(0);
2202 andres 574 CBC 15 : SEG *b = PG_GETARG_SEG_P(1);
2202 andres 575 ECB :
2202 andres 576 GIC 15 : PG_RETURN_BOOL(((a->upper >= b->upper) && (a->lower <= b->upper)) ||
2202 andres 577 ECB : ((b->upper >= a->upper) && (b->lower <= a->upper)));
578 : }
579 :
580 : /* seg_over_left -- is the right edge of (a) located at or left of the right edge of (b)?
581 : */
582 : Datum
2202 andres 583 GIC 11 : seg_over_left(PG_FUNCTION_ARGS)
8154 tgl 584 ECB : {
2202 andres 585 GIC 11 : SEG *a = PG_GETARG_SEG_P(0);
2202 andres 586 CBC 11 : SEG *b = PG_GETARG_SEG_P(1);
2202 andres 587 ECB :
2202 andres 588 GIC 11 : PG_RETURN_BOOL(a->upper <= b->upper);
8154 tgl 589 ECB : }
590 :
591 : /* seg_left -- is (a) entirely on the left of (b)?
592 : */
593 : Datum
2202 andres 594 GIC 11 : seg_left(PG_FUNCTION_ARGS)
8154 tgl 595 ECB : {
2202 andres 596 GIC 11 : SEG *a = PG_GETARG_SEG_P(0);
2202 andres 597 CBC 11 : SEG *b = PG_GETARG_SEG_P(1);
2202 andres 598 ECB :
2202 andres 599 GIC 11 : PG_RETURN_BOOL(a->upper < b->lower);
8154 tgl 600 ECB : }
601 :
602 : /* seg_right -- is (a) entirely on the right of (b)?
603 : */
604 : Datum
2202 andres 605 GIC 11 : seg_right(PG_FUNCTION_ARGS)
8154 tgl 606 ECB : {
2202 andres 607 GIC 11 : SEG *a = PG_GETARG_SEG_P(0);
2202 andres 608 CBC 11 : SEG *b = PG_GETARG_SEG_P(1);
2202 andres 609 ECB :
2202 andres 610 GIC 11 : PG_RETURN_BOOL(a->lower > b->upper);
8154 tgl 611 ECB : }
612 :
613 : /* seg_over_right -- is the left edge of (a) located at or right of the left edge of (b)?
614 : */
615 : Datum
2202 andres 616 GIC 11 : seg_over_right(PG_FUNCTION_ARGS)
8154 tgl 617 ECB : {
2202 andres 618 GIC 11 : SEG *a = PG_GETARG_SEG_P(0);
2202 andres 619 CBC 11 : SEG *b = PG_GETARG_SEG_P(1);
8154 tgl 620 ECB :
2202 andres 621 GIC 11 : PG_RETURN_BOOL(a->lower >= b->lower);
2202 andres 622 ECB : }
623 :
624 : Datum
2202 andres 625 GIC 11893 : seg_union(PG_FUNCTION_ARGS)
8154 tgl 626 ECB : {
2202 andres 627 GIC 11893 : SEG *a = PG_GETARG_SEG_P(0);
2202 andres 628 CBC 11893 : SEG *b = PG_GETARG_SEG_P(1);
8053 bruce 629 ECB : SEG *n;
630 :
8053 bruce 631 GIC 11893 : n = (SEG *) palloc(sizeof(*n));
8053 bruce 632 ECB :
633 : /* take max of upper endpoints */
8053 bruce 634 GIC 11893 : if (a->upper > b->upper)
8053 bruce 635 ECB : {
8053 bruce 636 GIC 10498 : n->upper = a->upper;
8053 bruce 637 CBC 10498 : n->u_sigd = a->u_sigd;
638 10498 : n->u_ext = a->u_ext;
8053 bruce 639 ECB : }
640 : else
641 : {
8053 bruce 642 GIC 1395 : n->upper = b->upper;
8053 bruce 643 CBC 1395 : n->u_sigd = b->u_sigd;
644 1395 : n->u_ext = b->u_ext;
8053 bruce 645 ECB : }
646 :
647 : /* take min of lower endpoints */
8053 bruce 648 GIC 11893 : if (a->lower < b->lower)
8053 bruce 649 ECB : {
8053 bruce 650 GIC 11597 : n->lower = a->lower;
8053 bruce 651 CBC 11597 : n->l_sigd = a->l_sigd;
652 11597 : n->l_ext = a->l_ext;
8053 bruce 653 ECB : }
654 : else
655 : {
8053 bruce 656 GIC 296 : n->lower = b->lower;
8053 bruce 657 CBC 296 : n->l_sigd = b->l_sigd;
658 296 : n->l_ext = b->l_ext;
8053 bruce 659 ECB : }
660 :
2202 andres 661 GIC 11893 : PG_RETURN_POINTER(n);
8154 tgl 662 ECB : }
663 :
664 : Datum
2202 andres 665 UIC 0 : seg_inter(PG_FUNCTION_ARGS)
8154 tgl 666 EUB : {
2202 andres 667 UIC 0 : SEG *a = PG_GETARG_SEG_P(0);
2202 andres 668 UBC 0 : SEG *b = PG_GETARG_SEG_P(1);
8053 bruce 669 EUB : SEG *n;
670 :
8053 bruce 671 UIC 0 : n = (SEG *) palloc(sizeof(*n));
8053 bruce 672 EUB :
673 : /* take min of upper endpoints */
8053 bruce 674 UIC 0 : if (a->upper < b->upper)
8053 bruce 675 EUB : {
8053 bruce 676 UIC 0 : n->upper = a->upper;
8053 bruce 677 UBC 0 : n->u_sigd = a->u_sigd;
678 0 : n->u_ext = a->u_ext;
8053 bruce 679 EUB : }
680 : else
681 : {
8053 bruce 682 UIC 0 : n->upper = b->upper;
8053 bruce 683 UBC 0 : n->u_sigd = b->u_sigd;
684 0 : n->u_ext = b->u_ext;
8053 bruce 685 EUB : }
686 :
687 : /* take max of lower endpoints */
8053 bruce 688 UIC 0 : if (a->lower > b->lower)
8053 bruce 689 EUB : {
8053 bruce 690 UIC 0 : n->lower = a->lower;
8053 bruce 691 UBC 0 : n->l_sigd = a->l_sigd;
692 0 : n->l_ext = a->l_ext;
8053 bruce 693 EUB : }
694 : else
695 : {
8053 bruce 696 UIC 0 : n->lower = b->lower;
8053 bruce 697 UBC 0 : n->l_sigd = b->l_sigd;
698 0 : n->l_ext = b->l_ext;
8053 bruce 699 EUB : }
700 :
2202 andres 701 UIC 0 : PG_RETURN_POINTER(n);
8154 tgl 702 EUB : }
703 :
704 : static void
5050 bruce 705 GIC 10314 : rt_seg_size(SEG *a, float *size)
8154 tgl 706 ECB : {
8053 bruce 707 GIC 10314 : if (a == (SEG *) NULL || a->upper <= a->lower)
8053 bruce 708 LBC 0 : *size = 0.0;
8053 bruce 709 EUB : else
183 peter 710 GNC 10314 : *size = fabsf(a->upper - a->lower);
8154 tgl 711 CBC 10314 : }
8154 tgl 712 ECB :
713 : Datum
5468 tgl 714 UIC 0 : seg_size(PG_FUNCTION_ARGS)
8154 tgl 715 EUB : {
2202 andres 716 UIC 0 : SEG *seg = PG_GETARG_SEG_P(0);
8154 tgl 717 EUB :
183 peter 718 UNC 0 : PG_RETURN_FLOAT4(fabsf(seg->upper - seg->lower));
8154 tgl 719 EUB : }
720 :
721 :
722 : /*****************************************************************************
723 : * Miscellaneous operators
724 : *****************************************************************************/
725 : Datum
2202 andres 726 GIC 4433 : seg_cmp(PG_FUNCTION_ARGS)
8154 tgl 727 ECB : {
2202 andres 728 GIC 4433 : SEG *a = PG_GETARG_SEG_P(0);
2202 andres 729 CBC 4433 : SEG *b = PG_GETARG_SEG_P(1);
2202 andres 730 ECB :
731 : /*
732 : * First compare on lower boundary position
733 : */
8053 bruce 734 GIC 4433 : if (a->lower < b->lower)
2202 andres 735 CBC 904 : PG_RETURN_INT32(-1);
8053 bruce 736 3529 : if (a->lower > b->lower)
2202 andres 737 801 : PG_RETURN_INT32(1);
8053 bruce 738 ECB :
739 : /*
740 : * a->lower == b->lower, so consider type of boundary.
741 : *
742 : * A '-' lower bound is < any other kind (this could only be relevant if
743 : * -HUGE_VAL is used as a regular data value). A '<' lower bound is < any
744 : * other kind except '-'. A '>' lower bound is > any other kind.
745 : */
8053 bruce 746 GIC 2728 : if (a->l_ext != b->l_ext)
8154 tgl 747 ECB : {
8053 bruce 748 GIC 66 : if (a->l_ext == '-')
2202 andres 749 LBC 0 : PG_RETURN_INT32(-1);
8053 bruce 750 GBC 66 : if (b->l_ext == '-')
2202 andres 751 LBC 0 : PG_RETURN_INT32(1);
8053 bruce 752 GBC 66 : if (a->l_ext == '<')
2202 andres 753 CBC 26 : PG_RETURN_INT32(-1);
8053 bruce 754 40 : if (b->l_ext == '<')
2202 andres 755 21 : PG_RETURN_INT32(1);
8053 bruce 756 19 : if (a->l_ext == '>')
2202 andres 757 13 : PG_RETURN_INT32(1);
8053 bruce 758 6 : if (b->l_ext == '>')
2202 andres 759 6 : PG_RETURN_INT32(-1);
8154 tgl 760 ECB : }
761 :
762 : /*
763 : * For other boundary types, consider # of significant digits first.
764 : */
6385 bruce 765 GIC 2662 : if (a->l_sigd < b->l_sigd) /* (a) is blurred and is likely to include (b) */
2202 andres 766 CBC 18 : PG_RETURN_INT32(-1);
8053 bruce 767 2644 : if (a->l_sigd > b->l_sigd) /* (a) is less blurred and is likely to be
8053 bruce 768 ECB : * included in (b) */
2202 andres 769 GIC 18 : PG_RETURN_INT32(1);
8053 bruce 770 ECB :
771 : /*
772 : * For same # of digits, an approximate boundary is more blurred than
773 : * exact.
774 : */
8053 bruce 775 GIC 2626 : if (a->l_ext != b->l_ext)
8154 tgl 776 ECB : {
8053 bruce 777 UIC 0 : if (a->l_ext == '~') /* (a) is approximate, while (b) is exact */
2202 andres 778 UBC 0 : PG_RETURN_INT32(-1);
8053 bruce 779 0 : if (b->l_ext == '~')
2202 andres 780 0 : PG_RETURN_INT32(1);
8154 tgl 781 EUB : /* can't get here unless data is corrupt */
7199 tgl 782 UIC 0 : elog(ERROR, "bogus lower boundary types %d %d",
8154 tgl 783 EUB : (int) a->l_ext, (int) b->l_ext);
784 : }
785 :
786 : /* at this point, the lower boundaries are identical */
787 :
788 : /*
789 : * First compare on upper boundary position
790 : */
8053 bruce 791 GIC 2626 : if (a->upper < b->upper)
2202 andres 792 CBC 164 : PG_RETURN_INT32(-1);
8053 bruce 793 2462 : if (a->upper > b->upper)
2202 andres 794 126 : PG_RETURN_INT32(1);
8053 bruce 795 ECB :
796 : /*
797 : * a->upper == b->upper, so consider type of boundary.
798 : *
799 : * A '-' upper bound is > any other kind (this could only be relevant if
800 : * HUGE_VAL is used as a regular data value). A '<' upper bound is < any
801 : * other kind. A '>' upper bound is > any other kind except '-'.
802 : */
8053 bruce 803 GIC 2336 : if (a->u_ext != b->u_ext)
8154 tgl 804 ECB : {
8053 bruce 805 GIC 39 : if (a->u_ext == '-')
2202 andres 806 LBC 0 : PG_RETURN_INT32(1);
8053 bruce 807 GBC 39 : if (b->u_ext == '-')
2202 andres 808 LBC 0 : PG_RETURN_INT32(-1);
8053 bruce 809 GBC 39 : if (a->u_ext == '<')
2202 andres 810 CBC 3 : PG_RETURN_INT32(-1);
8053 bruce 811 36 : if (b->u_ext == '<')
2202 andres 812 1 : PG_RETURN_INT32(1);
8053 bruce 813 35 : if (a->u_ext == '>')
2202 andres 814 18 : PG_RETURN_INT32(1);
8053 bruce 815 17 : if (b->u_ext == '>')
2202 andres 816 17 : PG_RETURN_INT32(-1);
8154 tgl 817 ECB : }
818 :
819 : /*
820 : * For other boundary types, consider # of significant digits first. Note
821 : * result here is converse of the lower-boundary case.
822 : */
6385 bruce 823 GIC 2297 : if (a->u_sigd < b->u_sigd) /* (a) is blurred and is likely to include (b) */
2202 andres 824 CBC 5 : PG_RETURN_INT32(1);
8053 bruce 825 2292 : if (a->u_sigd > b->u_sigd) /* (a) is less blurred and is likely to be
8053 bruce 826 ECB : * included in (b) */
2202 andres 827 GIC 4 : PG_RETURN_INT32(-1);
8053 bruce 828 ECB :
829 : /*
830 : * For same # of digits, an approximate boundary is more blurred than
831 : * exact. Again, result is converse of lower-boundary case.
832 : */
8053 bruce 833 GIC 2288 : if (a->u_ext != b->u_ext)
8154 tgl 834 ECB : {
8053 bruce 835 UIC 0 : if (a->u_ext == '~') /* (a) is approximate, while (b) is exact */
2202 andres 836 UBC 0 : PG_RETURN_INT32(1);
8053 bruce 837 0 : if (b->u_ext == '~')
2202 andres 838 0 : PG_RETURN_INT32(-1);
8154 tgl 839 EUB : /* can't get here unless data is corrupt */
7199 tgl 840 UIC 0 : elog(ERROR, "bogus upper boundary types %d %d",
8154 tgl 841 EUB : (int) a->u_ext, (int) b->u_ext);
842 : }
843 :
2202 andres 844 GIC 2288 : PG_RETURN_INT32(0);
8154 tgl 845 ECB : }
846 :
847 : Datum
2202 andres 848 UIC 0 : seg_lt(PG_FUNCTION_ARGS)
8154 tgl 849 EUB : {
1165 alvherre 850 UIC 0 : int cmp = DatumGetInt32(DirectFunctionCall2(seg_cmp,
1165 alvherre 851 EUB : PG_GETARG_DATUM(0),
852 : PG_GETARG_DATUM(1)));
853 :
2202 andres 854 UIC 0 : PG_RETURN_BOOL(cmp < 0);
8154 tgl 855 EUB : }
856 :
857 : Datum
2202 andres 858 UIC 0 : seg_le(PG_FUNCTION_ARGS)
8154 tgl 859 EUB : {
1165 alvherre 860 UIC 0 : int cmp = DatumGetInt32(DirectFunctionCall2(seg_cmp,
1165 alvherre 861 EUB : PG_GETARG_DATUM(0),
862 : PG_GETARG_DATUM(1)));
863 :
2202 andres 864 UIC 0 : PG_RETURN_BOOL(cmp <= 0);
8154 tgl 865 EUB : }
866 :
867 : Datum
2202 andres 868 UIC 0 : seg_gt(PG_FUNCTION_ARGS)
8154 tgl 869 EUB : {
1165 alvherre 870 UIC 0 : int cmp = DatumGetInt32(DirectFunctionCall2(seg_cmp,
1165 alvherre 871 EUB : PG_GETARG_DATUM(0),
872 : PG_GETARG_DATUM(1)));
873 :
2202 andres 874 UIC 0 : PG_RETURN_BOOL(cmp > 0);
8154 tgl 875 EUB : }
876 :
877 : Datum
2202 andres 878 UIC 0 : seg_ge(PG_FUNCTION_ARGS)
8154 tgl 879 EUB : {
1165 alvherre 880 UIC 0 : int cmp = DatumGetInt32(DirectFunctionCall2(seg_cmp,
1165 alvherre 881 EUB : PG_GETARG_DATUM(0),
882 : PG_GETARG_DATUM(1)));
883 :
2202 andres 884 UIC 0 : PG_RETURN_BOOL(cmp >= 0);
8154 tgl 885 EUB : }
886 :
887 :
888 : Datum
2202 andres 889 GIC 2 : seg_different(PG_FUNCTION_ARGS)
8154 tgl 890 ECB : {
1165 alvherre 891 GIC 2 : int cmp = DatumGetInt32(DirectFunctionCall2(seg_cmp,
1165 alvherre 892 ECB : PG_GETARG_DATUM(0),
893 : PG_GETARG_DATUM(1)));
894 :
2202 andres 895 GIC 2 : PG_RETURN_BOOL(cmp != 0);
2543 tgl 896 ECB : }
897 :
898 :
899 :
900 : /*****************************************************************************
901 : * Auxiliary functions
902 : *****************************************************************************/
903 :
904 : /*
905 : * The purpose of this routine is to print the given floating point
906 : * value with exactly n significant digits. Its behaviour
907 : * is similar to %.ng except it prints 8.00 where %.ng would
908 : * print 8. Returns the length of the string written at "result".
909 : *
910 : * Caller must provide a sufficiently large result buffer; 16 bytes
911 : * should be enough for all known float implementations.
912 : */
913 : static int
8053 bruce 914 GIC 325 : restore(char *result, float val, int n)
8154 tgl 915 ECB : {
8053 bruce 916 GIC 325 : char buf[25] = {
8053 bruce 917 ECB : '0', '0', '0', '0', '0',
918 : '0', '0', '0', '0', '0',
919 : '0', '0', '0', '0', '0',
920 : '0', '0', '0', '0', '0',
921 : '0', '0', '0', '0', '\0'
922 : };
923 : char *p;
924 : int exp;
925 : int i,
926 : dp,
927 : sign;
928 :
929 : /*
930 : * Put a cap on the number of significant digits to avoid garbage in the
931 : * output and ensure we don't overrun the result buffer. (n should not be
932 : * negative, but check to protect ourselves against corrupted data.)
933 : */
109 tgl 934 GIC 325 : if (n <= 0)
109 tgl 935 LBC 0 : n = FLT_DIG;
109 tgl 936 EUB : else
109 tgl 937 GIC 325 : n = Min(n, FLT_DIG);
8053 bruce 938 ECB :
939 : /* remember the sign */
8053 bruce 940 GIC 325 : sign = (val < 0 ? 1 : 0);
8053 bruce 941 ECB :
942 : /* print, in %e style to start with */
2562 tgl 943 GIC 325 : sprintf(result, "%.*e", n - 1, val);
8053 bruce 944 ECB :
945 : /* find the exponent */
2562 tgl 946 GIC 325 : p = strchr(result, 'e');
8053 bruce 947 ECB :
948 : /* punt if we have 'inf' or similar */
2562 tgl 949 GIC 325 : if (p == NULL)
2562 tgl 950 LBC 0 : return strlen(result);
8053 bruce 951 EUB :
2562 tgl 952 GIC 325 : exp = atoi(p + 1);
8053 bruce 953 CBC 325 : if (exp == 0)
8053 bruce 954 ECB : {
955 : /* just truncate off the 'e+00' */
2562 tgl 956 GIC 169 : *p = '\0';
8154 tgl 957 ECB : }
958 : else
959 : {
184 peter 960 GNC 156 : if (abs(exp) <= 4)
8053 bruce 961 ECB : {
962 : /*
963 : * remove the decimal point from the mantissa and write the digits
964 : * to the buf array
965 : */
8053 bruce 966 GIC 637 : for (p = result + sign, i = 10, dp = 0; *p != 'e'; p++, i++)
8053 bruce 967 ECB : {
8053 bruce 968 GIC 499 : buf[i] = *p;
8053 bruce 969 CBC 499 : if (*p == '.')
8053 bruce 970 ECB : {
8053 bruce 971 GIC 130 : dp = i--; /* skip the decimal point */
8053 bruce 972 ECB : }
973 : }
8053 bruce 974 GIC 138 : if (dp == 0)
8053 bruce 975 CBC 8 : dp = i--; /* no decimal point was found in the above
8053 bruce 976 ECB : * for() loop */
977 :
8053 bruce 978 GIC 138 : if (exp > 0)
8053 bruce 979 ECB : {
8053 bruce 980 GIC 133 : if (dp - 10 + exp >= n)
8053 bruce 981 ECB : {
982 : /*
983 : * the decimal point is behind the last significant digit;
984 : * the digits in between must be converted to the exponent
985 : * and the decimal point placed after the first digit
986 : */
8053 bruce 987 GIC 43 : exp = dp - 10 + exp - n;
8053 bruce 988 CBC 43 : buf[10 + n] = '\0';
8053 bruce 989 ECB :
990 : /* insert the decimal point */
8053 bruce 991 GIC 43 : if (n > 1)
8053 bruce 992 ECB : {
8053 bruce 993 GIC 39 : dp = 11;
8053 bruce 994 CBC 507 : for (i = 23; i > dp; i--)
995 468 : buf[i] = buf[i - 1];
996 39 : buf[dp] = '.';
8053 bruce 997 ECB : }
998 :
999 : /*
1000 : * adjust the exponent by the number of digits after the
1001 : * decimal point
1002 : */
8053 bruce 1003 GIC 43 : if (n > 1)
8053 bruce 1004 CBC 39 : sprintf(&buf[11 + n], "e%d", exp + n - 1);
8053 bruce 1005 ECB : else
8053 bruce 1006 GIC 4 : sprintf(&buf[11], "e%d", exp + n - 1);
8053 bruce 1007 ECB :
8053 bruce 1008 GIC 43 : if (sign)
8053 bruce 1009 ECB : {
8053 bruce 1010 UIC 0 : buf[9] = '-';
8053 bruce 1011 UBC 0 : strcpy(result, &buf[9]);
8053 bruce 1012 EUB : }
1013 : else
8053 bruce 1014 GIC 43 : strcpy(result, &buf[10]);
8053 bruce 1015 ECB : }
1016 : else
1017 : { /* insert the decimal point */
8053 bruce 1018 GIC 90 : dp += exp;
8053 bruce 1019 CBC 1080 : for (i = 23; i > dp; i--)
1020 990 : buf[i] = buf[i - 1];
1021 90 : buf[11 + n] = '\0';
1022 90 : buf[dp] = '.';
1023 90 : if (sign)
8053 bruce 1024 ECB : {
8053 bruce 1025 UIC 0 : buf[9] = '-';
8053 bruce 1026 UBC 0 : strcpy(result, &buf[9]);
8053 bruce 1027 EUB : }
1028 : else
8053 bruce 1029 GIC 90 : strcpy(result, &buf[10]);
8053 bruce 1030 ECB : }
1031 : }
1032 : else
1033 : { /* exp <= 0 */
8053 bruce 1034 GIC 5 : dp += exp - 1;
8053 bruce 1035 CBC 5 : buf[10 + n] = '\0';
1036 5 : buf[dp] = '.';
1037 5 : if (sign)
8053 bruce 1038 ECB : {
8053 bruce 1039 UIC 0 : buf[dp - 2] = '-';
8053 bruce 1040 UBC 0 : strcpy(result, &buf[dp - 2]);
8053 bruce 1041 EUB : }
1042 : else
8053 bruce 1043 GIC 5 : strcpy(result, &buf[dp - 1]);
8053 bruce 1044 ECB : }
1045 : }
1046 :
1047 : /* do nothing for abs(exp) > 4; %e must be OK */
1048 : /* just get rid of zeroes after [eE]- and +zeroes after [Ee]. */
1049 :
1050 : /* ... this is not done yet. */
1051 : }
2061 peter_e 1052 GIC 325 : return strlen(result);
8154 tgl 1053 ECB : }
1054 :
1055 :
1056 : /*
1057 : ** Miscellany
1058 : */
1059 :
1060 : /* find out the number of significant digits in a string representing
1061 : * a floating point number
1062 : */
1063 : int
1986 peter_e 1064 GIC 5187 : significant_digits(const char *s)
8154 tgl 1065 ECB : {
1986 peter_e 1066 GIC 5187 : const char *p = s;
8053 bruce 1067 ECB : int n,
1068 : c,
1069 : zeroes;
1070 :
8053 bruce 1071 GIC 5187 : zeroes = 1;
8053 bruce 1072 ECB : /* skip leading zeroes and sign */
8053 bruce 1073 GIC 5324 : for (c = *p; (c == '0' || c == '+' || c == '-') && c != 0; c = *(++p));
8154 tgl 1074 ECB :
1075 : /* skip decimal point and following zeroes */
8053 bruce 1076 GIC 5208 : for (c = *p; (c == '0' || c == '.') && c != 0; c = *(++p))
8053 bruce 1077 ECB : {
8053 bruce 1078 GIC 21 : if (c != '.')
8053 bruce 1079 CBC 11 : zeroes++;
8053 bruce 1080 ECB : }
1081 :
1082 : /* count significant digits (n) */
8053 bruce 1083 GIC 20346 : for (c = *p, n = 0; c != 0; c = *(++p))
8053 bruce 1084 ECB : {
8053 bruce 1085 GIC 15186 : if (!((c >= '0' && c <= '9') || (c == '.')))
8053 bruce 1086 CBC 27 : break;
1087 15159 : if (c != '.')
1088 10614 : n++;
8053 bruce 1089 ECB : }
1090 :
8053 bruce 1091 GIC 5187 : if (!n)
2061 peter_e 1092 CBC 97 : return zeroes;
8154 tgl 1093 ECB :
2061 peter_e 1094 GIC 5090 : return n;
8154 tgl 1095 ECB : }
|