├── .editorconfig ├── .github ├── dependabot.yml └── workflows │ ├── codeql.yml │ ├── create-release.yml │ └── dotnet.yml ├── .gitignore ├── CHANGELOG.md ├── Directory.Build.props ├── LICENSE ├── LinkDotNet.LinqSIMDExtensions.sln ├── README.md ├── src └── LinkDotNet.LinqSIMDExtensions │ ├── Average.cs │ ├── Contains.cs │ ├── LinkDotNet.LinqSIMDExtensions.csproj │ ├── Max.cs │ ├── Min.cs │ ├── SequenceEqual.cs │ ├── Sum.cs │ └── VectorHelper.cs └── tests ├── LinkDotNet.LinqSIMDExtensions.Benchmarks ├── AverageBenchmark.cs ├── ContainsBenchmark.cs ├── LinkDotNet.LinqSIMDExtensions.Benchmarks.csproj ├── MinBenchmark.cs ├── Program.cs ├── SequenceEqualBenchmark.cs └── SumBenchmark.cs └── LinkDotNet.LinqSIMDExtensions.Tests ├── AverageTests.cs ├── ContainsTests.cs ├── LinkDotNet.LinqSIMDExtensions.Tests.csproj ├── MaxTests.cs ├── MinTests.cs ├── SequenceEqualTests.cs └── SumTests.cs /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = tab 6 | tab_size = 4 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.cs] 12 | tab_size = 4 13 | 14 | [*.{xml,config,*proj,nuspec,props,resx,targets,yml,tasks}] 15 | tab_size = 2 16 | 17 | [*.{htm,html,js,jsm,ts,tsx,css,sass,scss,less,svg,vue}] 18 | tab_size = 2 19 | 20 | [*.json] 21 | tab_size = 2 22 | 23 | [*.{ps1,psm1}] 24 | tab_size = 4 25 | 26 | [*.sh] 27 | tab_size = 4 28 | end_of_line = lf 29 | 30 | [*.{yml,yaml}] 31 | indent_style = space 32 | tab_size = 2 33 | 34 | [*.md] 35 | trim_trailing_whitespace = false 36 | 37 | [*.{cmd,bat}] 38 | end_of_line = crlf 39 | 40 | [Makefile] 41 | indent_style = tab 42 | 43 | ########################################## 44 | # .NET Language Conventions 45 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions 46 | ########################################## 47 | 48 | # Default Severity for .NET Code Style 49 | # https://docs.microsoft.com/dotnet/fundamentals/code-analysis/configuration-options#scope 50 | dotnet_analyzer_diagnostic.severity = error 51 | 52 | # Misc preferences 53 | file_header_template = unset # IDE0073 54 | dotnet_sort_system_directives_first = true 55 | dotnet_separate_import_directive_groups = false 56 | 57 | # .NET Code Style Settings 58 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#net-code-style-settings 59 | [*.{cs,csx,cake}] 60 | # "this." and "Me." qualifiers 61 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#this-and-me 62 | dotnet_style_qualification_for_field = false 63 | dotnet_style_qualification_for_property = false 64 | dotnet_style_qualification_for_method = false 65 | dotnet_style_qualification_for_event = false 66 | 67 | # Language keywords instead of framework type names for type references 68 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#language-keywords 69 | dotnet_style_predefined_type_for_locals_parameters_members = true # IDE0049 70 | dotnet_style_predefined_type_for_member_access = true # IDE0049 71 | 72 | # Modifier preferences 73 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#normalize-modifiers 74 | dotnet_style_require_accessibility_modifiers = always # IDE0040 75 | csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async # IDE0036 76 | dotnet_style_readonly_field = true # IDE0044 77 | 78 | # Parentheses preferences 79 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#parentheses-preferences 80 | dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity # IDE0047 and IDE0048 81 | dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity # IDE0047 and IDE0048 82 | dotnet_style_parentheses_in_other_binary_operators = always_for_clarity # IDE0047 and IDE0048 83 | dotnet_style_parentheses_in_other_operators = always_for_clarity # IDE0047 and IDE0048 84 | 85 | # Expression-level preferences 86 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#expression-level-preferences 87 | dotnet_style_object_initializer = true # IDE0017 88 | dotnet_style_collection_initializer = true # IDE0028 89 | dotnet_style_explicit_tuple_names = true # IDE0033 90 | dotnet_style_prefer_inferred_tuple_names = true # IDE0037 91 | dotnet_style_prefer_inferred_anonymous_type_member_names = true # IDE0037 92 | dotnet_style_prefer_auto_properties = true # IDE0050 93 | dotnet_style_prefer_is_null_check_over_reference_equality_method = true # IDE0041 94 | dotnet_style_prefer_conditional_expression_over_assignment = true # IDE0045 95 | dotnet_style_prefer_conditional_expression_over_return = true # IDE0046 96 | dotnet_style_prefer_compound_assignment = true # IDE0054 and IDE0074 97 | dotnet_style_prefer_simplified_interpolation = true # IDE0071 98 | dotnet_style_prefer_simplified_boolean_expressions = true # IDE0075 99 | 100 | # Null-checking preferences 101 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#null-checking-preferences 102 | dotnet_style_coalesce_expression = true # IDE0029 and IDE0030 103 | dotnet_style_null_propagation = true # IDE0031 104 | 105 | # Parameter preferences 106 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#parameter-preferences 107 | dotnet_code_quality_unused_parameters = all # IDE0060 108 | 109 | # Suppression preferences 110 | dotnet_remove_unnecessary_suppression_exclusions = none # IDE0079 111 | 112 | # More style options (Undocumented) 113 | # https://github.com/MicrosoftDocs/visualstudio-docs/issues/3641 114 | dotnet_style_operator_placement_when_wrapping = end_of_line 115 | 116 | # C# Code Style Settings 117 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#c-code-style-settings 118 | [*.{cs,csx,cake}] 119 | # Implicit and explicit types 120 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#implicit-and-explicit-types 121 | csharp_style_var_for_built_in_types = true # IDE0007 and IDE0008 122 | csharp_style_var_when_type_is_apparent = true # IDE0007 and IDE0008 123 | csharp_style_var_elsewhere = true # IDE0007 and IDE0008 124 | 125 | # Expression-bodied members 126 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#expression-bodied-members 127 | csharp_style_expression_bodied_constructors = when_on_single_line # IDE0021 128 | csharp_style_expression_bodied_methods = true # IDE0022 129 | csharp_style_expression_bodied_operators = true # IDE0023 and IDE0024 130 | csharp_style_expression_bodied_properties = true # IDE0025 131 | csharp_style_expression_bodied_indexers = true # IDE0026 132 | csharp_style_expression_bodied_accessors = true # IDE0027 133 | csharp_style_expression_bodied_lambdas = true # IDE0053 134 | csharp_style_expression_bodied_local_functions = true # IDE0061 135 | 136 | # Pattern matching 137 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#pattern-matching 138 | csharp_style_pattern_matching_over_as_with_null_check = true # IDE0019 139 | csharp_style_pattern_matching_over_is_with_cast_check = true # IDE0020 140 | csharp_style_prefer_switch_expression = true:suggestion # IDE0066 141 | csharp_style_prefer_pattern_matching = true:silent # IDE0078 142 | csharp_style_prefer_not_pattern = true:suggestion # IDE0083 143 | 144 | # Inlined variable declarations 145 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#inlined-variable-declarations 146 | csharp_style_inlined_variable_declaration = true # IDE0018 147 | 148 | # Expression-level preferences 149 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#expression-level-preferences 150 | csharp_prefer_simple_default_expression = true # IDE0034 151 | 152 | # "Null" checking preferences 153 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#c-null-checking-preferences 154 | csharp_style_throw_expression = true # IDE0016 155 | csharp_style_conditional_delegate_call = true # IDE1005 156 | 157 | # Code block preferences 158 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#code-block-preferences 159 | csharp_prefer_braces = true # IDE0011 160 | 161 | # Unused value preferences 162 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#unused-value-preferences 163 | csharp_style_unused_value_expression_statement_preference = discard_variable # IDE0058 164 | csharp_style_unused_value_assignment_preference = discard_variable # IDE0059 165 | 166 | # Index and range preferences 167 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#index-and-range-preferences 168 | csharp_style_prefer_index_operator = true # IDE0056 169 | csharp_style_prefer_range_operator = true # IDE0057 170 | 171 | # Miscellaneous preferences 172 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#miscellaneous-preferences 173 | csharp_style_pattern_local_over_anonymous_function = true # IDE0039 174 | csharp_style_deconstructed_variable_declaration = true # IDE0042 175 | csharp_prefer_static_local_function = true # IDE0062 176 | csharp_prefer_simple_using_statement = true # IDE0063 177 | csharp_using_directive_placement = outside_namespace # IDE0065 178 | 179 | ########################################## 180 | # .NET Formatting Conventions 181 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-code-style-settings-reference#formatting-conventions 182 | ########################################## 183 | 184 | # Newline options 185 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#new-line-options 186 | csharp_new_line_before_open_brace = all 187 | csharp_new_line_before_else = true 188 | csharp_new_line_before_catch = true 189 | csharp_new_line_before_finally = true 190 | csharp_new_line_before_members_in_object_initializers = true 191 | csharp_new_line_before_members_in_anonymous_types = true 192 | csharp_new_line_between_query_expression_clauses = true 193 | 194 | # Indentation options 195 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#indentation-options 196 | csharp_indent_case_contents = true 197 | csharp_indent_switch_labels = true 198 | csharp_indent_labels = no_change 199 | csharp_indent_block_contents = true 200 | csharp_indent_braces = false 201 | csharp_indent_case_contents_when_block = false 202 | 203 | # Spacing options 204 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#spacing-options 205 | csharp_space_after_cast = false 206 | csharp_space_after_keywords_in_control_flow_statements = true 207 | csharp_space_between_parentheses = false 208 | csharp_space_before_colon_in_inheritance_clause = true 209 | csharp_space_after_colon_in_inheritance_clause = true 210 | csharp_space_around_binary_operators = before_and_after 211 | csharp_space_between_method_declaration_parameter_list_parentheses = false 212 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false 213 | csharp_space_between_method_declaration_name_and_open_parenthesis = false 214 | csharp_space_between_method_call_parameter_list_parentheses = false 215 | csharp_space_between_method_call_empty_parameter_list_parentheses = false 216 | csharp_space_between_method_call_name_and_opening_parenthesis = false 217 | csharp_space_after_comma = true 218 | csharp_space_before_comma = false 219 | csharp_space_after_dot = false 220 | csharp_space_before_dot = false 221 | csharp_space_after_semicolon_in_for_statement = true 222 | csharp_space_before_semicolon_in_for_statement = false 223 | csharp_space_around_declaration_statements = false 224 | csharp_space_before_open_square_brackets = false 225 | csharp_space_between_empty_square_brackets = false 226 | csharp_space_between_square_brackets = false 227 | 228 | # Wrapping options 229 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#wrap-options 230 | csharp_preserve_single_line_statements = false 231 | csharp_preserve_single_line_blocks = true 232 | csharp_style_namespace_declarations = file_scoped:warning 233 | 234 | ########################################## 235 | # .NET Naming Conventions 236 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-naming-conventions 237 | ########################################## 238 | 239 | [*.{cs,csx,cake}] 240 | 241 | ########################################## 242 | # Styles 243 | ########################################## 244 | 245 | # camel_case_style - Define the camelCase style 246 | dotnet_naming_style.camel_case_style.capitalization = camel_case 247 | # pascal_case_style - Define the PascalCase style 248 | dotnet_naming_style.pascal_case_style.capitalization = pascal_case 249 | # first_upper_style - The first character must start with an upper-case character 250 | dotnet_naming_style.first_upper_style.capitalization = first_word_upper 251 | # prefix_interface_with_i_style - Interfaces must be PascalCase and the first character of an interface must be an 'I' 252 | dotnet_naming_style.prefix_interface_with_i_style.capitalization = pascal_case 253 | dotnet_naming_style.prefix_interface_with_i_style.required_prefix = I 254 | # prefix_type_parameters_with_t_style - Generic Type Parameters must be PascalCase and the first character must be a 'T' 255 | dotnet_naming_style.prefix_type_parameters_with_t_style.capitalization = pascal_case 256 | dotnet_naming_style.prefix_type_parameters_with_t_style.required_prefix = T 257 | # disallowed_style - Anything that has this style applied is marked as disallowed 258 | dotnet_naming_style.disallowed_style.capitalization = pascal_case 259 | dotnet_naming_style.disallowed_style.required_prefix = 260 | dotnet_naming_style.disallowed_style.required_suffix = 261 | # internal_error_style - This style should never occur... if it does, it indicates a bug in file or in the parser using the file 262 | dotnet_naming_style.internal_error_style.capitalization = pascal_case 263 | dotnet_naming_style.internal_error_style.required_prefix = 264 | dotnet_naming_style.internal_error_style.required_suffix = 265 | 266 | ########################################## 267 | # .NET Design Guideline Field Naming Rules 268 | # Naming rules for fields follow the .NET Framework design guidelines 269 | # https://docs.microsoft.com/dotnet/standard/design-guidelines/index 270 | ########################################## 271 | 272 | # All public/protected/protected_internal constant fields must be PascalCase 273 | # https://docs.microsoft.com/dotnet/standard/design-guidelines/field 274 | dotnet_naming_symbols.public_protected_constant_fields_group.applicable_accessibilities = public, protected, protected_internal 275 | dotnet_naming_symbols.public_protected_constant_fields_group.required_modifiers = const 276 | dotnet_naming_symbols.public_protected_constant_fields_group.applicable_kinds = field 277 | dotnet_naming_rule.public_protected_constant_fields_must_be_pascal_case_rule.symbols = public_protected_constant_fields_group 278 | dotnet_naming_rule.public_protected_constant_fields_must_be_pascal_case_rule.style = pascal_case_style 279 | dotnet_naming_rule.public_protected_constant_fields_must_be_pascal_case_rule.severity = warning 280 | 281 | # All public/protected/protected_internal static readonly fields must be PascalCase 282 | # https://docs.microsoft.com/dotnet/standard/design-guidelines/field 283 | dotnet_naming_symbols.public_protected_static_readonly_fields_group.applicable_accessibilities = public, protected, protected_internal 284 | dotnet_naming_symbols.public_protected_static_readonly_fields_group.required_modifiers = static, readonly 285 | dotnet_naming_symbols.public_protected_static_readonly_fields_group.applicable_kinds = field 286 | dotnet_naming_rule.public_protected_static_readonly_fields_must_be_pascal_case_rule.symbols = public_protected_static_readonly_fields_group 287 | dotnet_naming_rule.public_protected_static_readonly_fields_must_be_pascal_case_rule.style = pascal_case_style 288 | dotnet_naming_rule.public_protected_static_readonly_fields_must_be_pascal_case_rule.severity = warning 289 | 290 | # No other public/protected/protected_internal fields are allowed 291 | # https://docs.microsoft.com/dotnet/standard/design-guidelines/field 292 | dotnet_naming_symbols.other_public_protected_fields_group.applicable_accessibilities = public, protected, protected_internal 293 | dotnet_naming_symbols.other_public_protected_fields_group.applicable_kinds = field 294 | dotnet_naming_rule.other_public_protected_fields_disallowed_rule.symbols = other_public_protected_fields_group 295 | dotnet_naming_rule.other_public_protected_fields_disallowed_rule.style = disallowed_style 296 | dotnet_naming_rule.other_public_protected_fields_disallowed_rule.severity = error 297 | 298 | ########################################## 299 | # StyleCop Field Naming Rules 300 | # Naming rules for fields follow the StyleCop analyzers 301 | # This does not override any rules using disallowed_style above 302 | # https://github.com/DotNetAnalyzers/StyleCopAnalyzers 303 | ########################################## 304 | 305 | # All constant fields must be PascalCase 306 | # https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1303.md 307 | dotnet_naming_symbols.stylecop_constant_fields_group.applicable_accessibilities = public, internal, protected_internal, protected, private_protected, private 308 | dotnet_naming_symbols.stylecop_constant_fields_group.required_modifiers = const 309 | dotnet_naming_symbols.stylecop_constant_fields_group.applicable_kinds = field 310 | dotnet_naming_rule.stylecop_constant_fields_must_be_pascal_case_rule.symbols = stylecop_constant_fields_group 311 | dotnet_naming_rule.stylecop_constant_fields_must_be_pascal_case_rule.style = pascal_case_style 312 | dotnet_naming_rule.stylecop_constant_fields_must_be_pascal_case_rule.severity = warning 313 | 314 | # All static readonly fields must be PascalCase 315 | # https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1311.md 316 | dotnet_naming_symbols.stylecop_static_readonly_fields_group.applicable_accessibilities = public, internal, protected_internal, protected, private_protected, private 317 | dotnet_naming_symbols.stylecop_static_readonly_fields_group.required_modifiers = static, readonly 318 | dotnet_naming_symbols.stylecop_static_readonly_fields_group.applicable_kinds = field 319 | dotnet_naming_rule.stylecop_static_readonly_fields_must_be_pascal_case_rule.symbols = stylecop_static_readonly_fields_group 320 | dotnet_naming_rule.stylecop_static_readonly_fields_must_be_pascal_case_rule.style = pascal_case_style 321 | dotnet_naming_rule.stylecop_static_readonly_fields_must_be_pascal_case_rule.severity = warning 322 | 323 | # No non-private instance fields are allowed 324 | # https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1401.md 325 | dotnet_naming_symbols.stylecop_fields_must_be_private_group.applicable_accessibilities = public, internal, protected_internal, protected, private_protected 326 | dotnet_naming_symbols.stylecop_fields_must_be_private_group.applicable_kinds = field 327 | dotnet_naming_rule.stylecop_instance_fields_must_be_private_rule.symbols = stylecop_fields_must_be_private_group 328 | dotnet_naming_rule.stylecop_instance_fields_must_be_private_rule.style = disallowed_style 329 | dotnet_naming_rule.stylecop_instance_fields_must_be_private_rule.severity = error 330 | 331 | # Private fields must be camelCase 332 | # https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1306.md 333 | dotnet_naming_symbols.stylecop_private_fields_group.applicable_accessibilities = private 334 | dotnet_naming_symbols.stylecop_private_fields_group.applicable_kinds = field 335 | dotnet_naming_rule.stylecop_private_fields_must_be_camel_case_rule.symbols = stylecop_private_fields_group 336 | dotnet_naming_rule.stylecop_private_fields_must_be_camel_case_rule.style = camel_case_style 337 | dotnet_naming_rule.stylecop_private_fields_must_be_camel_case_rule.severity = warning 338 | 339 | # Local variables must be camelCase 340 | # https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1312.md 341 | dotnet_naming_symbols.stylecop_local_fields_group.applicable_accessibilities = local 342 | dotnet_naming_symbols.stylecop_local_fields_group.applicable_kinds = local 343 | dotnet_naming_rule.stylecop_local_fields_must_be_camel_case_rule.symbols = stylecop_local_fields_group 344 | dotnet_naming_rule.stylecop_local_fields_must_be_camel_case_rule.style = camel_case_style 345 | dotnet_naming_rule.stylecop_local_fields_must_be_camel_case_rule.severity = silent 346 | 347 | # This rule should never fire. However, it's included for at least two purposes: 348 | # First, it helps to understand, reason about, and root-case certain types of issues, such as bugs in .editorconfig parsers. 349 | # Second, it helps to raise immediate awareness if a new field type is added (as occurred recently in C#). 350 | dotnet_naming_symbols.sanity_check_uncovered_field_case_group.applicable_accessibilities = * 351 | dotnet_naming_symbols.sanity_check_uncovered_field_case_group.applicable_kinds = field 352 | dotnet_naming_rule.sanity_check_uncovered_field_case_rule.symbols = sanity_check_uncovered_field_case_group 353 | dotnet_naming_rule.sanity_check_uncovered_field_case_rule.style = internal_error_style 354 | dotnet_naming_rule.sanity_check_uncovered_field_case_rule.severity = error 355 | 356 | ########################################## 357 | # Other Naming Rules 358 | ########################################## 359 | 360 | # All of the following must be PascalCase: 361 | # - Namespaces 362 | # https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-namespaces 363 | # https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1300.md 364 | # - Classes and Enumerations 365 | # https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces 366 | # https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1300.md 367 | # - Delegates 368 | # https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces#names-of-common-types 369 | # - Constructors, Properties, Events, Methods 370 | # https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-type-members 371 | dotnet_naming_symbols.element_group.applicable_kinds = namespace, class, enum, struct, delegate, event, method, property 372 | dotnet_naming_rule.element_rule.symbols = element_group 373 | dotnet_naming_rule.element_rule.style = pascal_case_style 374 | dotnet_naming_rule.element_rule.severity = warning 375 | 376 | # Interfaces use PascalCase and are prefixed with uppercase 'I' 377 | # https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces 378 | dotnet_naming_symbols.interface_group.applicable_kinds = interface 379 | dotnet_naming_rule.interface_rule.symbols = interface_group 380 | dotnet_naming_rule.interface_rule.style = prefix_interface_with_i_style 381 | dotnet_naming_rule.interface_rule.severity = warning 382 | 383 | # Generics Type Parameters use PascalCase and are prefixed with uppercase 'T' 384 | # https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces 385 | dotnet_naming_symbols.type_parameter_group.applicable_kinds = type_parameter 386 | dotnet_naming_rule.type_parameter_rule.symbols = type_parameter_group 387 | dotnet_naming_rule.type_parameter_rule.style = prefix_type_parameters_with_t_style 388 | dotnet_naming_rule.type_parameter_rule.severity = warning 389 | 390 | # Function parameters use camelCase 391 | # https://docs.microsoft.com/dotnet/standard/design-guidelines/naming-parameters 392 | dotnet_naming_symbols.parameters_group.applicable_kinds = parameter 393 | dotnet_naming_rule.parameters_rule.symbols = parameters_group 394 | dotnet_naming_rule.parameters_rule.style = camel_case_style 395 | dotnet_naming_rule.parameters_rule.severity = warning 396 | 397 | ########################################## 398 | 399 | 400 | ########################################## 401 | # Code Analyzers Rules 402 | ########################################## 403 | 404 | # AsyncFixer 405 | # http://www.asyncfixer.com 406 | 407 | 408 | # Meziantou 409 | # https://www.meziantou.net/enforcing-asynchronous-code-good-practices-using-a-roslyn-analyzer.htm 410 | dotnet_diagnostic.MA0003.severity = suggestion # https://github.com/atc-net/atc-coding-rules/blob/main/documentation/CodeAnalyzersRules/Meziantou/MA0003.md 411 | dotnet_diagnostic.MA0004.severity = suggestion # https://github.com/atc-net/atc-coding-rules/blob/main/documentation/CodeAnalyzersRules/Meziantou/MA0004.md 412 | dotnet_diagnostic.MA0016.severity = error # https://github.com/atc-net/atc-coding-rules/blob/main/documentation/CodeAnalyzersRules/Meziantou/MA0016.md 413 | dotnet_diagnostic.MA0025.severity = suggestion # https://github.com/atc-net/atc-coding-rules/blob/main/documentation/CodeAnalyzersRules/Meziantou/MA0025.md 414 | dotnet_diagnostic.MA0026.severity = suggestion # https://github.com/atc-net/atc-coding-rules/blob/main/documentation/CodeAnalyzersRules/Meziantou/MA0026.md 415 | dotnet_diagnostic.MA0028.severity = none # https://github.com/atc-net/atc-coding-rules/blob/main/documentation/CodeAnalyzersRules/Meziantou/MA0028.md 416 | 417 | 418 | # Microsoft - Code Analysis 419 | # https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ 420 | dotnet_diagnostic.CA1707.severity = error # https://github.com/atc-net/atc-coding-rules/blob/main/documentation/CodeAnalyzersRules/MicrosoftCodeAnalysis/CA1707.md 421 | dotnet_diagnostic.CA2007.severity = suggestion # https://github.com/atc-net/atc-coding-rules/blob/main/documentation/CodeAnalyzersRules/MicrosoftCodeAnalysis/CA2007.md 422 | 423 | 424 | # SonarAnalyzer.CSharp 425 | # https://rules.sonarsource.com/csharp 426 | dotnet_diagnostic.S1135.severity = suggestion # https://github.com/atc-net/atc-coding-rules/blob/main/documentation/CodeAnalyzersRules/SonarAnalyzerCSharp/S1135.md 427 | 428 | ########################################## 429 | # Custom - Code Analyzers Rules 430 | ########################################## 431 | 432 | # Visual Studio 433 | dotnet_diagnostic.IDE0079.severity = warning # IDE0079: Remove unnecessary suppression 434 | 435 | # AsyncFixer 436 | 437 | # Meziantou 438 | dotnet_diagnostic.MA0004.severity = none # MA0004: Use .ConfigureAwait(false) 439 | dotnet_diagnostic.MA0012.severity = none # MA0012: Do not raise reserved exception type 440 | dotnet_diagnostic.MA0015.severity = suggestion # MA0015: Specify the parameter name 441 | dotnet_diagnostic.MA0018.severity = none # MA0018: Do not declare static members on generic types - same as CA1000 442 | 443 | # Microsoft - Code Analysis 444 | # https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ 445 | dotnet_diagnostic.CA1014.severity = none # CA1014: Mark assemblies with CLSCompliant 446 | dotnet_diagnostic.CA1031.severity = suggestion # CA1031: Do not catch general exception types 447 | dotnet_diagnostic.CA1032.severity = none # CA1032: Implement standard exception constructors 448 | dotnet_diagnostic.CA2201.severity = suggestion # CA2201: Do not raise reserved exception types 449 | 450 | # SonarAnalyzer.CSharp 451 | # https://rules.sonarsource.com/csharp 452 | dotnet_diagnostic.S112.severity = none # S112: General exceptions should never be thrown 453 | dotnet_diagnostic.S101.severity = none # S101: Types should be named in PascalCase 454 | dotnet_diagnostic.S1075.severity = suggestion # S1075: URIs should not be hardcoded 455 | dotnet_diagnostic.S1186.severity = suggestion # S1186: Methods should not be empty 456 | dotnet_diagnostic.S2292.severity = suggestion # S2292: Trivial properties should be auto-implemented 457 | dotnet_diagnostic.S3267.severity = none # S3267: Loops should be simplified with "LINQ" expressions 458 | dotnet_diagnostic.S4158.severity = none # BUGGY with C#9 code - doesnt understand local methods 459 | 460 | ########################################## 461 | # Custom Test Code Analyzers Rules 462 | ########################################## 463 | [tests/**.cs] 464 | 465 | # Visual Studio 466 | csharp_style_pattern_local_over_anonymous_function = false # IDE0039: Use local function 467 | 468 | # AsyncFixer 469 | # http://www.asyncfixer.com 470 | dotnet_diagnostic.AsyncFixer01.severity = none # AsyncFixer01: Unnecessary async/await usage 471 | 472 | # Meziantou 473 | # https://www.meziantou.net/enforcing-asynchronous-code-good-practices-using-a-roslyn-analyzer.htm 474 | dotnet_diagnostic.MA0006.severity = suggestion # MA0006: use String.Equals 475 | dotnet_diagnostic.MA0007.severity = none # MA0007: Add a comma after the last value 476 | dotnet_diagnostic.MA0048.severity = silent # MA0048: File name must match type name 477 | 478 | # Microsoft - Code Analysis 479 | # https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ 480 | dotnet_diagnostic.CA1054.severity = none # CA1054: URI-like parameters should not be strings 481 | dotnet_diagnostic.CA1062.severity = none # CA1062: Validate arguments of public methods 482 | dotnet_diagnostic.CA1707.severity = none # CA1707: Identifiers should not contain underscores 483 | dotnet_diagnostic.CA1812.severity = none # CA1812: Avoid uninstantiated internal classes - components under test are never instantiated directly. 484 | dotnet_diagnostic.CA1822.severity = suggestion # CA1822: Mark members as static 485 | dotnet_diagnostic.CA2007.severity = none # CA2007: Consider calling ConfigureAwait on the awaited task 486 | 487 | # Microsoft - FxCop 488 | # https://github.com/dotnet/roslyn-analyzers 489 | dotnet_diagnostic.CA1031.severity = none # CA1031: Do not catch general exception types 490 | dotnet_diagnostic.CA2012.severity = none # CA2012: Use ValueTasks correctly 491 | dotnet_diagnostic.CA2201.severity = none # CA2201: Do not raise reserved exception types 492 | 493 | # SonarAnalyzer.CSharp 494 | # https://rules.sonarsource.com/csharp 495 | dotnet_diagnostic.S125.severity = none # S125: Sections of code should not be commented out 496 | dotnet_diagnostic.S3459.severity = none # S3459: Unassigned members should be removed 497 | dotnet_diagnostic.S3871.severity = none # S3871: Exception types should be "public" 498 | dotnet_diagnostic.S1186.severity = none # S1186: Methods should not be empty 499 | dotnet_diagnostic.S1133.severity = none # S1133: Deprecated code should be removed 500 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "nuget" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "monthly" 12 | 13 | - package-ecosystem: "github-actions" 14 | directory: "/" 15 | schedule: 16 | interval: "monthly" 17 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: 4 | schedule: 5 | # ┌───────────── minute (0 - 59) 6 | # │ ┌───────────── hour (0 - 23) 7 | # │ │ ┌───────────── day of the month (1 - 31) 8 | # │ │ │ ┌───────────── month (1 - 12 or JAN-DEC) 9 | # │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT) 10 | # │ │ │ │ │ 11 | # │ │ │ │ │ 12 | # │ │ │ │ │ 13 | # * * * * * 14 | - cron: '30 1 * * 0' 15 | 16 | jobs: 17 | CodeQL-Build: 18 | runs-on: ubuntu-latest 19 | 20 | permissions: 21 | security-events: write 22 | 23 | steps: 24 | - name: Checkout repository 25 | uses: actions/checkout@v4 26 | 27 | - uses: actions/setup-dotnet@v4 28 | with: 29 | dotnet-version: | 30 | 7.0.x 31 | 8.0.x 32 | 33 | - name: Initialize CodeQL 34 | uses: github/codeql-action/init@v3 35 | 36 | - name: Autobuild 37 | uses: github/codeql-action/autobuild@v3 38 | 39 | - name: Perform CodeQL Analysis 40 | uses: github/codeql-action/analyze@v3 41 | -------------------------------------------------------------------------------- /.github/workflows/create-release.yml: -------------------------------------------------------------------------------- 1 | name: Create new Release 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | versionIncrement: 7 | description: 'The new version. For example: 1.1.0' 8 | required: true 9 | default: '' 10 | prerelease: 11 | description: 'Is this a pre-release?' 12 | type: boolean 13 | required: false 14 | default: false 15 | 16 | jobs: 17 | release: 18 | name: Publish new release 19 | runs-on: ubuntu-latest 20 | steps: 21 | 22 | - name: Checkout repository 23 | uses: actions/checkout@v4 24 | with: 25 | token: ${{ secrets.PAT }} 26 | persist-credentials: true 27 | fetch-depth: 0 28 | 29 | - name: Get changelog entries 30 | id: changelog 31 | uses: mindsers/changelog-reader-action@v2 32 | with: 33 | version: Unreleased 34 | path: ./CHANGELOG.md 35 | 36 | - name: Setup dotnet 37 | uses: actions/setup-dotnet@v4 38 | with: 39 | dotnet-version: | 40 | 7.0.x 41 | 8.0.x 42 | 43 | - name: Update CHANGELOG file 44 | uses: thomaseizinger/keep-a-changelog-new-release@3.1.0 45 | with: 46 | version: ${{ github.event.inputs.versionIncrement }} 47 | 48 | - name: Set git config 49 | run: | 50 | git config --local user.email "linkdotnet@action.com" 51 | git config --local user.name "LinkDotNet Bot" 52 | 53 | - name: Commit changes and push changes 54 | run: | 55 | git add CHANGELOG.md 56 | git commit -m "Update Changelog.md for ${{github.event.inputs.versionIncrement}} release" 57 | git push origin main 58 | 59 | - name: Create release on GitHub 60 | uses: thomaseizinger/create-release@2.0.0 61 | env: 62 | GITHUB_TOKEN: ${{ secrets.PAT }} 63 | with: 64 | tag_name: v${{ github.event.inputs.versionIncrement }} 65 | target_commitish: ${{ env.RELEASE_COMMIT_HASH }} 66 | name: v${{ github.event.inputs.versionIncrement }} 67 | body: ${{ steps.changelog.outputs.changes }} 68 | draft: false 69 | prerelease: ${{ github.event.inputs.prerelease }} 70 | 71 | - name: Create release package 72 | run: | 73 | dotnet pack -c RELEASE -p:PackageVersion=${{ github.event.inputs.versionIncrement }} --property:PackageOutputPath=${GITHUB_WORKSPACE}/packages /p:ContinuousIntegrationBuild=true --nologo 74 | 75 | - name: Upload to nuget 76 | run: | 77 | dotnet nuget push ${GITHUB_WORKSPACE}/packages/*.nupkg -k ${{ secrets.NUGET_API_KEY }} -s https://api.nuget.org/v3/index.json --skip-duplicate 78 | 79 | -------------------------------------------------------------------------------- /.github/workflows/dotnet.yml: -------------------------------------------------------------------------------- 1 | name: .NET 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v4 16 | - name: Setup .NET 17 | uses: actions/setup-dotnet@v4 18 | with: 19 | dotnet-version: | 20 | 7.0.x 21 | 8.0.x 22 | - name: Setup color 23 | run: | 24 | echo "DOTNET_SYSTEM_CONSOLE_ALLOW_ANSI_COLOR_REDIRECTION=1" >> $GITHUB_ENV 25 | echo "TERM=xterm" >> $GITHUB_ENV 26 | - name: Restore dependencies 27 | run: dotnet restore 28 | - name: Build 29 | run: dotnet build --no-restore -c Release /p:ContinuousIntegrationBuild=true 30 | - name: Test 31 | run: dotnet test -c Release --no-build 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | obj/ 3 | /packages/ 4 | riderModule.iml 5 | /_ReSharper.Caches/ 6 | 7 | appsettings.Development.json 8 | appsettings.Production.json 9 | 10 | *.[Pp]ublish.xml 11 | *.azurePubxml 12 | *.pubxml 13 | *.pubxml.user 14 | *.publishproj 15 | *.suo 16 | sitemap.xml 17 | robots.txt 18 | .vs/ 19 | .idea/ 20 | *.csproj.user 21 | *.dotsettings.user 22 | 23 | # Coverage files and reports 24 | /**/TestResults/* 25 | /**/coverage*.xml 26 | /CoverageReport/ 27 | 28 | # MacOS 29 | .DS_Store -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to **ValueStringBuilder** will be documented in this file. The project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 4 | 5 | 6 | 7 | ## [Unreleased] 8 | 9 | ## [1.5.0] - 2024-01-08 10 | 11 | ### Added 12 | 13 | - `Average` can return more specific return types to enable scenarios where the input is an `integer` but the result should be a `double`. 14 | 15 | ### Changed 16 | 17 | - `Min`, `Max`, `Average` will throw an `InvalidOperationException` when the input is empty. This is to be consistent with the behavior of the **LINQ** versions of these methods. 18 | 19 | ## [1.4.1] - 2024-01-07 20 | 21 | ### Fixed 22 | 23 | - `Min` and `Max` did return wrong values for longer lists. 24 | 25 | ## [1.4.0] - 2023-07-23 26 | 27 | ### Added 28 | 29 | - Support for `net7.0` and `net8.0` 30 | 31 | ## [1.3.0] - 2023-05-07 32 | 33 | ### Changed 34 | 35 | - `Sum` uses a better implementation that reduces 33% of the time needed to calculate. This has direct performance improvements on `Average` as well. 36 | - `Min`, `Max` also have a better runtime (also 33% faster) thanks to a better algorithm. 37 | 38 | ## [1.2.2] - 2023-04-12 39 | 40 | ### Added 41 | 42 | - Smaller improvement in `Sum` 43 | 44 | ## [1.2.1] - 2023-04-10 45 | 46 | ## [1.2.0] - 2023-04-04 47 | 48 | ### Added 49 | 50 | - New `Contains` method to check if an collection contains a specific value. 51 | 52 | ## [1.1.0] - 2023-04-04 53 | 54 | ### Added 55 | 56 | - Overloads for all functions that expects a `Memory` object. 57 | 58 | ## [1.0.0] - 2023-04-01 59 | 60 | This is the initial release! 61 | 62 | ### Added 63 | 64 | - Added `Min`, `Max`, `Sum`, `SequenceEqual` and `Average` 65 | 66 | [Unreleased]: https://github.com/linkdotnet/LinqSIMDExtensions/compare/1.5.0...HEAD 67 | 68 | [1.5.0]: https://github.com/linkdotnet/LinqSIMDExtensions/compare/1.4.1...1.5.0 69 | 70 | [1.4.1]: https://github.com/linkdotnet/LinqSIMDExtensions/compare/1.4.0...1.4.1 71 | 72 | [1.4.0]: https://github.com/linkdotnet/LinqSIMDExtensions/compare/1.3.0...1.4.0 73 | 74 | [1.3.0]: https://github.com/linkdotnet/LinqSIMDExtensions/compare/1.2.2...1.3.0 75 | 76 | [1.2.2]: https://github.com/linkdotnet/LinqSIMDExtensions/compare/1.2.1...1.2.2 77 | 78 | [1.2.1]: https://github.com/linkdotnet/LinqSIMDExtensions/compare/1.2.0...1.2.1 79 | 80 | [1.2.0]: https://github.com/linkdotnet/LinqSIMDExtensions/compare/1.1.0...1.2.0 81 | 82 | [1.1.0]: https://github.com/linkdotnet/LinqSIMDExtensions/compare/1.0.0...1.1.0 83 | 84 | [1.0.0]: https://github.com/linkdotnet/LinqSIMDExtensions/compare/e70becb4068b55fd771e09975d6b223076ce6d2c...1.0.0 85 | -------------------------------------------------------------------------------- /Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | all 6 | runtime; build; native; contentfiles; analyzers; buildtransitive 7 | 8 | 9 | 10 | 11 | 5 12 | true 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Steven Giesel 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LinkDotNet.LinqSIMDExtensions.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.0.31903.59 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LinkDotNet.LinqSIMDExtensions", "src\LinkDotNet.LinqSIMDExtensions\LinkDotNet.LinqSIMDExtensions.csproj", "{BF0BFA64-3B97-4D22-BA0D-39CC2DEDA30A}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{590AFBE7-652B-4C97-8F64-A2528282E9BD}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{44C99A55-12E2-47CA-98F8-9B54C7D267AE}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LinkDotNet.LinqSIMDExtensions.Tests", "tests\LinkDotNet.LinqSIMDExtensions.Tests\LinkDotNet.LinqSIMDExtensions.Tests.csproj", "{ACBFC08F-F088-4E81-BF64-DCCC14DCD092}" 13 | EndProject 14 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".text", ".text", "{8513963A-4592-4DEF-BC56-004EEA5B48FA}" 15 | ProjectSection(SolutionItems) = preProject 16 | CHANGELOG.md = CHANGELOG.md 17 | README.md = README.md 18 | .editorconfig = .editorconfig 19 | EndProjectSection 20 | EndProject 21 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LinkDotNet.LinqSIMDExtensions.Benchmarks", "tests\LinkDotNet.LinqSIMDExtensions.Benchmarks\LinkDotNet.LinqSIMDExtensions.Benchmarks.csproj", "{71B0E9C3-96BA-416B-A924-CF6ECB1F2E37}" 22 | EndProject 23 | Global 24 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 25 | Debug|Any CPU = Debug|Any CPU 26 | Release|Any CPU = Release|Any CPU 27 | EndGlobalSection 28 | GlobalSection(SolutionProperties) = preSolution 29 | HideSolutionNode = FALSE 30 | EndGlobalSection 31 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 32 | {BF0BFA64-3B97-4D22-BA0D-39CC2DEDA30A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {BF0BFA64-3B97-4D22-BA0D-39CC2DEDA30A}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {BF0BFA64-3B97-4D22-BA0D-39CC2DEDA30A}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {BF0BFA64-3B97-4D22-BA0D-39CC2DEDA30A}.Release|Any CPU.Build.0 = Release|Any CPU 36 | {ACBFC08F-F088-4E81-BF64-DCCC14DCD092}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 37 | {ACBFC08F-F088-4E81-BF64-DCCC14DCD092}.Debug|Any CPU.Build.0 = Debug|Any CPU 38 | {ACBFC08F-F088-4E81-BF64-DCCC14DCD092}.Release|Any CPU.ActiveCfg = Release|Any CPU 39 | {ACBFC08F-F088-4E81-BF64-DCCC14DCD092}.Release|Any CPU.Build.0 = Release|Any CPU 40 | {71B0E9C3-96BA-416B-A924-CF6ECB1F2E37}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 41 | {71B0E9C3-96BA-416B-A924-CF6ECB1F2E37}.Debug|Any CPU.Build.0 = Debug|Any CPU 42 | {71B0E9C3-96BA-416B-A924-CF6ECB1F2E37}.Release|Any CPU.ActiveCfg = Release|Any CPU 43 | {71B0E9C3-96BA-416B-A924-CF6ECB1F2E37}.Release|Any CPU.Build.0 = Release|Any CPU 44 | EndGlobalSection 45 | GlobalSection(NestedProjects) = preSolution 46 | {BF0BFA64-3B97-4D22-BA0D-39CC2DEDA30A} = {590AFBE7-652B-4C97-8F64-A2528282E9BD} 47 | {ACBFC08F-F088-4E81-BF64-DCCC14DCD092} = {44C99A55-12E2-47CA-98F8-9B54C7D267AE} 48 | {71B0E9C3-96BA-416B-A924-CF6ECB1F2E37} = {44C99A55-12E2-47CA-98F8-9B54C7D267AE} 49 | EndGlobalSection 50 | EndGlobal 51 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LinqSIMDExtensions 2 | 3 | [![.NET](https://github.com/linkdotnet/LinqSIMDExtensions/actions/workflows/dotnet.yml/badge.svg)](https://github.com/linkdotnet/LinqSIMDExtensions/actions/workflows/dotnet.yml) 4 | [![Nuget](https://img.shields.io/nuget/dt/LinkDotNet.LinqSIMDExtensions)](https://www.nuget.org/packages/LinkDotNet.LinqSIMDExtensions/) 5 | [![GitHub tag](https://img.shields.io/github/v/tag/linkdotnet/LinqSIMDExtensions?include_prereleases&logo=github&style=flat-square)](https://github.com/linkdotnet/LinqSIMDExtensions/releases) 6 | 7 | LinqSIMDExtensions is a high-performance library that combines the power of SIMD (Single Instruction, Multiple Data) and the elegance of LINQ (Language Integrated Query) syntax. SIMD uses features like AVX, SSE, NEON, etc. to process multiple data in parallel. The performance depends on the hardware and the data type. Some extensions like AVX-512 are only available on x86/x64 architectures. 8 | 9 | LinqSIMDExtensions leverages the generic math features introduced in .NET 7 to provide a wide range of data type support. 10 | With LinkDotNet.LinqSIMDExtensions, you can efficiently process large datasets in parallel, improving the performance of your applications. 11 | 12 | Using this library for small datasets is not recommended as the overhead of the SIMD operations is not worth it. 13 | 14 | ## Features 15 | * Leverage SIMD operations for fast and parallel processing of data 16 | * Support for a wide range of data types (thanks to generic math) 17 | * LINQ syntax so you can almost use it as drop-in replacement 18 | * Currently supports: `Min`, `Max`, `Sum`, `SequenceEqual`, `Average`, `Contains` 19 | 20 | ## Installation 21 | To install the package via NuGet, run the following command : 22 | ```no-class 23 | dotnet add package LinkDotNet.LinqSIMDExtensions 24 | ``` 25 | 26 | ## Usage 27 | First you have to import the namespace: 28 | ```csharp 29 | using LinkDotNet.LinqSIMDExtensions; 30 | ``` 31 | 32 | Then you can use the extension methods: 33 | ```csharp 34 | List numbers = GetNumbers(); 35 | var result = numbers.Min(); 36 | ``` 37 | 38 | Some functions like `Average` have convenient overloads to specify the return type: 39 | ```csharp 40 | List numbers = GetNumbers(); 41 | double result = numbers.Average(); 42 | ``` 43 | 44 | This can overcome the limitation of the return type being the same as the input type. This is especially useful for `Average` as the result is often a `double` but the input is an `int`. 45 | 46 | ## Benchmark 47 | You can head over to [benchmark section](tests/LinkDotNet.LinqSIMDExtensions.Benchmarks/) to see the setup. The following section will show you some results of different machines and architectures. Keep in mind to test against your specific use case with the hardware that will run it! SIMD can vary a lot depending on the hardware. Newer hardware tends to have better support for SIMD (if x86/x64 is used). 48 | 49 | Here are the benchmarks for a M1 Pro. Keep in mind that the M1 (arm64) does not support all SIMD operations. So the performance is not as good as on a x64 machine. 50 | 51 | ```no-class 52 | BenchmarkDotNet=v0.13.5, OS=macOS Ventura 13.2.1 (22D68) [Darwin 22.3.0] 53 | Apple M1 Pro, 1 CPU, 10 logical and 10 physical cores 54 | .NET SDK=7.0.202 55 | [Host] : .NET 7.0.4 (7.0.423.11508), Arm64 RyuJIT AdvSIMD 56 | DefaultJob : .NET 7.0.4 (7.0.423.11508), Arm64 RyuJIT AdvSIMD 57 | 58 | 59 | | Method | Mean | Error | StdDev | Ratio | 60 | | --------------- | ----------: | -------: | -------: | ----: | 61 | | LinqMin | 176.93 ns | 0.783 ns | 0.732 ns | 1.00 | 62 | | LinqSIMDMin | 65.48 ns | 0.255 ns | 0.238 ns | 0.37 | 63 | | | | | | | 64 | | LinqAverage | 1,058.29 ns | 5.354 ns | 5.008 ns | 1.00 | 65 | | LinqSIMDAverage | 80.97 ns | 0.465 ns | 0.435 ns | 0.08 | 66 | ``` 67 | 68 | ## Constraints 69 | As we are using SIMD the following constraints apply: 70 | * The collection type has to be contiguous memory (e.g. `List`, `T[]`, `Span`). Types like `IEnumerable` or `IReadOnlyList` are not supported. 71 | * The underlying number has to implement specific interfaces (like `IMinMaxValue`) to be able to determine the min/max value of the type. 72 | * Some functions like `Average` can not return a more specific type than the input out of the box. This means that if you have a `List` and call `Average` on it, the result will be a `int` and not an `double`. There are overloads that enable a more specific return type than the input. 73 | * There are no arithmetic checks. So it is prone to overflow or underflow. 74 | * `Contains` on `List` has to be invoked like this: `LinqSIMDExtensions.Contains(list, value)`. This is due to the fact that the `Contains` method is already defined on `List` and the compiler can not resolve the correct method. 75 | * The underlying data type has to be supported by the SIMD instruction. For example `Complex` is not supported as it is not a primitive type. 76 | -------------------------------------------------------------------------------- /src/LinkDotNet.LinqSIMDExtensions/Average.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace LinkDotNet.LinqSIMDExtensions; 5 | 6 | public static partial class LinqSIMDExtensions 7 | { 8 | /// 9 | /// Returns the average of the elements in the list. 10 | /// 11 | /// Any number-like object that is able to use the division operation. 12 | /// Returns the average in the same given type as the input. 13 | /// 14 | /// As the input as well as the output is of type the result is maybe not rounded mathematically correct. 15 | /// Given two integers 1 and 2 the average is 1.5 but the result is 1. 16 | /// 17 | public static T Average(this List list) 18 | where T : unmanaged, INumberBase, IDivisionOperators 19 | { 20 | ArgumentNullException.ThrowIfNull(list); 21 | 22 | return Average(CollectionsMarshal.AsSpan(list)); 23 | } 24 | 25 | /// 26 | /// Returns the average of the elements in the list and returns the result in the given type . 27 | /// 28 | /// The input type of the list. 29 | /// The return type that is used for the calculation of the average (division). 30 | public static TReturn Average(this List list) 31 | where T : unmanaged, INumberBase 32 | where TReturn : unmanaged, INumberBase, IDivisionOperators 33 | { 34 | ArgumentNullException.ThrowIfNull(list); 35 | 36 | return Average(CollectionsMarshal.AsSpan(list)); 37 | } 38 | 39 | /// 40 | /// Returns the average of the elements in the array. 41 | /// 42 | /// Any number-like object that is able to use the division operation. 43 | /// Returns the average in the same given type as the input. 44 | /// 45 | /// As the input as well as the output is of type the result is maybe not rounded mathematically correct. 46 | /// Given two integers 1 and 2 the average is 1.5 but the result is 1. 47 | /// 48 | public static T Average(this T[] array) 49 | where T : unmanaged, INumberBase, IDivisionOperators 50 | { 51 | ArgumentNullException.ThrowIfNull(array); 52 | 53 | return Average(array.AsSpan()); 54 | } 55 | 56 | /// 57 | /// Returns the average of the elements in the list and returns the result in the given type . 58 | /// 59 | /// The input type of the list. 60 | /// The return type that is used for the calculation of the average (division). 61 | public static TReturn Average(this T[] array) 62 | where T : unmanaged, INumberBase 63 | where TReturn : unmanaged, INumberBase, IDivisionOperators 64 | { 65 | ArgumentNullException.ThrowIfNull(array); 66 | 67 | return Average(array.AsSpan()); 68 | } 69 | 70 | /// 71 | /// Returns the average of the elements in the memory. 72 | /// 73 | /// Any number-like object that is able to use the division operation. 74 | /// Returns the average in the same given type as the input. 75 | /// 76 | /// As the input as well as the output is of type the result is maybe not rounded mathematically correct. 77 | /// Given two integers 1 and 2 the average is 1.5 but the result is 1. 78 | /// 79 | public static T Average(this Memory memory) 80 | where T : unmanaged, INumberBase, IDivisionOperators 81 | => Average(memory.Span); 82 | 83 | /// 84 | /// Returns the average of the elements in the span. 85 | /// 86 | /// Any number-like object that is able to use the division operation. 87 | /// Returns the average in the same given type as the input. 88 | /// 89 | /// As the input as well as the output is of type the result is maybe not rounded mathematically correct. 90 | /// Given two integers 1 and 2 the average is 1.5 but the result is 1. 91 | /// 92 | public static T Average(this Span span) 93 | where T : unmanaged, INumberBase, IDivisionOperators 94 | { 95 | if (span.IsEmpty) 96 | { 97 | throw new InvalidOperationException("Sequence contains no elements"); 98 | } 99 | 100 | var length = T.CreateChecked(span.Length); 101 | var divisionOperators = span.Sum() / length; 102 | return divisionOperators; 103 | } 104 | 105 | /// 106 | /// Returns the average of the elements in the list and returns the result in the given type . 107 | /// 108 | /// The input type of the list. 109 | /// The return type that is used for the calculation of the average (division). 110 | public static TReturn Average(this Span span) 111 | where T : unmanaged, INumberBase 112 | where TReturn : unmanaged, INumberBase, IDivisionOperators 113 | { 114 | if (span.IsEmpty) 115 | { 116 | throw new InvalidOperationException("Sequence contains no elements"); 117 | } 118 | 119 | var length = TReturn.CreateChecked(span.Length); 120 | var divisionOperators = TReturn.CreateChecked(span.Sum()) / length; 121 | return divisionOperators; 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/LinkDotNet.LinqSIMDExtensions/Contains.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace LinkDotNet.LinqSIMDExtensions; 5 | 6 | public static partial class LinqSIMDExtensions 7 | { 8 | /// 9 | /// Determines whether the list contains the specified value. 10 | /// 11 | public static bool Contains(this List list, T value) 12 | where T : unmanaged, INumberBase 13 | { 14 | ArgumentNullException.ThrowIfNull(list); 15 | var span = CollectionsMarshal.AsSpan(list); 16 | 17 | return Contains(span, value); 18 | } 19 | 20 | /// 21 | /// Determines whether the array contains the specified value. 22 | /// 23 | public static bool Contains(this T[] array, T value) 24 | where T : unmanaged, INumberBase 25 | { 26 | ArgumentNullException.ThrowIfNull(array); 27 | 28 | return Contains(array.AsSpan(), value); 29 | } 30 | 31 | /// 32 | /// Determines whether the memory contains the specified value. 33 | /// 34 | public static bool Contains(this Memory memory, T value) 35 | where T : unmanaged, INumberBase 36 | => Contains(memory.Span, value); 37 | 38 | /// 39 | /// Determines whether the span contains the specified value. 40 | /// 41 | public static bool Contains(this Span span, T value) 42 | where T : unmanaged, INumberBase 43 | { 44 | if (span.IsEmpty) 45 | { 46 | return false; 47 | } 48 | 49 | var spanAsVectors = MemoryMarshal.Cast>(span); 50 | var valueVector = VectorHelper.CreateWithValue(value); 51 | 52 | foreach (var spanAsVector in spanAsVectors) 53 | { 54 | if (Vector.EqualsAny(spanAsVector, valueVector)) 55 | { 56 | return true; 57 | } 58 | } 59 | 60 | var remainingElements = span.Length % Vector.Count; 61 | return remainingElements > 0 && MemoryExtensions.Contains(span[^remainingElements..], value); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/LinkDotNet.LinqSIMDExtensions/LinkDotNet.LinqSIMDExtensions.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | enable 5 | enable 6 | enable 7 | latest 8 | Steven Giesel (linkdotnet) 9 | Steven Giesel (linkdotnet) 10 | LinkDotNet.LinqSIMDExtensions 11 | A LINQ-like extensions for C# that uses SIMD extensions to parallelize the operations 12 | https://github.com/linkdotnet/LinqSIMDExtensions 13 | https://github.com/linkdotnet/LinqSIMDExtensions 14 | csharp,dotnet,linq,simd,performance 15 | README.md 16 | MIT 17 | net7.0;net8.0 18 | 19 | 20 | 21 | 22 | True 23 | \ 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/LinkDotNet.LinqSIMDExtensions/Max.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace LinkDotNet.LinqSIMDExtensions; 5 | 6 | public static partial class LinqSIMDExtensions 7 | { 8 | /// 9 | /// Retrieves the maximum value of the list. 10 | /// 11 | /// The max as type T. 12 | public static T Max(this List list) 13 | where T : unmanaged, IMinMaxValue, INumber 14 | { 15 | ArgumentNullException.ThrowIfNull(list); 16 | var span = CollectionsMarshal.AsSpan(list); 17 | 18 | return Max(span); 19 | } 20 | 21 | /// 22 | /// Retrieves the maximum value of the array. 23 | /// 24 | /// The max as type T. 25 | public static T Max(this T[] array) 26 | where T : unmanaged, IMinMaxValue, INumber 27 | { 28 | ArgumentNullException.ThrowIfNull(array); 29 | 30 | return Max(array.AsSpan()); 31 | } 32 | 33 | /// 34 | /// Retrieves the maximum value of the memory. 35 | /// 36 | /// The max as type T. 37 | public static T Max(this Memory memory) 38 | where T : unmanaged, IMinMaxValue, INumber 39 | => Max(memory.Span); 40 | 41 | /// 42 | /// Retrieves the maximum value of the span. 43 | /// 44 | /// The max as type T. 45 | public static T Max(this Span span) 46 | where T : unmanaged, IMinMaxValue, INumber 47 | { 48 | if (span.IsEmpty) 49 | { 50 | throw new InvalidOperationException("Sequence contains no elements"); 51 | } 52 | 53 | var spanAsVectors = MemoryMarshal.Cast>(span); 54 | var maxVector = VectorHelper.CreateWithValue(T.MinValue); 55 | 56 | for (var i = 0; i < spanAsVectors.Length - 1; i += 2) 57 | { 58 | var iterationMax = Vector.Max(spanAsVectors[i], spanAsVectors[i + 1]); 59 | maxVector = Vector.Max(maxVector, iterationMax); 60 | } 61 | 62 | if (spanAsVectors.Length % 2 == 1) 63 | { 64 | maxVector = Vector.Max(maxVector, spanAsVectors[^1]); 65 | } 66 | 67 | var remainingElements = span.Length % Vector.Count; 68 | if (remainingElements > 0) 69 | { 70 | Span lastVectorElements = stackalloc T[Vector.Count]; 71 | lastVectorElements.Fill(T.MinValue); 72 | span[^remainingElements..].CopyTo(lastVectorElements); 73 | maxVector = Vector.Max(maxVector, new Vector(lastVectorElements)); 74 | } 75 | 76 | var minValue = T.MinValue; 77 | for (var i = 0; i < Vector.Count; i++) 78 | { 79 | minValue = T.Max(minValue, maxVector[i]); 80 | } 81 | 82 | return minValue; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/LinkDotNet.LinqSIMDExtensions/Min.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace LinkDotNet.LinqSIMDExtensions; 5 | 6 | public static partial class LinqSIMDExtensions 7 | { 8 | /// 9 | /// Retrieves the minimum value of the list. 10 | /// 11 | public static T Min(this List list) 12 | where T : unmanaged, IMinMaxValue, INumber 13 | { 14 | ArgumentNullException.ThrowIfNull(list); 15 | var span = CollectionsMarshal.AsSpan(list); 16 | 17 | return Min(span); 18 | } 19 | 20 | /// 21 | /// Retrieves the minimum value of the array. 22 | /// 23 | public static T Min(this T[] array) 24 | where T : unmanaged, IMinMaxValue, INumber 25 | { 26 | ArgumentNullException.ThrowIfNull(array); 27 | 28 | return Min(array.AsSpan()); 29 | } 30 | 31 | /// 32 | /// Retrieves the minimum value of the memory. 33 | /// 34 | /// The max as type T. 35 | public static T Min(this Memory memory) 36 | where T : unmanaged, IMinMaxValue, INumber 37 | => Min(memory.Span); 38 | 39 | /// 40 | /// Retrieves the minimum value of the span. 41 | /// 42 | public static T Min(this Span span) 43 | where T : unmanaged, IMinMaxValue, INumber 44 | { 45 | if (span.IsEmpty) 46 | { 47 | throw new InvalidOperationException("Sequence contains no elements"); 48 | } 49 | 50 | var spanAsVectors = MemoryMarshal.Cast>(span); 51 | var minVector = VectorHelper.CreateWithValue(T.MaxValue); 52 | 53 | for (var i = 0; i < spanAsVectors.Length - 1; i += 2) 54 | { 55 | var iterationMin = Vector.Min(spanAsVectors[i], spanAsVectors[i + 1]); 56 | minVector = Vector.Min(minVector, iterationMin); 57 | } 58 | 59 | if (spanAsVectors.Length % 2 == 1) 60 | { 61 | minVector = Vector.Min(minVector, spanAsVectors[^1]); 62 | } 63 | 64 | var remainingElements = span.Length % Vector.Count; 65 | if (remainingElements > 0) 66 | { 67 | Span lastVectorElements = stackalloc T[Vector.Count]; 68 | lastVectorElements.Fill(T.MaxValue); 69 | span[^remainingElements..].CopyTo(lastVectorElements); 70 | minVector = Vector.Min(minVector, new Vector(lastVectorElements)); 71 | } 72 | 73 | var minValue = T.MaxValue; 74 | for (var i = 0; i < Vector.Count; i++) 75 | { 76 | minValue = T.Min(minValue, minVector[i]); 77 | } 78 | 79 | return minValue; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/LinkDotNet.LinqSIMDExtensions/SequenceEqual.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace LinkDotNet.LinqSIMDExtensions; 5 | 6 | public static partial class LinqSIMDExtensions 7 | { 8 | /// 9 | /// Determines whether two sequences are equal by comparing the elements by using the default equality comparer for their type. 10 | /// 11 | public static bool SequenceEqual(this List list, List other) 12 | where T : unmanaged 13 | { 14 | ArgumentNullException.ThrowIfNull(list); 15 | ArgumentNullException.ThrowIfNull(other); 16 | var span = CollectionsMarshal.AsSpan(list); 17 | var otherSpan = CollectionsMarshal.AsSpan(other); 18 | 19 | return SequenceEqual(span, otherSpan); 20 | } 21 | 22 | /// 23 | /// Determines whether two sequences are equal by comparing the elements by using the default equality comparer for their type. 24 | /// 25 | public static bool SequenceEqual(this T[] array, T[] other) 26 | where T : unmanaged 27 | { 28 | ArgumentNullException.ThrowIfNull(array); 29 | ArgumentNullException.ThrowIfNull(other); 30 | var span = array.AsSpan(); 31 | var otherSpan = other.AsSpan(); 32 | 33 | return SequenceEqual(span, otherSpan); 34 | } 35 | 36 | /// 37 | /// Determines whether two sequences are equal by comparing the elements by using the default equality comparer for their type. 38 | /// 39 | public static bool SequenceEqual(this Memory memory, Memory other) 40 | where T : unmanaged 41 | => SequenceEqual(memory.Span, other.Span); 42 | 43 | /// 44 | /// Determines whether two sequences are equal by comparing the elements by using the default equality comparer for their type. 45 | /// 46 | public static bool SequenceEqual(this Span span, Span other) 47 | where T : unmanaged 48 | { 49 | if (span.Length != other.Length) 50 | { 51 | return false; 52 | } 53 | 54 | var spanAsVectors = MemoryMarshal.Cast>(span); 55 | var otherAsVectors = MemoryMarshal.Cast>(other); 56 | 57 | for (var i = 0; i < spanAsVectors.Length; i++) 58 | { 59 | if (spanAsVectors[i] != otherAsVectors[i]) 60 | { 61 | return false; 62 | } 63 | } 64 | 65 | var remainingElements = span.Length % Vector.Count; 66 | if (remainingElements > 0) 67 | { 68 | Span lastVectorElements = stackalloc T[Vector.Count]; 69 | span[^remainingElements..].CopyTo(lastVectorElements); 70 | Span otherLastVectorElements = stackalloc T[Vector.Count]; 71 | other[^remainingElements..].CopyTo(otherLastVectorElements); 72 | if (new Vector(lastVectorElements) != new Vector(otherLastVectorElements)) 73 | { 74 | return false; 75 | } 76 | } 77 | 78 | return true; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/LinkDotNet.LinqSIMDExtensions/Sum.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace LinkDotNet.LinqSIMDExtensions; 5 | 6 | public static partial class LinqSIMDExtensions 7 | { 8 | /// 9 | /// Gets the sum of the elements in the list. 10 | /// 11 | public static T Sum(this List list) 12 | where T : unmanaged, INumberBase 13 | { 14 | ArgumentNullException.ThrowIfNull(list); 15 | var span = CollectionsMarshal.AsSpan(list); 16 | 17 | return Sum(span); 18 | } 19 | 20 | /// 21 | /// Gets the sum of the elements in the array. 22 | /// 23 | public static T Sum(this T[] array) 24 | where T : unmanaged, INumberBase 25 | { 26 | ArgumentNullException.ThrowIfNull(array); 27 | 28 | return Sum(array.AsSpan()); 29 | } 30 | 31 | /// 32 | /// Gets the sum of the elements in the memory. 33 | /// 34 | public static T Sum(this Memory memory) 35 | where T : unmanaged, INumberBase 36 | => Sum(memory.Span); 37 | 38 | /// 39 | /// Gets the sum of the elements in the span. 40 | /// 41 | public static T Sum(this Span span) 42 | where T : unmanaged, INumberBase 43 | { 44 | var spanAsVectors = MemoryMarshal.Cast>(span); 45 | var remainingElements = span.Length % Vector.Count; 46 | var accVector = new Vector(); 47 | 48 | for (var i = 0; i < spanAsVectors.Length - 1; i += 2) 49 | { 50 | accVector += spanAsVectors[i] + spanAsVectors[i + 1]; 51 | } 52 | 53 | if (spanAsVectors.Length % 2 == 1) 54 | { 55 | accVector += spanAsVectors[^1]; 56 | } 57 | 58 | if (remainingElements > 0) 59 | { 60 | Span lastVectorElements = stackalloc T[Vector.Count]; 61 | span[^remainingElements..].CopyTo(lastVectorElements); 62 | accVector += new Vector(lastVectorElements); 63 | } 64 | 65 | return Vector.Sum(accVector); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/LinkDotNet.LinqSIMDExtensions/VectorHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | 3 | namespace LinkDotNet.LinqSIMDExtensions; 4 | 5 | internal static class VectorHelper 6 | { 7 | public static Vector CreateWithValue(T fillValue) 8 | where T : unmanaged 9 | { 10 | Span vector = stackalloc T[Vector.Count]; 11 | vector.Fill(fillValue); 12 | return new Vector(vector); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tests/LinkDotNet.LinqSIMDExtensions.Benchmarks/AverageBenchmark.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | 3 | namespace LinkDotNet.LinqSIMDExtensions.Benchmarks; 4 | 5 | public class AverageBenchmark 6 | { 7 | private readonly float[] _numbers = Enumerable.Range(0, 1000).Select(f => (float)f).ToArray(); 8 | 9 | [Benchmark(Baseline = true)] 10 | public float LinqAverage() => Enumerable.Average(_numbers); 11 | 12 | [Benchmark] 13 | public float LinqSIMDAverage() => LinqSIMDExtensions.Average(_numbers); 14 | 15 | [Benchmark] 16 | public float SIMDLinqAverage() => SimdLinq.SimdLinqExtensions.Average(_numbers); 17 | } 18 | -------------------------------------------------------------------------------- /tests/LinkDotNet.LinqSIMDExtensions.Benchmarks/ContainsBenchmark.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | 3 | namespace LinkDotNet.LinqSIMDExtensions.Benchmarks; 4 | 5 | public class ContainsBenchmark 6 | { 7 | private readonly int[] _numbers = Enumerable.Range(0, 100_000).ToArray(); 8 | 9 | [Benchmark(Baseline = true)] 10 | public bool LinqContains() => Enumerable.Contains(_numbers, 80000); 11 | 12 | [Benchmark] 13 | public bool LinqSIMDContains() => LinqSIMDExtensions.Contains(_numbers, 80000); 14 | 15 | [Benchmark] 16 | public bool SIMDLinqContains() => SimdLinq.SimdLinqExtensions.Contains(_numbers, 80000); 17 | } 18 | -------------------------------------------------------------------------------- /tests/LinkDotNet.LinqSIMDExtensions.Benchmarks/LinkDotNet.LinqSIMDExtensions.Benchmarks.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net7.0 6 | enable 7 | enable 8 | false 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /tests/LinkDotNet.LinqSIMDExtensions.Benchmarks/MinBenchmark.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | 3 | namespace LinkDotNet.LinqSIMDExtensions.Benchmarks; 4 | 5 | public class MinBenchmark 6 | { 7 | private readonly int[] _numbers = Enumerable.Range(0, 1000).ToArray(); 8 | 9 | [Benchmark(Baseline = true)] 10 | public int LinqMin() => Enumerable.Min(_numbers); 11 | 12 | [Benchmark] 13 | public int LinqSIMDMin() => LinqSIMDExtensions.Min(_numbers); 14 | 15 | [Benchmark] 16 | public int SIMDLinqMin() => SimdLinq.SimdLinqExtensions.Min(_numbers); 17 | } 18 | -------------------------------------------------------------------------------- /tests/LinkDotNet.LinqSIMDExtensions.Benchmarks/Program.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Running; 2 | 3 | BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(); 4 | -------------------------------------------------------------------------------- /tests/LinkDotNet.LinqSIMDExtensions.Benchmarks/SequenceEqualBenchmark.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | 3 | namespace LinkDotNet.LinqSIMDExtensions.Benchmarks; 4 | 5 | public class SequenceEqualBenchmark 6 | { 7 | private readonly int[] _numbers1 = Enumerable.Range(0, 10_000).ToArray(); 8 | private readonly int[] _numbers2 = Enumerable.Range(0, 10_000).ToArray(); 9 | 10 | [Benchmark(Baseline = true)] 11 | public bool LinqSequenceEqual() => Enumerable.SequenceEqual(_numbers1, _numbers2); 12 | 13 | [Benchmark] 14 | public bool LinqSIMDSequenceEqual() => LinqSIMDExtensions.SequenceEqual(_numbers1, _numbers2); 15 | 16 | [Benchmark] 17 | public bool SIMDLinqSequenceEqual() => SimdLinq.SimdLinqExtensions.SequenceEqual(_numbers1, _numbers2); 18 | } 19 | -------------------------------------------------------------------------------- /tests/LinkDotNet.LinqSIMDExtensions.Benchmarks/SumBenchmark.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using LinkDotNet.LinqSIMDExtensions; 3 | 4 | namespace LinkDotNet.LinqSIMDExtensions.Benchmarks; 5 | 6 | public class SumBenchmark 7 | { 8 | private readonly int[] _numbers = Enumerable.Range(0, 1000).ToArray(); 9 | 10 | [Benchmark(Baseline = true)] 11 | public int LinqSum() => Enumerable.Sum(_numbers); 12 | 13 | [Benchmark] 14 | public int LinqSIMDSum() => LinqSIMDExtensions.Sum(_numbers); 15 | 16 | [Benchmark] 17 | public int SIMDLinq() => SimdLinq.SimdLinqExtensions.Sum(_numbers); 18 | } 19 | -------------------------------------------------------------------------------- /tests/LinkDotNet.LinqSIMDExtensions.Tests/AverageTests.cs: -------------------------------------------------------------------------------- 1 | using Shouldly; 2 | using Xunit; 3 | 4 | namespace LinkDotNet.LinqSIMDExtensions.Tests; 5 | 6 | public class AverageTests 7 | { 8 | [Fact] 9 | public void GivenSomeIntegers_WhenAverage_ThenAverageIsReturned() 10 | { 11 | var numbers = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 12 | 13 | var average = numbers.AsSpan().Average(); 14 | 15 | average.ShouldBe(5); 16 | } 17 | 18 | [Fact] 19 | public void GivenSomeFloats_WhenAverage_ThenAverageIsReturned() 20 | { 21 | var numbers = new[] { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f }; 22 | 23 | var average = numbers.AsSpan().Average(); 24 | 25 | average.ShouldBe(5.5f); 26 | } 27 | 28 | [Fact] 29 | public void GivenSomeDoublesInAList_WhenAverage_ThenAverageIsReturned() 30 | { 31 | var numbers = new List { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0 }; 32 | 33 | var average = numbers.Average(); 34 | 35 | average.ShouldBe(5.5); 36 | } 37 | 38 | [Fact] 39 | public void GivenNullList_WhenAverage_ThenArgumentNullExceptionIsThrown() 40 | { 41 | List numbers = null!; 42 | 43 | Should.Throw(() => numbers.Average()); 44 | } 45 | 46 | [Fact] 47 | public void GivenSomeIntegersInArray_WhenAverage_ThenAverageIsReturned() 48 | { 49 | var numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 50 | 51 | var average = numbers.Average(); 52 | 53 | average.ShouldBe(5); 54 | } 55 | 56 | [Fact] 57 | public void GivenNullArray_WhenAverage_ThenArgumentNullExceptionIsThrown() 58 | { 59 | int[] numbers = null!; 60 | 61 | Should.Throw(() => numbers.Average()); 62 | } 63 | 64 | [Fact] 65 | public void GivenMemory_WhenAverage_ThenAverageIsReturned() 66 | { 67 | var numbers = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 68 | 69 | var average = numbers.AsMemory().Average(); 70 | 71 | average.ShouldBe(5); 72 | } 73 | 74 | [Fact] 75 | public void GivenSomeIntegersAsSpan_WhenAverageDouble_ThenAverageIsReturned() 76 | { 77 | var numbers = new[] { 1, 2, 3, 4, 5, 6, 7, 8 }; 78 | 79 | var average = numbers.AsSpan().Average(); 80 | 81 | average.ShouldBe(4.5); 82 | } 83 | 84 | [Fact] 85 | public void GivenSomeIntegersAsList_WhenAverageDouble_ThenAverageIsReturned() 86 | { 87 | var numbers = new List { 1, 2, 3, 4, 5, 6, 7, 8 }; 88 | 89 | var average = numbers.Average(); 90 | 91 | average.ShouldBe(4.5); 92 | } 93 | 94 | [Fact] 95 | public void GivenSomeIntegersAsArray_WhenAverageDouble_ThenAverageIsReturned() 96 | { 97 | var numbers = new[] { 1, 2, 3, 4, 5, 6, 7, 8 }; 98 | 99 | var average = numbers.Average(); 100 | 101 | average.ShouldBe(4.5); 102 | } 103 | 104 | [Fact] 105 | public void ShouldThrowInvalidOperationException_WhenSequenceIsEmpty() 106 | { 107 | var sequence = new List(); 108 | 109 | Should.Throw(() => sequence.Average()); 110 | } 111 | 112 | [Fact] 113 | public void ShouldThrowInvalidOperationException_WhenSequenceIsEmptyAndIsCasting() 114 | { 115 | var sequence = new List(); 116 | 117 | Should.Throw(() => sequence.Average()); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /tests/LinkDotNet.LinqSIMDExtensions.Tests/ContainsTests.cs: -------------------------------------------------------------------------------- 1 | using Shouldly; 2 | using Xunit; 3 | 4 | namespace LinkDotNet.LinqSIMDExtensions.Tests; 5 | 6 | public class ContainsTests 7 | { 8 | [Fact] 9 | public void GivenSomeNumbers_WhenCheckingIfSpanContainsNumber_ThenTheCorrectResultIsReturned() 10 | { 11 | var numbers = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 12 | 13 | var contains = numbers.AsSpan().Contains(5); 14 | 15 | contains.ShouldBeTrue(); 16 | } 17 | 18 | [Fact] 19 | public void GiveSomeNumbersAtTheEnd_WhenCheckingIfSpanContainsNumber_ThenTheCorrectResultIsReturned() 20 | { 21 | var numbers = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 22 | 23 | var contains = numbers.AsSpan().Contains(10); 24 | 25 | contains.ShouldBeTrue(); 26 | } 27 | 28 | [Fact] 29 | public void GivenSomeNumbers_WhenCheckingIfListContainsNumber_ThenTheCorrectResultIsReturned() 30 | { 31 | var numbers = new List { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 32 | 33 | var contains = LinqSIMDExtensions.Contains(numbers, 5); 34 | 35 | contains.ShouldBeTrue(); 36 | } 37 | 38 | [Fact] 39 | public void GivenNullList_WhenCheckingIfListContainsNumber_ThenArgumentNullExceptionIsThrown() 40 | { 41 | List numbers = null!; 42 | 43 | Action act = () => LinqSIMDExtensions.Contains(numbers, 5 ); 44 | 45 | act.ShouldThrow(); 46 | } 47 | 48 | [Fact] 49 | public void GivenSomeNumbers_WhenCheckingIfArrayContainsNumber_ThenTheCorrectResultIsReturned() 50 | { 51 | var numbers = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 52 | 53 | var contains = numbers.Contains(5); 54 | 55 | contains.ShouldBeTrue(); 56 | } 57 | 58 | [Fact] 59 | public void GivenNullArray_WhenCheckingIfArrayContainsNumber_ThenArgumentNullExceptionIsThrown() 60 | { 61 | int[] numbers = null!; 62 | 63 | Action act = () => numbers.Contains(5); 64 | 65 | act.ShouldThrow(); 66 | } 67 | 68 | [Fact] 69 | public void GivenSomeNumbers_WhenCheckingIfMemoryContainsNumber_ThenTheCorrectResultIsReturned() 70 | { 71 | var numbers = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 72 | 73 | var contains = numbers.AsMemory().Contains(5); 74 | 75 | contains.ShouldBeTrue(); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /tests/LinkDotNet.LinqSIMDExtensions.Tests/LinkDotNet.LinqSIMDExtensions.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | enable 5 | enable 6 | 7 | false 8 | true 9 | net7.0;net8.0 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | runtime; build; native; contentfiles; analyzers; buildtransitive 18 | all 19 | 20 | 21 | runtime; build; native; contentfiles; analyzers; buildtransitive 22 | all 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /tests/LinkDotNet.LinqSIMDExtensions.Tests/MaxTests.cs: -------------------------------------------------------------------------------- 1 | using Shouldly; 2 | using Xunit; 3 | 4 | namespace LinkDotNet.LinqSIMDExtensions.Tests; 5 | 6 | public class MaxTests 7 | { 8 | [Fact] 9 | public void GivenSomeNumbers_WhenRetrievingMaximumInArrays_ThenTheCorrectMaximumIsReturned() 10 | { 11 | var numbers = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 12 | 13 | var max = numbers.Max(); 14 | 15 | max.ShouldBe(10); 16 | } 17 | 18 | [Fact] 19 | public void GivenSomeNumbers_WhenRetrievingMaximumInList_ThenTheCorrectMaximumIsReturned() 20 | { 21 | var numbers = new List { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 22 | 23 | var max = numbers.Max(); 24 | 25 | max.ShouldBe(10); 26 | } 27 | 28 | [Fact] 29 | public void GivenSomeNumbers_WhenRetrievingMaximumInSpan_ThenTheCorrectMaximumIsReturned() 30 | { 31 | var numbers = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 32 | 33 | var max = numbers.AsSpan().Max(); 34 | 35 | max.ShouldBe(10); 36 | } 37 | 38 | [Fact] 39 | public void GivenNullList_WhenRetrievingMaximum_ThenArgumentNullExceptionIsThrown() 40 | { 41 | List numbers = null!; 42 | 43 | Action act = () => numbers.Max(); 44 | act.ShouldThrow(); 45 | } 46 | 47 | [Fact] 48 | public void GivenNullArray_WhenRetrievingMaximum_ThenArgumentNullExceptionIsThrown() 49 | { 50 | int[] numbers = null!; 51 | 52 | Action act = () => numbers.Max(); 53 | act.ShouldThrow(); 54 | } 55 | 56 | [Fact] 57 | public void GivenMemory_WhenRetrievingMaximum_ThenTheCorrectMaximumIsReturned() 58 | { 59 | var numbers = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 60 | 61 | var max = numbers.AsMemory().Max(); 62 | 63 | max.ShouldBe(10); 64 | } 65 | 66 | [Theory] 67 | [InlineData(6, 5)] 68 | [InlineData(6, 5, 4, 3)] 69 | [InlineData(1, 2, 3, 4, 5, 6)] 70 | public void GivenUltraShortList_WhenGettingMinimum_ThenTheCorrectMinimumIsReturned(params int[] numbers) 71 | { 72 | var max = numbers.Max(); 73 | 74 | max.ShouldBe(6); 75 | } 76 | 77 | [Fact] 78 | public void GivenLongerList_WhenGettingMaximum_ThenTheCorrectMaximumIsReturned() 79 | { 80 | var sequence = Enumerable.Range(0, 21).Select(i => 20 - i).ToList(); 81 | 82 | var max = sequence.Max(); 83 | 84 | max.ShouldBe(20); 85 | } 86 | 87 | [Fact] 88 | public void ShouldThrowInvalidOperationException_WhenSequenceIsEmpty() 89 | { 90 | var sequence = new List(); 91 | 92 | Should.Throw(() => sequence.Max()); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /tests/LinkDotNet.LinqSIMDExtensions.Tests/MinTests.cs: -------------------------------------------------------------------------------- 1 | using Shouldly; 2 | using Xunit; 3 | 4 | namespace LinkDotNet.LinqSIMDExtensions.Tests; 5 | 6 | public class MinTests 7 | { 8 | [Fact] 9 | public void GivenSomeNumbers_WhenRetrievingMinimumInArrays_ThenTheCorrectMinimumIsReturned() 10 | { 11 | var numbers = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 12 | 13 | var min = numbers.Min(); 14 | 15 | min.ShouldBe(1); 16 | } 17 | 18 | [Fact] 19 | public void GivenSomeNumbers_WhenRetrievingMinimumInList_ThenTheCorrectMinimumIsReturned() 20 | { 21 | var numbers = new List { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 22 | 23 | var min = numbers.Min(); 24 | 25 | min.ShouldBe(1); 26 | } 27 | 28 | [Fact] 29 | public void GivenSomeNumbers_WhenRetrievingMinimumInSpan_ThenTheCorrectMinimumIsReturned() 30 | { 31 | var numbers = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 32 | 33 | var min = numbers.AsSpan().Min(); 34 | 35 | min.ShouldBe(1); 36 | } 37 | 38 | [Fact] 39 | public void GivenNullList_WhenRetrievingMinimum_ThenArgumentNullExceptionIsThrown() 40 | { 41 | List numbers = null!; 42 | 43 | Assert.Throws(() => numbers.Min()); 44 | } 45 | 46 | [Fact] 47 | public void GivenNullArray_WhenRetrievingMinimum_ThenArgumentNullExceptionIsThrown() 48 | { 49 | int[] numbers = null!; 50 | 51 | Assert.Throws(() => numbers.Min()); 52 | } 53 | 54 | [Fact] 55 | public void GivenMemory_WhenRetrievingMinimum_ThenTheCorrectMinimumIsReturned() 56 | { 57 | var numbers = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 58 | 59 | var min = numbers.AsMemory().Min(); 60 | 61 | min.ShouldBe(1); 62 | } 63 | 64 | [Theory] 65 | [InlineData(1, 2)] 66 | [InlineData(1, 2, 3, 4)] 67 | [InlineData(1, 2, 3, 4, 5, 6)] 68 | public void GivenUltraShortList_WhenGettingMinimum_ThenTheCorrectMinimumIsReturned(params int[] numbers) 69 | { 70 | var min = numbers.Min(); 71 | 72 | min.ShouldBe(1); 73 | } 74 | 75 | [Fact] 76 | public void GivenLongerList_WhenGettingMinimum_ThenTheCorrectMinimumIsReturned() 77 | { 78 | var sequence = Enumerable.Range(0, 100).ToList(); 79 | 80 | var min = sequence.Min(); 81 | 82 | min.ShouldBe(0); 83 | } 84 | 85 | [Fact] 86 | public void ShouldThrowInvalidOperationException_WhenSequenceIsEmpty() 87 | { 88 | var sequence = new List(); 89 | 90 | Should.Throw(() => sequence.Min()); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /tests/LinkDotNet.LinqSIMDExtensions.Tests/SequenceEqualTests.cs: -------------------------------------------------------------------------------- 1 | using Shouldly; 2 | using Xunit; 3 | 4 | namespace LinkDotNet.LinqSIMDExtensions.Tests; 5 | 6 | public class SequenceEqualTests 7 | { 8 | [Fact] 9 | public void GivenTwoSpans_WhenCheckingSequenceEquals_ThenTheCorrectResultIsReturned() 10 | { 11 | var first = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 12 | var second = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 13 | 14 | var result = first.AsSpan().SequenceEqual(second.AsSpan()); 15 | 16 | result.ShouldBeTrue(); 17 | } 18 | 19 | [Fact] 20 | public void GivenTwoSpans_WhenCheckingSequenceEqualsWithDifferentLength_ThenTheCorrectResultIsReturned() 21 | { 22 | var first = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 23 | var second = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; 24 | 25 | var result = MemoryExtensions.SequenceEqual(first.AsSpan(), second.AsSpan()); 26 | 27 | result.ShouldBeFalse(); 28 | } 29 | 30 | [Fact] 31 | public void GivenTwoSpans_WhenCheckingSequenceEqualWithDifferentValues_ThenTheCorrectResultIsReturned() 32 | { 33 | var first = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 34 | var second = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 11 }; 35 | 36 | var result = MemoryExtensions.SequenceEqual(first.AsSpan(), second.AsSpan()); 37 | 38 | result.ShouldBeFalse(); 39 | } 40 | 41 | [Fact] 42 | public void GivenTwoLists_WhenCheckingSequenceEqual_ThenTheCorrectResultIsReturned() 43 | { 44 | var first = new List { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 45 | var second = new List { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 46 | 47 | var result = first.SequenceEqual(second); 48 | 49 | result.ShouldBeTrue(); 50 | } 51 | 52 | [Fact] 53 | public void GivenTwoLists_WhenOneIsNull_ThenArgumentNullExceptionIsThrown() 54 | { 55 | List first = null!; 56 | var second = new List { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 57 | 58 | Action act = () => first.SequenceEqual(second); 59 | 60 | act.ShouldThrow(); 61 | } 62 | 63 | [Fact] 64 | public void GivenTwoArrays_WhenCheckingSequenceEqual_ThenTheCorrectResultIsReturned() 65 | { 66 | var first = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 67 | var second = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 68 | 69 | var result = first.SequenceEqual(second); 70 | 71 | result.ShouldBeTrue(); 72 | } 73 | 74 | [Fact] 75 | public void GivenTwoArrays_WhenCheckingSequenceEqualWhereOneIsNull_ThenExceptionIsThrown() 76 | { 77 | int[] first = null!; 78 | var second = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 79 | 80 | Action act = () => first.SequenceEqual(second); 81 | 82 | act.ShouldThrow(); 83 | } 84 | 85 | [Fact] 86 | public void GivenMemory_WhenCheckingSequenceEqual_ThenTheCorrectResultIsReturned() 87 | { 88 | var first = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 89 | var second = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 90 | 91 | var result = first.AsMemory().SequenceEqual(second.AsMemory()); 92 | 93 | result.ShouldBeTrue(); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /tests/LinkDotNet.LinqSIMDExtensions.Tests/SumTests.cs: -------------------------------------------------------------------------------- 1 | using Shouldly; 2 | using Xunit; 3 | 4 | namespace LinkDotNet.LinqSIMDExtensions.Tests; 5 | 6 | public class SumTests 7 | { 8 | [Fact] 9 | public void GivenSomeNumbers_WhenRetrievingTheSumInArrays_ThenTheCorrectSumIsReturned() 10 | { 11 | var numbers = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 12 | 13 | var sum = numbers.Sum(); 14 | 15 | sum.ShouldBe(55); 16 | } 17 | 18 | [Fact] 19 | public void GivenSomeNumbers_WhenRetrievingSumInLists_ThenTheCorrectSumIsReturned() 20 | { 21 | var numbers = new List { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 22 | 23 | var sum = numbers.Sum(); 24 | 25 | sum.ShouldBe(55); 26 | } 27 | 28 | [Fact] 29 | public void GivenNullList_WhenCallingSum_ThenArgumentNullExceptionIsThrown() 30 | { 31 | List numbers = null!; 32 | 33 | Action act = () => numbers.Sum(); 34 | act.ShouldThrow(); 35 | } 36 | 37 | [Fact] 38 | public void GivenNullArray_WhenCallingSum_ThenArgumentNullExceptionIsThrown() 39 | { 40 | int[] numbers = null!; 41 | 42 | Action act = () => numbers.Sum(); 43 | act.ShouldThrow(); 44 | } 45 | 46 | [Fact] 47 | public void GivenSomeNumbers_WhenRetrievingSumInSpans_ThenTheCorrectSumIsReturned() 48 | { 49 | var numbers = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 50 | 51 | var sum = numbers.AsSpan().Sum(); 52 | 53 | sum.ShouldBe(55); 54 | } 55 | 56 | [Fact] 57 | public void GivenMemory_WhenRetrievingSum_ThenTheCorrectSumIsReturned() 58 | { 59 | var numbers = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 60 | 61 | var sum = numbers.AsMemory().Sum(); 62 | 63 | sum.ShouldBe(55); 64 | } 65 | 66 | [Fact] 67 | public void GivenEmptyList_WhenRetrievingSum_ThenZeroIsReturned() 68 | { 69 | var numbers = new List(); 70 | 71 | var sum = numbers.Sum(); 72 | 73 | sum.ShouldBe(0); 74 | } 75 | } 76 | --------------------------------------------------------------------------------