Skip to content

Commit 7805837

Browse files
Add samples/
1 parent 88955a1 commit 7805837

File tree

7 files changed

+542
-1
lines changed

7 files changed

+542
-1
lines changed

CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,10 @@ set(LIBNAME iterplus)
2929
add_library(${LIBNAME} INTERFACE)
3030

3131
# Add the headers to the library interface
32-
target_include_directories(${LIBNAME} INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include)
32+
target_include_directories(${LIBNAME} INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR})
3333

3434
# Set standard to C99
3535
target_compile_features(${LIBNAME} INTERFACE c_std_99)
3636

3737
add_subdirectory(tests)
38+
add_subdirectory(samples)

samples/CMakeLists.txt

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
##################################################
2+
# Configure target for building the testing executable
3+
4+
set(SOURCES
5+
${CMAKE_CURRENT_SOURCE_DIR}/main.c
6+
${CMAKE_CURRENT_SOURCE_DIR}/impls.c
7+
${CMAKE_CURRENT_SOURCE_DIR}/sugar.c
8+
)
9+
10+
set(HEADERS
11+
${CMAKE_CURRENT_SOURCE_DIR}/impls.h
12+
${CMAKE_CURRENT_SOURCE_DIR}/sugar.h
13+
)
14+
15+
set(EXCNAME iterplus_samples)
16+
17+
# Add the main executable
18+
add_executable(${EXCNAME} ${HEADERS} ${SOURCES})
19+
20+
# Link the iterators interface lib
21+
target_link_libraries(${EXCNAME} ${LIBNAME})
22+
23+
# Set C language standard to C11 (for `_Generic`)
24+
# NOTE: The iterplus library works for C99 (and above), but the examples use C11 for convenience
25+
set_property(TARGET ${EXCNAME} PROPERTY C_STANDARD 11)
26+
set_property(TARGET ${EXCNAME} PROPERTY C_STANDARD_REQUIRED ON)

samples/impls.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#include "impls.h"
2+
3+
/* `next` implementation for the `StrArrIter` struct */
4+
static Maybe(char) chrarrnxt(ChrArrIter* self)
5+
{
6+
return self->i < self->size ? Just(self->arr[self->i++], char) : Nothing(char);
7+
}
8+
9+
/* `next` implementation for the `StrArrIter` struct */
10+
static Maybe(string) strarrnxt(StrArrIter* self)
11+
{
12+
return self->i < self->size ? Just(self->arr[self->i++], string) : Nothing(string);
13+
}
14+
15+
/* `next` implementation for the `U64ArrIter` struct */
16+
static Maybe(uint64_t) u64arrnxt(U64ArrIter* self)
17+
{
18+
return self->i < self->size ? Just(self->arr[self->i++], uint64_t) : Nothing(uint64_t);
19+
}
20+
21+
// clang-format off
22+
/* Implement `Iterator` for `ChrArrIter`, `StrArrIter`, and `U64ArrIter` */
23+
impl_iterator(ChrArrIter*, char, prep_chrarr_itr, chrarrnxt)
24+
impl_iterator(StrArrIter*, string, prep_strarr_itr, strarrnxt)
25+
impl_iterator(U64ArrIter*, uint64_t, prep_u64arr_itr, u64arrnxt)
26+
/* Define the iterplus utilities for the necessary types */
27+
DefnIterplus(char, takechr, dropchr, map_chrchr, filtchr, chr_reduce, chr_fold, filtmap_chrchr, chainchr, takewhlchr,
28+
dropwhlchr, enmrchr, zip_chrchr, chr_collect)
29+
30+
define_itertakewhile_func(Pair(char, char), takewhl_chrchr)
31+
define_itermap_func(Pair(char, char), char, map_chrchr_chr)
32+
define_iterfold_func(string, char*, str_fold)
33+
34+
define_iterzip_func(uint64_t, uint64_t, zip_u64u64)
35+
define_itermap_func(Pair(uint64_t, uint64_t), uint64_t, map_u64u64_u64)
36+
define_iterreduce_func(uint64_t, u64_reduce)

