aboutsummaryrefslogtreecommitdiff
path: root/optional/optional.h
diff options
context:
space:
mode:
authorYaroslav de la Peña Smirnov <yps@yaroslavps.com>2023-07-22 03:03:09 +0300
committerYaroslav de la Peña Smirnov <yps@yaroslavps.com>2023-07-22 03:03:09 +0300
commitcb1a40859029f33184355475e51fec95afb79a73 (patch)
tree5aea859d3a3e10ddd058beac9d6734d17979d560 /optional/optional.h
downloadc-wares-cb1a40859029f33184355475e51fec95afb79a73.tar.gz
c-wares-cb1a40859029f33184355475e51fec95afb79a73.zip
init
Just some C wares; hmap, list, optional, unit tests.
Diffstat (limited to 'optional/optional.h')
-rw-r--r--optional/optional.h92
1 files changed, 92 insertions, 0 deletions
diff --git a/optional/optional.h b/optional/optional.h
new file mode 100644
index 0000000..6dcc3e2
--- /dev/null
+++ b/optional/optional.h
@@ -0,0 +1,92 @@
+/* SPDX-License-Identifier: MIT */
+/**
+ * optional.h - Macros for optional types. v0.1.0
+ *
+ * Copyright (C) 2023 Yaroslav de la Peña Smirnov
+ *
+ * Documentation
+ * =============
+ *
+ * Poor man's optional "type templates" for C.
+ *
+ * An object of optional type is an object that may or may not hold an object of
+ * a certain type inside itself at any time. Before declaring a variable of a
+ * certain OPTIONAL type, said OPTIONAL type should be declared with the
+ * OPTIONALDEC macro.
+ *
+ * Currently only supports types that are composed of one token, i.e. no
+ * structs, enums, unions, etc. Might expand it in the future to support them.
+ */
+
+#ifndef OPTIONAL_H
+#define OPTIONAL_H
+
+#include <stdbool.h>
+
+/**
+ * OPTIONALDEC - declare OPTIONAL type that holds data of type @T
+ * @T: the type of data to hold.
+ */
+#define OPTIONALDEC(T) struct __OPTIONAL_##T { bool has; T data; }
+
+/**
+ * OPTIONAL - declare an object that optionally holds type @T
+ * @T: the type of data to hold.
+ */
+#define OPTIONAL(T) struct __OPTIONAL_##T
+
+/**
+ * OPTNONE - initialize an OPTIONAL object to hold nothing.
+ */
+#define OPTNONE { .has = false }
+
+/**
+ * OPTSOME - initialize an OPTIONAL object to hold something.
+ * @d: data to hold.
+ */
+#define OPTSOME(d) { .has = true, .data = d }
+
+/**
+ * opt_set_none - set an OPTIONAL object to hold nothing.
+ * @opt: OPTIONAL object.
+ */
+#define opt_set_none(opt) opt.has = false
+
+/**
+ * opt_set_some - set an OPTIONAL object to hold something.
+ * @opt: OPTIONAL object.
+ * @d: data to hold.
+ */
+#define opt_set_some(opt, d) \
+ ((opt).has = true, (opt).data = d)
+
+/**
+ * opt_has - true if an OPTIONAL object has something.
+ * @opt: OPTIONAL object.
+ */
+#define opt_has(opt) ((opt).has)
+
+/**
+ * opt_hasnt - true if an OPTIONAL object has nothing.
+ * @opt: OPTIONAL object.
+ */
+#define opt_hasnt(opt) (!(opt).has)
+
+/**
+ * opt_unwrap - if there's something in @src, copy it to @dst.
+ * @src: OPTIONAL object to copy data of type T from.
+ * @dst: variable of type T to copy to.
+ *
+ * Returns true if there was something, false if there wasn't.
+ */
+#define opt_unwrap(src, dst) \
+ (opt_has(src) ? (dst = (src).data, true) : (false))
+
+/**
+ * opt_default - get something from @src or default to @def.
+ * @src: OPTIONAL object to get data from.
+ * @def: default value if there's nothing.
+ */
+#define opt_default(src, def) opt_has(src) ? (src).data : def
+
+#endif