{"id":17163138,"url":"https://github.com/isty001/collection","last_synced_at":"2025-03-24T16:41:44.036Z","repository":{"id":96616603,"uuid":"82407054","full_name":"Isty001/collection","owner":"Isty001","description":null,"archived":false,"fork":false,"pushed_at":"2017-09-15T21:14:58.000Z","size":17,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-29T21:54:39.548Z","etag":null,"topics":["c","collection","linked-list"],"latest_commit_sha":null,"homepage":null,"language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Isty001.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-02-18T18:23:46.000Z","updated_at":"2019-10-22T06:36:19.000Z","dependencies_parsed_at":null,"dependency_job_id":"01a34688-9914-4d98-a93d-01fef7348452","html_url":"https://github.com/Isty001/collection","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Isty001%2Fcollection","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Isty001%2Fcollection/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Isty001%2Fcollection/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Isty001%2Fcollection/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Isty001","download_url":"https://codeload.github.com/Isty001/collection/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245314302,"owners_count":20595200,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c","collection","linked-list"],"created_at":"2024-10-14T22:47:54.372Z","updated_at":"2025-03-24T16:41:44.016Z","avatar_url":"https://github.com/Isty001.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"## C Collection\n\nDoubly linked list based collection in C. \nGCC is required to compile, because of the nested functions, and statement expression.\n\nCheck the full API reference below. A quick example:\n\n```c\nint main(void)\n{\n    int initial = 0;\n    int a = 10, b = 20, c = 99, d = 50;\n    List *first = list_new();\n    List *second = list_new();\n    \n    first\n        -\u003eappend(first, \u0026c)\n        -\u003eappend(first, \u0026d);\n\n    int sum = *(int *) second\n        -\u003eappend(second, \u0026a)\n        -\u003eappend(second, \u0026b)\n        -\u003econcat(second, first-\u003efilter(first, (Predicate) function(bool, (int *item) {\n            return 0 == *item % 5;\n        })))\n        -\u003emap(second, (Map) function(int *, (int *item) {\n            *item += 5;\n            return item;\n        }))\n        -\u003efold_l(second, \u0026initial, (Fold) function(int *, (int *val, int *item) {\n            *val += *item;\n            return val;\n        }));\n\n    printf(\"%d\", sum); // Will output 95 \n\n    second-\u003efree(second);\n    first-\u003efree(first);\n\n    return 0;\n}\n```\n\n## API\n\nThe API uses a kinda 'oo' interface, storing the function pointers on the `List` instance\nmainly for a bit of syntactic sugar to allow chainable consecutive calls. Thus the functions\nreturn the `List` pointer they received. Of course when passing a `List *` to a method, it does not\nmatter on which instance it's stored on.\n\nFunctions ending with `_f` will free the argument they got, except the first 'self' `List` argument.\n\nGCC allows the following cool macro, (found [here](http://stackoverflow.com/questions/10405436/anonymous-functions-using-gcc-statement-expressions)) that makes possible to simulate anonymous functions, as you can \nsee in the examples\n\n```c\n#define function(return_type, function_body) ({ return_type __fn__ function_body __fn__; })\n```\n\n#### Create and free a List\n\n```c\nList *list = list_new();\n//\nlist-\u003efree(list);\n```\n\nIf you need custom allocator functions you can set the default via `list_set_allocators();`\nThe first two arguments are the `List` node allocator and free functions, the third is a free, for\nyour items stored. If you pass `NULL` at any argument, the defaults will be used. For custom behavior\non a given instance, just override `release_item`, `alloc_node`, or `release_node` members.\n\n\nIt's also possible to create a copy of an existing `List`. It can be useful if you don't want to\nmodify it, but rather create a modified version.\n\n\n```c\nList *new = original-\u003eclone(original);\n```\n\n\n#### Foreach\n\nYou can iterate the `List` from both direction. (left = from head, right = from last)\n```c\nlist\n    -\u003eforeach_l(list, function(void, (void *item) {\n        //\n    }))\n    -\u003eforeach_r(list, function(void, (void *item) {\n        //\n    }));\n```\n\n\n#### Fold\n\nFold operation is also possible from both directions.\n\n```c\nchar initial[50] = \"\";\n\nchar *folded = list\n    -\u003eappend(list, \"Unit\")\n    -\u003eappend(list, \"Test\")\n    -\u003efold_l(list, initial, (Fold) function(char *, (char *val, char *item) {\n        sprintf(val, \"%s%s\", val, item);\n        return val;\n    }));\n\nputs(folded); // UnitTest\n\n```\nWith `fold_r` the output will be `TestUnit`\n\n\n#### Map\n\nMapping new values to the `List` is also done by a callback function\n\n```c\nchar hello[10] = \"Hello\";\nchar hi[10] = \"Hi\";\n    \ngreetings\n    -\u003eappend(greetings, hello)\n    -\u003eappend(greetings, hi)\n    -\u003emap(greetings, (Map) function(char *, (char *greeting) {\n        sprintf(greeting, \"%s!!\", greeting);\n        return greeting;\n    }))\n    -\u003eforeach_l(greetings, (Foreach) puts);\n    \n    //Hello!!\n    //Hi!!\n```\n\n\n#### Filter\n\nIf the callback returns `false`, the item will be removed\n\n```c\nlist-\u003eappend(list, \"Unit\")\n    -\u003eappend(list, \"Test\")\n    -\u003efilter(list, function(bool, (void *item) {\n        return 0 == strcmp(\"Test\", item);\n    }))\n    -\u003eforeach_l(list, (Foreach) puts);\n    \n    //Test\n```\n\n\n#### Concat and Merge\n\nItems of the other `List` will be simply appended to the other\n\n```c\nchar *unit = \"Unit \";\n\nList *list_1 = list_new();\nlist_1\n    -\u003eappend(list_1, unit)\n    -\u003eappend(list_1, \"Test\");\n\nList *list_2 = list_new();\nlist_2\n    -\u003eappend(list_2, \"I \")\n    -\u003eappend(list_2, \"said: \")\n    -\u003eappend(list_2, unit)\n    -\u003econcat(list_2, list_1)\n    -\u003eforeach_l(list_2, (Foreach) printf);\n    \n    // I said: Unit Unit Test\n```\n\nMerge method is the same, except that it will only add items that are not already in the `List`.\nUsing `merge()` with the above example, the otput will be `I said: Unit Test`\n\n\n#### Manipulating the ends of the List:\n\nadd: \n```c\nlist-\u003eprepend(list, \u0026item)-\u003eappend(list, \u0026other_item);\n```\n\nremove:\n```c\nvoid *first = list-\u003eshift(list);\nvoid *last = list-\u003epop(list);\n```\n\nreplace:\n```c\nlist-\u003ereplace(list, \u0026from, \u0026to);\n```\n\nget the first/last item without removing\n```c\nvoid *first = list-\u003ehead(list);\nvoid *last = list-\u003elast(list);\n```\n\nIf the list is empty, `NULL` will be returned\n\n\n#### Accessing elements of the List\n\nby index:\n\n```c\nif (0 == strcmp(\"delete_me\", list-\u003eget(list, 0))) {\n    list-\u003edelete_at(list, 0);\n} else if (0 == strcmp(\"replace_me\", list-\u003eget(list, 10))) {\n    list-\u003eset(list, 10, \"Something else\");\n}\n```\nNegative indexes can also be used. For example, -2 will be the second from the last.\n`get()` will return `NULL` if the index is out of bounds.\n`set()`, `delete_at()` and `delete()` will ignore the invalid indexes.\n\n\nYou can always check the size of the `List` via the `count` field.\n\n\nor by pointer:\n\n```c\nif (list-\u003ehas(list, \u0026item)) {\n    list-\u003edelete(list, \u0026item);\n}\n```\n\nYou can also find/test items by predicates, this will return on the first match:\n\n```c\nPredicate is_ten = function(bool, (void *item) {\n    return 10 == *(int *)item;\n});\n\nbool exists = list-\u003eexists(list, is_ten);\nint *item = list-\u003efind(list, is_ten);\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fisty001%2Fcollection","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fisty001%2Fcollection","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fisty001%2Fcollection/lists"}