samples/impls.h

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
#ifndef LIB_ITPLUS_SAMPL_IMPL_H
2+
#define LIB_ITPLUS_SAMPL_IMPL_H
3+
4+
#define ITPLUS_COLLECT_BUFSZ 16 /* Custom collect buffer size for iterplus collect utility */
5+
6+
#include "itplus.h"
7+
8+
#include <stdint.h>
9+
10+
/* Type for string literals, the only type of strings used in the examples */
11+
typedef char const* string;
12+
13+
/* Implement the necessary struct and functions */
14+
15+
Iterplus(char);
16+
DeclIterplus(char, takechr, dropchr, map_chrchr, filtchr, chr_reduce, chr_fold, filtmap_chrchr, chainchr, takewhlchr,
17+
dropwhlchr, enmrchr, zip_chrchr, chr_collect);
18+
19+
/* Define some extra iterplus utilities for `Pair(char, char)` */
20+
DefineIterTakeWhile(Pair(char, char));
21+
DefineIterMap(Pair(char, char), char);
22+
Iterable(Pair(char, char)) takewhl_chrchr(IterTakeWhile(Pair(char, char)) * x);
23+
Iterable(char) map_chrchr_chr(IterMap(Pair(char, char), char) * x);
24+
25+
/* Also define `Iterable(string)` with a specific folding utility */
26+
// clang-format off
27+
DefineMaybe(string)
28+
DefineIteratorOf(string);
29+
// clang-format on
30+
char* str_fold(Iterable(string) it, char* init, char* (*acc)(char* acc, string x));
31+
32+
/* Also define `Iterable(uint64_t)` with some utilities */
33+
// clang-format off
34+
DefineMaybe(uint64_t)
35+
DefinePair(uint64_t, uint64_t);
36+
DefineMaybe(Pair(uint64_t, uint64_t))
37+
DefineIteratorOf(uint64_t);
38+
DefineIteratorOf(Pair(uint64_t, uint64_t));
39+
// clang-format on
40+
DefineIterZip(uint64_t, uint64_t);
41+
DefineIterMap(Pair(uint64_t, uint64_t), uint64_t);
42+
Iterable(Pair(uint64_t, uint64_t)) zip_u64u64(IterZip(uint64_t, uint64_t)* x);
43+
Iterable(uint64_t) map_u64u64_u64(IterMap(Pair(uint64_t, uint64_t), uint64_t) * x);
44+
Maybe(uint64_t) u64_reduce(Iterable(uint64_t) it, uint64_t (*acc)(uint64_t acc, uint64_t x));
45+
46+
/* ArrIter for the `char` array type */
47+
typedef struct
48+
{
49+
size_t i;
50+
size_t const size;
51+
/* Array of string literals */
52+
char const* const arr;
53+
} ChrArrIter;
54+
55+
/* ArrIter for the `string` array type */
56+
typedef struct
57+
{
58+
size_t i;
59+
size_t const size;
60+
/* Array of string literals */
61+
string const* const arr;
62+
} StrArrIter;
63+
64+
/* ArrIter for the `uint64_t` array type */
65+
typedef struct
66+
{
67+
size_t i;
68+
size_t const size;
69+
/* Array of string literals */
70+
uint64_t const* const arr;
71+
} U64ArrIter;
72+
73+
74+
/* Turn a pointer to a `ChrArrIter` struct to an iterable */
75+
Iterable(char) prep_chrarr_itr(ChrArrIter* self);
76+
/* Turn a pointer to a `StrArrIter` struct to an iterable */
77+
Iterable(string) prep_strarr_itr(StrArrIter* self);
78+
/* Turn a pointer to a `U64ArrIter` struct to an iterable */
79+
Iterable(uint64_t) prep_u64arr_itr(U64ArrIter* self);
80+
81+
/* Convert an array of chars into an `Iterable` */
82+
#define chrarr_to_iter(srcarr, len) prep_chrarr_itr(&(ChrArrIter){.size = (len), .arr = (srcarr)})
83+
/* Convert an array of string literals into an `Iterable` */
84+
#define strarr_to_iter(srcarr, len) prep_strarr_itr(&(StrArrIter){.size = (len), .arr = (srcarr)})
85+
/* Convert an array of string literals into an `Iterable` */
86+
#define u64arr_to_iter(srcarr, len) prep_u64arr_itr(&(U64ArrIter){.size = (len), .arr = (srcarr)})
87+
88+
#endif /* !LIB_ITPLUS_SAMPL_IMPL_H */

