Skip to content

Instantly share code, notes, and snippets.

@qexat
Last active August 5, 2023 18:19
Show Gist options
  • Select an option

  • Save qexat/8fda20d8b7e094c139999b89644a3b81 to your computer and use it in GitHub Desktop.

Select an option

Save qexat/8fda20d8b7e094c139999b89644a3b81 to your computer and use it in GitHub Desktop.
idk i wrote some range iterator
#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