Skip to content

Enhance ExcelReader to Support Ref Structs - #36

Merged
GabrielMarquezMatte merged 2 commits into
masterfrom
develop
Jul 21, 2026
Merged

Enhance ExcelReader to Support Ref Structs#36
GabrielMarquezMatte merged 2 commits into
masterfrom
develop

Conversation

@GabrielMarquezMatte

Copy link
Copy Markdown
Owner
  • Introduced ExcelRowContext to provide context for row parsing.
  • Updated ColumnParserFactory to support ref structs, enabling zero-copy parsing for ReadOnlySpan<byte>.
  • Added NamedColumnBinding and NamedRefRowEnumerable to facilitate named column parsing for ref structs.
  • Implemented NamedRefRowEnumerator to handle row enumeration for ref structs, ensuring zero-allocation.
  • Created RefParser for reflection-based parsing of ref structs, mirroring existing functionality for classes.
  • Added benchmarks to measure performance improvements with ref structs.
  • Developed comprehensive tests for RefParser, validating attribute-driven parsing and zero-copy behavior.

GabrielMarquezMatte and others added 2 commits July 21, 2026 01:14
- Introduced `ExcelRowContext` to provide context for row parsing.
- Updated `ColumnParserFactory` to support ref structs, enabling zero-copy parsing for `ReadOnlySpan<byte>`.
- Added `NamedColumnBinding` and `NamedRefRowEnumerable` to facilitate named column parsing for ref structs.
- Implemented `NamedRefRowEnumerator` to handle row enumeration for ref structs, ensuring zero-allocation.
- Created `RefParser` for reflection-based parsing of ref structs, mirroring existing functionality for classes.
- Added benchmarks to measure performance improvements with ref structs.
- Developed comprehensive tests for `RefParser`, validating attribute-driven parsing and zero-copy behavior.
@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 82.35294% with 24 lines in your changes missing coverage. Please review.
✅ Project coverage is 88.66%. Comparing base (bbd1407) to head (12e2406).

Files with missing lines Patch % Lines
src/ExcelReader.Core/Parser/RefParser.cs 20.00% 16 Missing ⚠️
...ader.Core/Parser/Internal/NamedRefRowEnumerator.cs 91.25% 4 Missing and 3 partials ⚠️
...ader.Core/Parser/Internal/NamedRefRowEnumerable.cs 95.00% 0 Missing and 1 partial ⚠️
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.
Additional details and impacted files
@@            Coverage Diff             @@
##           master      #36      +/-   ##
==========================================
- Coverage   88.79%   88.66%   -0.14%     
==========================================
  Files          83       88       +5     
  Lines        5464     5600     +136     
  Branches     1038     1067      +29     
==========================================
+ Hits         4852     4965     +113     
- Misses        385      405      +20     
- Partials      227      230       +3     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions

Copy link
Copy Markdown

Benchmark Results

Measured on ubuntu-latest (GitHub Actions). Runner noise may affect absolute numbers; use these for relative comparisons within a PR.

ExcelReader.Benchmarks.ColdStartBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.4 LTS (Noble Numbat)
AMD EPYC 7763 2.45GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.302
  [Host]     : .NET 10.0.10 (10.0.10, 10.0.1026.32716), X64 RyuJIT x86-64-v3
  Job-GOEFXF : .NET 10.0.10 (10.0.10, 10.0.1026.32716), X64 RyuJIT x86-64-v3

InvocationCount=1  IterationCount=1  LaunchCount=16  
RunStrategy=ColdStart  UnrollFactor=1  WarmupCount=0  

Method Rows Mean Error StdDev Allocated
TypedParseFirstUse 200 47.31 ms 0.419 ms 0.412 ms 29.55 KB
RecordWriteFirstUse 200 25.46 ms 1.981 ms 1.945 ms 79.41 KB

ExcelReader.Benchmarks.CsvParseBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.4 LTS (Noble Numbat)
AMD EPYC 7763 2.45GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.302
  [Host]     : .NET 10.0.10 (10.0.10, 10.0.1026.32716), X64 RyuJIT x86-64-v3
  Job-MEHJPP : .NET 10.0.10 (10.0.10, 10.0.1026.32716), X64 RyuJIT x86-64-v3

IterationCount=5  WarmupCount=1  

