{"id":13521262,"url":"https://github.com/arturbac/small_vectors","last_synced_at":"2025-03-31T20:31:09.477Z","repository":{"id":43305586,"uuid":"463103108","full_name":"arturbac/small_vectors","owner":"arturbac","description":"Optimized C++20/23 vectors, strings with in class buffer storage, and utility algorithms","archived":false,"fork":false,"pushed_at":"2024-07-17T12:12:41.000Z","size":431,"stargazers_count":9,"open_issues_count":2,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-08-02T06:12:11.721Z","etag":null,"topics":["basic-string","containers","expected","expected-unexpected","interprocess","interprocess-communication","meta-struct","metastruct","shared-memory","small-vector","small-vectors","static-vector","string","strongly-typed","strongly-typed-types","type-safety","unaligned-access","utility-library"],"latest_commit_sha":null,"homepage":"","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/arturbac.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":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-02-24T10:23:49.000Z","updated_at":"2024-07-17T12:12:45.000Z","dependencies_parsed_at":"2024-03-06T00:24:10.937Z","dependency_job_id":"3c5dd7c3-2336-489e-a821-ce0a8821d9e8","html_url":"https://github.com/arturbac/small_vectors","commit_stats":null,"previous_names":[],"tags_count":77,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arturbac%2Fsmall_vectors","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arturbac%2Fsmall_vectors/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arturbac%2Fsmall_vectors/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arturbac%2Fsmall_vectors/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/arturbac","download_url":"https://codeload.github.com/arturbac/small_vectors/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":222679160,"owners_count":17021812,"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":["basic-string","containers","expected","expected-unexpected","interprocess","interprocess-communication","meta-struct","metastruct","shared-memory","small-vector","small-vectors","static-vector","string","strongly-typed","strongly-typed-types","type-safety","unaligned-access","utility-library"],"created_at":"2024-08-01T06:00:31.872Z","updated_at":"2025-03-31T20:31:09.471Z","avatar_url":"https://github.com/arturbac.png","language":"C++","funding_links":[],"categories":["算法"],"sub_categories":[],"readme":"# small_vectors \n![MIT](https://img.shields.io/badge/license-MIT-blue.svg) ![CMake](https://github.com/arturbac/fixed_math/workflows/CMake/badge.svg)\n![language](https://img.shields.io/badge/language-C%2B%2B23-red.svg) \n\nC++23 utilities library\n\n## Features\n- **implements 2 relocation optimizations** - clang triviall relocatation (from trait __is_trivially_relocatable) and trivially_destructible_after_move by annotating non trivial classes with adl function\n- **Static Vector**: Trivially copyable for types that are trivially copyable, enabling compiler optimizations such as `memcpy` for copying operations (since v3.0.3-devel).\n- **Address Independence**: static vectors and static string offer in-class storage, making them address-independent and suitable for interprocess data exchange.\n- **Dynamic and Custom Sized Storage**: Small vectors support dynamic memory allocation with customizable size types. Static vectors adjust the minimal size type based on the number of elements.\n- **Constant Evaluation**: Static vectors can be fully evaluated at compile time for trivial element types.\n- **Basic String with Dual Storage**: Provides a basic string implementation with both dynamic and static in-class storage options. The static storage variant is address-independent.\n- **Basic Fixed String**: Enables manipulation of constant evaluated string literals.\n- **Expected/Unexpected Implementation**: Offers a C++23 standard `expected/unexpected` implementation with monadic operations for C++20 and up.\n\n## Minor Utility Features\n- **Meta Packed Struct**: Supports bit-packing data with strong typing. Version 2.3.0 introduced signed type support.\n- **Strong Type Wrapping**: Allows for the strong type wrapping of primitive types.\n- **Unaligned Access**: Functions for memory unaligned access are fully capable of being executed at compile time starting with v2.4.2.\n\n## Interprocess Features\n- **Fork Wrapper**: Simplifies process spawning with an interface similar to `std::async`.\n- **Shared Memory Utilities**: Facilitates the construction and access of data in shared interprocess memory with automated memory access indexing to prevent errors.\n\n### examples\n\n#### small_vector and static_vector\n```C++\n\n#include \u003ccoll/static_vector.h\u003e\n\n//static vector with in buffer class memory for 10 elements\ncoll::static_vector\u003cuint32_t,10u\u003e vec10;\n\n//small vector with in buffer class memory for coll::union_min_number_of_elements\u003cint32_t,uint8_t\u003e\n\ncoll::small_vector\u003cint32_t,uint8_t\u003e vec10;\n\n//equivalent for std::vector\u003cint32_t\u003e with size type eq size_t and not in class buffer memory\ncoll::small_vector\u003cint32_t,size_t,0\u003e vec10;\n\n```\n\n#### expected/unexpected\n```C++\nusing expected_type = expected\u003cvalue_type,error_type\u003e;\nauto f = [](value_type v) noexcept { return expected_type{ in_place, ++v}; };\nexpected_type ex{ in_place, value_type{2} };\nauto res { std::move(ex).and_then(f) };\nconstexpr_test( std::same_as\u003cdecltype(res), expected_type\u003e);\nconstexpr_test( res == value_type{3});\n```\n#### memutil::unaligned\n```C++\nconsteval auto make_version_data(string_view sub_ver, string_view data_ver, uint16_t ver_minor, uint16_t comp_minor)\n  {\n  constexpr auto converter = [](char c) noexcept -\u003e std::byte { return static_cast\u003cstd::byte\u003e(c); };\n  std::array\u003cstd::byte, map_version_t::map_version_raw_size\u003e res{};\n  auto it{ranges::transform(sub_ver, res.begin(), converter).out};\n  *it = std::byte(' ');  // make space\n  ++it;\n  it = ranges::transform(data_ver, it, converter).out;\n  *it = std::byte{};\n  it = ranges::next(res.begin(), map_version_t::map_version_name_chars);\n  it = memutil::unaligned_store\u003cuint16_t\u003e(it, expected_version_major);\n  it = memutil::unaligned_store\u003cuint16_t\u003e(it, expected_version_minor);\n  it = memutil::unaligned_store\u003cuint16_t\u003e(it, expected_version_major);\n  memutil::unaligned_store\u003cuint16_t\u003e(it, expected_cmp_minor);\n  return res;\n  }\nstatic constexpr std::array\u003cstd::byte, map_version_t::map_version_raw_size\u003e \n  polska_6_1451_6_18{ make_version_data(\"Polska\", \"2403\", 1451, 18)};\n```\n#### shared mem utils\nexample using static vector, basic_static_string between processes with memory offset table declaration\n```C++\n//used types between processes\nstruct foo\n  {\n  int a,a_;\n  double b;\n  int64_t c;\n  };\n\nusing message = coll::static_u8string\u003c512\u003e;\nusing vector_type = coll::static_vector\u003cuint32_t,128u\u003e;\n\n// memory offset table\nusing foo_obj_decl = ip::shared_type_decl\u003cfoo\u003e;\nusing shared_vector_decl = ip::shared_type_decl\u003cvector_type,foo_obj_decl\u003e;\nusing ref_obj_decl = ip::shared_type_decl\u003cint,shared_vector_decl\u003e;\nusing message_decl = ip::shared_type_decl\u003cmessage,ref_obj_decl\u003e;\n\nbip::mapped_region region ( shm, bip::read_write );\n\n// construct objects in main process\nfoo \u0026 foo_obj{*ip::construct_at\u003cfoo_obj_decl\u003e(region, foo{.a=1,.a_=0,.b=0.5, .c=0xffffffff })};\nauto \u0026 ref_obj{*ip::construct_at\u003cref_obj_decl\u003e(region, 2u)};\nauto \u0026 ref_string { *ip::construct_at\u003cmessage_decl\u003e(region, u8\"message hello world\"sv) };\nvector_type \u0026 vector_obj{ *ip::construct_at\u003cshared_vector_decl\u003e(region) };\nresize(vector_obj,1);\nfront(vector_obj) = 2;\n\n//alter data at forked process\nauto child = ip::fork([](std::string_view shared_mem_name )\n  {\n  bip::shared_memory_object shm_obj{ bip::open_only, shared_mem_name.data() , bip::read_write };\n  bip::mapped_region cregion{ shm_obj, bip::read_write };\n  \n  //reference shared objects\n  foo \u0026 cfoo_obj{ ip::ref\u003cfoo_obj_decl\u003e(cregion) };\n  vector_type \u0026 vector { ip::ref\u003cshared_vector_decl\u003e(cregion) };\n  auto \u0026 cref_string { ip::ref\u003cmessage_decl\u003e(cregion) };\n  auto \u0026 cref_obj{ip::ref\u003cref_obj_decl\u003e(cregion)};\n\n  //read write data\n  ut::expect( cfoo_obj.a == 1 );\n  ut::expect( cfoo_obj.b == 0.5 );\n  ut::expect( cfoo_obj.c == 0xffffffff );\n  cfoo_obj.a = 2;\n  cfoo_obj.b = 1.5;\n  cfoo_obj.c = -0x1ffffffff;\n  \n  ut::expect(size(vector) == 1u );\n  ut::expect(front(vector) == 2u );\n  ut::expect(resize(vector,128) == coll::vector_outcome_e::no_error ) \u003e\u003e ut::fatal;\n  pop_back(vector);\n  std::iota(begin(vector), end(vector), 2);\n  \n  ut::expect( cref_string.view() == u8\"message hello world\"sv );\n  cref_string = u8\"hello world from child\"sv;\n  cref_obj += 2;\n\n  return true;\n  },\n  shmem_name );\n\n// check modified data at forked process\nut::expect(child-\u003ejoin()) \u003e\u003e ut::fatal;\nut::expect( foo_obj.a == 2 );\nut::expect( foo_obj.b == 1.5 );\nut::expect( foo_obj.c == -0x1ffffffff );\n\nut::expect( ref_string.view() == u8\"hello world from child\"sv );\n\nut::expect(ref_obj == 4 );\n\nut::expect(size(vector_obj) == 127u );\nut::expect(front(vector_obj) == 2 );\nut::expect(back(vector_obj) == 128 );\n```\n\n#### meta_packed_struct\n```C++\nenum struct mbs_fields \n  {\n    field_1, field_2, field_3, field_4\n  };\nenum struct example_enum_value : uint8_t\n  { value0 = 0, value1, value2, value3 };\n\nusing enum mbs_fields;\n// pack bit struct\nusing mixed_bitfiled_struct3 = \n    meta_packed_struct\u003c\n      member\u003cuint8_t,mbs_fields::field_1,4\u003e,\n      member\u003cbool,mbs_fields::field_2,1\u003e,\n      member\u003cuint64_t ,mbs_fields::field_3,56\u003e,\n      member\u003cexample_enum_value, mbs_fields::field_4,3\u003e\n      \u003e;\nmixed_bitfiled_struct3 mbs;\nget\u003cfield_3\u003e(mbs) = (0x1llu\u003c\u003c56)-1;\nconstexpr_test(get\u003cfield_1\u003e(mbs) == 0 );\nconstexpr_test(get\u003cfield_2\u003e(mbs) == false );\nconstexpr_test(get\u003cfield_3\u003e(mbs) == (0x1llu\u003c\u003c56)-1 );\nconstexpr_test(get\u003cfield_4\u003e(mbs) == example_enum_value{} );\n\nauto packed_value = pack_value\u003cuint64_t\u003e(mbs);\nconstexpr_test(packed_value == 0b00'11111111111111111111111111111111111111111111111111111111'0'0000 );\n\n// unpack bitstruct\nusing mixed_bitfiled_struct2 = \n  meta_packed_struct\u003c\n    member\u003cuint8_t,mbs_fields::field_1,4\u003e,\n    member\u003cbool,mbs_fields::field_2,1\u003e,\n    member\u003cuint16_t ,mbs_fields::field_3,16\u003e,\n    member\u003cexample_enum_value, mbs_fields::field_4,3\u003e\n    \u003e;\nconstexpr auto fcount = filed_count\u003cmixed_bitfiled_struct2\u003e();\nconstexpr_test(fcount == 4);\nconstexpr auto s_bit_width = bit_width\u003cmixed_bitfiled_struct2\u003e();\nconstexpr_test(s_bit_width == 24);\nuint32_t packed_value{ 0b011000011111111000010010 };\nauto mbs{ unpack_value\u003cmixed_bitfiled_struct2\u003e(packed_value) };\n\nconstexpr_test(get\u003cfield_1\u003e(mbs) == 0x02 );\nconstexpr_test(get\u003cfield_2\u003e(mbs) == true );\nconstexpr_test(get\u003cfield_3\u003e(mbs) == 0x0ff0 );\nconstexpr_test(get\u003cfield_4\u003e(mbs) == value3 );\n```\n## Tested Compilers (as of v2.4.2)\n\n### Make Workflows Tested\n- `cmake --workflow --preset=\"clang-18-libc++release\"`\n- `cmake --workflow --preset=\"clang-18-release\"` using GNU libstdc++ on Linux\n- `cmake --workflow --preset=\"gcc-14-release\"`\n\n### MSVC\n- Tested intermittently\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farturbac%2Fsmall_vectors","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Farturbac%2Fsmall_vectors","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farturbac%2Fsmall_vectors/lists"}