-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathitplus_filter.h
110 lines (103 loc) · 4.75 KB
/
itplus_filter.h
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
/**
* @file
* @brief Macros for implementing the `filter` abstraction using the `IterFilt` struct.
*
* https://hackage.haskell.org/package/base-4.15.0.0/docs/Data-List.html#v:filter
* An IterFilt struct is a struct that stores a filtering function within it, as well as the source iterable.
*/
#ifndef LIB_ITPLUS_FILT_H
#define LIB_ITPLUS_FILT_H
#include "itplus_foreach.h"
#include "itplus_iterator.h"
#include "itplus_macro_utils.h"
#include "itplus_maybe.h"
#include <stdbool.h>
/**
* @def IterFilt(T)
* @brief Convenience macro to get the type of the IterFilt struct with given element type.
*
* # Example
*
* @code
* DefineIterFilt(int);
* IterFilt(int) i; // Declares a variable of type IterFilt(int)
* @endcode
*
* @param T The type of value the `Iterable` wrapped in this `IterFilt` will yield. Must be the same type name passed to
* #DefineIterFilt(T).
*
* @note If `T` is a pointer, it needs to be typedef-ed into a type that does not contain the `*`. Only alphanumerics.
*/
#define IterFilt(T) ITPL_CONCAT(IterFilt_, T)
/**
* @def DefineIterFilt(T)
* @brief Define an IterFilt struct that works on `Iterable(T)`s.
*
* # Example
*
* @code
* DefineIterFilt(int); // Defines an IterFilt(int) struct
* @endcode
*
* @param T The type of value the `Iterable` wrapped in this `IterFilt` will yield.
*
* @note If `T` is a pointer, it needs to be typedef-ed into a type that does not contain the `*`. Only alphanumerics.
* @note An #Iterator(T) for the given `T` **must** also exist.
*/
#define DefineIterFilt(T) \
typedef struct \
{ \
bool (*pred)(T x); \
Iterable(T) src; \
} IterFilt(T)
/**
* @def define_iterfilt_func(T, Name)
* @brief Define a function to turn an #IterFilt(T) into an #Iterable(T).
*
* Define the `next` function implementation for the #IterFilt(T) struct, and use it to implement the Iterator
* typeclass, for given `T`.
*
* The defined function takes in a value of type `IterFilt(T)*` and wraps it in an `Iterable(T)`.
*
* # Example
*
* @code
* DefineIterFilt(int);
*
* // Implement `Iterator` for `IterFilt(int)`
* // The defined function has the signature- `Iterable(int) wrap_intitrfilt(IterFilt(int)* x)`
* define_iterfilt_func(int, wrap_intitrfilt)
* @endcode
*
* Usage of the defined function-
*
* @code
* static bool is_even(int x) { return x % 2 == 0; }
* @endcode
*
* @code
* // Filter `it` (of type `Iterable(int)`) by `is_even`
* Iterable(int) evens = wrap_intitrfilt(&(IterFilt(int)){ .pred = is_even, .src = it });
* @endcode
*
* @param T The type of value the `Iterable` wrapped in this `IterFilt` will yield.
* @param Name Name to define the function as.
*
* @note If `T` is a pointer, it needs to be typedef-ed into a type that does not contain the `*`. Only
* alphanumerics.
* @note An #IterFilt(T) for the given `T` **must** exist.
* @note This should not be delimited by a semicolon.
*/
#define define_iterfilt_func(T, Name) \
static Maybe(T) ITPL_CONCAT(IterFilt(T), _nxt)(IterFilt(T) * self) \
{ \
Iterable(T) const srcit = self->src; \
foreach (T, el, srcit) { \
if (self->pred(el)) { \
return Just(el, T); \
} \
} \
return Nothing(T); \
} \
impl_iterator(IterFilt(T)*, T, Name, ITPL_CONCAT(IterFilt(T), _nxt))
#endif /* !LIB_ITPLUS_FILT_H */