Method Rows Mean Error StdDev Ratio Gen0 Gen1 Allocated Alloc Ratio
ExcelParserSync 50000 8.065 ms 0.0261 ms 0.0068 ms 1.00 234.3750 - 3.86 MB 1.00
ExcelParserAsync 50000 8.266 ms 0.1950 ms 0.0506 ms 1.02 234.3750 - 3.86 MB 1.00
Sep 50000 14.689 ms 0.0937 ms 0.0243 ms 1.82 234.3750 - 3.87 MB 1.00
Sylvan 50000 19.698 ms 0.5567 ms 0.0861 ms 2.44 656.2500 62.5000 10.95 MB 2.84
CsvHelperLib 50000 35.412 ms 0.2512 ms 0.0652 ms 4.39 866.6667 66.6667 14.41 MB 3.73

ExcelReader.Benchmarks.CsvReadBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.4 LTS (Noble Numbat)
AMD EPYC 7763 2.45GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.302
  [Host]     : .NET 10.0.10 (10.0.10, 10.0.1026.32716), X64 RyuJIT x86-64-v3
  Job-MEHJPP : .NET 10.0.10 (10.0.10, 10.0.1026.32716), X64 RyuJIT x86-64-v3

IterationCount=5  WarmupCount=1  

Method Rows Mean Error StdDev Ratio RatioSD Gen0 Gen1 Allocated Alloc Ratio
ExcelReader 50000 5.628 ms 0.0238 ms 0.0037 ms 1.00 0.00 - - 232 B 1.00
ExcelReaderAsync 50000 5.490 ms 0.0481 ms 0.0074 ms 0.98 0.00 - - 352 B 1.52
Sep 50000 13.627 ms 0.2446 ms 0.0378 ms 2.42 0.01 - - 4024 B 17.34
Sylvan 50000 6.518 ms 0.0272 ms 0.0042 ms 1.16 0.00 93.7500 7.8125 1688701 B 7,278.88
CsvHelperLib 50000 37.470 ms 1.5485 ms 0.2396 ms 6.66 0.04 857.1429 71.4286 15073424 B 64,971.66

ExcelReader.Benchmarks.CsvWriteBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.4 LTS (Noble Numbat)
AMD EPYC 9V74 2.74GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.302
  [Host]     : .NET 10.0.10 (10.0.10, 10.0.1026.32716), X64 RyuJIT x86-64-v3
  Job-MEHJPP : .NET 10.0.10 (10.0.10, 10.0.1026.32716), X64 RyuJIT x86-64-v3

IterationCount=5  WarmupCount=1  

Method Rows Mean Error StdDev Ratio RatioSD Gen0 Gen1 Gen2 Allocated Alloc Ratio
ExcelReaderWriter 50000 9.534 ms 0.1826 ms 0.0474 ms 1.00 0.01 500.0000 500.0000 500.0000 4 MB 1.00
Sep 50000 9.802 ms 0.2061 ms 0.0319 ms 1.03 0.01 500.0000 500.0000 500.0000 4.01 MB 1.00
SylvanWriter 50000 9.816 ms 0.4955 ms 0.1287 ms 1.03 0.01 500.0000 500.0000 500.0000 4.04 MB 1.01
CsvHelperLib 50000 20.218 ms 1.4050 ms 0.2174 ms 2.12 0.02 1187.5000 656.2500 593.7500 13.79 MB 3.44

ExcelReader.Benchmarks.ParseBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.4 LTS (Noble Numbat)
AMD EPYC 7763 2.45GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.302
  [Host]     : .NET 10.0.10 (10.0.10, 10.0.1026.32716), X64 RyuJIT x86-64-v3
  Job-MEHJPP : .NET 10.0.10 (10.0.10, 10.0.1026.32716), X64 RyuJIT x86-64-v3

IterationCount=5  WarmupCount=1  

Method Rows Mean Error StdDev Ratio RatioSD Gen0 Allocated Alloc Ratio
ExcelParserSync 50000 22.177 ms 0.0833 ms 0.0216 ms 1.00 0.00 218.7500 3968.19 KB 1.000
ExcelParserStructSync 50000 21.749 ms 0.0495 ms 0.0077 ms 0.98 0.00 93.7500 1624.46 KB 0.409
RefParserParseNamedSync 50000 18.071 ms 0.1137 ms 0.0295 ms 0.81 0.00 - 12.96 KB 0.003
ExcelParserAsync 50000 21.868 ms 0.0645 ms 0.0100 ms 0.99 0.00 218.7500 3970.34 KB 1.001
ExcelParserXlsbSync 50000 9.712 ms 0.1935 ms 0.0503 ms 0.44 0.00 234.3750 3969.92 KB 1.000
ExcelParserXlsbAsync 50000 10.054 ms 0.1566 ms 0.0407 ms 0.45 0.00 234.3750 3972.49 KB 1.001
MiniExcel 50000 228.458 ms 8.0429 ms 1.2447 ms 10.30 0.05 12000.0000 202527.98 KB 51.038
Sylvan 50000 89.389 ms 1.4318 ms 0.3718 ms 4.03 0.02 - 10726.71 KB 2.703
SylvanAsync 50000 94.133 ms 37.6579 ms 5.8276 ms 4.24 0.23 - 10727.74 KB 2.703

