aboutsummaryrefslogtreecommitdiff
path: root/include/libtio/iter.h
blob: 31d113321afee8bf9eb97ba994e549a316a0b5c5 (plain)
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
#ifndef  LIBTIO_ITER_H
# define LIBTIO_ITER_H 20180710
# include "cdefs.h"

TIO_BEGIN_NAMESPACE

/* A few things in libtio work using iterators. This is the centralized
 * iterator interface. */

struct         tio_iter;
typedef struct tio_iter           tio_iter_t;
struct         tio_iter_functions;
typedef struct tio_iter_functions tio_iter_functions_t;

/* ---
 * Define something.
 * --- */

/* The way this is done:
 *
 * When `tio_next()` is called, if there was a previous element,
 * the `tio_nextfree_t` callback, if not NULL, will be called to free
 * it, then in all cases, the `tio_next_t` callback will be called to
 * get the next element. If the `tio_next_t` callback returns
 * `tio_error_iter`, all following calls to `tio_next()` with this
 * iterator won't call the callbacks and directly return the same error.
 *
 * When `tio_end()` is called, the `tio_end_t` callback, if not NULL,
 * will be called. */

typedef TIO_HOOK_TYPE(int)  tio_next_t
	OF((void *tio__cookie, void **tio__ptr));
typedef TIO_HOOK_TYPE(void) tio_nextfree_t
	OF((void *tio__cookie, void *tio__ptr));
typedef TIO_HOOK_TYPE(void) tio_end_t
	OF((void *tio__cookie));

struct tio_iter_functions {
	tio_next_t     *tio_iter_functions_next;
	tio_nextfree_t *tio_iter_functions_nextfree;
	tio_end_t      *tio_iter_functions_end;
};

/* ---
 * Functions.
 * --- */

TIO_BEGIN_DECLS

/* Start an iterator with `tio_iter_<whatever>(&iter, <other data>)`,
 * with `iter` being of the `tio_iter_t *` type.
 * Get the next element through `tio_next_<whatever>(iter, &ptr)`,
 * which is usually a macro or function defined as
 * `tio_next(iter, (void **)(PTRP))`.
 * Then end the iterator using `tio_end(iter)`.
 *
 * Beware: any time you use `tio_next()` or `tio_end()`, the previous
 * element might be free'd or re-used, so if you are interested in what is
 * in it, copy the data before using one of the previous functions. */

TIO_EXTERN(int) tio_iter
	OF((tio_iter_t **tio__iterp, void *tio__cookie,
		tio_iter_functions_t const *tio__funcs));

TIO_EXTERN(int) tio_next
	OF((tio_iter_t *tio__iter, void **tio__ptr));

# define tio_end(ITER) tio_free(ITER)

/* You can make a “super iterator” that makes an iterator out of two
 * iterators! It will empty the first one, then the second one.
 * It will also take care of closing them. */

TIO_EXTERN(int) tio_combine_iterators
	OF((tio_iter_t **tio__iterp,
		tio_iter_t *tio__first,
		tio_iter_t *tio__second));

TIO_END_DECLS
TIO_END_NAMESPACE

#endif /* LIBTIO_ITER_H */