Repository navigation
Expand file tree
/
Copy pathoptional.h
More file actions
162 lines (141 loc) · 4.78 KB
/
Copy pathoptional.h
File metadata and controls
162 lines (141 loc) · 4.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
// SPDX-License-Identifier: MIT
// Copyright (c) 2021 Michael Bäck <mhcoma@gmail.com>
#ifndef __CCTL_OPTIONAL_H__
#define __CCTL_OPTIONAL_H__
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include "cctl.h"
// Optional
/// `optional(T)` ⇒ `T_optional`
///
/// Generates the optional value container type name for `T`.
#define optional(T) cctl_join(T, optional)
/// `optional_func(FUNC, T)` ⇒ `T_optional_FUNC`
///
/// Generates a mangled function identifier for `optional(T)`.
#define optional_func(FUNC, T) cctl_join(optional(T), FUNC)
/// `optional_struct(T)` ⇒ `struct T_optional_struct`
///
/// Generates the underlying structure tag for `optional(T)`.
#define optional_struct(T) cctl_join(optional(T), struct)
/// ```c
/// void optional_init(T, optional(T)* p_opt)
/// ```
/// Initializes the optional container to a disengaged (empty) state.
///
/// `p_opt` is a pointer to the optional instance.
#define optional_init(T, p_opt) optional_func(init, T)(p_opt)
/// ```c
/// void optional_reset(T, optional(T)* p_opt)
/// ```
/// Resets the optional container to a disengaged (empty) state.
#define optional_reset(T, p_opt) optional_func(reset, T)(p_opt)
/// ```c
/// void optional_set(T, optional(T)* p_opt, T value)
/// ```
/// Assigns `value` to the optional container and marks it as engaged.
#define optional_set(T, p_opt, value) optional_func(set, T)(p_opt, value)
/// ```c
/// optional(T) optional_some(T, T value)
/// ```
/// Constructs an engaged optional container holding `value`.
#define optional_some(T, value) optional_func(some, T)(value)
/// ```c
/// optional(T) optional_none(T)
/// ```
/// Constructs a disengaged (empty) optional container.
#define optional_none(T) optional_func(none, T)()
/// ```c
/// T* optional_get(T, optional(T)* p_opt)
/// ```
/// Returns a pointer to the stored value, or `NULL` if disengaged.
#define optional_get(T, p_opt) optional_func(get, T)(p_opt)
/// ```c
/// T optional_value(T, const optional(T)* p_opt)
/// ```
/// Returns the stored value directly.
#define optional_value(T, p_opt) optional_func(value, T)(p_opt)
/// ```c
/// T optional_value_or(T, const optional(T)* p_opt, T default_value)
/// ```
/// Returns the stored value if engaged, or `default_value` if disengaged.
#define optional_value_or(T, p_opt, default_value) optional_func(value_or, T)(p_opt, default_value)
/// ```c
/// bool optional_has_value(T, const optional(T)* p_opt)
/// ```
/// Checks whether the optional container currently contains a value.
#define optional_has_value(T, p_opt) optional_func(has_value, T)(p_opt)
/// ```c
/// bool optional_is_empty(T, const optional(T)* p_opt)
/// ```
/// Checks whether the optional container is empty (disengaged).
#define optional_is_empty(T, p_opt) (!optional_has_value(T, p_opt))
/// Forward declares the `optional(T)` container type for prior references.
#define optional_fd(T) \
typedef struct optional_struct(T) optional(T);
/// Declares optional struct and function prototypes in a header file.
#define optional_imp_h(T) \
struct optional_struct(T) { \
bool has_value; \
T value; \
}; \
\
void optional_func(init, T)(optional(T)* p_opt); \
void optional_func(reset, T)(optional(T)* p_opt); \
void optional_func(set, T)(optional(T)* p_opt, T value); \
optional(T) optional_func(some, T)(T value); \
optional(T) optional_func(none, T)(void); \
T* optional_func(get, T)(optional(T)* p_opt); \
T optional_func(value, T)(const optional(T)* p_opt); \
T optional_func(value_or, T)(const optional(T)* p_opt, T default_value); \
bool optional_func(has_value, T)(const optional(T)* p_opt);
/// Implements optional functions in a source file.
#define optional_imp_c(T) \
void optional_func(init, T)(optional(T)* p_opt) { \
if (!p_opt) return; \
memset(p_opt, 0, sizeof(optional(T))); \
} \
\
void optional_func(reset, T)(optional(T)* p_opt) { \
if (!p_opt) return; \
memset(p_opt, 0, sizeof(optional(T))); \
} \
\
void optional_func(set, T)(optional(T)* p_opt, T value) { \
if (!p_opt) return; \
p_opt->has_value = true; \
p_opt->value = value; \
} \
\
optional(T) optional_func(some, T)(T value) { \
optional(T) opt; \
opt.has_value = true; \
opt.value = value; \
return opt; \
} \
\
optional(T) optional_func(none, T)(void) { \
optional(T) opt; \
memset(&opt, 0, sizeof(optional(T))); \
return opt; \
} \
\
T* optional_func(get, T)(optional(T)* p_opt) { \
if (!p_opt || !p_opt->has_value) return NULL; \
return &(p_opt->value); \
} \
\
T optional_func(value, T)(const optional(T)* p_opt) { \
return p_opt->value; \
} \
\
T optional_func(value_or, T)(const optional(T)* p_opt, T default_value) { \
if (!p_opt || !p_opt->has_value) return default_value; \
return p_opt->value; \
} \
\
bool optional_func(has_value, T)(const optional(T)* p_opt) { \
return p_opt ? p_opt->has_value : false; \
}
#endif