{"id":15285826,"url":"https://github.com/processone/mqtree","last_synced_at":"2025-04-23T21:26:17.437Z","repository":{"id":57529287,"uuid":"169211123","full_name":"processone/mqtree","owner":"processone","description":"Index tree for MQTT topic filters","archived":false,"fork":false,"pushed_at":"2024-06-27T09:08:26.000Z","size":301,"stargazers_count":14,"open_issues_count":0,"forks_count":5,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-04-14T02:05:46.896Z","etag":null,"topics":["data-structures","erlang","mqtt","tree-structure"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/processone.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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":"2019-02-05T08:39:18.000Z","updated_at":"2024-10-23T02:04:18.000Z","dependencies_parsed_at":"2024-01-29T09:44:32.391Z","dependency_job_id":"d3a38731-2f90-4802-9bf0-2b1e2d73e54a","html_url":"https://github.com/processone/mqtree","commit_stats":{"total_commits":66,"total_committers":6,"mean_commits":11.0,"dds":0.6666666666666667,"last_synced_commit":"b72c0daff81e57d2388b837e8379ae1543804fc4"},"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/processone%2Fmqtree","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/processone%2Fmqtree/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/processone%2Fmqtree/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/processone%2Fmqtree/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/processone","download_url":"https://codeload.github.com/processone/mqtree/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250516322,"owners_count":21443601,"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":["data-structures","erlang","mqtt","tree-structure"],"created_at":"2024-09-30T15:07:46.724Z","updated_at":"2025-04-23T21:26:17.420Z","avatar_url":"https://github.com/processone.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"mqtree: Index tree for MQTT topic filters\n====================================================\n\n[![CI](https://github.com/processone/mqtree/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/processone/mqtree/actions/workflows/ci.yml)\n[![Coverage Status](https://coveralls.io/repos/processone/mqtree/badge.svg?branch=master\u0026service=github)](https://coveralls.io/github/processone/mqtree?branch=master)\n[![Hex version](https://img.shields.io/hexpm/v/mqtree.svg \"Hex version\")](https://hex.pm/packages/mqtree)\n\nmqtree is an Erlang NIF implementation of N-ary tree to keep MQTT\ntopic filters for efficient matching.\n\n# System requirements\n\nTo compile mqtree you need:\n\n - GNU Make.\n - GCC.\n - Erlang/OTP 17.5 or higher.\n\n# Compiling\n\n```\n$ git clone https://github.com/processone/mqtree.git\n$ cd mqtree\n$ make\n```\n\n# API\n\n## new/0\n```erlang\n-spec new() -\u003e tree().\n```\nCreates new tree. The tree is mutable just like ETS, so there is\nno need to keep its updated version between calls.\nThe created tree gets destroyed when it's garbage collected.\n\nComplexity: `O(1)`.\n\n**NOTE**: a registered tree (see [register/2](#register2)) is\nnot a subject for garbage collection until [unregister/1](#unregister1)\nis called **explicitly**.\n\n## insert/2\n```erlang\n-spec insert(Tree :: tree(), Filter :: iodata()) -\u003e ok.\n```\nInserts `Filter` into `Tree` and increases its reference counter.\nThe reference counter is increased every time when the same\nfilter is inserted into the tree. The reference counter is decreased\nwhen the filter is deleted, see [delete/2](#delete2).\n\nComplexity: `O(H)` where `H` is the number of slashes (`/`) in `Filter`.\n\n**NOTE**: no checks are performed on the filter being inserted:\nit's up to the caller to check if the filter conforms to the MQTT\nspecification.\n\n## delete/2\n```erlang\n-spec delete(Tree :: tree(), Filter :: iodata()) -\u003e ok.\n```\nDeletes `Filter` from `Tree` and decreases its reference counter.\nNothing is done if the filter is not found in the tree.\n\nComplexity: `O(H)` where `H` is the number of slashes (`/`) in `Filter`.\n\n**NOTE**: no checks are performed on the filter being deleted:\nit's up to the caller to check if the filter conforms to the MQTT\nspecification.\n\n## match/2\n```erlang\n-spec match(Tree :: tree(), Path :: iodata()) -\u003e [binary()].\n```\nFinds filters in `Tree` matching `Path` according to the MQTT\nspecification.\n\nComplexity: `O(2^H)` worst case, where `H` is the number of slashes (`/`) in `Path`.\nNote that the worst case complexity is only achieved when an attacker forces to\nstore in the tree a massive amount of filters containing `+` meta-symbol. The\nobvious protection is to restrict the filter depth. Another approach is to\nmake filter \"deduplication\" during subscription registration, e.g. filters\n`a/+`, `+/b` and `+/+` should be \"merged\" into single `+/+`.\n\n**NOTE**: no checks are performed on the path being matched:\nit's up to the caller to check if the path conforms to the MQTT\nspecification.\n\n**NOTE**: any path starting with `$` won't match filters starting with\n`+` or `#`. This is in accordance with the MQTT specification.\n\n## refc/2\n```erlang\n-spec refc(Tree :: tree(), Filter :: iodata()) -\u003e non_neg_intger().\n```\nReturns the reference counter of `Filter` in `Tree`. In particular,\nzero (0) is returned if the filter is not found in the tree.\n\nComplexity: `O(H)` where `H` is the number of slashes (`/`) in `Filter`.\n\n**NOTE**: no checks are performed on the filter being searched:\nit's up to the caller to check if the filter conforms to the MQTT\nspecification.\n\n## clear/1\n```erlang\n-spec clear(Tree :: tree()) -\u003e ok.\n```\nDeletes all filters from `Tree`.\n\nComplexity: `O(N)` where `N` is the number of filters in the tree.\n\n## size/1\n```erlang\n-spec size(Tree :: tree()) -\u003e non_neg_integer().\n```\nReturns the size of `Tree`. That is, the number of filters in the\ntree (irrespective of their reference counters).\n\nComplexity: `O(N)` where `N` is the number of filters in the tree.\n\n## is_empty/1\n```erlang\n-spec is_empty(Tree :: tree()) -\u003e boolean().\n```\nReturns `true` if `Tree` holds no filters. Returns `false` otherwise.\n\nComplexity: `O(1)`.\n\n## register/2\n```erlang\n-spec register(RegName :: atom(), Tree :: tree()) -\u003e ok.\n```\nAssociates `RegName` with `Tree`. The tree is then available via call\nto [whereis/1](#whereis1). Fails with `badarg` exception if:\n\n- `RegName` is already in use (even by the tree being registered)\n- `RegName` is atom `undefined`\n- Either `RegName` or `Tree` has invalid type\n\nIt is safe to register already registered tree to another name. In this\ncase the old name will be freed automatically.\n\nComplexity: `O(1)`.\n\n**NOTE**: a registered tree is not a subject for garbage collection.\nYou must call [unregister/1](#unregister1) **explicitly** if you want\nthe tree to be freed by garbage collector.\n\n## unregister/1\n```erlang\n-spec unregister(RegName :: atom()) -\u003e ok.\n```\nRemoves the registered name `RegName` associated with a tree.\nFails with `badarg` exception if `RegName` is not a registered name.\n\nComplexity: `O(1)`.\n\n## whereis/1\n```erlang\n-spec whereis(RegName :: atom()) -\u003e Tree :: tree() | undefined.\n```\nReturns `Tree` with registered name `RegName`. Returns `undefined` otherwise.\n\nComplexity: `O(1)`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprocessone%2Fmqtree","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fprocessone%2Fmqtree","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprocessone%2Fmqtree/lists"}