feat: add pure-Go LatLngToCell drop-in in x/purego#122
Conversation
Coverage Report for CI Build 27372399066Coverage remained the same at 100.0%Details
Uncovered ChangesNo uncovered changes found. Coverage RegressionsNo coverage regressions found. Coverage Stats
💛 - Coveralls |
a97aecf to
5795a22
Compare
| // LatLngToCell returns the Cell at res for a geographic coordinate, computed | ||
| // entirely in Go. It is a drop-in, bit-for-bit compatible replacement for the | ||
| // cgo-backed h3.LatLngToCell. | ||
| func LatLngToCell(latLng h3.LatLng, res int) (h3.Cell, error) { |
There was a problem hiding this comment.
Hmm I was debating whether we should completely redefine things here.. By returning h3.Cell, I can't actually override any of the methods on cell (like .Resolution(), .Parent(), etc.)
|
I like the approach, we can extend it to become fully isolated over time and eventually drop the CGO requirement entirely. My only hesitation on this PR is |
Yeah I flagged on Slack, but one draw back of returning a |
5795a22 to
e7bde84
Compare
Yea that sounds good! I'm all for redefining as much as you need to get a clean API surface |
Add x/h3go, a zero-allocation pure-Go implementation of LatLngToCell. It ports the entire latLngToCell pipeline (vec3d projection, face lookup, IJK coordinate transforms, H3 index encoding) to Go, so the per-call compute path runs entirely in Go: no cgo call and no allocations. x/h3go defines its own Cell, LatLng and Err* values rather than aliasing the cgo h3 package. Owning these types lets the package define its own methods (Cell.String, Cell.Resolution, ...) and grow into a full pure-Go reimplementation of H3 that can drop-in replace the h3 package. The underlying int64 cell encoding is identical to h3.Cell, so values remain interconvertible via a plain numeric conversion. The main h3 package keeps its cgo implementation unchanged. Because it no longer imports the cgo h3 package, x/h3go is itself cgo-free: it depends only on the cgo-free internal/h3core package and builds with CGO_ENABLED=0. Shared H3 index-format primitives (the bit-layout offsets/masks and the pentagon base-cell table) live in internal/h3core so the constants are declared once instead of duplicated across packages. The package is covered at 100% of statements. An external suite (h3go_test.go) asserts bit-for-bit equality and error-domain parity against the cgo reference across a structured grid (poles/antimeridian), a 100k seeded-random sweep, and all 12 pentagon base cells, at every resolution, and checks Cell.String/Cell.Resolution against the reference; an internal white-box test (internal_test.go) exercises the defensive overflow guards and the at-face-center projection branch that valid geographic inputs cannot reach. The pure-Go path trades ~6% higher per-call latency (Go's math trig vs C's libm) for zero allocations, cutting GC pressure in workloads that call LatLngToCell millions of times: h3.LatLngToCell (cgo): ~270 ns/op 24 B/op 2 allocs/op h3go.LatLngToCell (pure Go): ~289 ns/op 0 B/op 0 allocs/op Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
e7bde84 to
72e3434
Compare
Add x/h3go, a zero-allocation pure-Go implementation of LatLngToCell. It
ports the entire latLngToCell pipeline (vec3d projection, face lookup,
IJK coordinate transforms, H3 index encoding) to Go, so the per-call
compute path runs entirely in Go: no cgo call and no allocations.
x/h3go defines its own Cell, LatLng and Err* values rather than aliasing
the cgo h3 package. Owning these types lets the package define its own
methods (Cell.String, Cell.Resolution, ...) and grow into a full pure-Go
reimplementation of H3 that can drop-in replace the h3 package. The
underlying int64 cell encoding is identical to h3.Cell, so values remain
interconvertible via a plain numeric conversion. The main h3 package
keeps its cgo implementation unchanged.
Because it no longer imports the cgo h3 package, x/h3go is itself
cgo-free: it depends only on the cgo-free internal/h3core package and
builds with CGO_ENABLED=0. Shared H3 index-format primitives (the
bit-layout offsets/masks and the pentagon base-cell table) live in
internal/h3core so the constants are declared once instead of duplicated
across packages.
The package is covered at 100% of statements. An external suite
(h3go_test.go) asserts bit-for-bit equality and error-domain parity
against the cgo reference across a structured grid (poles/antimeridian),
a 100k seeded-random sweep, and all 12 pentagon base cells, at every
resolution, and checks Cell.String/Cell.Resolution against the reference;
an internal white-box test (internal_test.go) exercises the defensive
overflow guards and the at-face-center projection branch that valid
geographic inputs cannot reach.
The pure-Go path trades ~6% higher per-call latency (Go's math trig vs
C's libm) for zero allocations, cutting GC pressure in workloads that
call LatLngToCell millions of times:
h3.LatLngToCell (cgo): ~270 ns/op 24 B/op 2 allocs/op
h3go.LatLngToCell (pure Go): ~289 ns/op 0 B/op 0 allocs/op