From 6d1f5d3b4cb7e92db3a7d00a190ef39ec46a2f7f Mon Sep 17 00:00:00 2001
From: Abdelrahman Said <said.abdelrahman89@gmail.com>
Date: Sat, 30 Dec 2023 19:09:29 +0000
Subject: [PATCH] Impelement version with X macros

---
 03_xmacros/main.c  | 18 +++++++++++
 03_xmacros/vec.h   | 51 ++++++++++++++++++++++++++++++
 03_xmacros/vec.inc | 79 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 148 insertions(+)
 create mode 100644 03_xmacros/main.c
 create mode 100644 03_xmacros/vec.h
 create mode 100644 03_xmacros/vec.inc

diff --git a/03_xmacros/main.c b/03_xmacros/main.c
new file mode 100644
index 0000000..4b7f6d3
--- /dev/null
+++ b/03_xmacros/main.c
@@ -0,0 +1,18 @@
+#define VEC_IMPLEMENTATION
+#include "vec.h"
+#undef VEC_IMPLEMENTATION
+#include <stdio.h>
+
+int main(int argc, char *argv[]) {
+  vec2i_t v1 = (vec2i_t){2, 3};
+  vec2i_t v2 = (vec2i_t){4, 5};
+
+  vec_print(vec2i_t, vec_add(vec2i_t, v1, v2));
+  vec_print(vec2i_t, vec_sub(vec2i_t, v1, v2));
+  vec_print(vec2i_t, vec_mul(vec2i_t, v1, v2));
+  printf("%d\n", vec_dot(vec2i_t, v1, v2));
+  printf("%d\n", vec_magnitude(vec2i_t, v1));
+  printf("%d\n", vec_magnitude(vec2i_t, v2));
+
+  return 0;
+}
diff --git a/03_xmacros/vec.h b/03_xmacros/vec.h
new file mode 100644
index 0000000..3a54d08
--- /dev/null
+++ b/03_xmacros/vec.h
@@ -0,0 +1,51 @@
+#ifndef VEC_MACRO_H
+#define VEC_MACRO_H
+
+#include "../aliases.h"
+
+#define vec_print(T, v1) vec_print_##T(v1)
+#define vec_add(T, v1, v2) vec_add_##T(v1, v2)
+#define vec_sub(T, v1, v2) vec_sub_##T(v1, v2)
+#define vec_mul(T, v1, v2) vec_mul_##T(v1, v2)
+#define vec_dot(T, v1, v2) vec_dot_##T(v1, v2)
+#define vec_magnitude(T, v) vec_magnitude_##T(v)
+
+#define T i32
+#define C 2
+#define I i
+#define PI d
+#define VEC_FIELDS                                                             \
+  VEC(i32, x)                                                                  \
+  VEC(i32, y)
+#include "vec.inc"
+
+#define T i32
+#define C 3
+#define I i
+#define PI d
+#define VEC_FIELDS                                                             \
+  VEC(i32, x)                                                                  \
+  VEC(i32, y)                                                                  \
+  VEC(i32, z)
+#include "vec.inc"
+
+#define T f32
+#define C 2
+#define I f
+#define PI f
+#define VEC_FIELDS                                                             \
+  VEC(f32, x)                                                                  \
+  VEC(f32, y)
+#include "vec.inc"
+
+#define T f32
+#define C 3
+#define I f
+#define PI f
+#define VEC_FIELDS                                                             \
+  VEC(f32, x)                                                                  \
+  VEC(f32, y)                                                                  \
+  VEC(f32, z)
+#include "vec.inc"
+
+#endif // !VEC_MACRO_H
diff --git a/03_xmacros/vec.inc b/03_xmacros/vec.inc
new file mode 100644
index 0000000..48f842e
--- /dev/null
+++ b/03_xmacros/vec.inc
@@ -0,0 +1,79 @@
+#include "../aliases.h"
+#include <stdio.h>
+#include <math.h>
+
+#define obj(o, m) o.m
+#define stringify(x) #x
+#define printf_spec(PI) "%" stringify(PI) ", "
+#define typename_concat(C, I) vec##C##I##_t
+#define typename(C, I) typename_concat(C, I)
+#define funcname_concat(B, C, I) vec_##B##_vec##C##I##_t
+#define funcname(B, C, I) funcname_concat(B, C, I)
+
+typedef struct {
+	#define VEC(type, name) type name;
+	VEC_FIELDS
+	#undef VEC
+} typename(C, I);
+
+INTERNAL void funcname(print, C, I)(typename(C, I) v1);
+INTERNAL typename(C, I) funcname(add, C, I)(typename(C, I) v1, typename(C, I) v2);
+INTERNAL typename(C, I) funcname(sub, C, I)(typename(C, I) v1, typename(C, I) v2);
+INTERNAL typename(C, I) funcname(mul, C, I)(typename(C, I) v1, typename(C, I) v2);
+INTERNAL T funcname(dot, C, I)(typename(C, I) v1, typename(C, I) v2);
+INTERNAL T funcname(magnitude, C, I)(typename(C, I) v1);
+
+#ifdef VEC_IMPLEMENTATION
+	void funcname(print, C, I)(typename(C, I) v1) {
+		printf("{ "
+			#define VEC(type, name) printf_spec(PI)
+			VEC_FIELDS "%c}\n",
+			#undef VEC
+			#define VEC(type, name) obj(v1, name),
+			VEC_FIELDS
+			#undef VEC
+		'\0');
+	}
+
+INTERNAL typename(C, I) funcname(add, C, I)(typename(C, I) v1, typename(C, I) v2) {
+	return (typename(C, I)) {
+	#define VEC(type, name) obj(v1, name) + obj(v2, name),
+	VEC_FIELDS
+	#undef VEC
+	};
+}
+
+INTERNAL typename(C, I) funcname(sub, C, I)(typename(C, I) v1, typename(C, I) v2) {
+	return (typename(C, I)) {
+	#define VEC(type, name) obj(v1, name) - obj(v2, name),
+	VEC_FIELDS
+	#undef VEC
+	};
+}
+
+INTERNAL typename(C, I) funcname(mul, C, I)(typename(C, I) v1, typename(C, I) v2) {
+	return (typename(C, I)) {
+	#define VEC(type, name) obj(v1, name) * obj(v2, name),
+	VEC_FIELDS
+	#undef VEC
+	};
+}
+
+INTERNAL T funcname(dot, C, I)(typename(C, I) v1, typename(C, I) v2) {
+	return
+	#define VEC(type, name) obj(v1, name) * obj(v2, name) +
+	VEC_FIELDS 0;
+	#undef VEC
+}
+
+INTERNAL T funcname(magnitude, C, I)(typename(C, I) v1) {
+	T dotproduct = funcname(dot, C, I)(v1, v1);
+	return (T)sqrtf(dotproduct);
+}
+#endif
+
+#undef VEC_FIELDS
+#undef PI
+#undef I
+#undef C
+#undef T