ExcelReader.Benchmarks.ReadBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.4 LTS (Noble Numbat)
AMD EPYC 7763 2.45GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.302
  [Host]     : .NET 10.0.10 (10.0.10, 10.0.1026.32716), X64 RyuJIT x86-64-v3
  Job-MEHJPP : .NET 10.0.10 (10.0.10, 10.0.1026.32716), X64 RyuJIT x86-64-v3

IterationCount=5  WarmupCount=1  

Method Rows Mean Error StdDev Ratio RatioSD Gen0 Allocated Alloc Ratio
ExcelReader 50000 17.527 ms 0.0493 ms 0.0128 ms 1.00 0.00 - 12.59 KB 1.00
ExcelReaderAsync 50000 17.241 ms 0.1186 ms 0.0183 ms 0.98 0.00 - 14.72 KB 1.17
ExcelReaderXlsb 50000 6.162 ms 0.0157 ms 0.0041 ms 0.35 0.00 - 14.32 KB 1.14
ExcelReaderXlsbAsync 50000 6.349 ms 0.0411 ms 0.0107 ms 0.36 0.00 - 16.88 KB 1.34
MiniExcel 50000 229.669 ms 6.6001 ms 1.7140 ms 13.10 0.09 13000.0000 214016.6 KB 17,004.42
Sylvan 50000 57.498 ms 2.8050 ms 0.7284 ms 3.28 0.04 - 1939.18 KB 154.08

ExcelReader.Benchmarks.RealDataReadBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.4 LTS (Noble Numbat)
INTEL XEON PLATINUM 8573C 2.30GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.302
  [Host]     : .NET 10.0.10 (10.0.10, 10.0.1026.32716), X64 RyuJIT x86-64-v4
  Job-MEHJPP : .NET 10.0.10 (10.0.10, 10.0.1026.32716), X64 RyuJIT x86-64-v4

IterationCount=5  WarmupCount=1  

Method Mean Error StdDev Ratio RatioSD Gen0 Gen1 Allocated Alloc Ratio
Xlsx_ExcelReader 92.865 ms 8.4604 ms 1.3093 ms 1.00 0.02 - - 35016 B 1.000
Xlsx_Sylvan 270.424 ms 5.7650 ms 1.4972 ms 2.91 0.04 - - 659568 B 18.836
Xlsm_ExcelReader 91.320 ms 1.4072 ms 0.2178 ms 0.98 0.01 - - 35048 B 1.001
Xlsm_Sylvan 270.124 ms 0.8089 ms 0.1252 ms 2.91 0.04 - - 659648 B 18.838
Xlsb_ExcelReader 35.590 ms 0.1248 ms 0.0193 ms 0.38 0.00 - - 41640 B 1.189
Xlsb_Sylvan 42.910 ms 0.4922 ms 0.1278 ms 0.46 0.01 - - 346673 B 9.900
Xls_ExcelReader 17.306 ms 0.1580 ms 0.0245 ms 0.19 0.00 - - 10208 B 0.292
Xls_Sylvan 23.467 ms 0.0861 ms 0.0133 ms 0.25 0.00 - - 190366 B 5.437
Csv_ExcelReader 9.512 ms 0.0536 ms 0.0139 ms 0.10 0.00 - - 232 B 0.007
Csv_Sylvan 18.084 ms 0.2500 ms 0.0387 ms 0.19 0.00 437.5000 31.2500 37483923 B 1,070.480

ExcelReader.Benchmarks.RecordWriteBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.4 LTS (Noble Numbat)
AMD EPYC 9V74 2.74GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.302
  [Host]     : .NET 10.0.10 (10.0.10, 10.0.1026.32716), X64 RyuJIT x86-64-v3
  Job-MEHJPP : .NET 10.0.10 (10.0.10, 10.0.1026.32716), X64 RyuJIT x86-64-v3

