{"id":19458720,"url":"https://github.com/improbable-eng/phtree-cpp","last_synced_at":"2025-07-04T12:06:13.678Z","repository":{"id":41415770,"uuid":"244593671","full_name":"improbable-eng/phtree-cpp","owner":"improbable-eng","description":"PH-Tree C++ implementation by Improbable.","archived":false,"fork":false,"pushed_at":"2023-03-07T17:55:51.000Z","size":400,"stargazers_count":23,"open_issues_count":7,"forks_count":16,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-06-02T21:15:47.683Z","etag":null,"topics":[],"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/improbable-eng.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","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":"2020-03-03T09:26:30.000Z","updated_at":"2025-04-10T05:10:55.000Z","dependencies_parsed_at":"2024-11-11T16:15:28.994Z","dependency_job_id":null,"html_url":"https://github.com/improbable-eng/phtree-cpp","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/improbable-eng/phtree-cpp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/improbable-eng%2Fphtree-cpp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/improbable-eng%2Fphtree-cpp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/improbable-eng%2Fphtree-cpp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/improbable-eng%2Fphtree-cpp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/improbable-eng","download_url":"https://codeload.github.com/improbable-eng/phtree-cpp/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/improbable-eng%2Fphtree-cpp/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263507880,"owners_count":23477403,"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-10T17:28:14.071Z","updated_at":"2025-07-04T12:06:13.611Z","avatar_url":"https://github.com/improbable-eng.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"**Note: for updates please also check the [fork](https://github.com/tzaeschke/phtree-cpp) by the original PH-Tree developer.**\n\n# PH-Tree C++\n\nThe PH-Tree is an ordered index on an n-dimensional space (quad-/oct-/2^n-tree) where each dimension is (by default)\nindexed by a 64bit integer. The index order follows z-order / Morton order. The default implementation is effectively\na 'map', i.e. *each key is associated with at most one value.*\nKeys are points or boxes in n-dimensional space.\n\nTwo strengths of PH-Trees are fast insert/removal operations and scalability with large datasets. It also provides fast\nwindow queries and _k_-nearest neighbor queries, and it scales well with higher dimensions. The default implementation\nis limited to 63 dimensions.\n\nThe API ist mostly analogous to STL's `std::map`, see function descriptions for details.\n\nTheoretical background is listed [here](#theory).\n\nMore information about PH-Trees (including a Java implementation) is available [here](http://www.phtree.org).\n\n----------------------------------\n\n## User Guide\n\n### API Usage\n\n[Key Types](#key-types)\n\n[Basic operations](#basic-operations)\n\n[Queries](#queries)\n\n* [for_each](#for-each-example)\n\n* [Iterators](#iterator-examples)\n\n* [Filters](#filters)\n\n* [Distance Functions](#distance-functions)\n\n[Converters](#converters)\n\n[Custom Key Types](#custom-key-types)\n\n[Restrictions](#restrictions)\n\n[Troubleshooting / FAQ](#troubleshooting-faq)\n\n### Performance\n\n[When to use a PH-Tree](#when-to-use-a-ph-tree)\n\n[Optimising Performance](#optimising-performance)\n\n### Compiling / Building\n\n[Build system \u0026 dependencies](#build-system-and-dependencies)\n\n[bazel](#bazel)\n\n[cmake](#cmake)\n\n## Further Resources\n\n[Theory](#theory)\n\n----------------------------------\n\n## API Usage\n\n\u003ca id=\"key-types\"\u003e\u003c/a\u003e\n\n#### Key Types\n\nThe **PH-Tree Map** supports out of the box five types:\n\n- `PhTreeD` uses `PhPointD` keys, which are vectors/points of 64 bit `double`.\n- `PhTreeF` uses `PhPointF` keys, which are vectors/points of 32 bit `float`.\n- `PhTreeBoxD` uses `PhBoxD` keys, which consist of two `PhPointD` that define an axis-aligned rectangle/box.\n- `PhTreeBoxF` uses `PhBoxF` keys, which consist of two `PhPointF` that define an axis-aligned rectangle/box.\n- `PhTree` uses `PhPoint` keys, which are vectors/points of `std::int64`\n\nThe **PH-Tree MultiMap** supports out of the box three types:\n\n- `PhTreeMultiMapD` uses `PhPointD` keys, which are vectors/points of 64 bit `double`.\n- `PhTreeMultiMapBoxD` uses `PhBoxD` keys, which consist of two `PhPointD` that define an axis-aligned rectangle/box.\n- `PhTreeMultiMap` uses `PhPoint` keys, which are vectors/points of `std::int64`\n\nAdditional tree types can be defined easily analogous to the types above, please refer to the declaration of the tree\ntypes for an example. Support for custom key classes (points and boxes) as well as custom coordinate mappings can be\nimplemented using custom `Converter` classes, see below. The `PhTreeMultiMap` is by default backed\nby `std::unordered_set` but this can be changed via a template parameter.\n\nThe `PhTree` and `PhTreeMultiMap` types are available from `phtree.h` and `phtree_multimap.h`.\n\n\u003ca id=\"basic-operations\"\u003e\u003c/a\u003e\n\n#### Basic Operations\n\n```C++\nclass MyData { ... };\nMyData my_data; \n\n// Create a 3D point tree with floating point coordinates and a value type of `MyData`.\nauto tree = PhTreeD\u003c3, MyData\u003e();\n\n// Create coordinate\nPhPointD\u003c3\u003e p{1.1, 1.0, 10.};\n\n// Some operations\ntree.emplace(p, my_data);\ntree.emplace_hint(hint, p, my_data);\ntree.insert(p, my_data);\ntree[p] = my_data;\ntree.count(p);\ntree.find(p);\ntree.erase(p);\ntree.erase(iterator);\ntree.size();\ntree.empty();\ntree.clear();\n\n// Multi-map only\ntree.relocate(p_old, p_new, value);\ntree.estimate_count(query);\n```\n\n\u003ca id=\"queries\"\u003e\u003c/a\u003e\n\n#### Queries\n\n* For-each over all elements: `tree.fore_each(callback);`\n* Iterator over all elements: `auto iterator = tree.begin();`\n* For-each with box shaped window queries: `tree.fore_each(PhBoxD(min, max), callback);`\n* Iterator for box shaped window queries: `auto q = tree.begin_query(PhBoxD(min, max));`\n* Iterator for _k_ nearest neighbor queries: `auto q = tree.begin_knn_query(k, center_point, distance_function);`\n* Custom query shapes, such as spheres: `tree.for_each(callback, FilterSphere(center, radius, tree.converter()));`\n\n\u003ca id=\"for-each-example\"\u003e\u003c/a\u003e\n\n##### For-each example\n\n```C++\n// Callback for counting entries\nstruct Counter {\n    void operator()(PhPointD\u003c3\u003e key, T\u0026 t) {\n        ++n_;\n    }\n    size_t n_ = 0;\n};\n\n// Count entries inside of an axis aligned box defined by the two points (1,1,1) and (3,3,3)\nCounter callback;\ntree.for_each({{1, 1, 1}, {3, 3, 3}}, callback);\n// callback.n_ is now the number of entries in the box.\n```\n\n\u003ca id=\"iterator-examples\"\u003e\u003c/a\u003e\n\n##### Iterator examples\n\n```C++\n// Iterate over all entries\nfor (auto it : tree) {\n    ...\n}\n\n// Iterate over all entries inside of an axis aligned box defined by the two points (1,1,1) and (3,3,3)    \nfor (auto it = tree.begin_query({{1, 1, 1}, {3, 3, 3}}); it != tree.end(); ++it) {\n    ...\n}\n\n// Find 5 nearest neighbors of (1,1,1)    \nfor (auto it = tree.begin_knn_query(5, {1, 1, 1}); it != tree.end(); ++it) {\n    ...\n}\n```\n\n\u003ca id=\"Filters\"\u003e\u003c/a\u003e\n\n##### Filters\n\nAll queries allow specifying an additional filter. The filter is called for every key/value pair that would normally be\nreturned (subject to query constraints) and to every node in the tree that the query decides to traverse (also subject\nto query constraints). Returning `true` in the filter does not change query behaviour, returning `false` means that the\ncurrent value or child node is not returned or traversed. An example of a geometric filter can be found\nin `phtree/common/filter.h` in `FilterAABB`.\n\n```C++\ntemplate \u003cdimension_t DIM, typename T\u003e\nstruct FilterByValueId {\n    [[nodiscard]] constexpr bool IsEntryValid(const PhPoint\u003cDIM\u003e\u0026 key, const T\u0026 value) const {\n        // Arbitrary example: Only allow values with even values of id_\n        return value.id_ % 2 == 0;\n    }\n    [[nodiscard]] constexpr bool IsNodeValid(const PhPoint\u003cDIM\u003e\u0026 prefix, int bits_to_ignore) const {\n        // Allow all nodes\n        return true;\n    }\n};\n\n// Iterate over all entries inside of an axis aligned box defined by the two points (1,1,1) and (3,3,3).\n// Return only entries that suffice the filter condition.    \nfor (auto it = tree.begin_query({1, 1, 1}, {3, 3, 3}, FilterByValueId\u003c3, T\u003e())); it != tree.end(); ++it) {\n    ...\n}\n```\n\n\u003ca id=\"distance-functions\"\u003e\u003c/a\u003e\n\n##### Distance function\n\nNearest neighbor queries can also use custom distance metrics, such as L1 distance. Note that this returns a special\niterator that provides a function to get the distance of the current entry:\n\n```C++\n#include \"phtree/phtree.h\"\n\n// Find 5 nearest neighbors of (1,1,1) using L1 distance    \nfor (auto it = tree.begin_knn_query(5, {1, 1, 1}, DistanceL1\u003c3\u003e())); it != tree.end(); ++it) {\n    std::cout \u003c\u003c \"distance = \" \u003c\u003c it.distance() \u003c\u003c std::endl;\n    ...\n}\n\n```\n\n\u003ca id=\"converters\"\u003e\u003c/a\u003e\n\n#### Converters\n\nThe PH-Tree can internally only process integer keys. In order to use floating point coordinates, the floating point\ncoordinates must be converted to integer coordinates. The `PhTreeD` and `PhTreeBoxD` use by default the\n`PreprocessIEEE` \u0026 `PostProcessIEEE` functions. The `IEEE` processor is a loss-less converter (in terms of numeric\nprecision) that simply takes the 64bits of a double value and treats them as if they were a 64bit integer\n(it is slightly more complicated than that, see discussion in the papers referenced above). In other words, it treats\nthe IEEE 754 representation of the double value as integer, hence the name `IEEE` converter.\n\nThe `IEEE` conversion is fast and reversible without loss of precision. However, it has been shown that other converters\ncan result in indexes that are up to 20% faster. One useful alternative is a `Multiply` converter that convert floating\npoint to integer by multiplication and casting:\n\n```C++\ndouble my_float = ...;\n// Convert to int \nstd::int64_t my_int = (std::int64_t) my_float * 1000000.;\n\n// Convert back\ndouble resultung_float = ((double)my_int) / 1000000.;  \n```\n\nIt is obvious that this approach leads to a loss of numerical precision. Moreover, the loss of precision depends on the\nactual range of the double values and the constant. The chosen constant should probably be as large as possible but\nsmall enough such that converted values do not exceed the 64bit limit of `std::int64_t`. Note that the PH-Tree provides\nseveral `ConverterMultiply` implementations for point/box and double/float.\n\n```C++\ntemplate \u003cdimension_t DIM\u003e\nstruct MyConverterMultiply : public ConverterPointBase\u003cDIM, double, scalar_64_t\u003e {\n    explicit MyConverterMultiply(double multiplier)\n    : multiplier_{multiplier}, divider_{1. / multiplier} {}\n\n    [[nodiscard]] PhPoint\u003cDIM\u003e pre(const PhPointD\u003cDIM\u003e\u0026 point) const {\n        PhPoint\u003cDIM\u003e out;\n        for (dimension_t i = 0; i \u003c DIM; ++i) {\n            out[i] = point[i] * multiplier_;\n        }\n        return out;\n    }\n\n    [[nodiscard]] PhPointD\u003cDIM\u003e post(const PhPoint\u003cDIM\u003e\u0026 in) const {\n        PhPointD\u003cDIM\u003e out;\n        for (dimension_t i = 0; i \u003c DIM; ++i) {\n            out[i] = ((double)in[i]) * divider_;\n        }\n        return out;\n    }\n\n    [[nodiscard]] auto pre_query(const PhBoxD\u003cDIM\u003e\u0026 query_box) const {\n        return PhBox{pre(query_box.min()), pre(query_box.max())};\n    }\n\n    const double multiplier_;\n    const double divider_;\n};\n\ntemplate \u003cdimension_t DIM, typename T\u003e\nusing MyTree = PhTreeD\u003cDIM, T, MyConverterMultiply\u003cDIM\u003e\u003e;\n\nvoid test() {\n    MyConverterMultiply\u003c3\u003e converter{1000000};\n    MyTree\u003c3, MyData\u003e tree(converter);\n    ...  // use the tree\n}\n```  \n\nIt is also worth trying out constants that are 1 or 2 orders of magnitude smaller or larger than this maximum value.\nExperience shows that this may affect query performance by up to 10%. This is due to a more compact structure of the\nresulting index tree.\n\n\u003ca id=\"custom-key-types\"\u003e\u003c/a\u003e\n\n##### Custom key types\n\nWith custom converters it is also possible to use your own custom classes as keys (instead of `PhPointD` or `PhBoxF`).\nThe following example defined custom `MyPoint` and `MyBox` types and a converter that allows using them with a `PhTree`:\n\n```c++\nstruct MyPoint {\n    double x_;\n    double y_;\n    double z_;\n};\n\nusing MyBox = std::pair\u003cMyPoint, MyPoint\u003e;\n\nclass MyConverterMultiply : public ConverterBase\u003c3, 3, double, scalar_64_t, MyPoint, MyBox\u003e {\n    using BASE = ConverterPointBase\u003c3, double, scalar_64_t\u003e;\n    using PointInternal = typename BASE::KeyInternal;\n    using QueryBoxInternal = typename BASE::QueryBoxInternal;\n\n  public:\n    explicit MyConverterMultiply(double multiplier = 1000000)\n    : multiplier_{multiplier}, divider_{1. / multiplier} {}\n\n    [[nodiscard]] PointInternal pre(const MyPoint\u0026 point) const {\n        return {static_cast\u003clong\u003e(point.x_ * multiplier_),\n                static_cast\u003clong\u003e(point.y_ * multiplier_),\n                static_cast\u003clong\u003e(point.z_ * multiplier_)};\n    }\n\n    [[nodiscard]] MyPoint post(const PointInternal\u0026 in) const {\n        return {in[0] * divider_, in[1] * divider_, in[2] * divider_};\n    }\n\n    [[nodiscard]] QueryBoxInternal pre_query(const MyBox\u0026 box) const {\n        return {pre(box.first), pre(box.second)};\n    }\n\n  private:\n    const double multiplier_;\n    const double divider_;\n};\n\nvoid test() {\n    MyConverterMultiply tm;\n    PhTree\u003c3, Id, MyConverterMultiply\u003e tree(tm);\n    ... // use the tree\n}\n```\n\n\u003ca id=\"restrictions\"\u003e\u003c/a\u003e\n\n#### Restrictions\n\n* **C++**: Supports value types of `T` and `T*`, but not `T\u0026`\n* **C++**: Return types of `find()`, `emplace()`, ... differ slightly from `std::map`, they have function `first()`\n  , `second()` instead of fields of the same name.\n* **General**: PH-Trees are **maps**, i.e. each coordinate can hold only *one* entry. In order to hold multiple values\n  per coordinate please use the `PhTreeMultiMap` implementations.\n* **General**: PH-Trees order entries internally in z-order (Morton order). However, the order is based on the (\n  unsigned) bit representation of keys, so negative coordinates are returned *after* positive coordinates.\n* **General**: The current implementation support between 2 and 63 dimensions.\n* **Differences to std::map**: There are several differences to `std::map`. Most notably for the iterators:\n    * `begin()`/`end()` are not comparable with `\u003c` or `\u003e`. Only `it == tree.end()` and `it != tree.end()` is supported.\n    * Value of `end()`: The tree has no linear memory layout, so there is no useful definition of a pointer pointing _\n      after_ the last entry or any entry. This should be irrelevant for normal usage.\n\n\u003ca id=\"troubleshooting-faq\"\u003e\u003c/a\u003e\n\n### Troubleshooting / FAQ\n\n**Problem**: The PH-Tree appears to be losing updates/insertions.\n\n**Solution**: Remember that the PH-Tree is a *map*, keys will not be inserted if an identical key already exists. The\neasiest solution is to use one of the `PhTreeMultiMap` implementations. Alternatively, this can be solved by turning the\nPH-Tree into a multi-map, for example by using something like `std::map` or `std::set` as member type:\n`PhTree\u003c3, std::set\u003cMyDataClass\u003e\u003e`. The `set` instances can then be used to handle key conflicts by storing multiple\nentries for the same key. The logic to handle conflicts must currently be implemented manually by the user.\n\n----------------------------------\n\n## Performance\n\n\u003ca id=\"when-to-use-a-ph-tree\"\u003e\u003c/a\u003e\n\n### When to use a PH-Tree\n\nThe PH-Tree is a multi-dimensional index or spatial index. This section gives a rough overview how the PH-Tree compares\nto other spatial indexes, such as *k*D-trees, R-trees/BV-hierarchies or quadtrees.\n\nDisclaimer: This overview cannot be comprehensive (there are 100s of spatial indexes out there) and performance depends\nheavily on the actual dataset, usage patterns, hardware, ... .\n\n**Generally, the PH-Tree tends to have the following advantages:**\n\n* Fast insertion/removal times. While some indexes, such as *k*-D-trees, trees can be build from scratch very fast, they\n  tend to be be much slower when removing entries or when indexing large datasets. Also, most indexes require\n  rebalancing which may result in unpredictable latency (R-trees) or may result in index degradation if delayed\n  (*k*D-trees).\n\n* Competitive query performance. Query performance is generally comparable to other index structures. The PH-Tree is\n  fast at looking up coordinates but requires more traversal than other indexes. This means it is especially efficient\n  if the query results are 'small', e.g. up to 100 results per query.\n\n* Scalability with large datasets. The PH-Tree's insert/remove/query performance tends to scale well to large datasets\n  with millions of entries.\n\n* Scalability with the number of dimensions. The PH-Tree has been shown to deal \"well\" with high dimensional data (\n  1000k+ dimensions). What does \"well\" mean?\n    * It works very well for up to 30 (sometimes 50) dimensions. **Please note that the C++ implementation has not been\n      optimised nearly as much as the Java implementation.**\n    * For more dimensions (Java was tested with 1000+ dimensions) the PH-Tree still has excellent insertion/deletion\n      performance. However, the query performance cannot compete with specialised high-dim indexes such as cover-trees\n      or pyramid-trees (these tend to be *very slow* on insertion/deletion though).\n\n* Modification operations (insert/delete) in a PH-Tree are guaranteed to modify only one Node (potentially\n  creating/deleting a second one). This guarantee can have advantages for concurrent implementations or when serializing\n  the index. Please note that this advantage is somewhat theoretical because this guarantee is not exploited by the\n  current implementation (it doesn't support concurrency or serialization).\n\n**PH-Tree disadvantages:**\n\n* A PH-Tree is a *map*, not a *multi-map*. This project also provides `PhTreeMultiMap` implementations that store a\n  hash-set at each coordinate. In practice, the overhead of storing sets appears to be usually small enough to not\n  matter much.\n\n* PH-Trees are not very efficient in scenarios where queries tend to return large result sets in the order of 1000 or\n  more.\n\n\u003ca id=\"optimising-performance\"\u003e\u003c/a\u003e\n\n### Optimising Performance\n\nThere are numerous ways to improve performance. The following list gives an overview over the possibilities.\n\n1) **Use `for_each` instead of iterators**. This should improve performance of queries by 5%-10%.\n\n2) **Use `emplace_hint` if possible**. When updating the position of an entry, the naive way is to use `erase()`\n   /`emplace()`. With `emplace_hint`, insertion can avoid navigation to the target node if the insertion coordinate is\n   close to the removal coordinate.\n    ```c++\n    auto iter = tree.find(old_position);\n    tree.erase(iter);\n    tree.emplace_hint(iter, new_position, value);\n    ```\n\n3) **Store pointers instead of large data objects**. For example, use `PhTree\u003c3, MyLargeClass*\u003e` instead of\n   `PhTree\u003c3, MyLargeClass\u003e` if `MyLargeClass` is large.\n    * This prevents the PH-Tree from storing the values inside the tree. This should improve cache-locality and thus\n      performance when operating on the tree.\n    * Using pointers is also useful if construction/destruction of values is expensive. The reason is that the tree has\n      to construct and destruct objects internally. This may be avoidable but is currently still happening.\n\n4) **Use non-box query shapes**. Depending on the use case it may be more suitable to use a custom filter for queries.\n   For example:\n\n   `tree.for_each(callback, FilterSphere(center, radius, tree.converter()));`\n\n5) **Use a different data converter**. The default converter of the PH-Tree results in a reasonably fast index. Its\n   biggest advantage is that it provides lossless conversion from floating point coordinates to PH-Tree coordinates\n   (integers) and back to floating point coordinates.\n    * The `ConverterMultiply` is a lossy converter but it tends to improve performance by 10% or more. This is not\n      caused by faster operation in the converter itself but by a more compact tree shape. The example shows how to use\n      a converter that multiplies coordinates by 100'000, thus preserving roughly 5 fractional digits:\n\n      `PhTreeD\u003cDIM, T, ConverterMultiply\u003c3, 100 * 1000, 1\u003e\u003e`\n\n6) **Use custom key types**. By default, the PH-Tree accepts only coordinates in the form of its own key types, such\n   as `PhPointD`, `PhBoxF` or similar. To avoid conversion from custom types to PH-Tree key types, custom classes can\n   often be adapted to be accepted directly by the PH-Tree without conversion. This requires implementing a custom\n   converter as described in the section about [Custom Key Types](#custom-key-types).\n\n7) Advanced: **Adapt internal Node representation**. Depending on the dimensionality `DIM`, the PH-Tree uses internally\n   in\n   `Nodes` different container types to hold entries. By default, it uses an array for `DIM\u003c=3`, a vector for `DIM\u003c=8`\n   and an ordered map for `DIM\u003e8`. Adapting these thresholds can have strong effects on performance as well as memory\n   usage. One example: Changing the threshold to use vector for `DIM==3` reduced performance of the `update_d` benchmark\n   by 40%-50% but improved performance of `query_d` by 15%-20%. The threshold is currently hardcoded.     \n   The effects are not always easy to predict but here are some guidelines:\n    * \"array\" is the fastest solution for insert/update/remove type operations. Query performance is \"ok\". Memory\n      consumption is\n      **O(DIM^2)** for every node regardless of number of entries in the node.\n    * \"vector\" is the fastest for queries but has for large nodes **worst case O(DIM^2)** insert/update/remove\n      performance.\n    * \"map\" scales well with `DIM` but is for low values of `DIM` generally slower than \"array\" or \"vector\".\n\n----------------------------------\n\n## Compiling the PH-Tree\n\nThis section will guide you through the initial build system and IDE you need to go through in order to build and run\ncustom versions of the PH-Tree on your machine.\n\n\u003ca id=\"build-system-and-dependencies\"\u003e\u003c/a\u003e\n\n### Build system \u0026 dependencies\n\nPH-Tree can be built with *cmake 3.14* or [Bazel](https://bazel.build) as build system. All code is written in C++\ntargeting the C++17 standard. The code has been verified to compile on Linux with Clang 9, 10, 11, 12, and GCC 9, 10,\n11, and on Windows with Visual Studio 2019.\n\n#### Ubuntu Linux\n\n* Installing [clang](https://apt.llvm.org/)\n\n* Installing [bazel](https://docs.bazel.build/versions/main/install-ubuntu.html)\n\n* To install [cmake](https://launchpad.net/~hnakamur/+archive/ubuntu/cmake):\n\n```\nsudo add-apt-repository ppa:hnakamur/libarchive\nsudo add-apt-repository ppa:hnakamur/libzstd\nsudo add-apt-repository ppa:hnakamur/cmake\nsudo apt update\nsudo apt install cmake\n```\n\n#### Windows\n\nTo build on Windows, you'll need to have a version of Visual Studio 2019 installed (likely Professional), in addition to\n[Bazel](https://docs.bazel.build/versions/master/windows.html) or\n[cmake](https://cmake.org/download/).\n\n\u003ca id=\"bazel\"\u003e\u003c/a\u003e\n\n### Bazel\n\nOnce you have set up your dependencies, you should be able to build the PH-Tree repository by running:\n\n```\nbazel build ...\n```\n\nSimilarly, you can run all unit tests with:\n\n```\nbazel test ...\n```\n\n\u003ca id=\"cmake\"\u003e\u003c/a\u003e\n\n### cmake\n\n```\nmkdir build\ncd build\ncmake ..\ncmake --build .\n./example/Example\n```\n\n## Further Resources\n\n\u003ca id=\"theory\"\u003e\u003c/a\u003e\n\n### Theory\n\nThe PH-Tree is discussed in the following publications and reports:\n\n- T. Zaeschke, C. Zimmerli, M.C. Norrie:\n  \"The PH-Tree -- A Space-Efficient Storage Structure and Multi-Dimensional Index\", (SIGMOD 2014)\n- T. Zaeschke: \"The PH-Tree Revisited\", (2015)\n- T. Zaeschke, M.C. Norrie: \"Efficient Z-Ordered Traversal of Hypercube Indexes\" (BTW 2017).\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fimprobable-eng%2Fphtree-cpp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fimprobable-eng%2Fphtree-cpp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fimprobable-eng%2Fphtree-cpp/lists"}