From 7e34c31e6bd3d4edcdc97a8afbd400af67060295 Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Sun, 25 Nov 2018 21:42:12 +0100 Subject: Add [e[n]]aligned_str[n]dup and aligned_str[n]dupa MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- Makefile | 5 ++ aligned_strndup.c | 29 ++++++++++ enaligned_strdup.c | 64 +++++++++++++++++++++ enaligned_strndup.c | 134 ++++++++++++++++++++++++++++++++++++++++++++ libsimple.h | 6 +- libsimple/aligned_strdup.h | 74 ++++++++++++++++++++++++ libsimple/aligned_strndup.h | 78 ++++++++++++++++++++++++++ 7 files changed, 388 insertions(+), 2 deletions(-) create mode 100644 aligned_strndup.c create mode 100644 enaligned_strdup.c create mode 100644 enaligned_strndup.c create mode 100644 libsimple/aligned_strdup.h create mode 100644 libsimple/aligned_strndup.h diff --git a/Makefile b/Makefile index 90e7363..6bb1c38 100644 --- a/Makefile +++ b/Makefile @@ -7,6 +7,8 @@ SUBHDR =\ libsimple/aligned_alloc.h\ libsimple/aligned_allocz.h\ libsimple/aligned_memdup.h\ + libsimple/aligned_strdup.h\ + libsimple/aligned_strndup.h\ libsimple/array.h\ libsimple/calloc.h\ libsimple/definitions.h\ @@ -40,6 +42,7 @@ HDR =\ OBJ =\ aligned_memdup.o\ + aligned_strndup.o\ allocn.o\ asprintf.o\ difftimespec.o\ @@ -48,6 +51,8 @@ OBJ =\ doubletotimeval.o\ enaligned_allocz.o\ enaligned_memdup.o\ + enaligned_strdup.o\ + enaligned_strndup.o\ encalloc.o\ enmalloc.o\ enmemdup.o\ diff --git a/aligned_strndup.c b/aligned_strndup.c new file mode 100644 index 0000000..a714387 --- /dev/null +++ b/aligned_strndup.c @@ -0,0 +1,29 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" +#ifndef TEST + + +char * +libsimple_aligned_strndup(const char *s, size_t alignment, size_t n) /* TODO test */ +{ + char *ret; + n = strnlen(s, n); + ret = aligned_alloc(alignment, (n + 1) + (alignment - (n + 1) % alignment) % alignment); + if (!ret) + return NULL; + memcpy(ret, s, n); + ret[n] = '\0'; + return ret; +} + + +#else +#include "test.h" + +int +main(void) +{ + return 0; +} + +#endif diff --git a/enaligned_strdup.c b/enaligned_strdup.c new file mode 100644 index 0000000..6390ab0 --- /dev/null +++ b/enaligned_strdup.c @@ -0,0 +1,64 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" +#ifndef TEST + + +char * +libsimple_enaligned_strdup(int status, const char *s, size_t alignment) +{ + void *ret = aligned_strdup(s, alignment); + if (!ret) + enprintf(status, "aligned_strdup:"); + return ret; +} + + +#else +#include "test.h" + +int +main(void) +{ + struct allocinfo *info; + void *s; + + assert((s = libsimple_enaligned_strdup(1, "hello", 2))); + if (have_custom_malloc()) { + assert((info = get_allocinfo(s))); + assert(info->size == 6); + assert(info->alignment == 2); + assert(!info->zeroed); + } + assert(!memcmp(s, "hello", 6)); + free(s); + + assert((s = libsimple_ealigned_strdup("test", 8))); + if (have_custom_malloc()) { + assert((info = get_allocinfo(s))); + assert(info->size == 8); + assert(info->alignment == 8); + assert(!info->zeroed); + } + assert(!memcmp(s, "test", 5)); + free(s); + + if (have_custom_malloc()) { + alloc_fail_in = 1; + assert_exit_ptr(libsimple_enaligned_strdup(44, "hello", 2)); + assert(exit_status == 44); + assert_stderr("%s: aligned_strdup: %s\n", argv0, strerror(ENOMEM)); + assert(!alloc_fail_in); + + libsimple_default_failure_exit = 55; + alloc_fail_in = 1; + assert_exit_ptr(libsimple_ealigned_strdup("test", 8)); + assert(exit_status == 55); + assert_stderr("%s: aligned_strdup: %s\n", argv0, strerror(ENOMEM)); + assert(!alloc_fail_in); + libsimple_default_failure_exit = 1; + } + + return 0; +} + +#endif diff --git a/enaligned_strndup.c b/enaligned_strndup.c new file mode 100644 index 0000000..7778cb2 --- /dev/null +++ b/enaligned_strndup.c @@ -0,0 +1,134 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" +#ifndef TEST + + +char * +libsimple_enaligned_strndup(int status, const char *s, size_t alignment, size_t n) +{ + void *ret = aligned_strndup(s, alignment, n); + if (!ret) + enprintf(status, "aligned_strdup:"); + return ret; +} + + +#else +#include "test.h" + +int +main(void) +{ + struct allocinfo *info; + void *s; + + assert((s = libsimple_enaligned_strndup(1, "hello", 2, SIZE_MAX))); + if (have_custom_malloc()) { + assert((info = get_allocinfo(s))); + assert(info->size == 6); + assert(info->alignment == 2); + assert(!info->zeroed); + } + assert(!memcmp(s, "hello", 6)); + free(s); + + assert((s = libsimple_ealigned_strndup("test", 8, SIZE_MAX))); + if (have_custom_malloc()) { + assert((info = get_allocinfo(s))); + assert(info->size == 8); + assert(info->alignment == 8); + assert(!info->zeroed); + } + assert(!memcmp(s, "test", 5)); + free(s); + + assert((s = libsimple_enaligned_strndup(1, "hello", 2, 100))); + if (have_custom_malloc()) { + assert((info = get_allocinfo(s))); + assert(info->size == 6); + assert(info->alignment == 2); + assert(!info->zeroed); + } + assert(!memcmp(s, "hello", 6)); + free(s); + + assert((s = libsimple_ealigned_strndup("test", 8, 100))); + if (have_custom_malloc()) { + assert((info = get_allocinfo(s))); + assert(info->size == 8); + assert(info->alignment == 8); + assert(!info->zeroed); + } + assert(!memcmp(s, "test", 5)); + free(s); + + assert((s = libsimple_enaligned_strndup(1, "hello", 2, 6))); + if (have_custom_malloc()) { + assert((info = get_allocinfo(s))); + assert(info->size == 6); + assert(info->alignment == 2); + assert(!info->zeroed); + } + assert(!memcmp(s, "hello", 6)); + free(s); + + assert((s = libsimple_ealigned_strndup("test", 8, 5))); + if (have_custom_malloc()) { + assert((info = get_allocinfo(s))); + assert(info->size == 8); + assert(info->alignment == 8); + assert(!info->zeroed); + } + assert(!memcmp(s, "test", 5)); + free(s); + + assert((s = libsimple_enaligned_strndup(1, "hello", 2, 5))); + if (have_custom_malloc()) { + assert((info = get_allocinfo(s))); + assert(info->size == 6); + assert(info->alignment == 2); + assert(!info->zeroed); + } + assert(!memcmp(s, "hello", 6)); + free(s); + + assert((s = libsimple_ealigned_strndup("test", 8, 4))); + if (have_custom_malloc()) { + assert((info = get_allocinfo(s))); + assert(info->size == 8); + assert(info->alignment == 8); + assert(!info->zeroed); + } + assert(!memcmp(s, "test", 5)); + free(s); + + assert((s = libsimple_enaligned_strndup(1, "hello", 2, 4))); + if (have_custom_malloc()) { + assert((info = get_allocinfo(s))); + assert(info->size == 6); + assert(info->alignment == 2); + assert(!info->zeroed); + } + assert(!memcmp(s, "hell", 5)); + free(s); + + if (have_custom_malloc()) { + alloc_fail_in = 1; + assert_exit_ptr(libsimple_enaligned_strndup(44, "hello", 2, 10)); + assert(exit_status == 44); + assert_stderr("%s: aligned_strdup: %s\n", argv0, strerror(ENOMEM)); + assert(!alloc_fail_in); + + libsimple_default_failure_exit = 55; + alloc_fail_in = 1; + assert_exit_ptr(libsimple_ealigned_strndup("test", 8, 10)); + assert(exit_status == 55); + assert_stderr("%s: aligned_strdup: %s\n", argv0, strerror(ENOMEM)); + assert(!alloc_fail_in); + libsimple_default_failure_exit = 1; + } + + return 0; +} + +#endif diff --git a/libsimple.h b/libsimple.h index f2dd4b9..22b0cca 100644 --- a/libsimple.h +++ b/libsimple.h @@ -51,10 +51,12 @@ #include "libsimple/printf.h" #include "libsimple/definitions.h" #include "libsimple/memalloc.h" -#include "libsimple/strdup.h" -#include "libsimple/strndup.h" #include "libsimple/memdup.h" #include "libsimple/aligned_memdup.h" +#include "libsimple/strdup.h" +#include "libsimple/aligned_strdup.h" +#include "libsimple/strndup.h" +#include "libsimple/aligned_strndup.h" #include "libsimple/mallocz.h" #include "libsimple/malloc.h" #include "libsimple/calloc.h" diff --git a/libsimple/aligned_strdup.h b/libsimple/aligned_strdup.h new file mode 100644 index 0000000..6dc3bfa --- /dev/null +++ b/libsimple/aligned_strdup.h @@ -0,0 +1,74 @@ +/* See LICENSE file for copyright and license details. */ + + +/** + * Stack allocation version of `aligned_strdup` + * + * @param s:const char * The string to copy + * @param alignment:size_t The alignment of the returned pointer + * @return :char * Duplicate of `s` with automatic storage + */ +#if defined(__GNUC__) || defined(__clang__) +# define libsimple_aligned_strdupa(s, alignment) /* TODO test, man */\ + ({\ + const char *__s = (s);\ + size_t __n = strlen(__s) + 1;\ + size_t __a = (alignment);\ + uintptr_t __misalignment;\ + char *__r;\ + __a += !__a;\ + __r = alloca(__n + (__a - 1));\ + __misalignment = (uintptr_t)__r % (uintptr_t)__a;\ + if (__misalignment)\ + __r += (uintptr_t)__a - __misalignment;\ + memcpy(__r, __s, __n);\ + }) +# ifndef aligned_strdupa +# define aligned_strdupa(s, alignment) libsimple_aligned_strdupa(s, alignment) +# endif +#endif + + +/** + * Version of strdup(3) that returns a pointer with a custom alignment + * + * @param s The string to copy + * @param alignment The alignment of the returned pointer + * @return Duplicate of `s`, `NULL` on failure + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(2), __nonnull__, __warn_unused_result__))) +static inline char *libsimple_aligned_strdup(const char * __s, size_t __alignment) /* TODO test, man */ +{ return libsimple_aligned_memdup(__s, __alignment, strlen(__s) + 1); } +#ifndef aligned_strdup +# define aligned_strdup libsimple_aligned_strdup +#endif + + +/** + * Version of `libsimple_aligned_strdup` that calls `libsimple_enprintf` on error + * + * @param status Exit value in case of failure + * @param s The string to copy + * @param alignment The alignment of the returned pointer + * @return Duplicate of `s` + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(3), __nonnull__, __warn_unused_result__, __returns_nonnull__))) +char *libsimple_enaligned_strdup(int, const char *, size_t); /* TODO man */ +#ifndef enaligned_strdup +# define enaligned_strdup libsimple_enaligned_strdup +#endif + + +/** + * Version of `libsimple_aligned_strdup` that calls `libsimple_eprintf` on error + * + * @param s The string to copy + * @param alignment The alignment of the returned pointer + * @return Duplicate of `s` + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(2), __nonnull__, __warn_unused_result__, __returns_nonnull__))) +static inline char *libsimple_ealigned_strdup(const char *__s, size_t __alignment) /* TODO man */ +{ return enaligned_strdup(libsimple_default_failure_exit, __s, __alignment); } +#ifndef ealigned_strdup +# define ealigned_strdup libsimple_ealigned_strdup +#endif diff --git a/libsimple/aligned_strndup.h b/libsimple/aligned_strndup.h new file mode 100644 index 0000000..cf41ae1 --- /dev/null +++ b/libsimple/aligned_strndup.h @@ -0,0 +1,78 @@ +/* See LICENSE file for copyright and license details. */ + + +/** + * Stack allocation version of `libsimple_aligned_strndup` + * + * @param s:const char * The string to copy + * @param alignment:size_t The alignment of the returned pointer + * @param n:size_t The maximum number of bytes to copy + * @return :char * Duplicate of `s` with automatic storage + */ +#if defined(__GNUC__) || defined(__clang__) +# define libsimple_aligned_strndupa(s, alignment, n) /* TODO test, man */\ + ({\ + const char *__s = (s);\ + size_t __n = strnlen(__s, n);\ + size_t __a = (alignment);\ + uintptr_t __misalignment;\ + char *__r;\ + __r = alloca(__n + (__a - 1));\ + __misalignment = (uintptr_t)__r % (uintptr_t)__a;\ + if (__misalignment)\ + __r += (uintptr_t)__a - __misalignment;\ + memcpy(__r, __s, __n);\ + __r[__n] = '\0';\ + __r;\ + }) +# ifndef aligned_strndupa +# define aligned_strndupa(s, alignment, n) libsimple_aligned_strndupa(s, alignment, n) +# endif +#endif + + +/** + * Version of strndup(3) that returns a pointer with a custom alignment + * + * @param s The string to copy + * @param alignment The alignment of the returned pointer + * @param n The maximum number of bytes to copy + * @return Duplicate of `s`, `NULL` on failure + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(2), __nonnull__, __warn_unused_result__))) +char *libsimple_aligned_strndup(const char * __s, size_t __alignment, size_t __n); /* TODO man */ +#ifndef aligned_strndup +# define aligned_strndup libsimple_aligned_strndup +#endif + + +/** + * Version of `libsimple_aligned_strndup` that calls `libsimple_enprintf` on error + * + * @param status Exit value in case of failure + * @param s The string to copy + * @param alignment The alignment of the returned pointer + * @param n The maximum number of bytes to copy + * @return Duplicate of `s` + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(3), __nonnull__, __warn_unused_result__, __returns_nonnull__))) +char *libsimple_enaligned_strndup(int, const char *, size_t, size_t); /* TODO man */ +#ifndef enaligned_strndup +# define enaligned_strndup libsimple_enaligned_strndup +#endif + + +/** + * Version of `libsimple_aligned_strndup` that calls `libsimple_eprintf` on error + * + * @param s The string to copy + * @param alignment The alignment of the returned pointer + * @param n The maximum number of bytes to copy + * @return Duplicate of `s` + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(2), __nonnull__, __warn_unused_result__, __returns_nonnull__))) +static inline char *libsimple_ealigned_strndup(const char *__s, size_t __alignment, size_t __n) /* TODO man */ +{ return enaligned_strndup(libsimple_default_failure_exit, __s, __alignment, __n); } +#ifndef ealigned_strndup +# define ealigned_strndup libsimple_ealigned_strndup +#endif -- cgit v1.2.3-70-g09d2