aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--lib/cbit/htab.h15
-rw-r--r--lib/cbit/misc.h6
-rw-r--r--lib/cbit/vec.c23
-rw-r--r--lib/cbit/vec.h121
-rw-r--r--test/test-vec.cpp23
6 files changed, 181 insertions, 9 deletions
diff --git a/Makefile b/Makefile
index efef980..7d25c61 100644
--- a/Makefile
+++ b/Makefile
@@ -70,6 +70,7 @@ LIB_OBJS := \
out/darwin/read.o \
out/darwin/substrate-compat.o \
out/darwin/execmem.o \
+ out/cbit/vec.o \
out/jump-dis.o \
out/transform-dis.o \
out/hook-functions.o \
@@ -143,6 +144,7 @@ $(eval $(call define_test,execmem,execmem,$(CC) -std=c11 out/darwin/execmem.o -s
$(eval $(call define_test,hook-functions,hook-functions,$(CC) -std=c11 -lsubstitute -segprot __TEST rwx rx))
$(eval $(call define_test,posixspawn-hook,posixspawn-hook,$(CC) -std=c11))
$(eval $(call define_test,htab,htab,$(CC) -std=c11))
+$(eval $(call define_test,vec,vec,$(CXX) -std=c++98 out/cbit/vec.o))
out/injected-test-dylib.dylib: test/injected-test-dylib.c Makefile
$(CC) -std=c11 -dynamiclib -o $@ $<
diff --git a/lib/cbit/htab.h b/lib/cbit/htab.h
index 5c9b993..ccb40b9 100644
--- a/lib/cbit/htab.h
+++ b/lib/cbit/htab.h
@@ -12,8 +12,6 @@ struct htab_internal {
char hi_storage[1]; // see vec.h
};
-#define UNUSED_STATIC_INLINE __attribute__((unused)) static inline
-
/* Declare the helper functions for a htab key type without static - put this
* in the .h and IMPL_HTAB_KEY in a .c. */
#define DECL_EXTERN_HTAB_KEY( \
@@ -188,7 +186,6 @@ struct htab_internal {
}; \
htab_ty { \
union { \
- char h[0]; \
struct htab_internal hi; \
struct { \
size_t length; \
@@ -273,11 +270,13 @@ struct htab_internal {
} while (0)
#define HTAB_FOREACH(ht, key_var, val_var, name) \
- LET(struct htab_##name *__ht = (ht)) \
- for (size_t __htfe_bucket = 0; __htfe_bucket < __ht->capacity; __htfe_bucket++) \
- if(__htab_is_null_##name(&__ht->base[__htfe_bucket].key)) \
+ LET(struct htab_##name *__htfe_ht = (ht)) \
+ for (size_t __htfe_bucket = 0; \
+ __htfe_bucket < __htfe_ht->capacity; \
+ __htfe_bucket++) \
+ if(__htab_is_null_##name(&__htfe_ht->base[__htfe_bucket].key)) \
continue; \
else \
- LET_LOOP(key_var = &__ht->base[__htfe_bucket].key) \
- LET_LOOP(val_var = &__ht->base[__htfe_bucket].value)
+ LET_LOOP(key_var = &__htfe_ht->base[__htfe_bucket].key) \
+ LET_LOOP(val_var = &__htfe_ht->base[__htfe_bucket].value)
diff --git a/lib/cbit/misc.h b/lib/cbit/misc.h
index 52835b1..7c558ce 100644
--- a/lib/cbit/misc.h
+++ b/lib/cbit/misc.h
@@ -1,5 +1,7 @@
#pragma once
+#define UNUSED_STATIC_INLINE __attribute__((unused)) static inline
+
#define LET_LOOP__(expr, ctr) \
if (0) \
__done_##ctr: continue; \
@@ -40,5 +42,7 @@
#define LET_(expr, ctr) LET__(expr, ctr)
#define LET(expr) LET_(expr, __COUNTER__)
-#define safe_mul(a, b) ((a) * (b)) /* XXX */
+/* XXX */
+#define safe_mul(a, b) ((a) * (b))
+#define safe_add(a, b) ((a) + (b))
diff --git a/lib/cbit/vec.c b/lib/cbit/vec.c
new file mode 100644
index 0000000..21038a2
--- /dev/null
+++ b/lib/cbit/vec.c
@@ -0,0 +1,23 @@
+#include "cbit/vec.h"
+#include <stdio.h>
+
+void vec_realloc_internal(struct vec_internal *vi, size_t new_capacity,
+ size_t esize) {
+ size_t new_size = safe_mul(new_capacity, esize);
+ if (vi->els == vi->storage) {
+ void *new = malloc(new_size);
+ memcpy(new, vi->els, vi->capacity * esize);
+ vi->els = new;
+ } else {
+ vi->els = realloc(vi->els, new_size);
+ }
+ vi->capacity = new_capacity;
+}
+void vec_realloc_internal_as_necessary(struct vec_internal *vi,
+ size_t min_capacity,
+ size_t esize) {
+ if (min_capacity > vi->capacity)
+ vec_realloc_internal(vi, safe_mul(vi->capacity, 2), esize);
+ else if (min_capacity < vi->capacity / 3)
+ vec_realloc_internal(vi, vi->capacity / 3, esize);
+}
diff --git a/lib/cbit/vec.h b/lib/cbit/vec.h
new file mode 100644
index 0000000..87e4c28
--- /dev/null
+++ b/lib/cbit/vec.h
@@ -0,0 +1,121 @@
+#pragma once
+#include "misc.h"
+#include <stdlib.h>
+#include <string.h>
+
+struct vec_internal {
+ size_t length;
+ size_t capacity;
+ void *els;
+ char storage[1]; // must be at least one byte so vec_free works correctly
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void vec_realloc_internal(struct vec_internal *vi, size_t new_capacity,
+ size_t esize);
+void vec_realloc_internal_as_necessary(struct vec_internal *vi,
+ size_t min_capacity,
+ size_t esize);
+#ifdef __cplusplus
+}
+#endif
+
+#define DECL_VEC(ty, name) \
+ typedef ty __VEC_TY_##name; \
+ struct vec_##name { \
+ union { \
+ struct vec_internal vi; \
+ struct { \
+ size_t length; \
+ size_t capacity; \
+ VEC_TY(name) *els; \
+ VEC_TY(name) storage[1]; \
+ }; \
+ }; \
+ }; \
+ UNUSED_STATIC_INLINE \
+ void vec_free_storage(struct vec_##name *v) { \
+ if (v->els != v->storage) \
+ free(v->els); \
+ } \
+ UNUSED_STATIC_INLINE \
+ struct vec_##name vec_borrow(VEC_TY(name) *els, size_t length) { \
+ struct vec_##name v; \
+ v.length = v.capacity = length; \
+ v.els = els; \
+ return v; \
+ } \
+ UNUSED_STATIC_INLINE \
+ void vec_realloc_##name(struct vec_##name *v, size_t new_capacity) { \
+ vec_realloc_internal(&v->vi, new_capacity, sizeof(v->els[0])); \
+ } \
+ UNUSED_STATIC_INLINE \
+ void vec_resize_##name(struct vec_##name *v, size_t new_length) { \
+ if (new_length >= v->capacity || new_length < v->capacity / 3) \
+ vec_realloc_internal_as_necessary(&v->vi, new_length, sizeof(v->els[0])); \
+ v->length = new_length; \
+ } \
+ UNUSED_STATIC_INLINE \
+ VEC_TY(name) *vec_appendp_##name(struct vec_##name *v) { \
+ size_t i = v->length++; \
+ if (i == v->capacity) \
+ vec_realloc_internal_as_necessary(&v->vi, i + 1, sizeof(v->els[0])); \
+ return &v->els[i]; \
+ } \
+ UNUSED_STATIC_INLINE \
+ void vec_append_##name(struct vec_##name *v, VEC_TY(name) val) { \
+ *vec_appendp_##name(v) = val; \
+ } \
+ UNUSED_STATIC_INLINE \
+ void vec_concat_##name(struct vec_##name *v1, const struct vec_##name *v2) { \
+ size_t l1 = v1->length, l2 = v2->length; \
+ vec_resize_##name(v1, safe_add(l1, l2)); \
+ memcpy(&v1->els[l1], v2->els, l2 * sizeof(v1->els[0])); \
+ } \
+ UNUSED_STATIC_INLINE \
+ void vec_add_space_##name(struct vec_##name *v, size_t idx, size_t num) { \
+ /* todo optimize */ \
+ size_t orig = v->length; \
+ vec_resize_##name(v, orig + num); \
+ memmove(&v->els[idx + num], &v->els[idx], \
+ (orig - idx) * sizeof(v->els[0])); \
+ } \
+ UNUSED_STATIC_INLINE \
+ void vec_remove_##name(struct vec_##name *v, size_t idx, size_t num) { \
+ /* todo optimize */ \
+ size_t orig = v->length; \
+ memmove(&v->els[idx], &v->els[idx + num], \
+ (orig - (idx + num)) * sizeof(v->els[0])); \
+ vec_resize_##name(v, orig - num); \
+ } \
+
+
+#define VEC_TY(name) __VEC_TY_##name
+
+#define VEC_STORAGE_CAPA(name, n) \
+ struct { \
+ struct vec_##name v; \
+ VEC_TY(name) rest[(n)-1]; \
+ }
+
+#define VEC_STORAGE(ty) \
+ VEC_STORAGE_CAPA(ty, 5)
+
+#define VEC_STORAGE_INIT(vs, name) do { \
+ struct vec_##name *v = &(vs)->v; \
+ v->length = 0; \
+ v->capacity = (sizeof((vs)->rest) / sizeof(VEC_TY(name))) + 1; \
+ v->els = v->storage; \
+} while (0)
+
+
+/* guaranteed to *not* cache vec->length - pretty simple */
+
+#define VEC_FOREACH(vec, idx_var, ptr_var, name) \
+ LET(struct vec_##name *__vfe_v = (vec)) \
+ for (size_t idx_var = 0; idx_var < __vfe_v->length; idx_var++) \
+ LET_LOOP(ptr_var = &__vfe_v->els[idx_var])
+
diff --git a/test/test-vec.cpp b/test/test-vec.cpp
new file mode 100644
index 0000000..f587c1b
--- /dev/null
+++ b/test/test-vec.cpp
@@ -0,0 +1,23 @@
+#include "cbit/vec.h"
+#include <stdio.h>
+DECL_VEC(const char *, ccp);
+
+int main() {
+ VEC_STORAGE(ccp) stor;
+ VEC_STORAGE_INIT(&stor, ccp);
+ struct vec_ccp *vec = &stor.v;
+ for (int i = 0; i < 20; i++) {
+ char *x;
+ asprintf(&x, "el%d", i);
+ vec_append_ccp(vec, x);
+ }
+ vec_remove_ccp(vec, 5, 4);
+ vec_add_space_ccp(vec, 9, 2);
+ for (int i = 9; i <= 10; i++)
+ vec->els[i] = "TILT";
+ vec_concat_ccp(vec, vec);
+ VEC_FOREACH(vec, i, const char **c, ccp) {
+ printf("%zd->%s\n", i, *c);
+ }
+
+}