{"id":21884042,"url":"https://github.com/leiless/rax-lpm","last_synced_at":"2025-03-22T01:27:44.942Z","repository":{"id":44500659,"uuid":"174365577","full_name":"leiless/rax-lpm","owner":"leiless","description":"Radix tree longest prefix match algorithm implementation","archived":false,"fork":false,"pushed_at":"2022-02-10T15:10:42.000Z","size":36,"stargazers_count":2,"open_issues_count":1,"forks_count":2,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-03-15T00:39:53.223Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://github.com/antirez/rax","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/leiless.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}},"created_at":"2019-03-07T14:58:21.000Z","updated_at":"2024-03-03T21:05:53.000Z","dependencies_parsed_at":"2022-08-22T12:40:18.951Z","dependency_job_id":null,"html_url":"https://github.com/leiless/rax-lpm","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/leiless%2Frax-lpm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leiless%2Frax-lpm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leiless%2Frax-lpm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leiless%2Frax-lpm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/leiless","download_url":"https://codeload.github.com/leiless/rax-lpm/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244892367,"owners_count":20527438,"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":[],"created_at":"2024-11-28T10:12:03.317Z","updated_at":"2025-03-22T01:27:44.920Z","avatar_url":"https://github.com/leiless.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# rax-lpm, A radix tree with longest prefix match API\n\nrax-lpm derived from [rax](https://github.com/antirez/rax), it implemented a widely used [longest prefix match algorithm](https://en.wikipedia.org/wiki/Longest_prefix_match) in radix tree.\n\nThe primary goal of this project is to implement the longest prefix match algorithm by providing [`raxFind`](https://github.com/antirez/rax#key-lookup)-like functionality without intervention of [rax iterators](https://github.com/antirez/rax#iterators). It's extremely useful when you do a path prefix match, or embed the [rax](https://github.com/antirez/rax) into embedded device by removing [rax iterators](https://github.com/antirez/rax#iterators).\n\nFor more information, please refers to [rax](https://github.com/antirez/rax) project.\n\n# Longest prefix match API\n\n[rax](https://github.com/antirez/rax) itself is a full-featured radix tree implementation, for basic API usage, please see [Basic API](https://github.com/antirez/rax#basic-api).\n\nThere're two APIs used for radix tree longest prefix match:\n\n```c\n/**\n * Find longest prefix match in a radix tree\n *\n * @tree        the tree\n * @key         key to match\n * @len         length of the key\n * @pos         [OUT] position(index) in the key\n *              ranged [-1, len]\n *              -1          indicate mismatch(will return raxNotFound)\n *              [0, len)    indicate a submatch\n *              len         indicate a full match\n * @return      value associated to the longest prefix match node\n *              raxNotFound if not match\n *\n * see: rax/rax.c#raxFind\n */\nvoid *raxLongestPrefixMatch(\n        rax *tree,\n        unsigned char *key,\n        size_t len,\n        ssize_t * __nullable pos);\n\n/**\n * Find longest prefix match in a radix tree\n *\n * @tree        the tree\n * @key         key to match\n * @len         length of the key\n * @pos         [OUT] position(index) in the key\n *              ranged [-1, len]\n *              -1          indicate mismatch(will return 0)\n *              [0, len)    indicate a submatch\n *              len         indicate a full match\n * @data        [OUT] value associated to the longest prefix match node if found\n * @return      1 if found any match  0 o.w.\n *\n * see: rax/rax.c#raxFind\n */\nint raxLongestPrefixMatch2(\n        rax *tree,\n        unsigned char *key,\n        size_t len,\n        ssize_t * __nullable pos,\n        void * __nullable * __nullable data);\n```\n\nThe `__nullable` keyword annotates that left hand side type can be `NULL`, i.e. it's optional. by default, pointer type shouldn't be `NULL`.\n\nThose two APIs used in different scenarios, they're the same per se, choose whichever you like.\n\n# Caveats\n\nWhen you insert any key into the radix tree in the following form:\n\n```c\nraxInsert(rax, (unsigned char *) _whatever1_, /* n.b. */ 0, (void *) _whatever2_, NULL);\n```\n\ne.g. the `len` parameter equals to zero, there'll always be a zero-length longest prefix match.\n\nThus, following longest prefix match assertion will always proceed:\n\n```c\n/* Assume `rax' contains only the zero-length key */\nssize_t sz;\nvoid *data = raxLongestPrefixMatch(rax, (unsigned char *) \"foobar\", 6, \u0026sz);\nassert(data == (void *) _whatever2_);\nassert(sz == 0);\n```\n\n### Rationale behind\n\nIt simply because when you insert a zero-length key, `rax-\u003ehead-\u003eiskey` always yields 1, hence there is a match.\n\nSimilar situations applys to [`raxFind`](https://github.com/antirez/rax#key-lookup), [`raxRemove`](https://github.com/antirez/rax#deleting-keys):\n\n```c\nint ok;\nvoid *data;\n\nok = raxInsert(rax, (unsigned char *) _whatever1_, /* n.b. */ 0, (void *) _whatever2_, NULL);\nassert(ok == 1);\n\ndata = raxFind(rax, (unsigned char *) _whatever3_, 0);\nassert(data == (void *) _whatever2_);\nok = raxRemove(rax, (unsigned char *) _whatever4_, 0, NULL);\nassert(ok == 1);\n```\n\n# Run `rax-lpm` tests\n\nThis project submoduled [rax](https://github.com/antirez/rax) source, so it can stay up-to-date automatically. Please specify `--recurse-submodules` when cloning this repository.\n\nBefore compile the source, you should first do:\n\n```shell\ngit apply --directory rax rax.c.patch\n```\n\nTo patch [rax/rax.c](https://github.com/antirez/rax/blob/master/rax.c)(only once)\n\nAnd then run the tests:\n\n```\n# `release' target for release build\nmake\n./test_lpm\n```\n\n# Debugging `rax-lpm`\n\nPlease see [Debugging Rax](https://github.com/antirez/rax#debugging-rax).\n\n# License\n\n[sic] [Rax](https://github.com/antirez/rax) is an open source project, released under the [BSD two clause license](https://github.com/antirez/rax/blob/master/COPYING).\n\nrax-lpm is also an open source project, released under the [BSD 3-clause license](LICENSE).\n\n\u003cbr\u003e\n\n*Created 180309+0800*\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleiless%2Frax-lpm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fleiless%2Frax-lpm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleiless%2Frax-lpm/lists"}