samples/main.c

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
#include "impls.h"
2+
#include "sugar.h"
3+
4+
#include <inttypes.h>
5+
#include <stdint.h>
6+
#include <string.h>
7+
#include <time.h>
8+
9+
static inline char* strdup_(char const* x)
10+
{
11+
char* s = malloc((strlen(x) + 1) * sizeof(*s));
12+
strcpy(s, x);
13+
return s;
14+
}
15+
16+
static bool pair_is_equal(Pair(char, char) x) { return fst(x) == snd(x); }
17+
static char fst_chr(Pair(char, char) chrpair) { return fst(chrpair); }
18+
19+
/* Using iterators to find common prefix - without C11 sugar */
20+
static char* cmn_prefx(string s1, string s2)
21+
{
22+
/* Turn the 2 strings into iterables */
23+
Iterable(char) s1it = chrarr_to_iter(s1, strlen(s1));
24+
Iterable(char) s2it = chrarr_to_iter(s2, strlen(s2));
25+
/* Zip together the 2 iterables */
26+
Iterable(Pair(char, char)) zipped = zip_chrchr(&(IterZip(char, char)){.asrc = s1it, .bsrc = s2it});
27+
/* Keep taking pairs while they match up - essentially extracting the common prefix */
28+
Iterable(Pair(char, char)) common =
29+
takewhl_chrchr(&(IterTakeWhile(Pair(char, char))){.pred = pair_is_equal, .src = zipped});
30+
31+
/* Only need either the first or second element from the equal pairs */
32+
Iterable(char) fstchars = map_chrchr_chr(&(IterMap(Pair(char, char), char)){.f = fst_chr, .src = common});
33+
34+
/* Collect the iterable into a string */
35+
size_t len = 0;
36+
char* const prefx = chr_collect(fstchars, &len);
37+
prefx[len] = '\0';
38+
return prefx;
39+
}
40+
41+
/* Using iterators to find common prefix - with C11 sugar */
42+
static char* cmn_prefx_sugar(string s1, string s2)
43+
{
44+
/* Common prefix but in an expression oriented way with C11 `_Generic` */
45+
size_t len = 0;
46+
47+
// clang-format off
48+
/* Collect the prefix into a string */
49+
char* const prefx = collect(
50+
/* Extract out only one of the chars */
51+
map(
52+
/* Take the common prefix */
53+
takewhile(
54+
/* Zip together the strings as iterables */
55+
zip(chrarr_to_iter(s1, strlen(s1)), chrarr_to_iter(s2, strlen(s2))),
56+
pair_is_equal),
57+
fst_chr),
58+
&len);
59+
// clang-format on
60+
prefx[len] = '\0';
61+
return prefx;
62+
}
63+
64+
/*
65+
Accumulator function to find longest common prefix by folding over a string array
66+
NOTE: This takes ownership of `acc`
67+
*/
68+
static inline char* acc_cmn_prefx(char* acc, string s)
69+
{
70+
char* const res = cmn_prefx(acc, s);
71+
free(acc);
72+
return res;
73+
}
74+
75+
/*
76+
Accumulator function to find longest common prefix by folding over a string array - with C11 sugar
77+
NOTE: This takes ownership of `acc`
78+
*/
79+
static inline char* acc_cmn_prefx_sugar(char* acc, string s)
80+
{
81+
char* const res = cmn_prefx_sugar(acc, s);
82+
free(acc);
83+
return res;
84+
}
85+
86+
static inline uint64_t sum_u64(uint64_t x, uint64_t y) { return x + y; }
87+
static inline uint64_t mult_u64u64(Pair(uint64_t, uint64_t) x) { return x.a * x.b; }
88+
89+
#define ARRSZ 100000
90+
91+
int main(void)
92+
{
93+
string arr[] = {"flower", "flow", "flight"};
94+
size_t arrlen = sizeof(arr) / sizeof(*arr);
95+
96+
/* Longest prefix fold without C11 sugar */
97+
char* lngest_prefx = str_fold(strarr_to_iter(arr + 1, arrlen - 1), strdup_(arr[0]), acc_cmn_prefx);
98+
puts(lngest_prefx);
99+
free(lngest_prefx);
100+
101+
/* Longest prefix fold with C11 sugar */
102+
lngest_prefx = fold(strarr_to_iter(arr + 1, arrlen - 1), strdup_(arr[0]), acc_cmn_prefx_sugar);
103+
puts(lngest_prefx);
104+
free(lngest_prefx);
105+
106+
srand(time(NULL));
107+
uint64_t arr1[ARRSZ];
108+
for (size_t i = 0; i < ARRSZ; i++) {
109+
arr1[i] = rand() % 100;
110+
}
111+
uint64_t arr2[ARRSZ];
112+
for (size_t i = 0; i < ARRSZ; i++) {
113+
arr2[i] = rand() % 100;
114+
}
115+
116+
/* Dot product sum without C11 sugar */
117+
Iterable(Pair(uint64_t, uint64_t)) dot = zip_u64u64(
118+
&(IterZip(uint64_t, uint64_t)){.asrc = u64arr_to_iter(arr1, ARRSZ), .bsrc = u64arr_to_iter(arr2, ARRSZ)});
119+
Iterable(uint64_t) dot_product =
120+
map_u64u64_u64(&(IterMap(Pair(uint64_t, uint64_t), uint64_t)){.f = mult_u64u64, .src = dot});
121+
uint64_t dot_product_sum = from_just(u64_reduce(dot_product, sum_u64), uint64_t);
122+
printf("Sum: %" PRIi64 "\n", dot_product_sum);
123+
124+
/* Dot product sum with C11 sugar */
125+
dot_product_sum = from_just(
126+
reduce(map(zip(u64arr_to_iter(arr1, ARRSZ), u64arr_to_iter(arr2, ARRSZ)), mult_u64u64), sum_u64), uint64_t);
127+
printf("Sum: %" PRIi64 "\n", dot_product_sum);
128+
129+
return 0;
130+
}

