-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathiterator.h
136 lines (128 loc) · 5.62 KB
/
iterator.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
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
/**
* @file
* Utilities to define and implement an Iterable.
*/
#ifndef IT_ITERATOR_H
#define IT_ITERATOR_H
#include "maybe.h"
#include "typeclass.h"
#define CONCAT_(A, B) A##B
#define CONCAT(A, B) CONCAT_(A, B)
/**
* @def Iterator(T)
* @brief Convenience macro to get the type of the Iterator (typeclass) with given element type.
*
* # Example
*
* @code
* DefineIteratorOf(int);
* Iterator(int) i; // Declares a variable of type Iterator(int) (a typeclass)
* @endcode
*
* @param T The type of value the `Iterator` instance will yield. Must be the same type name passed to
* #DefineIteratorOf(T).
*
* @note If `T` is a pointer, it needs to be typedef-ed into a type that does not contain the `*`. Only alphanumerics.
*/
#define Iterator(T) T##Iterator
/**
* @def Iterable(T)
* @brief Convenience macro to get the type of the Iterable (typeclass instance) with given element type.
*
* # Example
*
* @code
* DefineIteratorOf(int);
* Iterable(int) i; // Declares a variable of type Iterable(Int) (the typeclass instance)
* @endcode
*
* @param T The type of value the `Iterable` will yield. Must be the same type name passed to #DefineIteratorOf(T).
*
* @note If `T` is a pointer, it needs to be typedef-ed into a type that does not contain the `*`. Only alphanumerics.
*/
#define Iterable(T) T##Iterable
/**
* @def DefineIteratorOf(T)
* @brief Define an Iterator typeclass and its Iterable instance for given element type.
*
* # Example
*
* @code
* DefineIteratorOf(int); // Defines an Iterator(int) typeclass as well as its instance
* @endcode
*
* @param T The type of value the `Iterator` instance will yield. Must be alphanumeric.
*
* @note If `T` is a pointer, it needs to be typedef-ed into a type that does not contain the `*`. Only alphanumerics.
* @note A #Maybe(T) for the given `T` **must** also exist.
*/
#define DefineIteratorOf(T) \
typedef typeclass(Maybe(T) (*const next)(void* self)) Iterator(T); \
typedef typeclass_instance(Iterator(T)) Iterable(T)
/**
* @def impl_iterator(IterType, ElmntType, Name, next_f)
* @brief Define a function to turn given `IterType` into an #Iterable(ElmntType).
*
* Implement the Iterator typeclass for a type. Essentially defining a wrapper function that returns the Iterable.
*
* The defined function takes in a value of `IterType` and wraps it in an `Iterable` - which can be passed around to
* generic functions working on an iterable.
*
* The term "generic" is used here in the context of the **input**.
* As in, the function taking a generic iterable, does not care about what type is backing up the iterable; but,
* does care about what element type the iterator yields.
*
* # Example
*
* @code
* // Example of implementing an infinite iterator representing the fibonacci sequence
*
* #include <stdint.h>
*
* typedef struct fibonacci
* {
* uint32_t curr;
* uint32_t next;
* } Fibonacci;
*
* DefineMaybe(uint32_t)
* DefineIteratorOf(uint32_t);
*
* static Maybe(uint32_t) fibnxt(Fibonacci* self)
* {
* uint32_t new_nxt = self->curr + self->next;
* self->curr = self->next;
* self->next = new_nxt;
* return Just(new_nxt, uint32_t);
* }
*
* // Define a function named `prep_fib_itr`, which takes in a `Fibonacci*` and returns an `Iterable(int)`
* // The returned iterable is an infinite fibonacci sequence
* impl_iterator(Fibonacci*, uint32_t, prep_fib_itr, fibnxt)
* @endcode
*
* @param IterType The semantic type (C type) this impl is for, must be a pointer type.
* @param ElmntType The type of value the `Iterator` instance will yield.
* @param Name Name to define the function as.
* @param next_f Function pointer that serves as the `next` implementation for `IterType`. This function must have
* the signature of `Maybe(ElmntType) (*)(IterType self)` - i.e, should take IterType and return a value of the
* corresponding element type wrapped in a `Maybe` - `Nothing` value indicates end of iteration.
*
* @note If `ElmntType` is a pointer, it needs to be typedef-ed into a type that does not contain the `*`. Only
* alphanumerics.
* @note A #Maybe(T) for the given `ElmntType` **must** exist.
* @note This should not be delimited by a semicolon.
*/
#define impl_iterator(IterType, ElmntType, Name, next_f) \
static inline Maybe(ElmntType) CONCAT(next_f, __)(void* self) \
{ \
Maybe(ElmntType) (*const next_)(IterType self) = (next_f); \
(void)next_; \
return (next_f)(self); \
} \
Iterable(ElmntType) Name(IterType x) \
{ \
static Iterator(ElmntType) const tc = {.next = (CONCAT(next_f, __))}; \
return (Iterable(ElmntType)){.tc = &tc, .self = x}; \
}
#endif /* !IT_ITERATOR_H */