• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

go-playground / form / 18432284340
100%

Build:
DEFAULT BRANCH: master
Ran 11 Oct 2025 05:05PM UTC
Jobs 1
Files 6
Run time 1min
Badge
Embed ▾
README BADGES
x

If you need to use a raster PNG badge, change the '.svg' to '.png' in the link

Markdown

Textile

RDoc

HTML

Rst

11 Oct 2025 05:04PM UTC coverage: 99.723% (-0.09%) from 99.814%
18432284340

push

github

web-flow
Improve issue #71: Optimize nested structure decoding performance (#73)

## Problem
When decoding structs with data nested inside two or more layers of
slices or maps, the decoder exhibited exponential performance
degradation based on the number of values.

### Example Structure
```go
type FormRequest struct {
Foos []*NestedFoo `form:"foos"`
}

type NestedFoo struct {
Bars []*NestedBar `form:"bars"`
}

type NestedBar struct {
Bazs   []string          `form:"bazs"`
Lookup map[string]string `form:"lookup"`
}
```

### Performance Before Fix
- 50 values: ~1 second
- 100 values: ~4 seconds  
- 200 values: ~16 seconds

The performance degradation was exponential, making the decoder unusable
for real-world nested data.

## Root Cause
The `findAlias()` function performed a **linear O(n) search** through
the `dataMap` slice for every alias lookup. With deeply nested
structures, this function was called thousands or millions of times,
resulting in O(n²) or worse complexity.

For example, with 1000 nested elements, the parser would:
1. Create ~1002 unique aliases (1 for `foos`, 1 for `foos[0].bars`, 1000
for `foos[0].bars[N].lookup`)
2. Call `findAlias()` many times during parsing and decoding
3. Each `findAlias()` call would iterate through the entire dataMap
linearly

## Solution
Replaced the linear search with a **hash map lookup (O(1))**:

1. Added `aliasMap map[string]*recursiveData` field to the `decoder`
struct
2. Modified `parseMapData()` to populate the map as aliases are created
3. Changed `findAlias()` to use the map instead of iterating through the
slice

### Code Changes
**decoder.go:**
- Added `aliasMap` field to `decoder` struct for O(1) lookups
- Initialized/cleared the map in `parseMapData()`  
- Populated the map when creating new `recursiveData` entries
- Modified `findAlias()` to use map lookup instead of linear search

**decoder_test.go:**
- Added comprehensive test with 10, 50, and 200 nested values
- Uses race-detector-aware thresholds (st... (continued)

9 of 9 new or added lines in 1 file covered. (100.0%)

1 existing line in 1 file now uncovered.

1080 of 1083 relevant lines covered (99.72%)

43077.28 hits per line

Uncovered Existing Lines

Lines Coverage ∆ File
1
99.83
-0.17% decoder.go
Jobs
ID Job ID Ran Files Coverage
1 18432284340.1 11 Oct 2025 05:05PM UTC 6
99.72
GitHub Action Run
Source Files on build 18432284340
  • Tree
  • List 6
  • Changed 1
  • Source Changed 0
  • Coverage Changed 1
Coverage ∆ File Lines Relevant Covered Missed Hits/Line
  • Back to Repo
  • cd3bad62 on github
  • Prev Build on master (#13994600204)
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc