Update Spanish translation
[gnumeric.git] / src / collect.c
blobce32a092a637691786bf932d087cdac4bedc9542
1 /*
2 * collect.c: Helpers to collect ranges of data.
4 * Authors:
5 * Morten Welinder <terra@gnome.org>
6 * Jukka-Pekka Iivonen <iivonen@iki.fi>
7 */
9 #include <gnumeric-config.h>
10 #include <gnumeric.h>
11 #include <collect.h>
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>
27 /* ------------------------------------------------------------------------- */
29 typedef struct {
30 /* key */
31 GnmValue *value;
32 CollectFlags flags;
34 /* result */
35 int n;
36 gnm_float *data;
37 GnmValue *error;
38 } SingleFloatsCacheEntry;
40 static void
41 single_floats_cache_entry_free (SingleFloatsCacheEntry *entry)
43 value_release (entry->value);
44 value_release (entry->error);
45 g_free (entry->data);
46 g_free (entry);
49 static guint
50 single_floats_cache_entry_hash (const SingleFloatsCacheEntry *entry)
52 return value_hash (entry->value) ^ (guint)entry->flags;
55 static gboolean
56 single_floats_cache_entry_equal (const SingleFloatsCacheEntry *a,
57 const SingleFloatsCacheEntry *b)
60 return (a->flags == b->flags &&
61 value_equal (a->value, b->value));
64 /* ------------------------------------------------------------------------- */
66 typedef struct {
67 /* key */
68 GnmValue *vx;
69 GnmValue *vy;
70 CollectFlags flags;
72 /* result */
73 int n;
74 gnm_float *data_x;
75 gnm_float *data_y;
76 GnmValue *error;
77 } PairsFloatsCacheEntry;
79 static void
80 pairs_floats_cache_entry_free (PairsFloatsCacheEntry *entry)
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);
90 static guint
91 pairs_floats_cache_entry_hash (const PairsFloatsCacheEntry *entry)
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;
98 static gboolean
99 pairs_floats_cache_entry_equal (const PairsFloatsCacheEntry *a,
100 const PairsFloatsCacheEntry *b)
103 return (a->flags == b->flags &&
104 value_equal (a->vx, b->vx) &&
105 value_equal (a->vy, b->vy));
108 /* ------------------------------------------------------------------------- */
111 static gulong cache_handler;
112 static GHashTable *single_floats_cache;
113 static GHashTable *pairs_floats_cache;
114 static size_t total_cache_size;
116 static void
117 clear_caches (void)
119 if (!cache_handler)
120 return;
122 g_signal_handler_disconnect (gnm_app_get_app (), cache_handler);
123 cache_handler = 0;
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;
130 total_cache_size = 0;
133 static void
134 create_caches (void)
136 if (cache_handler)
137 return;
139 cache_handler =
140 g_signal_connect (gnm_app_get_app (), "recalc-clear-caches",
141 G_CALLBACK (clear_caches), NULL);
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);
154 total_cache_size = 0;
157 static gboolean
158 cb_prune (gpointer key, gpointer value, gpointer user)
160 return TRUE;
163 static void
164 prune_caches (void)
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);
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);
180 static SingleFloatsCacheEntry *
181 get_single_floats_cache_entry (GnmValue const *value, CollectFlags flags)
183 SingleFloatsCacheEntry key;
185 if (flags & (COLLECT_INFO | COLLECT_IGNORE_SUBTOTAL))
186 return NULL;
188 create_caches ();
190 key.value = (GnmValue *)value;
191 key.flags = flags;
193 return g_hash_table_lookup (single_floats_cache, &key);
196 static PairsFloatsCacheEntry *
197 get_pairs_floats_cache_entry (GnmValue const *vx, GnmValue const *vy,
198 CollectFlags flags)
200 PairsFloatsCacheEntry key;
202 if (flags & (COLLECT_INFO | COLLECT_IGNORE_SUBTOTAL))
203 return NULL;
205 create_caches ();
207 key.vx = (GnmValue *)vx;
208 key.vy = (GnmValue *)vy;
209 key.flags = flags;
211 return g_hash_table_lookup (pairs_floats_cache, &key);
214 static SingleFloatsCacheEntry *
215 get_or_fake_cache_entry (GnmValue const *key, CollectFlags flags,
216 GnmEvalPos const *ep)
218 SingleFloatsCacheEntry *ce;
220 ce = get_single_floats_cache_entry (key, flags);
221 if (ce) return ce;
223 if (flags & COLLECT_ORDER_IRRELEVANT) {
224 ce = get_single_floats_cache_entry (key, flags | COLLECT_SORT);
225 if (ce)
226 return ce;
229 if (flags & COLLECT_SORT) {
230 /* FIXME: Try unsorted. */
233 return NULL;
236 static PairsFloatsCacheEntry *
237 get_or_fake_pairs_cache_entry (GnmValue const *key_x, GnmValue const *key_y,
238 CollectFlags flags,
239 GnmEvalPos const *ep)
241 PairsFloatsCacheEntry *ce;
243 ce = get_pairs_floats_cache_entry (key_x, key_y, flags);
244 if (ce) return ce;
246 /* FIXME: we should also try the pairs switched */
248 return NULL;
251 static GnmValue *
252 get_single_cache_key_from_value (GnmValue const *r, GnmEvalPos const *ep)
254 GnmValue *key;
255 GnmSheetRange sr;
256 GnmRangeRef const *rr;
257 Sheet *end_sheet;
258 int h, w;
259 const int min_size = 25;
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 */
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;
271 key = value_new_cellrange_r (sr.sheet, &sr.range);
273 return key;
276 static GnmValue *
277 get_single_cache_key (GnmExpr const *e, GnmEvalPos const *ep)
279 GnmValue *r = gnm_expr_get_range (e);
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;
290 /* ------------------------------------------------------------------------- */
292 static int
293 float_compare (const void *a_, const void *b_)
295 gnm_float const *a = a_;
296 gnm_float const *b = b_;
298 if (*a < *b)
299 return -1;
300 else if (*a == *b)
301 return 0;
302 else
303 return 1;
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;
315 static GnmValue *
316 callback_function_collect (GnmEvalPos const *ep, GnmValue const *value,
317 void *closure)
319 gnm_float x = 0;
320 collect_floats_t *cl = closure;
321 gboolean ignore = FALSE;
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;
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;
342 case VALUE_CELLRANGE:
343 case VALUE_ARRAY:
344 /* Ranges and arrays are not singleton values treat as errors */
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;
355 case VALUE_FLOAT:
356 x = value_get_as_float (value);
357 break;
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;
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;
381 default:
382 g_warning ("Trouble in callback_function_collect. (%d)",
383 value->v_any.type);
384 ignore = TRUE;
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;
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);
400 cl->data[cl->count++] = x;
401 return NULL;
405 * collect_floats: (skip):
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.
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.
426 * Evaluate a list of expressions and return the result as an array of
427 * gnm_float.
429 gnm_float *
430 collect_floats (int argc, GnmExprConstPtr const *argv,
431 GnmEvalPos const *ep, CollectFlags flags,
432 int *n, GnmValue **error, GSList **info,
433 gboolean *constp)
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;
441 if (constp)
442 *constp = FALSE;
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;
454 /* ---------------------------------------- */
455 /* Try cache. */
457 if (argc == 1 &&
458 (flags & (COLLECT_INFO | COLLECT_IGNORE_SUBTOTAL)) == 0) {
459 key = get_single_cache_key (argv[0], ep);
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;
470 *n = ce->n;
471 if (constp) {
472 *constp = TRUE;
473 return ce->data;
475 return g_memdup (ce->data, *n * sizeof (gnm_float));
479 /* ---------------------------------------- */
481 if (flags & COLLECT_IGNORE_SUBTOTAL)
482 iter_flags |= (CELL_ITER_IGNORE_SUBTOTAL |
483 CELL_ITER_IGNORE_FILTERED);
485 strict = (flags & (COLLECT_IGNORE_ERRORS | COLLECT_ZERO_ERRORS)) == 0;
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);
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);
511 if (flags & COLLECT_SORT) {
512 qsort (cl.data, cl.count, sizeof (cl.data[0]),
513 float_compare);
517 if (info)
518 *info = cl.info;
519 *n = cl.count;
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 ();
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.
543 ce2 = g_hash_table_lookup (single_floats_cache, ce);
544 if (ce2)
545 total_cache_size -= 1 + ce2->n;
547 g_hash_table_replace (single_floats_cache, ce, ce);
548 total_cache_size += 1 + *n;
550 return cl.data;
553 /* ------------------------------------------------------------------------- */
554 /* Like collect_floats, but takes a value instead of an expression list.
555 Presumably most useful when the value is an array. */
557 gnm_float *
558 collect_floats_value (GnmValue const *val, GnmEvalPos const *ep,
559 CollectFlags flags, int *n, GnmValue **error)
561 GnmExpr expr_val;
562 GnmExprConstPtr argv[1] = { &expr_val };
564 gnm_expr_constant_init (&expr_val.constant, val);
565 return collect_floats (1, argv, ep, flags, n, error, NULL, NULL);
568 /* ------------------------------------------------------------------------- */
570 * collect_floats_value_with_info:
571 * @val: #GnmValue
572 * @ep: #GnmEvalPos
573 * @flags: #CollectFlags
574 * @n:
575 * @info: (element-type guint):
576 * @error:
578 * Like collect_floats_value, but keeps info on missing values
581 gnm_float *
582 collect_floats_value_with_info (GnmValue const *val, GnmEvalPos const *ep,
583 CollectFlags flags, int *n, GSList **info,
584 GnmValue **error)
586 GnmExpr expr_val;
587 GnmExprConstPtr argv[1] = { &expr_val };
588 gnm_float *res;
590 gnm_expr_constant_init (&expr_val.constant, val);
591 res = collect_floats (1, argv, ep, flags, n, error, info, NULL);
593 if (info)
594 *info = g_slist_reverse (*info);
596 return res;
600 /* ------------------------------------------------------------------------- */
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.
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.
616 * Returns: (transfer full): Function result or error value.
618 GnmValue *
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)
625 GnmValue *error = NULL;
626 gnm_float *vals, res;
627 int n, err;
628 gboolean constp;
630 vals = collect_floats (argc, argv, ei->pos, flags, &n, &error,
631 NULL, &constp);
632 if (!vals)
633 return error;
635 err = func (vals, n, &res);
636 if (!constp) g_free (vals);
638 if (err)
639 return value_new_error_std (ei->pos, func_error);
640 else
641 return value_new_float (res);
644 /* ------------------------------------------------------------------------- */
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
652 * gnm_slist_sort_merge merges two lists of unsigned integers.
654 * Returns: (element-type guint) (transfer container): the mergedlist.
656 GSList *
657 gnm_slist_sort_merge (GSList *l1,
658 GSList *l2)
660 GSList list, *l;
662 l = &list;
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);
673 l = l->next = l1;
674 l1 = l1->next;
675 } else {
676 l = l->next = l2;
677 l2 = l2->next;
680 l->next = l1 ? l1 : l2;
682 return list.next;
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.
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.
696 void
697 gnm_strip_missing (gnm_float *data, int *n, GSList *missing)
699 unsigned src, dst;
701 if (missing == NULL)
702 return;
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++;
715 static PairsFloatsCacheEntry *
716 collect_float_pairs_ce (GnmValue const *vx, GnmValue const *vy,
717 GnmEvalPos const *ep, CollectFlags flags)
719 PairsFloatsCacheEntry *ce = g_new0 (PairsFloatsCacheEntry, 1);
720 GSList *missing0 = NULL, *missing1 = NULL;
721 int n0, n1;
723 ce->flags = flags;
725 ce->data_x = collect_floats_value_with_info (vx, ep, flags,
726 &n0, &missing0, &ce->error);
727 if (ce->error)
728 goto err;
730 ce->data_y = collect_floats_value_with_info (vy, ep, flags,
731 &n1, &missing1, &ce->error);
733 if (ce->error)
734 goto err;
736 if (n0 != n1) {
737 ce->n = -1;
738 goto err;
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);
747 ce->n = n0;
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;
757 g_slist_free (missing0);
758 g_slist_free (missing1);
760 return ce;
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.
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.
780 * Note: introspection cannot handle this functions parameter mix.
782 * Returns: (transfer full) (nullable): Error value.
784 GnmValue *
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)
790 GnmValue *key_x = NULL;
791 GnmValue *key_y = NULL;
792 PairsFloatsCacheEntry *ce = NULL;
793 gboolean use_cache, free_keys = TRUE;
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);
800 if ((use_cache = (key_x && key_y)))
801 ce = get_or_fake_pairs_cache_entry (key_x, key_y, flags, ep);
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;
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.
817 ce2 = g_hash_table_lookup (pairs_floats_cache, ce);
818 if (ce2)
819 total_cache_size -= 1 + ce2->n;
821 g_hash_table_replace (pairs_floats_cache, ce, ce);
822 total_cache_size += 1 + ce->n;
826 if (free_keys) {
827 value_release (key_x);
828 value_release (key_y);
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;
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;
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));
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);
872 return NULL;
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
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.
891 * Returns: (transfer full): Function result or error value.
893 GnmValue *
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)
901 gnm_float *vals0, *vals1;
902 int n;
903 GnmValue *res;
904 gnm_float fres;
905 gboolean constp = FALSE;
907 res = collect_float_pairs (val0, val1, ei->pos, flags,
908 &vals0, &vals1, &n, &constp);
909 if (res)
910 return res;
912 if (n <= 0)
913 return value_new_error_std (ei->pos, func_error);
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);
920 if (!constp) {
921 g_free (vals0);
922 g_free (vals1);
924 return res;
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.
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.
941 * Returns: (transfer full): Function result or error value.
943 GnmValue *
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)
950 return float_range_function2d (val0, val1, ei,
951 (float_range_function2d_t)func,
952 flags,
953 func_error,
954 NULL);
957 /* ------------------------------------------------------------------------- */
958 /* ------------------------------------------------------------------------- */
960 typedef struct {
961 GPtrArray *data;
962 CollectFlags flags;
963 } collect_strings_t;
965 static GnmValue *
966 callback_function_collect_strings (GnmEvalPos const *ep, GnmValue const *value,
967 void *closure)
969 char *text;
970 collect_strings_t *cl = closure;
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);
980 if (text)
981 g_ptr_array_add (cl->data, text);
983 return NULL;
986 static void
987 collect_strings_free (GPtrArray *data)
989 g_ptr_array_foreach (data, (GFunc)g_free, NULL);
990 g_ptr_array_free (data, TRUE);
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
1002 * Evaluate a list of expressions and return the result as a #GPtrArray of
1003 * strings.
1005 * Returns: (transfer full) (nullable) (element-type utf8): array of strings.
1007 static GPtrArray *
1008 collect_strings (int argc, GnmExprConstPtr const *argv,
1009 GnmEvalPos const *ep, CollectFlags flags,
1010 GnmValue **error)
1012 collect_strings_t cl;
1013 CellIterFlags iter_flags = CELL_ITER_ALL;
1014 gboolean strict;
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);
1022 if (flags & COLLECT_IGNORE_BLANKS)
1023 iter_flags = CELL_ITER_IGNORE_BLANK;
1025 strict = (flags & (COLLECT_IGNORE_ERRORS | COLLECT_ZERO_ERRORS)) == 0;
1027 cl.data = g_ptr_array_new ();
1028 cl.flags = flags;
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;
1040 return cl.data;
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.
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.
1057 * Returns: (transfer full): Function result or error value.
1059 GnmValue *
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)
1067 GnmValue *error = NULL;
1068 GPtrArray *vals;
1069 char *res = NULL;
1070 int err;
1072 vals = collect_strings (argc, argv, ei->pos, flags, &error);
1073 if (!vals)
1074 return error;
1076 err = func (vals, &res, user);
1078 collect_strings_free (vals);
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);