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