IterationCount=5  WarmupCount=1  

Method Rows Mean Error StdDev Ratio Gen0 Gen1 Gen2 Allocated Alloc Ratio
Xlsx 50000 20.450 ms 0.3278 ms 0.0851 ms 1.00 500.0000 500.0000 500.0000 4.02 MB 1.00
Xlsb 50000 10.570 ms 1.0041 ms 0.1554 ms 0.52 500.0000 500.0000 500.0000 4.02 MB 1.00
Xls 50000 7.578 ms 0.1970 ms 0.0512 ms 0.37 273.4375 273.4375 273.4375 4.03 MB 1.00
Csv 50000 10.436 ms 0.4577 ms 0.0708 ms 0.51 500.0000 500.0000 500.0000 4 MB 1.00

ExcelReader.Benchmarks.WriteBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.4 LTS (Noble Numbat)
AMD EPYC 9V74 2.74GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.302
  [Host]     : .NET 10.0.10 (10.0.10, 10.0.1026.32716), X64 RyuJIT x86-64-v3
  Job-MEHJPP : .NET 10.0.10 (10.0.10, 10.0.1026.32716), X64 RyuJIT x86-64-v3

IterationCount=5  WarmupCount=1  

Method Rows Mean Error StdDev Ratio RatioSD Gen0 Gen1 Gen2 Allocated Alloc Ratio
ExcelReaderWriter 50000 19.57 ms 0.302 ms 0.047 ms 1.00 0.00 500.0000 500.0000 500.0000 4.02 MB 1.00
ExcelReaderWriterSharedStrings 50000 19.83 ms 0.461 ms 0.120 ms 1.01 0.01 500.0000 500.0000 500.0000 4.06 MB 1.01
ExcelReaderXlsbWriter 50000 10.31 ms 0.037 ms 0.006 ms 0.53 0.00 500.0000 500.0000 500.0000 4.02 MB 1.00
ExcelReaderXlsbWriterSharedStrings 50000 10.15 ms 0.389 ms 0.101 ms 0.52 0.00 500.0000 500.0000 500.0000 4.06 MB 1.01
MiniExcel 50000 108.91 ms 23.368 ms 6.069 ms 5.57 0.28 5000.0000 1000.0000 1000.0000 84.89 MB 21.13
SpreadCheetah 50000 21.67 ms 0.193 ms 0.030 ms 1.11 0.00 1437.5000 718.7500 718.7500 15.84 MB 3.94

ExcelReader.Benchmarks.XlsReadBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.4 LTS (Noble Numbat)
AMD EPYC 7763 2.45GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.302
  [Host]     : .NET 10.0.10 (10.0.10, 10.0.1026.32716), X64 RyuJIT x86-64-v3
  Job-MEHJPP : .NET 10.0.10 (10.0.10, 10.0.1026.32716), X64 RyuJIT x86-64-v3

IterationCount=5  WarmupCount=1  

Method Rows Mean Error StdDev Ratio Gen0 Gen1 Allocated Alloc Ratio
ExcelReader 50000 6.297 ms 0.0173 ms 0.0045 ms 1.00 - - 2.89 KB 1.00
ExcelReaderAsync 50000 6.521 ms 0.0279 ms 0.0043 ms 1.04 - - 2.96 KB 1.02
Sylvan 50000 8.781 ms 0.0742 ms 0.0115 ms 1.39 93.7500 15.6250 1717.73 KB 594.24

ExcelReader.Benchmarks.XlsWriteBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.4 LTS (Noble Numbat)
AMD EPYC 9V74 2.74GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.302
  [Host]     : .NET 10.0.10 (10.0.10, 10.0.1026.32716), X64 RyuJIT x86-64-v3
  Job-MEHJPP : .NET 10.0.10 (10.0.10, 10.0.1026.32716), X64 RyuJIT x86-64-v3

IterationCount=5  WarmupCount=1  

Method Rows Mean Error StdDev Ratio Gen0 Gen1 Gen2 Allocated Alloc Ratio
XlsWriter 50000 7.019 ms 0.1222 ms 0.0189 ms 1.00 492.1875 492.1875 492.1875 16.03 MB 1.00
XlsxWriter 50000 19.651 ms 0.1793 ms 0.0277 ms 2.80 500.0000 500.0000 500.0000 4.02 MB 0.25

@GabrielMarquezMatte
GabrielMarquezMatte merged commit ba6b932 into master Jul 21, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants