aboutsummaryrefslogtreecommitdiffstats
path: root/memelemmove.c
diff options
context:
space:
mode:
Diffstat (limited to 'memelemmove.c')
-rw-r--r--memelemmove.c124
1 files changed, 124 insertions, 0 deletions
diff --git a/memelemmove.c b/memelemmove.c
new file mode 100644
index 0000000..2a90e26
--- /dev/null
+++ b/memelemmove.c
@@ -0,0 +1,124 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+#ifndef TEST
+
+
+#define MEMELEMMOVE(TYPE)\
+ do {\
+ TYPE *p;\
+ if (d <= s) {\
+ for (; n; n--, s++)\
+ if ((*d++ = *s) == elem)\
+ return d;\
+ } else {\
+ for (p = *(TYPE **)(void *)&s; n; n--, p++) {\
+ if (*p == elem) {\
+ n = (size_t)(p - s);\
+ p = &d[n + 1];\
+ do { d[n] = s[n]; } while (n--);\
+ return p;\
+ }\
+ }\
+ for (n = (size_t)(p - s); n;) {\
+ n--;\
+ d[n] = s[n];\
+ }\
+ }\
+ return NULL;\
+ } while (0)
+
+
+static uint16_t *
+memelemmove16(uint16_t *restrict d, const uint16_t *restrict s, uint16_t elem, size_t n)
+{
+ MEMELEMMOVE(uint16_t);
+}
+
+
+static uint32_t *
+memelemmove32(uint32_t *restrict d, const uint32_t *restrict s, uint32_t elem, size_t n)
+{
+ MEMELEMMOVE(uint32_t);
+}
+
+
+static uint64_t *
+memelemmove64(uint64_t *restrict d, const uint64_t *restrict s, uint64_t elem, size_t n)
+{
+ MEMELEMMOVE(uint64_t);
+}
+
+
+static char *
+memelemmovex(char *restrict d, const char *restrict s, const char *restrict elem, size_t size, size_t n)
+{
+ char *p;
+ size_t i;
+ if (d <= s) {
+ for (; n; s += size, n--) {
+ for (i = 0; i < size; i++)
+ d[i] = s[i];
+ for (i = 0; i < size; i++)
+ if (d[i] != elem[i])
+ goto next_forwards;
+ d += size;
+ return d;
+ next_forwards:
+ d += size;
+ }
+ return NULL;
+ } else {
+ for (p = *(char **)(void *)&s; n; n--) {
+ for (i = 0; i < size; i++)
+ if (p[i] != elem[i])
+ goto next_backwards;
+
+ p += size;
+ n = (size_t)(p - s);
+ p = &d[n];
+ goto out_backwards;
+ next_backwards:
+ p += size;
+ }
+ n = (size_t)(p - s);
+ p = NULL;
+ out_backwards:
+ while (n) {
+ n--;
+ d[n] = s[n];
+ }
+ return p;
+ }
+}
+
+
+void *
+libsimple_memelemmove(void *d, const void *s, const void *restrict elem, size_t size, size_t n) /* TODO test, man */
+{
+ switch (size) {
+ case 0:
+ return d;
+ case 1:
+ return memcmove(d, s, *(const char *)elem, n);
+ case 2:
+ return memelemmove16(d, s, *(const uint16_t *)elem, n);
+ case 4:
+ return memelemmove32(d, s, *(const uint32_t *)elem, n);
+ case 8:
+ return memelemmove64(d, s, *(const uint64_t *)elem, n);
+ default:
+ return memelemmovex(d, s, elem, size, n);
+ }
+}
+
+
+#else
+#include "test.h"
+
+int
+main(void)
+{
+ return 0;
+}
+
+#endif