{"id":21426016,"url":"https://github.com/twig-energy/stronk","last_synced_at":"2025-07-12T07:35:07.272Z","repository":{"id":58715518,"uuid":"527972605","full_name":"twig-energy/stronk","owner":"twig-energy","description":"An easy to customize, strong type library with built in support for unit-like behavior","archived":false,"fork":false,"pushed_at":"2025-06-27T20:28:30.000Z","size":220,"stargazers_count":45,"open_issues_count":5,"forks_count":1,"subscribers_count":9,"default_branch":"main","last_synced_at":"2025-07-01T03:47:40.890Z","etag":null,"topics":["cpp"],"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/twig-energy.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":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-08-23T12:06:18.000Z","updated_at":"2025-06-27T20:28:34.000Z","dependencies_parsed_at":"2024-04-05T11:34:16.197Z","dependency_job_id":"3b63aba2-38ee-4055-8125-044ad77c42f3","html_url":"https://github.com/twig-energy/stronk","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/twig-energy/stronk","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/twig-energy%2Fstronk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/twig-energy%2Fstronk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/twig-energy%2Fstronk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/twig-energy%2Fstronk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/twig-energy","download_url":"https://codeload.github.com/twig-energy/stronk/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/twig-energy%2Fstronk/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264958196,"owners_count":23689011,"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"],"created_at":"2024-11-22T21:39:31.837Z","updated_at":"2025-07-12T07:35:07.251Z","avatar_url":"https://github.com/twig-energy.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=twig-energy_stronk\u0026metric=alert_status)](https://sonarcloud.io/summary/new_code?id=twig-energy_stronk)\n[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=twig-energy_stronk\u0026metric=coverage)](https://sonarcloud.io/summary/new_code?id=twig-energy_stronk)\n[![license](https://img.shields.io/github/license/twig-energy/stronk)](LICENSE)\n\n```text\n            ==================================================================\n\n            *      //   ) ) /__  ___/ //   ) )  //   ) ) /|    / / //   / /  *\n            *     ((          / /    //___/ /  //   / / //|   / / //__ / /   *\n            *       \\\\       / /    / ___ (   //   / / // |  / / //__  /     *\n            *         ) )   / /    //   | |  //   / / //  | / / //   \\ \\     *\n            *  ((___ / /   / /    //    | | ((___/ / //   |/ / //     \\ \\    *\n\n            ==================================================================\n```\n\n## An easy to customize, strong type library with built-in support for unit-like behavior\n\n#### What\n\n- Easy support for stron{g|k} typing, with plenty of built-in skills to add functionality to your own types.\n- Automatically combine types with physics-like unit behavior: `10 [Meter] / 2 [Second] = 5 [Meter / Second]`.\n\n#### Why\n\n- Strong types allow you to catch argument ordering mismatches.\n- Unit-like behavior allows you to use the type system to verify the correctness of your implementation.\n- Catch refactoring bugs at compile time by limiting access to the underlying values.\n\n#### How\n\n```cpp :file=./examples/firstname_lastname_example.cpp\n#include \u003ciostream\u003e\n#include \u003cstring\u003e\n\n#include \u003cstronk/skills/can_stream.hpp\u003e\n#include \u003cstronk/stronk.hpp\u003e\n\nstruct FirstName : twig::stronk\u003cFirstName, std::string, twig::can_ostream\u003e\n{\n    using stronk::stronk;\n};\nstruct LastName : twig::stronk\u003cLastName, std::string\u003e\n{\n    using stronk::stronk;\n};\n\n// Strong types protects you from accidentally passing the wrong argument to the wrong parameter.\nvoid print_name(const LastName\u0026 lastname, const FirstName\u0026 firstname)\n{\n    // The twig::can_ostream skill overloads the `operator\u003c\u003c(ostream\u0026)` for your type.\n    std::cout \u003c\u003c firstname \u003c\u003c \" \";\n    // You can also access the underlying type by using the .unwrap\u003cType\u003e() function.\n    std::cout \u003c\u003c lastname.unwrap\u003cLastName\u003e() \u003c\u003c std::endl;\n}\n\nauto main() -\u003e int\n{\n    print_name(LastName {\"Doe\"}, FirstName {\"John\"});\n}\n```\n\nOn top of providing strong type utilities, `stronk` also enables unit-like behavior:\n\n```cpp :file=./examples/unit_energy_example.cpp:line_start=0:line_end=27\n#include \u003cconcepts\u003e\n\n#include \u003cstronk/stronk.hpp\u003e\n#include \u003cstronk/unit.hpp\u003e\n\n#include \"stronk/utilities/ratio.hpp\"\n\n// We introduce a unit type with a default set of skills with the `stronk_default_unit` prefab\nstruct joules : twig::stronk_default_unit\u003cjoules, twig::ratio\u003c1\u003e\u003e\n{\n};\n\ntemplate\u003ctypename T\u003e\nusing joules_t = joules::value\u003cT\u003e;\n\nvoid joules_and_identity_units()\n{\n    auto energy = joules_t {30.};\n    energy += joules_t {4.} - joules_t {2.};  // we can add and subtract units\n\n    // Multiplying and dividing with an identity_unit (such as floats and integers) does not change the type.\n    energy *= 2.;\n\n    // However an identity_unit divided by a regular unit results in a new unit type.\n    auto one_over_joules = 1.0 / energy;\n    static_assert(!std::same_as\u003cdecltype(one_over_joules), joules_t\u003cdouble\u003e\u003e);\n}\n```\n\nDifferent units can be combined by multiplying or dividing them:\n\n```cpp :file=./examples/unit_energy_example.cpp:line_start=28:line_end=61\n// Let's introduce seconds as a new unit\nstruct seconds : twig::stronk_default_unit\u003cseconds, twig::ratio\u003c1\u003e\u003e\n{\n};\n\n// We can define ratios of a specific unit - these scaled units have the same dimension\ntemplate\u003ctypename T\u003e\nusing hours_t = seconds::scaled_t\u003ctwig::ratio\u003c60 * 60\u003e\u003e::value\u003cT\u003e;\n\n// We can now dynamically generate a new type!\nusing watt = twig::divided_unit_t\u003cjoules, seconds\u003e;\n\ntemplate\u003ctypename T\u003e\nusing watt_t = watt::value\u003cT\u003e;\n\n// or make custom names for already known types (joules) with specific scale\nusing watt_hours = decltype(watt_t\u003cdouble\u003e {} * hours_t\u003cdouble\u003e {})::unit_t;\n\ntemplate\u003ctypename T\u003e\nusing watt_hours_t = watt_hours::value\u003cT\u003e;\n\nvoid watt_hours_and_generating_new_units()\n{\n    // Multiplying the right units together will automatically produce the new type\n    watt_hours_t watt_hours_val = hours_t {3.} * watt_t {25.};\n\n    // The new type supports adding, subtracting, comparing etc by default.\n    watt_hours_val -= watt_hours_t {10.} + watt_hours_t {2.};\n\n    // We can get back to Hours or Watt by dividing the opposite out.\n    hours_t hours_val = watt_hours_val / watt_t {25.};\n    watt_t watt_val = watt_hours_val / hours_t {3.};\n}\n```\n\nThese new generated types are also units which can be used to generate new units:\n\n```cpp :file=./examples/unit_energy_example.cpp:line_start=62:line_end=86\n// Let's introduce a type for euros, and start combining more types.\nstruct euro : twig::stronk_default_unit\u003ceuro, twig::ratio\u003c1\u003e\u003e\n{\n};\ntemplate\u003ctypename T\u003e\nusing euro_t = euro::value\u003cT\u003e;\n\ntemplate\u003ctypename T\u003e\nusing mega_watt_hours_t = joules::scaled_t\u003ctwig::ratio_multiply\u003ctwig::mega, typename watt_hours::scale_t\u003e\u003e::value\u003cT\u003e;\n\nvoid introducing_another_type()\n{\n    // twig::make allows you to scale the input value but it does not change the resulting type\n    auto one_mega_watt_hour = mega_watt_hours_t {1.};\n    // Now we can generate a new type which consists of 3 types: `Euro / (Watt * Hours)`\n    auto euros_per_mega_watt_hour = euro_t {300.} / one_mega_watt_hour;\n\n    // This flexibility allows us to write expessive code, while having the type system check our implementation.\n    euro_t price_for_buying_5_mega_watt_hours =\n        euros_per_mega_watt_hour * (twig::identity_value_t\u003ctwig::mega, double\u003e {1} * watt_hours_t {5.});\n\n    auto mega_watt_hours_per_euro = 1. / euros_per_mega_watt_hour;  // `(Watt * Hours) / Euro`\n    mega_watt_hours_t mega_watt_hours_affordable_for_500_euros = mega_watt_hours_per_euro * euro_t {500.};\n}\n```\n\nUnits are a great way of using the type system to validate your code.\n\nCredit to [Jonathan Müller](https://github.com/foonathan)'s [blogpost](https://www.foonathan.net/2016/10/strong-typedefs/) and [Jonathan Boccara](https://github.com/joboccara)'s [blogpost](https://www.fluentcpp.com/2016/12/08/strong-types-for-strong-interfaces/) - both of which have been great sources of inspiration.\n\n## Current list of skills\n\nSkills adds functionality to your stronk types. We have implemented a number of generic skills which should help you get started.\n\n### Regular\n\n- `can_negate`: unary `operator-`\n- `can_add`: binary `operator+` `operator=+`\n- `can_subtract`: binary `operator-` and `operator=-`\n- `can_multiply`: binary `operator*` and `operator=*` (not compatible with units, we encourage you to use units instead)\n- `can_divide`: binary `operator/` and `operator=/` (not compatible with units, we encourage you to use units instead)\n- `can_abs`: overloads `twig::abs`\n- `can_isnan`: overloads `twig::isnan`\n- `can_stream`: overloads `operator\u003c\u003c(std::ostream)` and `operator\u003c\u003c(std::istream)`, stream the underlying value to the stream, or create from stream. For only `ostream` or `istream` functionality, use `can_ostream` or `can_istream` respectively.\n- `can_order`: `operator\u003c=\u003e`, note you probably also want to add `can_equate`, since the compiler cannot generate equality with the `operator\u003c=\u003e` for stronk types.\n- `can_equate`: `operator==` with regular equality\n- `can_equate_with_is_close`: `operator==` but with numpy's `is_close` definition of equal\n- `can_equate_with_is_close_nan_equals`: `operator==` but with numpy's `is_close` definition of equal, nans being equal\n- `can_equate_with_is_close_abs_tol_only`: `operator==` with a small absolute tolerance for difference\n- `can_less_than_greater_than`: `operator\u003c` and `operator\u003e` (prefer the `can_order` skill instead)\n- `can_less_than_greater_than_or_equal`: operator \u003c= and operator \u003e= (prefer the `can_order` skill instead)\n- `can_be_used_as_flag`: for boolean values used as flags\n- `can_hash`: specializes `std::hash\u003cT\u003e`.\n- `can_size`: implements `.size()` and `.empty()`\n- `can_const_iterate` implements `begin() const`, `end() const`, `cbegin() const` and `cend() const`.\n- `can_iterate` adds the `can_const_iterate` as well implementing `begin()`, `end()`.\n- `can_const_index` implements `operator[](const auto\u0026) const` and `at(const auto\u0026) const`\n- `can_index` adds the `can_const_index` as well implementing `operator[](const auto\u0026)` and `at(const auto\u0026)`.\n- `can_increment` adds both `operator++` operators.\n- `can_decrement` adds both `operator--` operators.\n\n### Third Party Library extensions (see `stronk/extensions/\u003clibrary\u003e.hpp`)\n\n- `can_absl_hash`: implements the `AbslHashValue` friend function.\n- `can_gtest_print`: for printing the values in gtest check macros\n- `can_fmt_format`: implements `struct fmt::formatter\u003cT\u003e` with default formatting string `\"{}\"`. In the future we will add a `can_format` for `std::format`.\n- `can_fmt_format_builder\u003c\"fmt format string{}\"\u003e::skill`: implements `struct fmt::formatter\u003cT\u003e`. In the future we will add a `can_format_builder\u003c\"std format string\"\u003e` for `std::format`.\n\nAdding new skills is easy so feel free to add more.\n\n## Prefabs: (see `stronk/prefabs/\u003cprefab\u003e.hpp`)\n\nOften you might just need a group of skills for your specific types. For this you can use prefabs.\n\n- `stronk_arithmetic`: a stronk number with addition, subtraction, negation, equation and ordering skills.\n- `stronk_flag`: a stronk flag-like boolean with equal operators etc.\n- `stronk_string`: a stronk string with equation and size skills.\n- `stronk_vector`: a stronk std::vector with equation, indexing, iterating and size skills.\n\n## Examples\n\n### Specializers\n\nSpecialization of unit multiplication and division is possible\n\nBy default the units are generated with the `stronk_default_unit` type.\n\n```cpp :file=./examples/specializers_example.cpp:line_end=33\n#include \u003cconcepts\u003e\n#include \u003ccstdint\u003e\n\n#include \"stronk/unit.hpp\"\n#include \"stronk/utilities/ratio.hpp\"\n\n// Let's consider the following units:\nstruct meters_unit : twig::unit\u003cmeters_unit, twig::ratio\u003c1\u003e\u003e\n{\n};\n\nstruct seconds : twig::unit\u003cseconds, twig::ratio\u003c1\u003e\u003e\n{\n};\n\n// Let's say you want to use a custom defined stronk type for certain unit combinations.\n// Let's introduce our own `Speed` type:\nstruct meters_per_second_unit : twig::unit\u003ctwig::divided_dimensions_t\u003cmeters_unit, seconds\u003e, twig::ratio\u003c1\u003e\u003e\n{\n};\n// Notice we are using twig::divided_dimensions_t instead of the regular tag\n\n// To make it possible for stronk to find this type we need to specialize `unit_lookup`:\ntemplate\u003c\u003e\nstruct twig::unit_lookup\u003ctwig::divided_dimensions_t\u003cmeters_unit, seconds\u003e\u003e\n{\n    template\u003cscale_like ScaleT\u003e  // scale is to support kilo meters / second, or nano meters / second\n    using unit_t = twig::unit_scaled_or_base_t\u003cmeters_per_second_unit, ScaleT\u003e;\n};\n\n// Now the automatically generated stronk unit for seconds^2 is meters_per_second\n\n// The above of course also works for `multiplied_unit` and `unit_multiplied_resulting_unit_type`\n```\n\n# Using Stronk in Your Project\n\nThe project is CMake FetchContent ready and is available on [vcpkg](https://github.com/microsoft/vcpkg/tree/master/ports/stronk).\nAfter retrieving stronk, add the following to your CMakeLists.txt\n\n```cmake\nfind_package(stronk CONFIG REQUIRED)\ntarget_link_libraries(\n    project_target PRIVATE\n    twig::stronk\n)\n```\n\n# Requirements\n\nA c++20 compatible compiler and standard library with concepts support.\n\nWe depend on Boost's type_index package to get compile time generated ids for each type to be able to sort types for units (so we can compare types generated from different expressions).\n\nIn the extensions subfolder we have added skills for common third party libraries: `fmt`, `absl` and `gtest`. Using these also requires the relevant third party libraries to be installed.\n\n# Building and installing\n\nFor more information on how to build see the [BUILDING](BUILDING.md) and [HACKING](HACKING.md) documents.\n\n# Benchmarks\n\nStronk is a close to zero cost abstraction - performance varies per compiler and we get the best results when running with gcc-14. Unfortunately the performance with MSVC is quite bad. We are investigating the [issue](https://github.com/twig-energy/stronk/issues/24), and initial results points to padding of the stronk structures being the root cause. You can see benchmark results for all the tested platforms in the [Continuous Integration Workflow](https://github.com/twig-energy/stronk/actions/workflows/ci.yml).\n\nConstructing and copying the structs performs identically or very close to identically with just passing the raw types:\n\n| relative |               ns/op |                op/s |    err% |     total | Default Construction onto Reserved Vector\n|---------:|--------------------:|--------------------:|--------:|----------:|:------------------------------------------\n|   100.0% |                1.03 |      971,250,261.72 |    0.2% |      0.01 | `int8_t`\n| 8,295.8% |                0.01 |   80,572,627,783.49 |    0.5% |      0.01 | `stronk_int8_t`\n|   100.0% |                0.09 |   11,040,892,957.64 |    0.2% |      0.01 | `int64_t`\n|   100.0% |                0.09 |   11,038,636,780.71 |    0.7% |      0.01 | `stronk_int64_t`\n|   100.0% |                2.85 |      350,589,982.10 |    0.2% |      0.01 | `std::string`\n|   100.0% |                2.85 |      350,574,762.95 |    0.3% |      0.01 | `string_stronk_t`\n\n| relative |               ns/op |                op/s |    err% |     total | Random Construction onto Reserved Vector\n|---------:|--------------------:|--------------------:|--------:|----------:|:-----------------------------------------\n|   100.0% |                5.43 |      184,104,291.14 |    0.1% |      0.01 | `int8_t`\n|    99.9% |                5.44 |      183,908,984.32 |    0.2% |      0.01 | `stronk_int8_t`\n|   100.0% |               15.49 |       64,577,158.35 |    0.1% |      0.01 | `int64_t`\n|   100.2% |               15.46 |       64,690,083.71 |    0.1% |      0.01 | `stronk_int64_t`\n|   100.0% |              327.60 |        3,052,463.47 |    0.2% |      0.03 | `std::string`\n|   100.1% |              327.12 |        3,056,949.11 |    0.1% |      0.03 | `string_stronk_t`\n\n| relative |               ns/op |                op/s |    err% |     total | Copy Vector Benchmarks\n|---------:|--------------------:|--------------------:|--------:|----------:|:-----------------------\n|   100.0% |            2,692.52 |          371,399.69 |    0.1% |      0.01 | `int8_t`\n|    99.9% |            2,694.08 |          371,183.71 |    0.1% |      0.01 | `stronk_int8_t`\n|   100.0% |           22,820.28 |           43,820.67 |    0.0% |      0.01 | `int64_t`\n|   100.0% |           22,820.89 |           43,819.50 |    0.1% |      0.01 | `stronk_int64_t`\n|   100.0% |           38,859.33 |           25,733.84 |    0.0% |      0.01 | `std::string`\n|   100.0% |           38,858.08 |           25,734.68 |    0.1% |      0.01 | `string_stronk_t`\n\nCalling \"Skill\" functions (which internally calls unwrap) performs close to identically with calling the functions directly on the raw types. However they do not seem to vectorize as well. We will investigate this further:\n\n | relative |               ns/op |                op/s |    err% |     total | Add Units\n|---------:|--------------------:|--------------------:|--------:|----------:|:----------\n|   100.0% |                1.09 |      916,332,894.41 |    0.1% |      0.01 | `int8_t + int8_t`\n|    87.1% |                1.25 |      798,272,122.38 |    0.8% |      0.01 | `stronk_int8_t + stronk_int8_t`\n|   100.0% |                1.16 |      862,869,523.84 |    0.7% |      0.01 | `int64_t + int64_t`\n|   100.3% |                1.15 |      865,822,162.10 |    0.6% |      0.01 | `stronk_int64_t + stronk_int64_t`\n|   100.0% |                1.16 |      862,616,711.01 |    0.1% |      0.01 | `double + double`\n|    92.8% |                1.25 |      800,919,023.29 |    0.1% |      0.01 | `stronk_double_t + stronk_double_t`\n\n| relative |               ns/op |                op/s |    err% |     total | Add Units SIMD\n|---------:|--------------------:|--------------------:|--------:|----------:|:---------------\n|   100.0% |                0.44 |    2,287,932,879.20 |    0.0% |      0.01 | `int8_t + int8_t`\n|    74.6% |                0.59 |    1,706,867,474.60 |    0.3% |      0.01 | `stronk_int8_t + stronk_int8_t`\n|   100.0% |                0.48 |    2,099,685,191.96 |    0.1% |      0.01 | `int64_t + int64_t`\n|    80.4% |                0.59 |    1,688,152,161.26 |    0.3% |      0.01 | `stronk_int64_t + stronk_int64_t`\n|   100.0% |                0.48 |    2,098,557,402.52 |    0.2% |      0.01 | `double + double`\n|    80.5% |                0.59 |    1,688,464,046.79 |    0.5% |      0.01 | `stronk_double_t + stronk_double_t`\n\n| relative |               ns/op |                op/s |    err% |     total | Subtract Units\n|---------:|--------------------:|--------------------:|--------:|----------:|:---------------\n|   100.0% |                1.10 |      911,857,398.39 |    0.5% |      0.01 | `int8_t - int8_t`\n|    88.0% |                1.25 |      802,442,563.29 |    0.3% |      0.01 | `stronk_int8_t - stronk_int8_t`\n|   100.0% |                1.15 |      868,967,946.80 |    0.2% |      0.01 | `int64_t - int64_t`\n|    91.6% |                1.26 |      795,783,363.99 |    0.4% |      0.01 | `stronk_int64_t - stronk_int64_t`\n|   100.0% |                1.12 |      895,845,385.46 |    0.5% |      0.01 | `double - double`\n|   100.1% |                1.11 |      896,986,529.46 |    0.6% |      0.01 | `stronk_double_t - stronk_double_t`\n\n| relative |               ns/op |                op/s |    err% |     total | Subtract Units SIMD\u003c32\u003e\n|---------:|--------------------:|--------------------:|--------:|----------:|:------------------------\n|   100.0% |                0.44 |    2,286,730,699.43 |    0.1% |      0.01 | `int8_t - int8_t`\n|    72.2% |                0.61 |    1,650,848,041.63 |    1.1% |      0.01 | `stronk_int8_t - stronk_int8_t`\n|   100.0% |                0.48 |    2,100,719,829.61 |    0.1% |      0.01 | `int64_t - int64_t`\n|    79.6% |                0.60 |    1,672,551,917.24 |    1.2% |      0.01 | `stronk_int64_t - stronk_int64_t`\n|   100.0% |                0.48 |    2,099,642,983.50 |    0.1% |      0.01 | `double - double`\n|    64.5% |                0.74 |    1,353,800,720.87 |    0.1% |      0.01 | `stronk_double_t - stronk_double_t`\n\n| relative |               ns/op |                op/s |    err% |     total | multiply_units_benchmarks\n|---------:|--------------------:|--------------------:|--------:|----------:|:--------------------------\n|   100.0% |                1.09 |      916,520,627.28 |    0.1% |      0.01 | `int8_t * int8_t`\n|    87.8% |                1.24 |      804,790,654.47 |    0.1% |      0.01 | `stronk_int8_t * stronk_int8_t`\n|   100.0% |                1.16 |      862,928,718.45 |    0.1% |      0.01 | `int64_t * int64_t`\n|    99.9% |                1.16 |      861,813,820.72 |    0.2% |      0.01 | `stronk_int64_t * stronk_int64_t`\n|   100.0% |                1.16 |      858,926,098.98 |    0.4% |      0.01 | `double * double`\n|    93.2% |                1.25 |      800,786,710.38 |    0.1% |      0.01 | `stronk_double_t * stronk_double_t`\n|   100.0% |                1.19 |      840,043,478.81 |    0.0% |      0.01 | `int64_t * double`\n|   106.5% |                1.12 |      894,897,013.01 |    0.6% |      0.01 | `stronk_int64_t * stronk_double_t`\n|   100.0% |                1.16 |      861,931,672.36 |    0.2% |      0.01 | `double * int64_t`\n|    99.7% |                1.16 |      859,383,332.31 |    0.4% |      0.01 | `stronk_double_t * stronk_int64_t`\n\n| relative |               ns/op |                op/s |    err% |     total | Multiply Units SIMD\u003c32\u003e\n|---------:|--------------------:|--------------------:|--------:|----------:|:------------------------\n|   100.0% |                0.44 |    2,288,625,819.49 |    0.1% |      0.01 | `int8_t * int8_t`\n|    81.3% |                0.54 |    1,860,009,562.89 |    0.2% |      0.01 | `stronk_int8_t * stronk_int8_t`\n|   100.0% |                0.72 |    1,385,183,403.83 |    0.0% |      0.01 | `int64_t * int64_t`\n|    71.1% |                1.02 |      984,214,573.25 |   18.5% |      0.01 | :wavy_dash: `stronk_int64_t * stronk_int64_t` (Unstable with ~4.2 iters. Increase `minEpochIterations` to e.g. 42)\n|   100.0% |                0.48 |    2,081,315,559.21 |    0.1% |      0.01 | `double * double`\n|    65.8% |                0.73 |    1,370,350,188.36 |    0.1% |      0.01 | `stronk_double_t * stronk_double_t`\n|   100.0% |                0.68 |    1,471,204,960.36 |    0.0% |      0.01 | `int64_t * double`\n|    70.0% |                0.97 |    1,029,532,221.67 |    0.1% |      0.01 | `stronk_int64_t * stronk_double_t`\n|   100.0% |                0.69 |    1,450,343,025.31 |    0.0% |      0.01 | `double * int64_t`\n|    94.4% |                0.73 |    1,369,031,807.06 |    0.1% |      0.01 | `stronk_double_t * stronk_int64_t`\n\n| relative |               ns/op |                op/s |    err% |     total | Divide Units\n|---------:|--------------------:|--------------------:|--------:|----------:|:-------------\n|   100.0% |                1.86 |      537,192,235.15 |    0.0% |      0.01 | `int8_t / int8_t`\n|    99.9% |                1.86 |      536,831,459.66 |    0.1% |      0.01 | `stronk_int8_t / stronk_int8_t`\n|   100.0% |                2.17 |      460,169,894.52 |    0.0% |      0.01 | `int64_t / int64_t`\n|   100.0% |                2.17 |      459,965,857.97 |    0.1% |      0.01 | `stronk_int64_t / stronk_int64_t`\n|   100.0% |                1.51 |      661,496,984.93 |    0.7% |      0.01 | `double / double`\n|    99.0% |                1.53 |      654,687,651.01 |    0.6% |      0.01 | `stronk_double_t / stronk_double_t`\n|   100.0% |                1.40 |      714,490,949.89 |    0.1% |      0.01 | `int64_t / double`\n|    99.5% |                1.41 |      710,694,688.44 |    0.1% |      0.01 | `stronk_int64_t / stronk_double_t`\n|   100.0% |                1.40 |      714,343,241.16 |    0.1% |      0.01 | `double / int64_t`\n|    96.5% |                1.45 |      689,027,611.68 |    0.2% |      0.01 | `stronk_double_t / stronk_int64_t`\n\n| relative |               ns/op |                op/s |    err% |     total | Divide Units SIMD\u003c32\u003e\n|---------:|--------------------:|--------------------:|--------:|----------:|:----------------------\n|   100.0% |                1.86 |      536,658,952.74 |    0.0% |      0.01 | `int8_t / int8_t`\n|   100.0% |                1.86 |      536,775,339.42 |    0.0% |      0.01 | `stronk_int8_t / stronk_int8_t`\n|   100.0% |                2.17 |      460,430,842.80 |    0.0% |      0.01 | `int64_t / int64_t`\n|    99.9% |                2.17 |      459,776,996.18 |    0.2% |      0.01 | `stronk_int64_t / stronk_int64_t`\n|   100.0% |                0.70 |    1,428,834,603.13 |    0.1% |      0.01 | `double / double`\n|    99.9% |                0.70 |    1,427,596,443.77 |    0.1% |      0.01 | `stronk_double_t / stronk_double_t`\n|   100.0% |                1.47 |      678,021,847.72 |    0.1% |      0.01 | `int64_t / double`\n|   105.2% |                1.40 |      713,302,950.70 |    0.1% |      0.01 | `stronk_int64_t / stronk_double_t`\n|   100.0% |                1.40 |      714,783,656.04 |    0.1% |      0.01 | `double / int64_t`\n|   100.0% |                1.40 |      715,090,979.30 |    0.1% |      0.01 | `stronk_double_t / stronk_int64_t`\n\n# Licensing\n\nSee the [LICENSE](LICENSE) document.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftwig-energy%2Fstronk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftwig-energy%2Fstronk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftwig-energy%2Fstronk/lists"}