samples/sugar.c

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
#include "sugar.h"
2+
3+
#include "impls.h"
4+
5+
/* Utility functions to fill pre-allocated iterplus structs and turn them into iterables */
6+
7+
/* Macro to define a function that turns a pre-allocated IterTake struct into iterable */
8+
#define prep_tk(T, Name, implfunc) \
9+
Iterable(T) Name(IterTake(T) * tk, Iterable(T) x) \
10+
{ \
11+
tk->src = x; \
12+
return implfunc(tk); \
13+
}
14+
15+
/* Macro to define a function that turns a pre-allocated IterTake struct into iterable */
16+
#define prep_drp(T, Name, implfunc) \
17+
Iterable(T) Name(IterDrop(T) * tk, Iterable(T) x) \
18+
{ \
19+
tk->src = x; \
20+
return implfunc(tk); \
21+
}
22+
23+
/* Macro to define a function that turns a pre-allocated IterMap struct into iterable */
24+
#define prep_mp(A, B, Name, implfunc) \
25+
Iterable(B) Name(IterMap(A, B) * mp, Iterable(A) x, B(*fn)(A)) \
26+
{ \
27+
mp->f = fn; \
28+
mp->src = x; \
29+
return implfunc(mp); \
30+
}
31+
32+
/* Macro to define a function that turns a pre-allocated IterFilt struct into iterable */
33+
#define prep_flt(T, Name, implfunc) \
34+
Iterable(T) Name(IterFilt(T) * flt, Iterable(T) x, bool (*pred)(T)) \
35+
{ \
36+
flt->pred = pred; \
37+
flt->src = x; \
38+
return implfunc(flt); \
39+
}
40+
41+
/* Macro to define a function that turns a pre-allocated IterFiltMap struct into iterable */
42+
#define prep_fltmap(A, B, Name, implfunc) \
43+
Iterable(B) Name(IterFiltMap(A, B) * fltmp, Iterable(A) x, Maybe(B)(*fn)(A)) \
44+
{ \
45+
fltmp->f = fn; \
46+
fltmp->src = x; \
47+
return implfunc(fltmp); \
48+
}
49+
50+
/* Macro to define a function that turns a pre-allocated IterChain struct into iterable */
51+
#define prep_chn(T, Name, implfunc) \
52+
Iterable(T) Name(IterChain(T) * chn, Iterable(T) x, Iterable(T) y) \
53+
{ \
54+
chn->curr = x; \
55+
chn->nxt = y; \
56+
return implfunc(chn); \
57+
}
58+
59+
/* Macro to define a function that turns a pre-allocated IterTakeWhile struct into iterable */
60+
#define prep_tkwhl(T, Name, implfunc) \
61+
Iterable(T) Name(IterTakeWhile(T) * tkwhl, Iterable(T) x, bool (*pred)(T)) \
62+
{ \
63+
tkwhl->pred = pred; \
64+
tkwhl->src = x; \
65+
return implfunc(tkwhl); \
66+
}
67+
68+
/* Macro to define a function that turns a pre-allocated IterTakeWhile struct into iterable */
69+
#define prep_drpwhl(T, Name, implfunc) \
70+
Iterable(T) Name(IterDropWhile(T) * drpwhl, Iterable(T) x, bool (*pred)(T)) \
71+
{ \
72+
drpwhl->pred = pred; \
73+
drpwhl->src = x; \
74+
return implfunc(drpwhl); \
75+
}
76+
77+
/* Macro to define a function that turns a pre-allocated IterEnumr struct into iterable */
78+
#define prep_enumr(T, Name, implfunc) \
79+
Iterable(Pair(size_t, T)) Name(IterEnumr(T) * enumr, Iterable(T) x) \
80+
{ \
81+
enumr->src = x; \
82+
return implfunc(enumr); \
83+
}
84+
85+
#define prep_zip(T, U, Name, implfunc) \
86+
Iterable(Pair(T, U)) Name(IterZip(T, U) * zipstrct, Iterable(T) x, Iterable(U) y) \
87+
{ \
88+
zipstrct->asrc = x; \
89+
zipstrct->bsrc = y; \
90+
return implfunc(zipstrct); \
91+
}
92+
93+
// clang-format off
94+
prep_tkwhl(Pair(char, char), prep_chrchr_tkwhl, takewhl_chrchr)
95+
96+
prep_zip(char, char, prep_chrchr_zip, zip_chrchr)
97+
prep_zip(uint64_t, uint64_t, prep_u64u64_zip, zip_u64u64)
98+
99+
prep_mp(Pair(char, char), char, prep_chrchr_chr_map, map_chrchr_chr)
100+
prep_mp(Pair(uint64_t, uint64_t), uint64_t, prep_u64u64_u64_map, map_u64u64_u64)

0 commit comments

Comments
 (0)