{"id":21888480,"url":"https://github.com/kelbon/anyany","last_synced_at":"2025-05-16T05:05:55.197Z","repository":{"id":37005686,"uuid":"469489158","full_name":"kelbon/AnyAny","owner":"kelbon","description":"C++17 library for comfortable and efficient dynamic polymorphism","archived":false,"fork":false,"pushed_at":"2025-01-13T09:47:43.000Z","size":327,"stargazers_count":459,"open_issues_count":0,"forks_count":15,"subscribers_count":13,"default_branch":"main","last_synced_at":"2025-04-12T01:59:56.955Z","etag":null,"topics":["cpp","cpp17","cpp20","type-erasure"],"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/kelbon.png","metadata":{"files":{"readme":"README.md","changelog":null,"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},"funding":{"github":["kelbon"]}},"created_at":"2022-03-13T20:39:08.000Z","updated_at":"2025-04-10T16:22:35.000Z","dependencies_parsed_at":"2023-02-18T17:25:16.907Z","dependency_job_id":"b547c548-fd4b-4a13-8c43-78116686fdd9","html_url":"https://github.com/kelbon/AnyAny","commit_stats":{"total_commits":106,"total_committers":1,"mean_commits":106.0,"dds":0.0,"last_synced_commit":"3f4ebb04129686c3e7c9dfe4e40c492647f65d7f"},"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kelbon%2FAnyAny","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kelbon%2FAnyAny/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kelbon%2FAnyAny/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kelbon%2FAnyAny/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kelbon","download_url":"https://codeload.github.com/kelbon/AnyAny/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254471061,"owners_count":22076585,"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":["cpp","cpp17","cpp20","type-erasure"],"created_at":"2024-11-28T11:15:50.028Z","updated_at":"2025-05-16T05:05:50.188Z","avatar_url":"https://github.com/kelbon.png","language":"C++","funding_links":["https://github.com/sponsors/kelbon"],"categories":[],"sub_categories":[],"readme":"## AnyAny\nLibrary for efficient dynamic polymorphism through type erasure(C++17 or later)\n\nGoals are efficiency, understandability and extensibility.\n\nclang, gcc, msvc\n[![](\nhttps://github.com/kelbon/AnyAny/actions/workflows/build_and_test.yml/badge.svg?branch=main)](\nhttps://github.com/kelbon/AnyAny/actions/workflows/build_and_test.yml)\n\n### See /examples folder for fast start!\n\n* [`How to build?`](#build)\n\n## Basic usage example\n\nFoundation of library'a type erase part is a _Methods_ - a description which part of the type we want to use after erasing.\n\nLet's create one for erasing types with `void draw()`:\n\n\u003cdetails\u003e\n  \u003csummary\u003eclick here to see short syntax with macros\u003c/summary\u003e\n  \n  There are `anyany_method` macro in \u003canyany/anyany_macro.hpp\u003e\n  For example, for Method 'foo', which accepts int and float + returns float\n  \n  ```C++\n  #include \u003canyany/anyany_macro.hpp\u003e\n  anyany_method(foo, (\u0026self, int i, float f) requires(self.foo(i, f)) -\u003e float);\n  \n  ...\n  \n  void example(aa::any_with\u003cfoo\u003e obj) {\n    if(obj.has_value())\n      float x = obj.foo(5, 3.14f); // all works\n    obj = some_type_with_foo{};\n    obj = some_other_type_with_foo();\n  }\n  ```\n  \n\u003c/details\u003e\n\n\n```C++\n// For each type T do value.draw()\nstruct Draw {\n  template\u003ctypename T\u003e\n  static void do_invoke(const T\u0026 self) {\n    self.draw();\n  }\n};\n```\n\nWe can use `Draw` for type erasion:\n\n```C++\n#include \u003canyany/anyany.hpp\u003e\nusing any_drawable = aa::any_with\u003cDraw\u003e;\n```\n\nAnd now we can use `any_drawable` to store any type with .draw()\n\n```C++\n// some types with .draw()\nstruct Circle {\n  void draw() const {\n    std::cout \u003c\u003c \"Draw Circle\\n\";\n  }\n};\nstruct Square {\n  void draw() const {\n    std::cout \u003c\u003c \"Draw Square\\n\";\n  }\n};\n\nint main() {\n  any_drawable shape = Circle{};\n  aa::invoke\u003cDraw\u003e(shape); // prints \"Draw Circle\"\n  shape = Square{};\n  aa::invoke\u003cDraw\u003e(shape); // prints \"Draw Square\"\n  // see /examples folder for more\n}\n```\n\nThere are no virtual functions, inheritance, pointers, memory management etc! Nice!\n\nYou can add any number of _Methods_:\n```C++\nusing any_my = aa::any_with\u003cDraw, Run, aa::copy\u003e;\n```\n\nWait, copy...? Yes, by default `aa::any_with` only have a destructor, you can add `aa::copy` method to do it copyable and movable or `aa::move` to make it\nmove only\n\nPredefined _Methods_:\n\n\u003cdetails\u003e\n  \u003csummary\u003ecopy\u003c/summary\u003e\n  \n  makes `any_with` copyable and movable, enables `aa::materialize` for references(this also requires `aa::destroy` method)\n  \n  There are also `copy_with\u003cAlloc, SooS\u003e`, this enables copy when you using custom Allocator and Small Object Optimization Size(`aa::basic_any_with`)\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003emove\u003c/summary\u003e\n  \n  makes 'any_with' movable\n  \n  Note: move constructor and move assignment operator for `any_with` always noexcept\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003ehash\u003c/summary\u003e\n  \n  enables `std::hash` specialization for `any_with`,`poly_ref`/...etc. If `any_with` is empty, then hash == 0.\n  \n  Note: `poly_ptr` has specialization of `std::hash` by default, but it is pointer-like hash.\n  \n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003etype_info\u003c/summary\u003e\n  \n  enables `aa::any_cast`, `aa::type_switch`, `aa::visit_invoke` by adding RTTI in vtable.\n  \n  Also adds `.type_descriptor() -\u003e aa::descriptor_t` for `any_with`/`poly_ref`/...etc.\n\n  \n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003eequal_to\u003c/summary\u003e\n  \n  enables `operator==` for `any_with`/`poly_ref`/...etc.\n  \n  Two objects are equal if they contain same type(or both empty) and stored values are equal.\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003espaceship\u003c/summary\u003e\n  \n  enables `operator\u003c=\u003e` and `operator==` for `any_with`/`poly_ref`/...etc.\n  \n  Note: operpator\u003c=\u003e always returns `std::partial_ordering`.\n  \n  If two objects do not contain same type returns `unordered`, otherwise\n  returns result of `operator \u003c=\u003e` for contained objects.\n  \n  Note: returns `std::partial_ordering::equivalent` if both empty\n  \n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003ecall\u0026ltR(Args...)\u0026gt\u003c/summary\u003e\n  \n  adds `R operator()(Args...)` for `any_with`/`poly_ref`/...etc.\n  \n  Note: also supported `const`, `noexcept` and `const noexcept` signatures\n  \n  example:\n  ```C++\n \n  // stateful::cref is a lightweight thing,\n  // it stores vtable in itself(in this case only one function ptr)\n  // and const void* to value\n  // This is most effective way to erase function\n  template \u003ctypename Signature\u003e\n  using function_ref = aa::stateful::cref\u003caa::call\u003cSignature\u003e\u003e;\n\n  void foo(function_ref\u003cint(float) const\u003e ref) {\n     int result = ref(3.14);\n  }\n\n  ```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003edestroy\u003c/summary\u003e\n  \n  adds destructor(`any_with` has it by default), but maybe you want to use it with `aa::poly_ptr` to manually manage lifetime.\n  Also enables `aa::materialize` for references(also requires aa::copy)\n\u003c/details\u003e\n\nSee `method` concept in anyany.hpp if you want all details about _Methods_\n\n#\n\nPolymorphic types:\n\n* [`any_with\u003cMethods...\u003e`](#any_with)\n* [`basic_any_with\u003cMethods...\u003e`](#basic_any_with)\n* [`poly_ref\u003cMethods...\u003e`](#poly_ref)\n* [`poly_ptr\u003cMethods...\u003e`](#poly_ptr)\n* [`cref\u003cMethods...\u003e`](#const_poly_ref)\n* [`cptr\u003cMethods...\u003e`](#const_poly_ptr)\n* [`stateful::ref\u003cMethods...\u003e`](#stateful_ref)\n* [`stateful::cref\u003cMethods...\u003e`](#stateful_cref)\n\nActions:\n\n* [`any_cast\u003cT\u003e`](#any_cast)\n* [`invoke\u003cMethod\u003e`](#invoke)\n* [`type_switch`](#type_switch)\n* [`visit_invoke`](#visit_invoke)\n\nPolymorphic containers:\n\n* [`variant_swarm\u003cTs...\u003e`](#variant_swarm)\n* [`data_parallel_vector\u003cT, Alloc\u003e`](#data_parallel_vector)\n\n\u003cdetails\u003e\n  \u003csummary\u003eCompile time information\u003c/summary\u003e\n\n```C++\ntemplate \u003ctypename T\u003e\nconcept method = /*...*/; // see anyany.hpp\n\n// true if type can be used as poly traits argument in any_cast / type_switch / visit_invoke etc\ntemplate \u003ctypename T\u003e\nconcept poly_traits = requires(T val, int some_val) {\n                        { val.get_type_descriptor(some_val) } -\u003e std::same_as\u003cdescriptor_t\u003e;\n                        { val.to_address(some_val) };\n                      };\n```\nYou can define traits for your polymorphic hierarchies(LLVM-like type ids, virutal functions etc).\n\nLibrary has two such traits built-in(you can use them as example for implementing your own):\n\n  * anyany_poly_traits - for types from \u003canyany.hpp\u003e\n  * std_variant_poly_traits - for std::variant (\u003canyany/utility.hpp\u003e header)\n\n\u003c/details\u003e\n\n\n\u003cdetails\u003e\n  \u003csummary\u003eInterface features\u003c/summary\u003e\n\nFor example, you want to have method .foo() in type created by `any_with` or `poly_ref` with your _Method_.\n\nThen you should use `plugins`:\n```C++\nstruct Foo {\n    template \u003ctypename T\u003e\n    static void do_invoke(T\u0026) { /* do something*/ }\n   \n    // any_with\u003cFoo\u003e will inherit plugin\u003cany_with\u003cFoo\u003e\u003e\n    template \u003ctypename CRTP\u003e\n    struct plugin {\n      void foo() const {\n        auto\u0026 self = *static_cast\u003cconst CRTP*\u003e(this);\n        // Note: *this may not contain value, you can check it by calling self.has_value()\n        aa::invoke\u003cFoo\u003e(self);\n      }\n    };\n};\n\n//\nany_with\u003cFoo\u003e val = /*...*/;\nval.foo(); // we have method .foo from plugin!\n\n```\nNote: You can 'shadow/override' other plugins by inherting from them in your plugin(even if inheritance is private)\n\nSee aa::spaceship/aa::copy_with plugins for example\n\nAlso you can specialize aa::plugin\u003cAny, Method\u003e for your Method or even for 'Any' with some requirements\n\n\u003c/details\u003e\n\n### `any_with`\nAccepts any number of _Methods_ and creates a type which can hold any value, which supports those _Methods_. Similar to runtime concept\n\nNote: There is tag 'aa::force_stable_pointers' to force allocoation, so `poly_ptr/cptr` to `any_with\u003c...\u003e` will not be invalidated after move.\n\nNote: `aa::unreachable_allocator`, which will break compilation, if `basic_any_with\u003cunreachable_allocator, ...\u003e` tries to allocate memory.\nSo you can force no-allocating in types\n\n\u003cdetails\u003e\n\u003csummary\u003e\nInterface of created type\n\u003c/summary\u003e\n\n```C++\n\n// All constructors and move assign operators are exception safe\n// move and move assign always noexcept\n\n// See 'construct_interface' alias in anyany.hpp and 'struct plugin'for details how it works(comments)\nstruct Any : construct_interface\u003cbasic_any\u003cAlloc, SooS, Methods...\u003e, Methods...\u003e{\n  // aliases to poly ref/ptr\n \n  using ptr = /*...*/;\n  using ref = /*...*/;\n  using const_ptr = /*...*/;\n  using const_ref = /*...*/;\n\n  // operator \u0026 for getting poly ptr\n \n  poly_ptr\u003cMethods...\u003e operator\u0026() noexcept;\n  const_poly_ptr\u003cMethods...\u003e operator\u0026() const noexcept;\n  \n  // main constructors\n  \n  // creates empty\n  constexpr Any();\n  Any(auto\u0026\u0026 value); // from any type\n \n  Any(const Any\u0026) requires aa::copy\n  Any\u0026 operator=(const Any\u0026) requires aa::move and aa::copy\n\n  Any(Any\u0026\u0026) noexcept requires aa::move;\n  Any\u0026 operator=(Any\u0026\u0026) requires method aa::move;\n  \n  // observers\n  \n  bool has_value() const noexcept;\n  \n  // returns true if poly_ptr/ref to *this will not be invalidated after moving value\n  bool is_stable_pointers() const noexcept\n \n  // returns count of bytes sufficient to store current value\n  // (not guaranteed to be smallest)\n  // return 0 if !has_value()\n  size_t sizeof_now() const noexcept;\n  \n  // returns descriptor_v\u003cvoid\u003e if value is empty\n  type_descriptor_t type_descriptor() const noexcept requires aa::type_info;\n \n  // forces that after creation is_stable_pointers() == true (allocates memory)\n  template \u003ctypename T\u003e\n  Any(force_stable_pointers_t, T\u0026\u0026 value);\n\n  // also emplace constructors(std::in_place_type_t\u003cT\u003e), initiaizer list versions\n  // same with force_stable_pointers_t tag etc etc\n  // same with Alloc...\n\n  // modifiers\n  \n  // emplaces value in any, if exception thrown - any is empty(use operator= if you need strong exception guarantee here)\n  template\u003ctypename T, typename... Args\u003e\n  std::decay_t\u003cT\u003e\u0026 emplace(Args\u0026\u0026...); // returns reference to emplaced value\n\n  template \u003ctypename T, typename U, typename... Args\u003e\n  std::decay_t\u003cT\u003e\u0026 emplace(std::initializer_list\u003cU\u003e list, Args\u0026\u0026... args)\n\n  // postcondition: has_value() == false\n  void reset() noexcept; \n\n  // see aa::equal_to description for behavior\n  bool operator==(const Any\u0026) const requires aa::spaceship || aa::equal_to;\n  // see aa::spaceship description for behavior\n  std::partial_ordering operator\u003c=\u003e(const Any\u0026) const requires aa::spaceship;\n  \n  // ... interface from plugins for Methods if presented ...\n};\n\n```\n\u003c/details\u003e\n\nAll constructors and copy/move assignment operators have strong exception guarantee\n\nNote: if your type has noexcept move constructor, it can really increase perfomance(like in std::vector case).\n\nExample:\n```C++\nusing any_printable = aa::any_with\u003cPrint, aa::move\u003e;\n```\n\n### `basic_any_with`\nSame as `any_with`, but with custom alloc and small object optimization buffer size - if you need a copyable `basic_any_with` use `copy_with`\n\n```C++\ntemplate\u003ctypename Alloc, size_t SooS, TTA... Methods\u003e\nusing basic_any_with = /*...*/;\n```\n\n### `poly_ref`\nNon owning, always not null, lightweight(~=void*)\n\n`poly_ref\u003cMethods...\u003e` implicitly converible to smaller count of Methods.\n\n`poly_ref\u003cA, B, C\u003e` is converible to`poly_ref\u003cA, B\u003e`, `poly_ref\u003cA\u003e`, `poly_ref\u003cB\u003e`... etc etc.\n\nThis means you can add in interface of functions only _Methods_ they are really require.\nThen if you add _Method_ to your `any_with` type there are NO abi/api break.\n\n```C++\n// you can invoke this function with any poly_ref\u003c..., A, ...\u003e\nvoid foo(poly_ref\u003cA\u003e);\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eInterface\u003c/summary\u003e\n\n```C++\ntemplate \u003ctemplate\u003ctypename\u003e typename... Methods\u003e\nstruct poly_ref {\n  poly_ref(const poly_ref\u0026) = default;\n  poly_ref(poly_ref\u0026\u0026) = default;\n  poly_ref\u0026 operator=(poly_ref\u0026\u0026) = default;\n  poly_ref\u0026 operator=(const poly_ref\u0026) = default;\n  \n  // only explicit rebind reference after creation\n  void operator=(auto\u0026\u0026) = delete;\n  \n  descriptor_t type_descriptor() const noexcept requires aa::type_info;\n \n  // from mutable lvalue\n  template \u003cnot_const_type T\u003e // not shadow copy ctor\n  poly_ref(T\u0026 value) noexcept\n  poly_ptr\u003cMethods...\u003e operator\u0026() const noexcept;\n  \n  // ... interface from plugins for Methods if presented ...\n}\n```\n\u003c/details\u003e\n\n### `const_poly_ref`\n\nSame as `poly_ref`, but can be created from `poly_ref` and `const T\u0026`\n\n`aa::cref` is a template alias to `aa::const_poly_ref`\n\nNote: do not extends lifetime\n\n### `poly_ptr`\nNon owning, nullable, lightweight(~=void*)\n\n`poly_ptr\u003cMethods...\u003e` implicitly converible to smaller count of Methods.\n\n`poly_ptr\u003cA, B, C\u003e` is converible to`poly_ptr\u003cA, B\u003e`, `poly_ptr\u003cA\u003e`, `poly_ptr\u003cB\u003e`... etc etc.\n\nThis means you can add in interface of functions only _Methods_ they are really require.\nThen if you add _Method_ to your `any_with` type there are NO abi/api break.\n\n```C++\n// you can invoke this function with any poly_ptr\u003c..., A, ...\u003e\nvoid foo(poly_ptr\u003cA\u003e);\n```\n\nNote: `poly_ptr` and `const_poly_ptr` are trivially copyable, so `std::atomic\u003cpoly_ptr\u003c...\u003e\u003e` works.\n\n\u003cdetails\u003e\n\u003csummary\u003e\nInterface\n\u003c/summary\u003e\n\n```C++\ntemplate \u003ctemplate\u003ctypename\u003e typename... Methods\u003e\nstruct poly_ptr {\n  poly_ptr() = default;\n  poly_ptr(std::nullptr_t) noexcept;\n  poly_ptr\u0026 operator=(std::nullptr_t) noexcept;\n\n  poly_ptr(not_const_type auto* ptr) noexcept;\n \n  // from non-const pointer to Any with same methods\n  template \u003cany_x Any\u003e\n  poly_ptr(Any* ptr) noexcept;\n  \n  // observers\n \n  // returns raw pointer to value\n  void* raw() const noexcept;\n  // NOTE: returns unspecified value if *this == nullptr\n  const vtable\u003cMethods...\u003e* raw_vtable_ptr() const noexcept;\n  \n  // returns descriptor_v\u003cvoid\u003e is nullptr\n  descriptor_t type_descriptor() const noexcept requires aa::type_info;\n  \n  bool has_value() const noexcept;\n  bool operator==(std::nullptr_t) const noexcept;\n  explicit operator bool() const noexcept;\n\n  // similar to common pointer operator* returns reference\n \n  poly_ref\u003cMethods...\u003e operator*() const noexcept;\n  const poly_ref\u003cMethods...\u003e* operator-\u003e() const noexcept;\n}\n```\n\u003c/details\u003e\n\n### `const_poly_ptr`\nSame as `poly_ptr`, but can be created from `poly_ptr` and `const T*` / `Any*`\n\n`aa::cptr` is a template alias to `aa::const_poly_ptr`\n\n### `stateful_ref`\n`aa::stateful::ref\u003cMethods...\u003e` contains vtable in itself.\n\nAlso can contain references to C-arrays and functions without decay\n\nIt has pretty simple interface, only creating from `T\u0026/poly_ref` and invoking(by aa::invoke for example)\n\nIt will have maximum performance if you need to erase 1-2 _Methods_ and dont need to use `any_cast`.\n\nTypical use-case - creating a function_ref\n\n```C++\ntemplate \u003ctypename Signature\u003e\nusing function_ref = aa::stateful::cref\u003caa::call\u003cSignature\u003e\u003e;\n\nbool foo(int) { return true; }\n\nvoid example(function_ref\u003cbool(int) const\u003e ref) {\n  ref(5);\n}\n\nint main() {\n  example(\u0026foo);\n  example([](int x) { return false; });\n}\n\n```\n\n### `stateful_cref`\nSame as `stateful::ref`, but may be created from `const T\u0026` and `aa::cref`\n\n# Actions\n\n### `any_cast`\n\nrequires aa::type_info method\n\nFunctional object with operator():\n\nWorks as std::any_cast - you can convert to T(copy), T\u0026(take ref) (throws aa::bad_cast if cast is bad)\n\nOr you can pass pointer(or poly_ptr) (returns nullptr, if cast is bad)\n\n```C++\n\nT* ptr = any_cast\u003cT\u003e(\u0026any);\n\n```\n\nExample:\n```C++\nusing any_comparable = aa::any_with\u003caa::copy, aa::spaceship, aa::move\u003e;\n\nvoid Foo() {\n  any_comparable value = 5;\n  value.emplace\u003cstd::vector\u003cint\u003e\u003e({ 1, 2, 3, 4}); // constructed in-place\n  // any_cast returns pointer to vector\u003cint\u003e(or nullptr if any do not contain vector\u003cint\u003e)\n  aa::any_cast\u003cstd::vector\u003cint\u003e\u003e(std::addressof(value))-\u003eback() = 0;\n  // version for reference\n  aa::any_cast\u003cstd::vector\u003cint\u003e\u0026\u003e(value).back() = 0;\n  // version which returns by copy (or move, if 'value' is rvalue) \n  auto vec = aa::any_cast\u003cstd::vector\u003cint\u003e\u003e(value);\n}\n```\n### `invoke`\nFunctional object with operator(), which accepts `any_with/ref/cref/stateful::ref/stateful::cref` as first argument and then all _Method_'s arguments and invokes _Method_\n\nIf arg is const `any_with` or `cref`, then only **const Methods** permitted.\n\nprecondition: any.has_value() == true\n\nExample:\n```C++\n\nvoid example(any_with\u003cSay\u003e pet) {\n  if(!pet.has_value())\n    return;\n  // invokes Method `Say`, passes std::cout as first argument\n  aa::invoke\u003cSay\u003e(pet, std::cout);\n}\nvoid foo(std::vector\u003caa::poly_ref\u003cFoo\u003e\u003e vec) {\n  // invokes Method `Foo` without arguments for each value in `vec`\n  std::ranges::for_each(vec, aa::invoke\u003cFoo\u003e);\n}\n\n\n```\n\n### `type_switch`\n\nSelects .case based on input arg dynamic type and invokes `visitor` with this dynamic type or default function\n\nAlso supports `poly_traits` as second template argument, so it supports any type for which you have poly traits\n\n\u003cdetails\u003e\n\u003csummary\u003eInterface\u003c/summary\u003e\n\n```C++\ntemplate\u003ctypename Result = void, poly_traits Traits = anyany_poly_traits\u003e\nstruct type_switch_fn {\n  \n  type_switch_fn(poly_ref\u003c...\u003e);\n\n  // invokes Fn if T contained\n  template \u003ctypename T, typename Fn\u003e\n  type_switch_impl\u0026 case_(Fn\u0026\u0026 f);\n \n  // If value is one of Ts... F invoked (invokes count \u003c= 1)\n  template \u003ctypename... Ts, typename Fn\u003e\n  type_switch_impl\u0026 cases(Fn\u0026\u0026 f);\n \n  // if no one case succeded invokes 'f' with input poly_ref argument\n  template \u003ctypename Fn\u003e\n  Result default_(Fn\u0026\u0026 f);\n \n  // if no one case succeded returns 'v'\n  Result default_(Result v);\n  \n  // if no one case succeded returns 'nullopt'\n  std::optional\u003cResult\u003e no_default();\n\n};\n\n```\n\n\u003c/details\u003e\n\nExample:\n\n```C++\n  Result val = aa::type_switch\u003cResult\u003e(value)\n      .case_\u003cfloat\u003e(foo1)\n      .case_\u003cbool\u003e(foo2)\n      .cases\u003cchar, int, unsigned char, double\u003e(foo3)\n      .default_(15);\n```\n\n### `visit_invoke`\n\nIts... runtime overload resolution! `aa::make_visit_invoke\u003cFoos...\u003e` creates overload set object with method `.resolve(Args...)`,\nwhich performs overload resolution based on Args... runtime types.\n\nResolve returns `nullopt` if no such function exist to accept input arguments\n\nThis example is very basic, see also /examples/visit_invoke_example.hpp for more\n\nExample:\n```C++\n\nauto ship_asteroid = [](spaceship s, asteroid a) -\u003e std::string { ... }\nauto ship_star = [](spaceship s, star) -\u003e std::string { ... }\nauto star_star = [](star a, star b) -\u003e std::string { ... }\nauto ship_ship = [](spaceship a, spaceship b) -\u003e std::string { ... }\n\n// Create multidispacter\nconstexpr inline auto collision = aa::make_visit_invoke\u003cstd::string\u003e(\n  ship_asteroid,\n  ship_star,\n  star_star,\n  ship_ship);\n\n...\n\n// Perform runtime overload resolution\nstd::optional\u003cstd::string\u003e foo(any_with\u003cA\u003e a, any_with\u003cB\u003e b) {\n  return collision.resolve(a, b);\n}\n\n```\n ### `variant_swarm`\n  Polymorphic container adaptor, which behaves as `Container\u003cstd::variant\u003cTypes...\u003e\u003e`, but much more effective.\n  \n  Supports operations:\n  * `visit\u003cTypes...\u003e(visitor)` - invokes `visitor` with all contained value of types `Types`\n  * `view\u003cT\u003e` - returns reference to container of all stored values of type `T`\n  \n  Container is a `std::vector` by default.\n  \n  \u003cdetails\u003e\n  \u003csummary\u003eInterface\u003c/summary\u003e\n \n```C++\ntemplate\u003ctemplate\u003ctypename\u003e typename Container, typename... Ts\u003e\nstruct basic_variant_swarm {\n\n  // modifiers\n \n  void swap(basic_variant_swarm\u0026 other) noexcept;\n  friend void swap(basic_variant_swarm\u0026 a, basic_variant_swarm\u0026 b) noexcept;\n  \n  // selects right container and inserts [it, sent) into it\n  template \u003cstd::input_iterator It\u003e\n    requires(tt::one_of\u003cstd::iter_value_t\u003cIt\u003e, std::ranges::range_value_t\u003cContainer\u003cTs\u003e\u003e...\u003e)\n  auto insert(It it, It sent);\n\n  // insert and erase overloads for each type in Ts...\n  using inserters_type::erase;\n  using inserters_type::insert;\n\n  // observe\n\n  bool empty() const noexcept;\n  \n  // returns count values, stored in container for T\n  template \u003ctt::one_of\u003cTs...\u003e T\u003e\n    requires(std::ranges::sized_range\u003ccontainer_for\u003cT\u003e\u003e)\n  auto count() const;\n\n  template \u003cstd::size_t I\u003e\n    requires(std::ranges::sized_range\u003cdecltype(std::get\u003cI\u003e(containers))\u003e)\n  auto count() const;\n  \n  // returns count of values stored in all containers\n  constexpr auto size() const requires(std::ranges::sized_range\u003ccontainer_for\u003cTs\u003e\u003e \u0026\u0026 ...);\n\n  // returns tuple of reference to containers #Is\n  template \u003cstd::size_t... Is\u003e\n  auto view();\n  \n  template \u003cstd::size_t... Is\u003e\n  auto view() const;\n\n  // returns tuple of reference to containers for Types\n  template \u003ctt::one_of\u003cTs...\u003e... Types\u003e\n  auto view();\n  \n  template \u003ctt::one_of\u003cTs...\u003e... Types\u003e\n  auto view() const;\n\n  // visit\n\n  // visits with 'v' and passes its results into 'out_visitor' (if result is not void)\n  template \u003ctt::one_of\u003cTs...\u003e... Types\u003e\n  void visit(visitor_for\u003cTypes...\u003e auto\u0026\u0026 v, auto\u0026\u0026 out_visitor);\n \n  // ignores visitor results\n  template \u003ctt::one_of\u003cTs...\u003e... Types\u003e\n  void visit(visitor_for\u003cTypes...\u003e auto\u0026\u0026 v);\n \n  // visits with 'v' and passes its results into 'out_visitor' (if result is not void)\n  void visit_all(visitor_for\u003cTs...\u003e auto\u0026\u0026 v, auto\u0026\u0026 out_visitor);\n  \n  // ignores visitor results\n  constexpr void visit_all(visitor_for\u003cTs...\u003e auto\u0026\u0026 v);\n\n  template \u003ctt::one_of\u003cTs...\u003e... Types, std::input_or_output_iterator Out\u003e\n  constexpr Out visit_copy(visitor_for\u003cTypes...\u003e auto\u0026\u0026 v, Out out);\n\n  template \u003ctt::one_of\u003cTs...\u003e... Types, std::input_or_output_iterator Out\u003e\n  constexpr Out visit_copy(Out out);\n  \n  // visits with 'v' and passes its results into output iterator 'out', returns 'out\" after all\n  template \u003cstd::input_or_output_iterator Out\u003e\n  constexpr Out visit_copy_all(visitor_for\u003cTs...\u003e auto\u0026\u0026 v, Out out);\n  \n  // passes all values into 'out' iterator, returns 'out' after all\n  template \u003cstd::input_or_output_iterator Out\u003e\n  constexpr Out visit_copy_all(Out out);\n\n  // ...also const versions for visit...\n};\n\n```\n\n\u003c/details\u003e\n\nExample:\n```C++\n  aa::variant_swarm\u003cint, double, std::string\u003e f;\n  // no runtime dispatching here, its just overloads\n  f.inesrt(\"hello world\");\n  f.insert(5);\n  f.insert(3.14);\n  auto visitor = [](auto\u0026\u0026 x) {\n    std::cout \u003c\u003c x \u003c\u003c '\\t';\n  };\n  f.visit_all(visitor); // prints 5, 3.14, \"hello world\"\n```\n ### `data_parallel_vector`\n \nThis container behaves as `std::vector\u003cT\u003e`, but stores fields separatelly.\n\nSupported operation: `view\u003cT\u003e` / `view\u003cI\u003e` to get span to all fields of this index\n\n`T` must be aggreagte or tuple-like type\n\nNote: `data_parallel_vector` is a random access range\nNote: ignores `std::vector\u003cbool\u003e` specialization, behaves as normal vector for bools\n\n\u003cdetails\u003e\n\u003csummary\u003eInterface\u003c/summary\u003e\n\n```C++\n\ntemplate \u003ctypename T, typename Alloc\u003e\nstruct data_parallel_vector {\n  using value_type = T;\n  using allocator_type = Alloc;\n  using difference_type = std::ptrdiff_t;\n  using size_type = std::size_t;\n  using reference = proxy; // similar to vector\u003cbool\u003e::reference type\n  using const_reference = const_proxy;\n\n  void swap(data_parallel_vector\u0026) noexcept;\n  friend void swap(data_parallel_vector\u0026) noexcept;\n\n  data_parallel_vector() = default;\n\n  explicit data_parallel_vector(const allocator_type\u0026 alloc);\n  data_parallel_vector(size_type count, const value_type\u0026 value,\n                               const allocator_type\u0026 alloc = allocator_type());\n  explicit data_parallel_vector(size_type count, const allocator_type\u0026 alloc = allocator_type());\n  \n  template \u003cstd::input_iterator It\u003e\n  data_parallel_vector(It first, It last, const allocator_type\u0026 alloc = allocator_type());\n  data_parallel_vector(const data_parallel_vector\u0026 other, const allocator_type\u0026 alloc);\n  data_parallel_vector(data_parallel_vector\u0026\u0026 other, const allocator_type\u0026 alloc);\n  data_parallel_vector(std::initializer_list\u003cvalue_type\u003e init,\n                               const allocator_type\u0026 alloc = allocator_type());\n\n  // copy-move all default\n\n  data_parallel_vector\u0026 operator=(std::initializer_list\u003cT\u003e ilist);\n\n  using iterator;\n  using const_iterator;\n\n  iterator begin();\n  const_iterator begin() const;\n  iterator end();\n  const_iterator end() const;\n  const_iterator cbegin() const;\n  const_iterator cend() const;\n\n  reference front();\n  const_reference front() const;\n  reference back();\n  reference back() const;\n  reference operator[](size_type pos);\n  const_reference operator[](size_type pos) const;\n\n  size_type capacity() const;\n  size_type max_size() const;\n\n  // returns tuple of spans to underlying containers\n  template \u003ctypename... Types\u003e\n  auto view();\n  template \u003ctypename... Types\u003e\n  auto view() const;\n  template \u003cstd::size_t... Nbs\u003e\n  auto view();\n  template \u003cstd::size_t... Nbs\u003e\n  auto view() const;\n\n  bool empty() const;\n  size_type size() const;\n\n  bool operator==(const data_parallel_impl\u0026) const = default;\n\n  iterator emplace(const_iterator pos, element_t\u003cIs\u003e... fields);\n  reference emplace_back(element_t\u003cIs\u003e... fields);\n\n  void push_back(const value_type\u0026 v);\n  void push_back(value_type\u0026\u0026 v);\n\n  iterator erase(const_iterator pos);\n  iterator erase(const_iterator b, const_iterator e);\n\n  iterator insert(const_iterator pos, const value_type\u0026 value);\n\n  iterator insert(const_iterator pos, value_type\u0026\u0026 value);\n\n  iterator insert(const_iterator pos, size_type count, const T\u0026 value);\n\n  template \u003cstd::input_iterator It\u003e\n  iterator insert(const_iterator pos, It first, It last);\n\n  iterator insert(const_iterator pos, std::initializer_list\u003cvalue_type\u003e ilist);\n\n  void assign(size_type count, const value_type\u0026 value);\n\n  template \u003cstd::input_iterator It\u003e\n  void assign(It first, It last);\n\n  void assign(std::initializer_list\u003cT\u003e ilist);\n\n  void clear();\n  void pop_back();\n  void reserve(size_type new_cap);\n  void resize(size_type sz);\n  void resize(size_type sz, const value_type\u0026 v);\n  void shrink_to_fit();\n};\n\n```\n\n\u003c/details\u003e\n\nExample:\n\n```C++\nstruct my_type {\n  int x;\n  float y;\n  bool l;\n};\nvoid foo() {\n  aa::data_parallel_vector\u003cmy_type\u003e magic;\n// ints, floats, bools are spans to all stored fields of my_type (\u0026::x, \u0026::y, \u0026::l)\n  auto [ints, floats, bools] = magic;\n  magic.emplace_back(5, 6.f, true);\n};\n``` \n \n## Using with CMake\nFetch content:\n```CMake\n\ninclude(FetchContent)\nFetchContent_Declare(\n  AnyAny\n  GIT_REPOSITORY https://github.com/kelbon/AnyAny\n  GIT_TAG        origin/main\n)\nFetchContent_MakeAvailable(AnyAny)\ntarget_link_libraries(MyTargetName anyanylib)\n```\n\u003cdetails\u003e\n\u003csummary\u003eor use add_subdirectory\u003c/summary\u003e\n  1. Clone this repository into folder with your project\n2. Add these lines to it's CMakeLists.txt\n  \n```CMake\nadd_subdirectory(AnyAny)\ntarget_link_libraries(MyTargetName PUBLIC anyanylib)\n```\n\u003c/details\u003e\n\n### `build`\n  \n```shell\ngit clone https://github.com/kelbon/AnyAny\ncd AnyAny\ncmake . -B build\ncmake --build build\n```\n### build examples\n```shell\ngit clone https://github.com/kelbon/AnyAny\ncd AnyAny/examples\ncmake . -B build\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkelbon%2Fanyany","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkelbon%2Fanyany","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkelbon%2Fanyany/lists"}