{"id":15036151,"url":"https://github.com/cathei/linqgen","last_synced_at":"2025-04-06T14:12:11.249Z","repository":{"id":65005446,"uuid":"554550663","full_name":"cathei/LinqGen","owner":"cathei","description":"Alloc-free and fast replacement for Linq, with code generation","archived":false,"fork":false,"pushed_at":"2024-07-07T08:20:57.000Z","size":2310,"stargazers_count":305,"open_issues_count":8,"forks_count":12,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-04-06T14:12:01.458Z","etag":null,"topics":["csharp","csharp-library","csharp-sourcegenerator","dotnet","linq","linq-to-objects","roslyn","roslyn-analyzer"],"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/cathei.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}},"created_at":"2022-10-20T02:00:18.000Z","updated_at":"2025-03-04T20:35:13.000Z","dependencies_parsed_at":"2023-10-24T10:28:35.096Z","dependency_job_id":"26d3c613-d996-4725-a20b-75a4718cf1b7","html_url":"https://github.com/cathei/LinqGen","commit_stats":null,"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cathei%2FLinqGen","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cathei%2FLinqGen/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cathei%2FLinqGen/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cathei%2FLinqGen/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cathei","download_url":"https://codeload.github.com/cathei/LinqGen/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247492557,"owners_count":20947545,"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":["csharp","csharp-library","csharp-sourcegenerator","dotnet","linq","linq-to-objects","roslyn","roslyn-analyzer"],"created_at":"2024-09-24T20:30:19.072Z","updated_at":"2025-04-06T14:12:11.225Z","avatar_url":"https://github.com/cathei.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# LinqGen ⚡\n[![Nuget](https://img.shields.io/nuget/v/LinqGen)](https://www.nuget.org/packages?q=LinqGen)\n[![openupm](https://img.shields.io/npm/v/com.cathei.linqgen?label=openupm\u0026registry_uri=https://package.openupm.com)](https://openupm.com/packages/com.cathei.linqgen/)\n[![Discord](https://img.shields.io/discord/942240862354702376?color=%235865F2\u0026label=discord\u0026logo=discord\u0026logoColor=%23FFFFFF)](https://discord.gg/kpuRTkpeQC)\n\n## Linq meets Source Generator\n\nLinqGen is project to optimize Linq queries using source generation of user code.\n\nIt aims to make allocation-free, specialized Linq queries per your type.\n\n## Install\nInstall from NuGet, both [LinqGen](https://www.nuget.org/packages/LinqGen) as library and [LinqGen.Generator](https://www.nuget.org/packages/LinqGen.Generator) as incremental source generator.\n\n```xml\n\u003cItemGroup\u003e\n    \u003cPackageReference Include=\"LinqGen\" Version=\"0.3.1\" /\u003e\n    \u003cPackageReference Include=\"LinqGen.Generator\" Version=\"0.3.1\" /\u003e\n\u003c/ItemGroup\u003e\n```\n\nFor Unity, you can install as git package from Unity Package Manager.\n```\nhttps://github.com/cathei/LinqGen.git?path=LinqGen.Unity/Packages/com.cathei.linqgen\n```\nOr install via OpenUPM.\n```\nopenupm add com.cathei.linqgen\n```\n\n### Any questions?\n\nFeel free to make an issue, or ask me directly from [Discord](https://discord.gg/kpuRTkpeQC)!\n\n## Usage\nJust add `Gen()` in front of your Linq query.\nIt will generate code to ensure zero-allocation, may have slightly better performance.\n```csharp\nusing Cathei.LinqGen;\n \nint[] array = new int[] { 1, 2, 3, 4, 5 };\n\nint result = array.Gen()\n                  .Where(x =\u003e x % 2 == 0)\n                  .Select(x =\u003e x * 2)\n                  .Sum();\n```\n\nFor additional performance boost, use struct functions with `IStructFunction` interface.\n```csharp\nint result = array.Gen()\n                  .Where(new Predicate())\n                  .Select(new Selector())\n                  .Sum();\n```\n\nThis is benchmark result for above code. You can see full benchmark results [here](./docs/BenchmarksResults).\n\n|             Method |  Count |     Mean |   Error |  StdDev | Ratio | Allocated | Alloc Ratio |\n|------------------- |------- |---------:|--------:|--------:|------:|----------:|------------:|\n|            ForLoop | 100000 | 449.8 us | 4.56 us | 4.27 us |  0.50 |         - |       0.000 |\n|        ForEachLoop | 100000 | 444.3 us | 1.48 us | 1.39 us |  0.49 |         - |       0.000 |\n|               Linq | 100000 | 899.8 us | 5.65 us | 5.01 us |  1.00 |     105 B |       1.000 |\n|    LinqGenDelegate | 100000 | 576.2 us | 4.43 us | 4.14 us |  0.64 |       1 B |       0.010 |\n|      LinqGenStruct | 100000 | 449.8 us | 4.06 us | 3.60 us |  0.50 |         - |       0.000 |\n\n## Why not just use struct Linq implementations?\n\nBecause of [this issue](https://github.com/dotnet/runtime/discussions/77192),\nstruct linq implementations with many generics must do runtime lookup.\nWhich makes them not much faster than original Linq.\n\nAlso, they have to have bunch of type information and tricks for type inference.\nWhich makes your code hard to read and understand. The error messages or stack trace will be very messy as well.\n\nUsing source generation also makes your code friendly for AOT platforms, such as Unity,\nwhich has [maximum generic depth](https://forum.unity.com/threads/il2cpp-max-nested-generic-types.540534/).\n\nBeing source generator makes `LinqGen` core library much small than other struct linq implementations, though it may grow as user uses Linq operations.\n\n## How does LinqGen work?\n\nLinqGen has two part of assembly, `LinqGen` and `LinqGen.Generator`.\nThe `LinqGen` assembly contains a stub method and types, which helps you autocomplete and helps generator infer types.\n\nAfter you write a Linq query with stub methods, then `LinqGen.Generator` runs and replace the stub methods with generated methods.\n\nHow is it possible, while modifying user code is not allowed with source generators?\nIt's because everything `LinqGen.Generator` generates designed to be precede over stub methods on [overload resolution](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/expressions#11782-method-invocations).\n\n## Does LinqGen works with Unity Burst compiler?\n\n**Yes!** LinqGen is aiming to support Unity Burst compiler. Below code is sample of using LinqGen in Burst-compiled job system.\n\n```csharp\n[BurstCompile(CompileSynchronously = true)]\npublic struct LinqGenSampleJob : IJob\n{\n    [ReadOnly]\n    public NativeArray\u003cint\u003e Input;\n\n    [WriteOnly]\n    public NativeArray\u003cint\u003e Output;\n\n    public void Execute()\n    {\n        int index = 0;\n\n        foreach (var item in Input.Gen()\n                     .Select(new Selector())\n                     .Order(new Comparer()))\n        {\n            Output[index++] = item;\n        }\n    }\n}\n\npublic struct Selector : IStructFunction\u003cint, int\u003e\n{\n    public int Invoke(int arg) =\u003e arg * 10;\n}\n\npublic struct Comparer : IComparer\u003cint\u003e\n{\n    public int Compare(int x, int y) =\u003e x - y;\n}\n```\n\n## Supported methods (working-in-progress)\n[List of Linq Operations](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/standard-query-operators-overview)\n\n### Generations\n* Empty\n* Range\n* Repeat\n\n### Operations\n* Select\n* Where\n* Cast, OfType\n* Skip, Take, TakeLast\n* SkipWhile, TakeWhile\n* Distinct\n* Order, OrderBy, OrderByDescending\n* ThenBy, ThenByDescending\n* GroupBy\n* Concat\n* Prepend, Append\n\n### Evaluations\n* GetEnumerator\n* ToArray, ToList\n* Any, All\n* First, FirstOrDefault\n* Last, LastOrDefault\n* Count\n* Aggregate\n* Sum\n  * Supports duck typing with `+` operator overload\n* Min, Max\n* MinBy, MaxBy\n\n### Etc\n* Gen\n    * Converts IEnumerable to LinqGen enumerable\n* AsEnumerable\n    * Converts LinqGen enumerable to IEnumerable\n* RemoveAll\n\n## Limitations\n* Element or key types that used with LinqGen must have at least `internal` accessibility.\n* Struct enumerable should implement `IStructEnumerable\u003c,\u003e` interface.\n* LinqGen queries should be treated as anonymous type, it cannot be used as return value or instance member. If you have these needs, use `AsEnumerable()` to convert.\n* LinqGen may not work well when `[InternalsVisibleTo]` is used while both assemblies are using LinqGen. It can be solved when [this language feature](https://github.com/dotnet/csharplang/issues/6794) is implemented.\n\n## Further readings\n* Jon Skeet's [Edulinq](https://codeblog.jonskeet.uk/category/edulinq/), reimplementing Linq-to-objects.\n* Article about [alloc-free Linq implementation and limitations](https://blog.devgenius.io/like-regular-linq-but-faster-and-without-allocations-is-it-possible-3d4724632e2a).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcathei%2Flinqgen","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcathei%2Flinqgen","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcathei%2Flinqgen/lists"}