Last active
August 5, 2023 18:19
-
-
Save qexat/8fda20d8b7e094c139999b89644a3b81 to your computer and use it in GitHub Desktop.
idk i wrote some range iterator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #define DEFAULT_START 0 | |
| #define DEFAULT_STEP(START, STOP) START < STOP ? 1 : -1 | |
| #define TO_INT(STR) (int)strtol(STR, NULL, 10) | |
| #define IS_HELP_FLAG(STR) (!strcmp(STR, "--help")) || (!strcmp(STR, "-h")) | |
| typedef struct range_t range_t; | |
| typedef struct iter_t iter_t; | |
| typedef void(*map_func_t)(int); | |
| typedef iter_t*(*map_meth_t)(iter_t*, map_func_t); | |
| typedef iter_t*(*run_meth_t)(iter_t*); | |
| typedef void(*delete_meth_t)(iter_t*); | |
| struct range_t { | |
| int start; | |
| int stop; | |
| int step; | |
| }; | |
| struct iter_t { | |
| // Private fields | |
| range_t* _range; | |
| int _i; | |
| map_func_t _map_func; | |
| // Methods | |
| map_meth_t map; | |
| run_meth_t run; | |
| delete_meth_t delete; | |
| }; | |
| iter_t* _iterator_map(iter_t *self, map_func_t function) | |
| { | |
| if (function != NULL) | |
| self->_map_func = function; | |
| return self; | |
| } | |
| iter_t* _iterator_run(iter_t *self) | |
| { | |
| int start, stop, step; | |
| // No map function has been defined on the iterator | |
| // meaning there is nothing to iterate over | |
| if (self->_map_func == NULL) | |
| { | |
| goto end; | |
| } | |
| start = self->_range->start; | |
| stop = self->_range->stop; | |
| step = self->_range->step; | |
| for (self->_i = start; (start < stop) ? (self->_i < stop) : (self->_i > stop); self->_i += step) | |
| { | |
| self->_map_func(self->_i); | |
| } | |
| end: | |
| return self; | |
| } | |
| void _iterator_delete(iter_t *self) | |
| { | |
| // Freeing the range first is necessary! | |
| free(self->_range); | |
| // Then we free the whole object | |
| free(self); | |
| } | |
| iter_t* iterator_new(const int start, const int stop, const int step) | |
| { | |
| iter_t* iter; | |
| range_t* range; | |
| if (step == 0) | |
| { | |
| fprintf(stderr, "iterator::new: step cannot be zero"); | |
| return NULL; | |
| } | |
| else if (step > 0 && start > stop) | |
| { | |
| fprintf(stderr, "iterator::new: step cannot be positive if start > stop"); | |
| return NULL; | |
| } | |
| else if (step < 0 && start < stop) | |
| { | |
| fprintf(stderr, "iterator::new: step cannot be negative if start < stop"); | |
| return NULL; | |
| } | |
| // We create the range_t object for our iterator | |
| range = malloc(sizeof(range_t)); | |
| range->start = start; | |
| range->stop = stop; | |
| range->step = step; | |
| // We create the iterator | |
| iter = malloc(sizeof(iter_t)); | |
| // We allocate/define its (private) fields | |
| iter->_range = range; | |
| iter->_map_func = malloc(sizeof(map_func_t)); | |
| // We "connect" the object to its methods | |
| iter->map = _iterator_map; | |
| iter->run = _iterator_run; | |
| iter->delete = _iterator_delete; | |
| return iter; | |
| } | |
| void print_each(int i) | |
| { | |
| printf("%d\n", i); | |
| } | |
| void print_missing_args_error() | |
| { | |
| fprintf(stderr, "\x1b[1;31mError:\x1b[0m missing arguments (received 0)\n"); | |
| } | |
| void print_usage(char *path) | |
| { | |
| fprintf(stderr, "\x1b[1;35mUsage:\x1b[0m %s [start] <stop> [step]\n", path); | |
| fprintf(stderr, "\x1b[2;37mNote: additional args are ignored\x1b[0m\n"); | |
| } | |
| int main(int argc, char *argv[]) | |
| { | |
| int start, stop, step; | |
| // We ignore the first arg (file path) | |
| switch (argc - 1) | |
| { | |
| case 0: | |
| print_missing_args_error(); | |
| print_usage(argv[0]); | |
| return EXIT_FAILURE; | |
| case 1: | |
| if (IS_HELP_FLAG(argv[1])) | |
| { | |
| print_usage(argv[0]); | |
| return EXIT_SUCCESS; | |
| } | |
| start = DEFAULT_START; | |
| stop = TO_INT(argv[1]); | |
| step = DEFAULT_STEP(start, stop); | |
| break; | |
| case 2: | |
| start = TO_INT(argv[1]); | |
| stop = TO_INT(argv[2]); | |
| step = DEFAULT_STEP(start, stop); | |
| break; | |
| default: // we ignore the additional args | |
| start = TO_INT(argv[1]); | |
| stop = TO_INT(argv[2]); | |
| step = TO_INT(argv[3]); | |
| } | |
| printf("start: %d, stop: %d, step: %d\n", start, stop, step); | |
| iter_t* iter = iterator_new(start, stop, step); | |
| if (iter == NULL) | |
| return EXIT_FAILURE; | |
| iter | |
| ->map(iter, print_each) | |
| ->run(iter) | |
| ->delete(iter); | |
| return EXIT_SUCCESS; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment