/* Strings with implicit length. * Richard W.M. Jones * * https://rwmj.wordpress.com/2016/01/08/half-baked-ideas-c-strings-with-implicit-length-field/ * * Inspired by this OCaml implementation of strings: * https://rwmj.wordpress.com/2009/08/05/ocaml-internals-part-2-strings-and-other-types/ * * NB: It's just for playing with. Don't actually use this in * production code!! In particular this uses malloc allocations in a * way which is not valid, standard C, and may break or corrupt things * at any time. */ #ifndef ilenstr_h_ #define ilenstr_h_ #include #include #include #include /* If your libc doesn't have glibc's malloc_usable_size, then * you need to find the equivalent function and define it here. */ #define ilenstr_malloc_size malloc_usable_size /* Although ilenstrs have a separate length field, it's implicit, * so they are convertable back to C strings (although C strings * are NOT ilenstrs so don't try to cast them the other way). */ typedef char *ilenstr; /* Allocate a new ilenstr from an arbitrary string + length. The * string may contain \0 characters within the string. */ static ilenstr new_ilenstr_with_len (const char *str, size_t len) { char *ilstr; size_t msize; uint8_t *p; ilstr = malloc (len+1); if (!ilstr) return NULL; memcpy (ilstr, str, len); ilstr[len] = '\0'; msize = ilenstr_malloc_size (ilstr); assert (len <= msize); /* Because we only have a single byte to use at the end of the * malloc allocation, we have this limit. It could be bypassed with * some horrible encoding scheme, but that would make getting the * string length slower. Hopefully this never asserts in practice. */ assert (msize-len <= 255); p = (uint8_t *) &ilstr[msize-1]; *p = msize-len; return ilstr; } /* Allocate an ilenstr from a C string. The C string cannot * contain \0 characters within the string. */ static ilenstr new_ilenstr (const char *cstr) { return new_ilenstr_with_len (cstr, strlen (cstr)); } /* Get the implicit length of an ilenstr. */ static size_t ilstrlen (const ilenstr ilstr) { size_t msize; uint8_t *p; msize = ilenstr_malloc_size (ilstr); p = (uint8_t *) (ilstr + msize - 1); return msize - *p; } #endif /* ilenstr_h_ */