[ccan] [PATCH] mem: module for common operations on addr+length regions

Rusty Russell rusty at rustcorp.com.au
Tue Aug 5 16:13:45 EST 2014


Cody P Schafer <dev at codyps.com> writes:
> Impliments 'mem' variants of <string.h> and <ccan/str/str.h> functions.
>
> Signed-off-by: Cody P Schafer <dev at codyps.com>

I see David's point about bytestring overlap, but agree also it makes
sense to have these.

And yes, roll in ccan/memmem, too.

I've given a thorough nit-picking below.  Ignore at your leisure :)

> +/**
> + * mem - provide various functions for handling memory (very similar to str for strings)

I get what you mean, but how about the punchier:
        mem - functions for handling memory (like ccan/str but for bytes)

> +#include "config.h"
> +
> +#include <string.h>
> +#include <stdbool.h>
> +#include <ccan/mem/mem.h>
> +
> +size_t memspn(const char *data, size_t len, const char *accept, size_t accept_len)
> +{
> +	size_t i, j;
> +	for (i = 0; i < len; i++) {
> +		for (j = 0; j < accept_len; j++)
> +			if (accept[j] == data[i])
> +				goto cont_outer;
> +		break;
> +cont_outer:
> +		;
> +	}
> +	return i;
> +}

The inner loop is memchr, isn't it?  And with many others...

> +void *memcchr(void const *data, int c, size_t data_len)
> +{
> +	char const *p = data;
> +	while((size_t)(p - ((char const *)data)) < data_len) {

The cast to size_t is a bit weird.


> +char *mempbrk(const char *data, size_t len, const char *accept, size_t accept_len);

Why are these char *?  Maybe that makes sense...

> +static inline bool memends(const char *m, size_t m_len, const char *postfix, size_t postfix_len)

But I don't think this one does.  I can imagine people comparing the end
of anything...

But basically, it's really nicely done!

Have you seen what I did with CCAN_STR_DEBUG() and typesafety?  It
might be a really nice thing to have for these.

In particular, making sure that you're not accidentally casting away
const via a mem* function (which needs __typeof__, see "GNU magic" at
the bottom of str.h), or dealing with two completely incompatible types,
eg:

/* a and be should be comparable: one void or the same type */
#define memeq(a, al, b, bl)
        (memeq_((a), (al), (b), (bl) + 0*sizeof((a) == (b)))

static inline bool memeq_(const void *a, size_t al, const void *b, size_t bl)
...

Sure, sometimes you'll really want to do that, but then a cast to void *
is probably preferable to letting weird mistakes through.

(The final litmas test is usage; if you have users for this see what
that change does to them...)

Cheers,
Rusty.


More information about the ccan mailing list