1 /*
2  * collect.c: Helpers to collect ranges of data.
3  *
4  * Authors:
5  *   Morten Welinder <terra@gnome.org>
6  *   Jukka-Pekka Iivonen <iivonen@iki.fi>
7  */
8 
9 #include <gnumeric-config.h>
10 #include <gnumeric.h>
11 #include <collect.h>
12 
13 #include <func.h>
14 #include <application.h>
15 #include <value.h>
16 #include <expr.h>
17 #include <expr-impl.h>
18 #include <gnm-datetime.h>
19 #include <workbook.h>
20 #include <sheet.h>
21 #include <ranges.h>
22 #include <number-match.h>
23 #include <goffice/goffice.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 /* ------------------------------------------------------------------------- */
28 
29 typedef struct {
30 	/* key */
31 	GnmValue *value;
32 	CollectFlags flags;
33 
34 	/* result */
35 	int n;
36 	gnm_float *data;
37 	GnmValue *error;
38 } SingleFloatsCacheEntry;
39 
40 static void
single_floats_cache_entry_free(SingleFloatsCacheEntry * entry)41 single_floats_cache_entry_free (SingleFloatsCacheEntry *entry)
42 {
43 	value_release (entry->value);
44 	value_release (entry->error);
45 	g_free (entry->data);
46 	g_free (entry);
47 }
48 
49 static guint
single_floats_cache_entry_hash(const SingleFloatsCacheEntry * entry)50 single_floats_cache_entry_hash (const SingleFloatsCacheEntry *entry)
51 {
52 	return value_hash (entry->value) ^ (guint)entry->flags;
53 }
54 
55 static gboolean
single_floats_cache_entry_equal(const SingleFloatsCacheEntry * a,const SingleFloatsCacheEntry * b)56 single_floats_cache_entry_equal (const SingleFloatsCacheEntry *a,
57 				 const SingleFloatsCacheEntry *b)
58 
59 {
60 	return (a->flags == b->flags &&
61 		value_equal (a->value, b->value));
62 }
63 
64 /* ------------------------------------------------------------------------- */
65 
66 typedef struct {
67 	/* key */
68 	GnmValue *vx;
69 	GnmValue *vy;
70 	CollectFlags flags;
71 
72 	/* result */
73 	int n;
74 	gnm_float *data_x;
75 	gnm_float *data_y;
76 	GnmValue *error;
77 } PairsFloatsCacheEntry;
78 
79 static void
pairs_floats_cache_entry_free(PairsFloatsCacheEntry * entry)80 pairs_floats_cache_entry_free (PairsFloatsCacheEntry *entry)
81 {
82 	value_release (entry->vx);
83 	value_release (entry->vy);
84 	value_release (entry->error);
85 	g_free (entry->data_x);
86 	g_free (entry->data_y);
87 	g_free (entry);
88 }
89 
90 static guint
pairs_floats_cache_entry_hash(const PairsFloatsCacheEntry * entry)91 pairs_floats_cache_entry_hash (const PairsFloatsCacheEntry *entry)
92 {
93 	/* FIXME: this does not consider the sheet, ie. the same pair of */
94 	/* ranges on two different sheets yields the same hash value     */
95 	return value_hash (entry->vx) ^ (value_hash (entry->vy) << 1) ^ (guint)entry->flags;
96 }
97 
98 static gboolean
pairs_floats_cache_entry_equal(const PairsFloatsCacheEntry * a,const PairsFloatsCacheEntry * b)99 pairs_floats_cache_entry_equal (const PairsFloatsCacheEntry *a,
100 				 const PairsFloatsCacheEntry *b)
101 
102 {
103 	return (a->flags == b->flags &&
104 		value_equal (a->vx, b->vx) &&
105 		value_equal (a->vy, b->vy));
106 }
107 
108 /* ------------------------------------------------------------------------- */
109 
110 
111 static gulong cache_handler;
112 static GHashTable *single_floats_cache;
113 static GHashTable *pairs_floats_cache;
114 static size_t total_cache_size;
115 
116 static void
clear_caches(void)117 clear_caches (void)
118 {
119 	if (!cache_handler)
120 		return;
121 
122 	g_signal_handler_disconnect (gnm_app_get_app (), cache_handler);
123 	cache_handler = 0;
124 
125 	g_hash_table_destroy (single_floats_cache);
126 	single_floats_cache = NULL;
127 	g_hash_table_destroy (pairs_floats_cache);
128 	pairs_floats_cache = NULL;
129 
130 	total_cache_size = 0;
131 }
132 
133 static void
create_caches(void)134 create_caches (void)
135 {
136 	if (cache_handler)
137 		return;
138 
139 	cache_handler =
140 		g_signal_connect (gnm_app_get_app (), "recalc-clear-caches",
141 				  G_CALLBACK (clear_caches), NULL);
142 
143 	single_floats_cache = g_hash_table_new_full
144 		((GHashFunc)single_floats_cache_entry_hash,
145 		 (GEqualFunc)single_floats_cache_entry_equal,
146 		 (GDestroyNotify)single_floats_cache_entry_free,
147 		 NULL);
148 	pairs_floats_cache = g_hash_table_new_full
149 		((GHashFunc)pairs_floats_cache_entry_hash,
150 		 (GEqualFunc)pairs_floats_cache_entry_equal,
151 		 (GDestroyNotify)pairs_floats_cache_entry_free,
152 		 NULL);
153 
154 	total_cache_size = 0;
155 }
156 
157 static gboolean
cb_prune(gpointer key,gpointer value,gpointer user)158 cb_prune (gpointer key, gpointer value, gpointer user)
159 {
160 	return TRUE;
161 }
162 
163 static void
prune_caches(void)164 prune_caches (void)
165 {
166 	if (total_cache_size > GNM_DEFAULT_ROWS * 32) {
167 		if (0) g_printerr ("Pruning collect cache from size %ld.\n",
168 				   (long)total_cache_size);
169 
170 		total_cache_size = 0;
171 		g_hash_table_foreach_remove (single_floats_cache,
172 					     cb_prune,
173 					     NULL);
174 		g_hash_table_foreach_remove (pairs_floats_cache,
175 					     cb_prune,
176 					     NULL);
177 	}
178 }
179 
180 static SingleFloatsCacheEntry *
get_single_floats_cache_entry(GnmValue const * value,CollectFlags flags)181 get_single_floats_cache_entry (GnmValue const *value, CollectFlags flags)
182 {
183 	SingleFloatsCacheEntry key;
184 
185 	if (flags & (COLLECT_INFO | COLLECT_IGNORE_SUBTOTAL))
186 		return NULL;
187 
188 	create_caches ();
189 
190 	key.value = (GnmValue *)value;
191 	key.flags = flags;
192 
193 	return g_hash_table_lookup (single_floats_cache, &key);
194 }
195 
196 static PairsFloatsCacheEntry *
get_pairs_floats_cache_entry(GnmValue const * vx,GnmValue const * vy,CollectFlags flags)197 get_pairs_floats_cache_entry (GnmValue const *vx, GnmValue const *vy,
198 			      CollectFlags flags)
199 {
200 	PairsFloatsCacheEntry key;
201 
202 	if (flags & (COLLECT_INFO | COLLECT_IGNORE_SUBTOTAL))
203 		return NULL;
204 
205 	create_caches ();
206 
207 	key.vx = (GnmValue *)vx;
208 	key.vy = (GnmValue *)vy;
209 	key.flags = flags;
210 
211 	return g_hash_table_lookup (pairs_floats_cache, &key);
212 }
213 
214 static SingleFloatsCacheEntry *
get_or_fake_cache_entry(GnmValue const * key,CollectFlags flags,GnmEvalPos const * ep)215 get_or_fake_cache_entry (GnmValue const *key, CollectFlags flags,
216 			 GnmEvalPos const *ep)
217 {
218 	SingleFloatsCacheEntry *ce;
219 
220 	ce = get_single_floats_cache_entry (key, flags);
221 	if (ce) return ce;
222 
223 	if (flags & COLLECT_ORDER_IRRELEVANT) {
224 		ce = get_single_floats_cache_entry (key, flags | COLLECT_SORT);
225 		if (ce)
226 			return ce;
227 	}
228 
229 	if (flags & COLLECT_SORT) {
230 		/* FIXME: Try unsorted.  */
231 	}
232 
233 	return NULL;
234 }
235 
236 static PairsFloatsCacheEntry *
get_or_fake_pairs_cache_entry(GnmValue const * key_x,GnmValue const * key_y,CollectFlags flags,GnmEvalPos const * ep)237 get_or_fake_pairs_cache_entry (GnmValue const *key_x, GnmValue const *key_y,
238 			       CollectFlags flags,
239 			       GnmEvalPos const *ep)
240 {
241 	PairsFloatsCacheEntry *ce;
242 
243 	ce = get_pairs_floats_cache_entry (key_x, key_y, flags);
244 	if (ce) return ce;
245 
246 	/* FIXME: we should also try the pairs switched */
247 
248 	return NULL;
249 }
250 
251 static GnmValue *
get_single_cache_key_from_value(GnmValue const * r,GnmEvalPos const * ep)252 get_single_cache_key_from_value (GnmValue const *r, GnmEvalPos const *ep)
253 {
254 	GnmValue *key;
255 	GnmSheetRange sr;
256 	GnmRangeRef const *rr;
257 	Sheet *end_sheet;
258 	int h, w;
259 	const int min_size = 25;
260 
261 	rr = value_get_rangeref (r);
262 	gnm_rangeref_normalize (rr, ep, &sr.sheet, &end_sheet, &sr.range);
263 	if (sr.sheet != end_sheet)
264 		return NULL; /* 3D */
265 
266 	h = range_height (&sr.range);
267 	w = range_width (&sr.range);
268 	if (h < min_size && w < min_size && h * w < min_size)
269 		return NULL;
270 
271 	key = value_new_cellrange_r (sr.sheet, &sr.range);
272 
273 	return key;
274 }
275 
276 static GnmValue *
get_single_cache_key(GnmExpr const * e,GnmEvalPos const * ep)277 get_single_cache_key (GnmExpr const *e, GnmEvalPos const *ep)
278 {
279 	GnmValue *r = gnm_expr_get_range (e);
280 
281 	if (r) {
282 		GnmValue *v = get_single_cache_key_from_value (r, ep);
283 		value_release (r);
284 		return v;
285 	} else
286 		return NULL;
287 
288 }
289 
290 /* ------------------------------------------------------------------------- */
291 
292 static int
float_compare(const void * a_,const void * b_)293 float_compare (const void *a_, const void *b_)
294 {
295 	gnm_float const *a = a_;
296 	gnm_float const *b = b_;
297 
298         if (*a < *b)
299                 return -1;
300 	else if (*a == *b)
301 		return 0;
302 	else
303 		return 1;
304 }
305 
306 typedef struct {
307 	guint alloc_count;
308 	gnm_float *data;
309 	guint count;
310 	CollectFlags flags;
311 	GSList *info;
312 	GODateConventions const *date_conv;
313 } collect_floats_t;
314 
315 static GnmValue *
callback_function_collect(GnmEvalPos const * ep,GnmValue const * value,void * closure)316 callback_function_collect (GnmEvalPos const *ep, GnmValue const *value,
317 			   void *closure)
318 {
319 	gnm_float x = 0;
320 	collect_floats_t *cl = closure;
321 	gboolean ignore = FALSE;
322 
323 	switch (value ? value->v_any.type : VALUE_EMPTY) {
324 	case VALUE_EMPTY:
325 		if (cl->flags & COLLECT_IGNORE_BLANKS)
326 			ignore = TRUE;
327 		else if (cl->flags & COLLECT_ZERO_BLANKS)
328 			x = 0;
329 		else
330 			return value_new_error_VALUE (ep);
331 		break;
332 
333 	case VALUE_BOOLEAN:
334 		if (cl->flags & COLLECT_IGNORE_BOOLS)
335 			ignore = TRUE;
336 		else if (cl->flags & COLLECT_ZEROONE_BOOLS)
337 			x = value_get_as_float (value);
338 		else
339 			return value_new_error_VALUE (ep);
340 		break;
341 
342 	case VALUE_CELLRANGE:
343 	case VALUE_ARRAY:
344 		/* Ranges and arrays are not singleton values treat as errors */
345 
346 	case VALUE_ERROR:
347 		if (cl->flags & COLLECT_IGNORE_ERRORS)
348 			ignore = TRUE;
349 		else if (cl->flags & COLLECT_ZERO_ERRORS)
350 			x = 0;
351 		else
352 			return value_new_error_VALUE (ep);
353 		break;
354 
355 	case VALUE_FLOAT:
356 		x = value_get_as_float (value);
357 		break;
358 
359 	case VALUE_STRING:
360 		if (cl->flags & COLLECT_COERCE_STRINGS) {
361 			GnmValue *vc = format_match_number (value_peek_string (value),
362 							    NULL,
363 							    cl->date_conv);
364 			gboolean bad = !vc || VALUE_IS_BOOLEAN (vc);
365 			if (vc) {
366 				x = value_get_as_float (vc);
367 				value_release (vc);
368 			} else
369 				x = 0;
370 
371 			if (bad)
372 				return value_new_error_VALUE (ep);
373 		} else if (cl->flags & COLLECT_IGNORE_STRINGS)
374 			ignore = TRUE;
375 		else if (cl->flags & COLLECT_ZERO_STRINGS)
376 			x = 0;
377 		else
378 			return value_new_error_VALUE (ep);
379 		break;
380 
381 	default:
382 		g_warning ("Trouble in callback_function_collect. (%d)",
383 			   value->v_any.type);
384 		ignore = TRUE;
385 	}
386 
387 	if (ignore) {
388 		if (cl->flags & COLLECT_INFO)
389 			cl->info = g_slist_prepend (cl->info, GUINT_TO_POINTER (cl->count));
390 		else {
391 			return NULL;
392 		}
393 	}
394 
395 	if (cl->count == cl->alloc_count) {
396 		cl->alloc_count = cl->alloc_count * 2 + 20;
397 		cl->data = g_renew (gnm_float, cl->data, cl->alloc_count);
398 	}
399 
400 	cl->data[cl->count++] = x;
401 	return NULL;
402 }
403 
404 /**
405  * collect_floats: (skip):
406  *
407  * exprlist:       List of expressions to evaluate.
408  * cr:             Current location (for resolving relative cells).
409  * flags:          COLLECT_IGNORE_STRINGS: silently ignore strings.
410  *                 COLLECT_COERCE_STRINGS: coerce string into numbers
411  *                 COLLECT_ZERO_STRINGS: count strings as 0.
412  *                   (Alternative: return #VALUE!.)
413  *                 COLLECT_IGNORE_BOOLS: silently ignore bools.
414  *                 COLLECT_ZEROONE_BOOLS: count FALSE as 0, TRUE as 1.
415  *                   (Alternative: return #VALUE!.)
416  *		   COLLECT_IGNORE_SUBTOTAL : ignore expressions that include
417  *			the function SUBTOTAL directly and ignore any content
418  *			in filtered rows.
419  * n:              Output parameter for number of floats.
420  *
421  * Return value:
422  *   NULL in case of strict and a blank.
423  *   A copy of the error in the case of strict and an error.
424  *   Non-NULL in case of success.  Then n will be set.
425  *
426  * Evaluate a list of expressions and return the result as an array of
427  * gnm_float.
428  */
429 gnm_float *
collect_floats(int argc,GnmExprConstPtr const * argv,GnmEvalPos const * ep,CollectFlags flags,int * n,GnmValue ** error,GSList ** info,gboolean * constp)430 collect_floats (int argc, GnmExprConstPtr const *argv,
431 		GnmEvalPos const *ep, CollectFlags flags,
432 		int *n, GnmValue **error, GSList **info,
433 		gboolean *constp)
434 {
435 	collect_floats_t cl;
436 	CellIterFlags iter_flags = CELL_ITER_ALL;
437 	GnmValue *key = NULL;
438 	CollectFlags keyflags = flags & ~COLLECT_ORDER_IRRELEVANT;
439 	gboolean strict;
440 
441 	if (constp)
442 		*constp = FALSE;
443 
444 	if (info) {
445 		*info = NULL;
446 		g_return_val_if_fail (!(flags & COLLECT_SORT), NULL);
447 		flags |= COLLECT_INFO;
448 	} else {
449 		if (flags & COLLECT_IGNORE_BLANKS)
450 			iter_flags = CELL_ITER_IGNORE_BLANK;
451 		flags &= ~COLLECT_INFO;
452 	}
453 
454 	/* ---------------------------------------- */
455 	/* Try cache. */
456 
457 	if (argc == 1 &&
458 	    (flags & (COLLECT_INFO | COLLECT_IGNORE_SUBTOTAL)) == 0) {
459 		key = get_single_cache_key (argv[0], ep);
460 	}
461 	if (key) {
462 		SingleFloatsCacheEntry *ce =
463 			get_or_fake_cache_entry (key, keyflags, ep);
464 		if (ce) {
465 			value_release (key);
466 			if (ce->error) {
467 				*error = value_dup (ce->error);
468 				return NULL;
469 			}
470 			*n = ce->n;
471 			if (constp) {
472 				*constp = TRUE;
473 				return ce->data;
474 			}
475 			return g_memdup (ce->data, *n * sizeof (gnm_float));
476 		}
477 	}
478 
479 	/* ---------------------------------------- */
480 
481 	if (flags & COLLECT_IGNORE_SUBTOTAL)
482 		iter_flags |= (CELL_ITER_IGNORE_SUBTOTAL |
483 			       CELL_ITER_IGNORE_FILTERED);
484 
485 	strict = (flags & (COLLECT_IGNORE_ERRORS | COLLECT_ZERO_ERRORS)) == 0;
486 
487 	cl.alloc_count = 0;
488 	cl.data = NULL;
489 	cl.count = 0;
490 	cl.flags = flags;
491 	cl.info = NULL;
492 	cl.date_conv = sheet_date_conv (ep->sheet);
493 
494 	*error = function_iterate_argument_values
495 		(ep, &callback_function_collect, &cl,
496 		 argc, argv,
497 		 strict, iter_flags);
498 	if (*error) {
499 		g_assert (VALUE_IS_ERROR (*error));
500 		g_free (cl.data);
501 		cl.data = NULL;
502 		cl.count = 0;
503 		g_slist_free (cl.info);
504 		cl.info = NULL;
505 	} else {
506 		if (cl.data == NULL) {
507 			cl.alloc_count = 1;
508 			cl.data = g_new (gnm_float, cl.alloc_count);
509 		}
510 
511 		if (flags & COLLECT_SORT) {
512 			qsort (cl.data, cl.count, sizeof (cl.data[0]),
513 			       float_compare);
514 		}
515 	}
516 
517 	if (info)
518 		*info = cl.info;
519 	*n = cl.count;
520 
521 	if (key) {
522 		SingleFloatsCacheEntry *ce = g_new (SingleFloatsCacheEntry, 1);
523 		SingleFloatsCacheEntry *ce2;
524 		ce->value = key;
525 		ce->flags = keyflags;
526 		ce->n = *n;
527 		ce->error = value_dup (*error);
528 		if (cl.data == NULL)
529 			ce->data = NULL;
530 		else if (constp) {
531 			*constp = TRUE;
532 			ce->data = cl.data;
533 		} else
534 			ce->data = g_memdup (cl.data, MAX (1, *n) * sizeof (gnm_float));
535 		prune_caches ();
536 
537 		/*
538 		 * We looked for the entry earlier and it was not there.
539 		 * However, sub-calculation might have added it so be careful
540 		 * to adjust sizes and replace the not-so-old entry.
541 		 * See bug 627079.
542 		 */
543 		ce2 = g_hash_table_lookup (single_floats_cache, ce);
544 		if (ce2)
545 			total_cache_size -= 1 + ce2->n;
546 
547 		g_hash_table_replace (single_floats_cache, ce, ce);
548 		total_cache_size += 1 + *n;
549 	}
550 	return cl.data;
551 }
552 
553 /* ------------------------------------------------------------------------- */
554 /* Like collect_floats, but takes a value instead of an expression list.
555    Presumably most useful when the value is an array.  */
556 
557 gnm_float *
collect_floats_value(GnmValue const * val,GnmEvalPos const * ep,CollectFlags flags,int * n,GnmValue ** error)558 collect_floats_value (GnmValue const *val, GnmEvalPos const *ep,
559 		      CollectFlags flags, int *n, GnmValue **error)
560 {
561 	GnmExpr expr_val;
562 	GnmExprConstPtr argv[1] = { &expr_val };
563 
564 	gnm_expr_constant_init (&expr_val.constant, val);
565 	return collect_floats (1, argv, ep, flags, n, error, NULL, NULL);
566 }
567 
568 /* ------------------------------------------------------------------------- */
569 /**
570  * collect_floats_value_with_info:
571  * @val: #GnmValue
572  * @ep: #GnmEvalPos
573  * @flags: #CollectFlags
574  * @n:
575  * @info: (element-type guint):
576  * @error:
577  *
578  * Like collect_floats_value, but keeps info on missing values
579  **/
580 
581 gnm_float *
collect_floats_value_with_info(GnmValue const * val,GnmEvalPos const * ep,CollectFlags flags,int * n,GSList ** info,GnmValue ** error)582 collect_floats_value_with_info (GnmValue const *val, GnmEvalPos const *ep,
583 				CollectFlags flags, int *n, GSList **info,
584 				GnmValue **error)
585 {
586 	GnmExpr expr_val;
587 	GnmExprConstPtr argv[1] = { &expr_val };
588 	gnm_float *res;
589 
590 	gnm_expr_constant_init (&expr_val.constant, val);
591 	res = collect_floats (1, argv, ep, flags, n, error, info, NULL);
592 
593 	if (info)
594 		*info = g_slist_reverse (*info);
595 
596 	return res;
597 }
598 
599 
600 /* ------------------------------------------------------------------------- */
601 
602 /**
603  * float_range_function:
604  * @argc: number of arguments
605  * @argv: (in) (array length=argc): function arguments
606  * @ei: #GnmFuncEvalInfo describing evaluation context
607  * @func: (scope call): implementation function
608  * @flags: #CollectFlags flags describing the collection and interpretation
609  * of values from @argv.
610  * @func_error: A #GnmStdError to use to @func indicates an error.
611  *
612  * This implements a Gnumeric sheet function that operates on a list of
613  * numbers.  This function collects the arguments and uses @func to do
614  * the actual computation.
615  *
616  * Returns: (transfer full): Function result or error value.
617  **/
618 GnmValue *
float_range_function(int argc,GnmExprConstPtr const * argv,GnmFuncEvalInfo * ei,float_range_function_t func,CollectFlags flags,GnmStdError func_error)619 float_range_function (int argc, GnmExprConstPtr const *argv,
620 		      GnmFuncEvalInfo *ei,
621 		      float_range_function_t func,
622 		      CollectFlags flags,
623 		      GnmStdError func_error)
624 {
625 	GnmValue *error = NULL;
626 	gnm_float *vals, res;
627 	int n, err;
628 	gboolean constp;
629 
630 	vals = collect_floats (argc, argv, ei->pos, flags, &n, &error,
631 			       NULL, &constp);
632 	if (!vals)
633 		return error;
634 
635 	err = func (vals, n, &res);
636 	if (!constp) g_free (vals);
637 
638 	if (err)
639 		return value_new_error_std (ei->pos, func_error);
640 	else
641 		return value_new_float (res);
642 }
643 
644 /* ------------------------------------------------------------------------- */
645 
646 /**
647  * gnm_slist_sort_merge:
648  * @list_1: (element-type guint) (transfer container): a sorted list of
649  * unsigned integers with no duplicates.
650  * @list_2: (element-type guint) (transfer container): another one
651  *
652  * gnm_slist_sort_merge merges two lists of unsigned integers.
653  *
654  * Returns: (element-type guint) (transfer container): the mergedlist.
655  **/
656 GSList *
gnm_slist_sort_merge(GSList * l1,GSList * l2)657 gnm_slist_sort_merge (GSList *l1,
658 		      GSList *l2)
659 {
660 	GSList list, *l;
661 
662 	l = &list;
663 
664 	while (l1 && l2) {
665 		if (GPOINTER_TO_UINT (l1->data) <= GPOINTER_TO_UINT (l2->data)) {
666 			if (GPOINTER_TO_UINT (l1->data) == GPOINTER_TO_UINT (l2->data)) {
667 				/* remove duplicates */
668 				GSList *m = l2;
669 				l2 = l2->next;
670 				m->next = NULL;
671 				g_slist_free_1 (m);
672 			}
673 			l = l->next = l1;
674 			l1 = l1->next;
675 		} else {
676 			l = l->next = l2;
677 			l2 = l2->next;
678 		}
679 	}
680 	l->next = l1 ? l1 : l2;
681 
682 	return list.next;
683 }
684 
685 
686 /**
687  * gnm_strip_missing:
688  * @data: (inout) (array length=n): Array
689  * @n: (inout): Number of elements in @data.
690  * @missing: (element-type guint): indices of elements to remove in increasing
691  * order.
692  *
693  * This removes the data elements from @data whose indices are given by
694  * @missing.  @n is the number of elements and it updated upon return.
695  **/
696 void
gnm_strip_missing(gnm_float * data,int * n,GSList * missing)697 gnm_strip_missing (gnm_float *data, int *n, GSList *missing)
698 {
699 	unsigned src, dst;
700 
701 	if (missing == NULL)
702 		return;
703 
704 	for (src = dst = 0; (int)dst < *n; src++) {
705 		if (missing && src == GPOINTER_TO_UINT (missing->data)) {
706 			missing = missing->next;
707 			(*n)--;
708 		} else {
709 			data[dst] = data[src];
710 			dst++;
711 		}
712 	}
713 }
714 
715 static PairsFloatsCacheEntry *
collect_float_pairs_ce(GnmValue const * vx,GnmValue const * vy,GnmEvalPos const * ep,CollectFlags flags)716 collect_float_pairs_ce (GnmValue const *vx, GnmValue const *vy,
717 			GnmEvalPos const *ep, CollectFlags flags)
718 {
719 	PairsFloatsCacheEntry *ce = g_new0 (PairsFloatsCacheEntry, 1);
720 	GSList *missing0 = NULL, *missing1 = NULL;
721 	int n0, n1;
722 
723 	ce->flags = flags;
724 
725 	ce->data_x = collect_floats_value_with_info (vx, ep, flags,
726 						     &n0, &missing0, &ce->error);
727 	if (ce->error)
728 		goto err;
729 
730 	ce->data_y = collect_floats_value_with_info (vy, ep, flags,
731 						     &n1, &missing1, &ce->error);
732 
733 	if (ce->error)
734 		goto err;
735 
736 	if (n0 != n1) {
737 		ce->n = -1;
738 		goto err;
739 	}
740 
741 	if (missing0 || missing1) {
742 		missing0 = gnm_slist_sort_merge (missing0, missing1);
743 		missing1 = NULL;
744 		gnm_strip_missing (ce->data_x, &n0, missing0);
745 		gnm_strip_missing (ce->data_y, &n1, missing0);
746 	}
747 	ce->n = n0;
748 
749  err:
750 	if (ce->n <= 0) {
751 		g_free (ce->data_x);
752 		ce->data_x = NULL;
753 		g_free (ce->data_y);
754 		ce->data_y = NULL;
755 	}
756 
757 	g_slist_free (missing0);
758 	g_slist_free (missing1);
759 
760 	return ce;
761 }
762 
763 /**
764  * collect_float_pairs: (skip)
765  * @v0: value describing first data range
766  * @v1: value describing second data range
767  * @ep: evaluation position
768  * @flags: flags describing how to handle value types
769  * @xs0: (out) (array length=n): return location for first data vector
770  * @xs1: (out) (array length=n): return location for second data vector
771  * @n: (out): return location for number of data points
772  * @constp: (out) (optional): Return location for a flag describing who own
773  * the vectors returned in @xs0 and @xs1.  If present and %TRUE, the
774  * resulting data vectors in @xs0 and @xs1 are not owned by the caller.
775  * If not-present or %FALSE, the callers owns and must free the result.
776  *
777  * If @n is not positive upon return, no data has been allocated.
778  * If @n is negative upon return, the two ranges had different sizes.
779  *
780  * Note: introspection cannot handle this functions parameter mix.
781  *
782  * Returns: (transfer full) (nullable): Error value.
783  */
784 GnmValue *
collect_float_pairs(GnmValue const * vx,GnmValue const * vy,GnmEvalPos const * ep,CollectFlags flags,gnm_float ** xs0,gnm_float ** xs1,int * n,gboolean * constp)785 collect_float_pairs (GnmValue const *vx, GnmValue const *vy,
786 		     GnmEvalPos const *ep, CollectFlags flags,
787 		     gnm_float **xs0, gnm_float **xs1, int *n,
788 		     gboolean *constp)
789 {
790 	GnmValue *key_x = NULL;
791 	GnmValue *key_y = NULL;
792 	PairsFloatsCacheEntry *ce = NULL;
793 	gboolean use_cache, free_keys = TRUE;
794 
795 	if (VALUE_IS_CELLRANGE (vx))
796 		key_x = get_single_cache_key_from_value (vx, ep);
797 	if (VALUE_IS_CELLRANGE (vy))
798 		key_y = get_single_cache_key_from_value (vy, ep);
799 
800 	if ((use_cache = (key_x && key_y)))
801 		ce = get_or_fake_pairs_cache_entry (key_x, key_y, flags, ep);
802 
803 	if (!ce) {
804 		ce = collect_float_pairs_ce (vx, vy, ep, flags);
805 		if (use_cache) {
806 			PairsFloatsCacheEntry *ce2;
807 			ce->vx = key_x;
808 			ce->vy = key_y;
809 			free_keys = FALSE;
810 
811 			/*
812 			 * We looked for the entry earlier and it was not there.
813 			 * However, sub-calculation might have added it so be careful
814 			 * to adjust sizes and replace the not-so-old entry.
815 			 * See bug 627079.
816 			 */
817 			ce2 = g_hash_table_lookup (pairs_floats_cache, ce);
818 			if (ce2)
819 				total_cache_size -= 1 + ce2->n;
820 
821 			g_hash_table_replace (pairs_floats_cache, ce, ce);
822 			total_cache_size += 1 + ce->n;
823 		}
824 	}
825 
826 	if (free_keys) {
827 		value_release (key_x);
828 		value_release (key_y);
829 	}
830 
831 	if (ce == NULL)
832 		return value_new_error_VALUE (ep);
833 	else {
834 		if (ce->error) {
835 			if (use_cache)
836 				return value_dup (ce->error);
837 			else {
838 				GnmValue *ret = ce->error;
839 				ce->error = NULL;
840 				pairs_floats_cache_entry_free (ce);
841 				return ret;
842 			}
843 		}
844 		*n = ce->n;
845 		if (ce->n <= 0) {
846 			if (!use_cache)
847 				pairs_floats_cache_entry_free (ce);
848 			*xs0 = NULL;
849 			*xs1 = NULL;
850 			if (constp)
851 				*constp = FALSE;
852 			return NULL;
853 		}
854 		if (use_cache) {
855 			if (constp) {
856 				*xs0 = ce->data_x;
857 				*xs1 = ce->data_y;
858 				*constp = TRUE;
859 			} else {
860 				*xs0 = g_memdup (ce->data_x, *n * sizeof (gnm_float));
861 				*xs1 = g_memdup (ce->data_y, *n * sizeof (gnm_float));
862 			}
863 		} else {
864 			if (constp)
865 				*constp = FALSE;
866 			*xs0 = ce->data_x;
867 			*xs1 = ce->data_y;
868 			ce->data_x = NULL;
869 			ce->data_y = NULL;
870 			pairs_floats_cache_entry_free (ce);
871 		}
872 		return NULL;
873 	}
874 }
875 
876 /**
877  * float_range_function2d:
878  * @val0: First range
879  * @val1: Second range
880  * @ei: #GnmFuncEvalInfo describing evaluation context
881  * @func: (scope call): implementation function
882  * @flags: #CollectFlags flags describing the collection and interpretation
883  * of values from @val0 and @val1.
884  * @func_error: A #GnmStdError to use to @func indicates an error.
885  * @data: user data for @func
886  *
887  * This implements a Gnumeric sheet function that operates on a matched
888  * pair of ranges.  This function collects the arguments and uses @func to do
889  * the actual computation.
890  *
891  * Returns: (transfer full): Function result or error value.
892  **/
893 GnmValue *
float_range_function2d(GnmValue const * val0,GnmValue const * val1,GnmFuncEvalInfo * ei,float_range_function2d_t func,CollectFlags flags,GnmStdError func_error,gpointer data)894 float_range_function2d (GnmValue const *val0, GnmValue const *val1,
895 			GnmFuncEvalInfo *ei,
896 			float_range_function2d_t func,
897 			CollectFlags flags,
898 			GnmStdError func_error,
899 			gpointer data)
900 {
901 	gnm_float *vals0, *vals1;
902 	int n;
903 	GnmValue *res;
904 	gnm_float fres;
905 	gboolean constp = FALSE;
906 
907 	res = collect_float_pairs (val0, val1, ei->pos, flags,
908 				   &vals0, &vals1, &n, &constp);
909 	if (res)
910 		return res;
911 
912 	if (n <= 0)
913 		return value_new_error_std (ei->pos, func_error);
914 
915 	if (func (vals0, vals1, n, &fres, data))
916 		res = value_new_error_std (ei->pos, func_error);
917 	else
918 		res = value_new_float (fres);
919 
920 	if (!constp) {
921 		g_free (vals0);
922 		g_free (vals1);
923 	}
924 	return res;
925 }
926 
927 /**
928  * float_range_function2:
929  * @val0: First range
930  * @val1: Second range
931  * @ei: #GnmFuncEvalInfo describing evaluation context
932  * @func: (scope call): implementation function
933  * @flags: #CollectFlags flags describing the collection and interpretation
934  * of values from @val0 and @val1.
935  * @func_error: A #GnmStdError to use to @func indicates an error.
936  *
937  * This implements a Gnumeric sheet function that operates on a matched
938  * pair of ranges.  This function collects the arguments and uses @func to do
939  * the actual computation.
940  *
941  * Returns: (transfer full): Function result or error value.
942  **/
943 GnmValue *
float_range_function2(GnmValue const * val0,GnmValue const * val1,GnmFuncEvalInfo * ei,float_range_function2_t func,CollectFlags flags,GnmStdError func_error)944 float_range_function2 (GnmValue const *val0, GnmValue const *val1,
945 		       GnmFuncEvalInfo *ei,
946 		       float_range_function2_t func,
947 		       CollectFlags flags,
948 		       GnmStdError func_error)
949 {
950 	return float_range_function2d (val0, val1, ei,
951 				       (float_range_function2d_t)func,
952 				       flags,
953 				       func_error,
954 				       NULL);
955 }
956 
957 /* ------------------------------------------------------------------------- */
958 /* ------------------------------------------------------------------------- */
959 
960 typedef struct {
961 	GPtrArray *data;
962 	CollectFlags flags;
963 } collect_strings_t;
964 
965 static GnmValue *
callback_function_collect_strings(GnmEvalPos const * ep,GnmValue const * value,void * closure)966 callback_function_collect_strings (GnmEvalPos const *ep, GnmValue const *value,
967 				   void *closure)
968 {
969 	char *text;
970 	collect_strings_t *cl = closure;
971 
972 	if (VALUE_IS_EMPTY (value)) {
973 		if (cl->flags & COLLECT_IGNORE_BLANKS)
974 			text = NULL;
975 		else
976 			text = g_strdup ("");
977 	} else
978 		text = value_get_as_string (value);
979 
980 	if (text)
981 		g_ptr_array_add (cl->data, text);
982 
983 	return NULL;
984 }
985 
986 static void
collect_strings_free(GPtrArray * data)987 collect_strings_free (GPtrArray *data)
988 {
989 	g_ptr_array_foreach (data, (GFunc)g_free, NULL);
990 	g_ptr_array_free (data, TRUE);
991 }
992 
993 /**
994  * collect_strings:
995  * @argc: number of arguments
996  * @argv: (in) (array length=argc): function arguments
997  * @ep: Evaluation position
998  * @flags: #CollectFlags flags describing the collection and interpretation
999  * of values from @argv.
1000  * @error: (out): Error return value
1001  *
1002  * Evaluate a list of expressions and return the result as a #GPtrArray of
1003  * strings.
1004  *
1005  * Returns: (transfer full) (nullable) (element-type utf8): array of strings.
1006  */
1007 static GPtrArray *
collect_strings(int argc,GnmExprConstPtr const * argv,GnmEvalPos const * ep,CollectFlags flags,GnmValue ** error)1008 collect_strings (int argc, GnmExprConstPtr const *argv,
1009 		 GnmEvalPos const *ep, CollectFlags flags,
1010 		 GnmValue **error)
1011 {
1012 	collect_strings_t cl;
1013 	CellIterFlags iter_flags = CELL_ITER_ALL;
1014 	gboolean strict;
1015 
1016 	/* We don't handle these flags */
1017 	g_return_val_if_fail (!(flags & COLLECT_ZERO_ERRORS), NULL);
1018 	g_return_val_if_fail (!(flags & COLLECT_ZERO_STRINGS), NULL);
1019 	g_return_val_if_fail (!(flags & COLLECT_ZEROONE_BOOLS), NULL);
1020 	g_return_val_if_fail (!(flags & COLLECT_ZERO_BLANKS), NULL);
1021 
1022 	if (flags & COLLECT_IGNORE_BLANKS)
1023 		iter_flags = CELL_ITER_IGNORE_BLANK;
1024 
1025 	strict = (flags & (COLLECT_IGNORE_ERRORS | COLLECT_ZERO_ERRORS)) == 0;
1026 
1027 	cl.data = g_ptr_array_new ();
1028 	cl.flags = flags;
1029 
1030 	*error = function_iterate_argument_values
1031 		(ep, &callback_function_collect_strings, &cl,
1032 		 argc, argv,
1033 		 strict, iter_flags);
1034 	if (*error) {
1035 		g_assert (VALUE_IS_ERROR (*error));
1036 		collect_strings_free (cl.data);
1037 		return NULL;
1038 	}
1039 
1040 	return cl.data;
1041 }
1042 
1043 /**
1044  * string_range_function:
1045  * @argc: number of arguments
1046  * @argv: (in) (array length=argc): function arguments
1047  * @ei: #GnmFuncEvalInfo describing evaluation context
1048  * @func: (scope call): implementation function
1049  * @flags: #CollectFlags flags describing the collection and interpretation
1050  * of values from @argv.
1051  * @func_error: A #GnmStdError to use to @func indicates an error.
1052  *
1053  * This implements a Gnumeric sheet function that operates on a list of
1054  * strings.  This function collects the arguments and uses @func to do
1055  * the actual computation.
1056  *
1057  * Returns: (transfer full): Function result or error value.
1058  **/
1059 GnmValue *
string_range_function(int argc,GnmExprConstPtr const * argv,GnmFuncEvalInfo * ei,string_range_function_t func,gpointer user,CollectFlags flags,GnmStdError func_error)1060 string_range_function (int argc, GnmExprConstPtr const *argv,
1061 		       GnmFuncEvalInfo *ei,
1062 		       string_range_function_t func,
1063 		       gpointer user,
1064 		       CollectFlags flags,
1065 		       GnmStdError func_error)
1066 {
1067 	GnmValue *error = NULL;
1068 	GPtrArray *vals;
1069 	char *res = NULL;
1070 	int err;
1071 
1072 	vals = collect_strings (argc, argv, ei->pos, flags, &error);
1073 	if (!vals)
1074 		return error;
1075 
1076 	err = func (vals, &res, user);
1077 
1078 	collect_strings_free (vals);
1079 
1080 	if (err) {
1081 		g_free (res);
1082 		return value_new_error_std (ei->pos, func_error);
1083 	} else {
1084 		return value_new_string_nocopy (res);
1085 	}
1086 }
1087