Hi, On Thu, Nov 21, 2019 at 06:09:38PM +0100, Stefano Brivio wrote: > On Wed, 20 Nov 2019 13:53:08 +0100 > Phil Sutter <phil@xxxxxx> wrote: > > > On Wed, Nov 20, 2019 at 12:49:54PM +0100, Stefano Brivio wrote: > > > > > On Tue, 19 Nov 2019 23:12:38 +0100 > > > Phil Sutter <phil@xxxxxx> wrote: > > [...] > > > > > So, the whole thing would look like (together with the other change > > > you suggest): > > > > > > -- > > > static int netlink_gen_concat_data_expr(const struct expr *i, > > > unsigned char *data) > > > { > > > if (i->etype == EXPR_RANGE) { > > > const struct expr *e; > > > > > > if (i->flags & EXPR_F_INTERVAL_END) > > > e = i->right; > > > else > > > e = i->left; > > > > > > return netlink_export_pad(data, e->value, e); > > > } > > > > > > if (i->etype == EXPR_PREFIX) { > > > if (i->flags & EXPR_F_INTERVAL_END) { > > > int count; > > > mpz_t v; > > > > > > mpz_init_bitmask(v, i->len - i->prefix_len); > > > mpz_add(v, i->prefix->value, v); > > > count = netlink_export_pad(data, v, i); > > > mpz_clear(v); > > > return count; > > > } > > > > > > return netlink_export_pad(data, i->prefix->value, i); > > > } > > > > > > assert(i->etype == EXPR_VALUE); > > > > > > return netlink_export_pad(data, i->value, i); > > > } > > > > I would even: > > > > | static int > > | netlink_gen_concat_data_expr(const struct expr *i, unsigned char *data) > > | { > > | mpz_t *valp = NULL; > > | > > | switch (i->etype) { > > | case EXPR_RANGE: > > | i = (i->flags & EXPR_F_INTERVAL_END) ? i->right : i->left; > > | break; > > | case EXPR_PREFIX: > > | if (i->flags & EXPR_F_INTERVAL_END) { > > | int count; > > | mpz_t v; > > | > > | mpz_init_bitmask(v, i->len - i->prefix_len); > > | mpz_add(v, i->prefix->value, v); > > | count = netlink_export_pad(data, v, i); > > | mpz_clear(v); > > | return count; > > | } > > | valp = &i->prefix->value; > > | break; > > | case EXPR_VALUE: > > | break; > > | default: > > | BUG("invalid expression type '%s' in set", expr_ops(i)->name); > > | } > > | > > | return netlink_export_pad(data, valp ? *valp : i->value, i); > > | } > > > > But that's up to you. :) > > I think it's nicer with a switch and that BUG() is more helpful than a > random assert, but I personally find that ternary condition on valp a > bit difficult to follow. Yes, I overdid it a bit there trying to have a single call to netlink_export_pad(). You found a good middle-ground! [...] > > > > So this is the fifth copy of the same piece of code. :( > > > > > > > > Isn't there a better way to solve that? > > > > > > I couldn't think of any. > > > > I guess we would need an intermediate state which is 'multiton_rhs_expr > > DOT multiton_rhs_expr'. Might turn into a mess as well. :) > > I just tried to add that, and kept losing myself in the middle of it. > It might be me, but it doesn't sound that promising when it comes to > readability later. I suspected that already. :) > I guess we already have enough levels of indirection here -- I'd just > go with the compound_expr_alloc_or_add() you suggested. > > > > > Intuitively, I would just: > > > > > > > > | int tmp = len; > > > > | while (start != end && !(start & 1) && (end & 1) && tmp) { > > > > | start >>= 1; > > > > | end >>= 1; > > > > | tmp--; > > > > | } > > > > | return (tmp && start == end) ? len - tmp : -1; > > > > > > > > Is that slow when dealing with gmp? > > > > > > I don't think so, it also avoid copies and allocations, while shifting > > > and setting bits have comparable complexities. I'd go with the gmp > > > version of this. > > Actually, I need to preserve the original elements, so the two copies > are needed anyway -- other than that, I basically recycled your > function. *Obviously* my algorithm assumed pass-by-value. ;) Thanks, Phil