commit c2c2c116755c2cc6ebcac07ad1dc6012ba660ff1
parent a54e194b360bec01fb404a369abf88b0c65b54a9
Author: Christian Grothoff <christian@grothoff.org>
Date: Sun, 15 Mar 2026 22:33:14 +0100
new amount set logic for #11253
Diffstat:
2 files changed, 158 insertions(+), 0 deletions(-)
diff --git a/src/include/taler/taler_amount_lib.h b/src/include/taler/taler_amount_lib.h
@@ -483,6 +483,69 @@ TALER_amount_round_down (struct TALER_Amount *amount,
const struct TALER_Amount *round_unit);
+/**
+ * Represents a set of amounts in different currencies.
+ * Useful when adding up various amounts in different
+ * currencies.
+ */
+struct TALER_AmountSet
+{
+ /**
+ * Array of amounts. Each currency should have at most one entry.
+ */
+ struct TALER_Amount *taa;
+
+ /**
+ * Length of the @e taa array.
+ */
+ unsigned int taa_size;
+
+};
+
+
+/**
+ * Free memory allocated within @a as, but not @a as itself.
+ * Effectively sets the total amount in @a as also back to zero.
+ *
+ * @param[in,out] as set to free (turned into an empty set)
+ */
+void
+TALER_amount_set_free (struct TALER_AmountSet *as);
+
+
+/**
+ * Add amount @a a to the total amount represented by @a as.
+ *
+ * @param[in,out] as set of amounts to update by adding @a a
+ * @param val amount to add
+ * @param cap cap for the sums to enforce, can be NULL;
+ * if given, then #TALER_AAR_INVALID_RESULT_OVERFLOW is impossible
+ * as we will use @a cap as a maximum value for this currency
+ * @return operation status, negative on failures;
+ * #TALER_AAR_INVALID_CURRENCIES_INCOMPATIBLE is impossible,
+ * except if @a cap does not match @a val
+ */
+enum TALER_AmountArithmeticResult
+TALER_amount_set_add (struct TALER_AmountSet *as,
+ const struct TALER_Amount *val,
+ const struct TALER_Amount *cap);
+
+
+/**
+ * Test if the amount @a b is available in @a as, that is if
+ * the total amount added to @a as in the currency of @a b
+ * is not below @a b. In other words, returns true if
+ * the available amount in @a as would suffice to pay for @a b.
+ *
+ * @param as set to compare
+ * @param b amount to check if it falls into the range
+ * @return true if b <= as(b.currency)
+ */
+bool
+TALER_amount_set_test_above (const struct TALER_AmountSet *as,
+ const struct TALER_Amount *b);
+
+
#if 0 /* keep Emacsens' auto-indent happy */
{
#endif
diff --git a/src/util/amount.c b/src/util/amount.c
@@ -849,4 +849,99 @@ TALER_amount_round_down (struct TALER_Amount *amount,
}
+void
+TALER_amount_set_free (struct TALER_AmountSet *as)
+{
+ GNUNET_array_grow (as->taa,
+ as->taa_size,
+ 0);
+}
+
+
+enum TALER_AmountArithmeticResult
+TALER_amount_set_add (struct TALER_AmountSet *as,
+ const struct TALER_Amount *val,
+ const struct TALER_Amount *cap)
+{
+ for (unsigned int i = 0; i<as->taa_size; i++)
+ {
+ struct TALER_Amount *ai = &as->taa[i];
+ enum TALER_AmountArithmeticResult aar;
+
+ if (GNUNET_OK !=
+ TALER_amount_cmp_currency (ai,
+ val))
+ continue;
+ aar = TALER_amount_add (ai,
+ ai,
+ val);
+ /* If we have a cap, we tolerate the overflow */
+ if ( (aar < 0) &&
+ ( (NULL == cap) ||
+ (TALER_AAR_INVALID_RESULT_OVERFLOW != aar) ) )
+ return aar; /* hard error */
+ if (TALER_AAR_INVALID_RESULT_OVERFLOW == aar)
+ {
+ if (GNUNET_OK !=
+ TALER_amount_cmp_currency (val,
+ cap))
+ return TALER_AAR_INVALID_CURRENCIES_INCOMPATIBLE;
+ *ai = *cap;
+ return (TALER_amount_is_zero (cap))
+ ? TALER_AAR_RESULT_ZERO
+ : TALER_AAR_RESULT_POSITIVE;
+ }
+ GNUNET_assert (aar >= 0);
+ if (NULL != cap)
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_min (ai,
+ ai,
+ cap));
+ return;
+ }
+ GNUNET_array_append (as->taa,
+ as->taa_size,
+ *val);
+ {
+ struct TALER_Amount *ai = &as->taa[as->taa_size - 1];
+
+ if (NULL != cap)
+ {
+ if (GNUNET_OK !=
+ TALER_amount_cmp_currency (val,
+ cap))
+ return TALER_AAR_INVALID_CURRENCIES_INCOMPATIBLE;
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_min (ai,
+ ai,
+ cap));
+ }
+ return (TALER_amount_is_zero (ai))
+ ? TALER_AAR_RESULT_ZERO
+ : TALER_AAR_RESULT_POSITIVE;
+ }
+}
+
+
+bool
+TALER_amount_set_test_above (const struct TALER_AmountSet *as,
+ const struct TALER_Amount *b)
+{
+ for (unsigned int i = 0; i<as->taa_size; i++)
+ {
+ const struct TALER_Amount *asi = &as->taa[i];
+
+ if (GNUNET_OK !=
+ TALER_amount_cmp_currency (b,
+ asi))
+ continue;
+ if (1 !=
+ TALER_amount_cmp (b,
+ asi))
+ return true;
+ }
+ return false;
+}
+
+
/* end of amount.c */