{"id":17049811,"url":"https://github.com/marzer/tagged_ptr","last_synced_at":"2026-02-26T15:41:09.624Z","repository":{"id":64055511,"uuid":"569798921","full_name":"marzer/tagged_ptr","owner":"marzer","description":"A tagged-pointer type for C++.","archived":false,"fork":false,"pushed_at":"2023-08-03T21:11:08.000Z","size":60,"stargazers_count":35,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-07-10T09:30:59.858Z","etag":null,"topics":[],"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/marzer.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","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,"zenodo":null},"funding":{"github":"marzer"}},"created_at":"2022-11-23T16:30:59.000Z","updated_at":"2025-07-02T14:48:31.000Z","dependencies_parsed_at":"2025-04-12T15:49:37.900Z","dependency_job_id":null,"html_url":"https://github.com/marzer/tagged_ptr","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/marzer/tagged_ptr","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marzer%2Ftagged_ptr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marzer%2Ftagged_ptr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marzer%2Ftagged_ptr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marzer%2Ftagged_ptr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/marzer","download_url":"https://codeload.github.com/marzer/tagged_ptr/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marzer%2Ftagged_ptr/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29863625,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-26T08:51:08.701Z","status":"ssl_error","status_checked_at":"2026-02-26T08:50:19.607Z","response_time":89,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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-10-14T09:55:26.460Z","updated_at":"2026-02-26T15:41:09.593Z","avatar_url":"https://github.com/marzer.png","language":"C++","funding_links":["https://github.com/sponsors/marzer"],"categories":[],"sub_categories":[],"readme":"# `mz::tagged_ptr` [![MIT license](docs/images/badge-license-MIT.svg)](./LICENSE) [![C++17](docs/images/badge-c++17.svg)][cpp_compilers] [![Sponsor](docs/images/badge-sponsor.svg)][sponsor] [![Gitter](docs/images/badge-gitter.svg)][gitter]\n\nA non-owning tagged pointer type for C++.\n\nRequires C++17.\n\n\u003cbr\u003e\n\n## _\"What is a tagged pointer?\"_\n\nA special pointer that uses some otherwise-unused bits of its memory representation to stash some extra data without taking up any more space (i.e. it still has `sizeof(void*)`).\n\nFrom [wikipedia/tagged_pointer](https://en.wikipedia.org/wiki/Tagged_pointer):\n\n\u003e In computer science, a tagged pointer is a pointer (concretely a memory address) with additional data associated with it, such as an indirection bit or reference count. This additional data is often \"folded\" into the pointer, meaning stored inline in the data representing the address, taking advantage of certain properties of memory addressing.\n\n\u003cbr\u003e\n\n## Features\n\n-   Familiar `std::unique_ptr`-like interface\n-   Support for storing enums and trivially-copyable structs in the tag data\n-   Lots of static checks and debug assertions to make sure you don't do The Bad™\n\n\u003cbr\u003e\n\n## Synopsis\n\n```cpp\nnamespace mz\n{\n    // template params:\n    //\tT\t\tthe pointed-to type\n    //\tAlign\tthe minimum alignment of any value stored in the pointer\n    //\n    // note:\n    //\tfunctions and `void` do not have a default alignment;\n    //\tyou must explicitly specify Align for pointers to these types.\n    template \u003ctypename T, size_t Align = alignof(T)\u003e\n    class tagged_ptr\n    {\n        //------------------------------------------\n        // typedefs + constants\n        //------------------------------------------\n\n        using element_type  = T;\n        using pointer       = T*;\n        using const_pointer = const T*;\n        using tag_type      = /* unsigned integer large enough to store the tag bits */;\n\n        static constexpr size_t   alignment     = Align;\n        static constexpr size_t   tag_bit_count = /* the number of tag bits that may be stored */;\n        static constexpr tag_type max_tag       = /* the largest tag value for this pointer */;\n\n        //------------------------------------------\n        // construction, copying, destruction\n        //------------------------------------------\n\n        // default construct the pointer and tag bits to zero\n        constexpr tagged_ptr() noexcept = default;\n\n        // initialize using nullptr\n        constexpr tagged_ptr(nullptr_t) noexcept;\n\n        // construct from a pointer, set tag bits to zero\n        explicit tagged_ptr(pointer value) noexcept;\n\n        // construct from a pointer and tag bits\n        //\n        // tag_value may be an integer, enum, or trivial object type small enough\n        template \u003ctypename U\u003e\n        tagged_ptr(pointer value, const U\u0026 tag_value) noexcept;\n\n        // tagged_ptr is trivially-copyable and trivially-destructible\n        constexpr tagged_ptr(const tagged_ptr\u0026) noexcept = default;\n        constexpr tagged_ptr\u0026 operator=(const tagged_ptr\u0026) noexcept = default;\n        ~tagged_ptr() noexcept = default;\n\n        //------------------------------------------\n        // retrieving the pointer value\n        //------------------------------------------\n\n        // gets the pointer value\n        pointer ptr() const noexcept;\n\n        // gets the pointer value (alias for ptr())\n        pointer get() const noexcept;\n\n        // gets the pointer value\n        explicit operator pointer() const noexcept;\n\n        // returns a reference to the pointed object\n        //\n        // this is only available when T is an object type\n        element_type\u0026 operator*() const noexcept;\n\n        // invokes the -\u003e operator on the pointed object\n        //\n        // this is only available when T is a class type\n        pointer operator-\u003e() const noexcept;\n\n        //------------------------------------------\n        // changing the pointer\n        //------------------------------------------\n\n        // changes the pointer value without changing the tag bits\n        tagged_ptr\u0026 ptr(pointer value) noexcept;\n\n        // changes the pointer value without changing the tag bits\n        tagged_ptr\u0026 operator=(pointer rhs) noexcept;\n\n        // clears the pointer value without changing the tag bits\n        constexpr tagged_ptr\u0026 clear_ptr() noexcept;\n\n        // checks if a raw pointer can be stored without clipping into the tag bits\n        static bool can_store_ptr(pointer value) noexcept;\n\n        //------------------------------------------\n        // retrieving the tag bits\n        //------------------------------------------\n\n        // gets the tag bits\n        //\n        // U defaults to tag_type, but can be any compatible unsigned integer/enum\n        // or trivially-copyable type\n        template \u003ctypename U = tag_type\u003e\n        U tag() const noexcept;\n\n        // gets the value of a particular tag bit\n        bool tag_bit(size_t tag_bit_index) const noexcept;\n\n        //------------------------------------------\n        // changing the tag\n        //------------------------------------------\n\n        // sets the tag bits\n        //\n        // tag_value may be an unsigned integer/enum or a trivially-copyable type small enough\n        template \u003ctypename U\u003e\n        tagged_ptr\u0026 tag(const U\u0026 tag_value) noexcept;\n\n        // sets the value of a particular tag bit\n        tagged_ptr\u0026 tag_bit(size_t tag_bit_index, bool val) noexcept;\n\n        // clears the tag bits\n        constexpr tagged_ptr\u0026 clear_tag() noexcept;\n\n        // checks if a tag value has compatible traits (copyable, small enough, etc.)\n        // and can be stored without clipping into the pointer bits\n        template \u003ctypename U\u003e\n        static bool can_store_tag(const U\u0026 tag_value) noexcept;\n\n        //------------------------------------------\n        // reset()\n        //------------------------------------------\n\n        // resets both the pointer value and tag bits to zero\n        constexpr tagged_ptr\u0026 reset() noexcept;\n\n        // overrides the pointer value and resets the tag bits to zero\n        tagged_ptr\u0026 reset(pointer value) noexcept;\n\n        // overrides both the pointer value and the tag bits\n        //\n        // tag_value may be an unsigned integer/enum or a trivially-copyable type small enough\n        template \u003ctypename U\u003e\n        tagged_ptr\u0026 reset(pointer value, const U\u0026 tag_value) noexcept;\n\n        //------------------------------------------\n        // comparison\n        //------------------------------------------\n\n        // returns true if the pointer value is non-null (tag bits are ignored)\n        explicit operator bool() const noexcept;\n\n        // compares two tagged pointers for exact equality (tag bits are NOT ignored)\n        friend constexpr bool operator==(tagged_ptr lhs, tagged_ptr rhs) noexcept;\n        friend constexpr bool operator!=(tagged_ptr lhs, tagged_ptr rhs) noexcept;\n\n        // compares a tagged pointer with a raw pointer of the same type (tag bits are ignored)\n        friend bool operator==(tagged_ptr lhs, const_pointer rhs) noexcept;\n        friend bool operator!=(tagged_ptr lhs, const_pointer rhs) noexcept;\n        friend bool operator==(const_pointer lhs, tagged_ptr rhs) noexcept;\n        friend bool operator!=(const_pointer lhs, tagged_ptr rhs) noexcept;\n\n        //------------------------------------------\n        // function pointers\n        //------------------------------------------\n\n        // invokes the function call operator on the pointed function\n        //\n        // this is only available when T is a function\n        template \u003ctypename... U\u003e\n        decltype(auto) operator()(U\u0026\u0026... args) const noexcept(/*...*/);\n    };\n\n    // deduction guides\n    template \u003ctypename T\u003e\n    tagged_ptr(T*) -\u003e tagged_ptr\u003cT\u003e;\n\n    template \u003ctypename T, typename U\u003e\n    tagged_ptr(T*, U) -\u003e tagged_ptr\u003cT\u003e;\n}\n\n// std::pointer_traits specialization\nnamespace std\n{\n    template \u003ctypename T, size_t Align\u003e\n    struct pointer_traits\u003cmz::tagged_ptr\u003cT, Align\u003e\u003e;\n}\n\n```\n\n\u003cbr\u003e\n\n## Usage\n\nThe library is a single-header so the easiest way to use it is to drop [tagged_ptr.hpp] somewhere in your project.\n\nAlternatively you can add `include` to your include paths then `#include \u003cmz/tagged_ptr.hpp\u003e`\n\nThere is also support for use as a `meson.build` subproject.\n\n\u003cbr\u003e\n\n## Configuration\n\nMacros you can define to customize how mz::tagged_ptr works. `#define` them in your build system or before including the header.\n\n| Define                     | Type           | Description                                                                                  | Default                    |\n| -------------------------- | -------------- | -------------------------------------------------------------------------------------------- | -------------------------- |\n| `MZ_ASSERT()`              | Function macro | Debug assert function.                                                                       | `assert()`                 |\n| `MZ_TAGGED_PTR_BITS`       | Integer        | The number of pointer bits actually used by the environment. \u003csup\u003e[1](#config-note-1)\u003c/sup\u003e  | `sizeof(void*) * CHAR_BIT` |\n| `MZ_TAGGED_PTR_HAS_TRAITS` | Boolean        | Should a specialization of `std::pointer_traits` be included? \u003csup\u003e[2](#config-note-2)\u003c/sup\u003e | `1`                        |\n\n1. \u003cspan id=\"config-note-1\"\u003eSome platforms will not use the full range of bits in the pointer, leaving some region of high bits essentially unused (e.g. [AMD64] may only use 48 or 57 bits). Defining this will allow `mz::tagged_pointer` to take advantage of these extra bits by shifting them down into the tag section. ⚠\u0026#xFE0F; Very non-portable; use with caution!\u003c/span\u003e\n2. \u003cspan id=\"config-note-2\"\u003eImplies `#include \u003cmemory\u003e` - users wishing to keep compile times lower and not needing the pointer traits might wish to set this to `0`.\u003c/span\u003e\n\n\u003cbr\u003e\n\n## Caveats\n\n-   ⚠\u0026#xFE0F; So far I've only been able to test this on x86 and AMD64. I welcome help testing it on other platforms! (see [Contributing])\n-   ⚠\u0026#xFE0F; Absolutely no idea if this will work on big-endian systems. Help welcome! (see [Contributing])\n-   ⚠\u0026#xFE0F; Some environments will perform pointer tagging natively (e.g. [Android on Armv8 AArch64](https://source.android.com/docs/security/test/tagged-pointers)); I recommend not using this class in those contexts.\n\n\u003cbr\u003e\n\n## Contributing\n\nThere are three ways you can contribute:\n\n1. Reporting bug or making feature requests [here](https://github.com/marzer/tagged_ptr/issues/new)\n2. Opening a pull request (see below)\n3. Becoming a [sponsor] ❤\u0026#xFE0F;\n\n### Pull requests\n\n`tagged_ptr.hpp` is programmatically extracted from a much larger project so I won't accept pull requests made for this repository directly; if you wish to contribute a bugfix or a feature, please find the `tagged_ptr` implementation [in this project](https://github.com/marzer/muu) and propose your changes there instead. I will then propagate them to this satellite library when they are merged.\n\n\u003cbr\u003e\n\n## License\n\nMIT. See [LICENSE](LICENSE).\n\n[tagged_ptr.hpp]: include/mz/tagged_ptr.hpp\n[license]: ./LICENSE\n[cpp_compilers]: https://en.cppreference.com/w/cpp/compiler_support\n[gitter]: https://gitter.im/marzer/community\n[sponsor]: https://github.com/sponsors/marzer\n[contributing]: #Contributing\n[amd64]: https://en.wikipedia.org/wiki/X86-64\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarzer%2Ftagged_ptr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarzer%2Ftagged_ptr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarzer%2Ftagged_ptr/lists"}