You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Three copies stood between an Arrow geometry column and the Arrow batch of
pieces it splits to, none of them necessary.
Reading copied every vertex out of the source buffer into a vector, one
push_back at a time. For interleaved 2D coordinates - which is what
to_geoarrow asks geopandas for - that buffer already *is* an array of
Coord, as the static_assert on its size has always said, and
splitLineStringGrid's first act is to walk its input transforming every
vertex into a second vector anyway. So the kernels now take a CoordSpan,
and the common layout is read in place. A z ordinate to step over, or x
and y held apart as GeoParquet writes them, still have to be gathered;
those keep a buffer that is reused from one geometry to the next.
Writing allocated a fresh LinePieces or PolygonPieces per geometry, then
concatenated its coordinates onto the batch and rebased its offsets one at
a time, widening size_t to int32 as it went. But endPiece() already
records coordinates.size(), which is absolute in whatever buffer it is
filling - so the kernels now append into an accumulator the batch owns,
the offsets come out already correct, and the concatenate-and-rebase
blocks are gone. Holding the offsets as int32, the width an Arrow list
takes, means the accumulator's vectors are handed to Arrow as they stand.
Appending needs the polygon kernel's two closing passes - back to world
coordinates, and the mirror correction - bounded to what each call adds
rather than run over the accumulator as a whole. Two new Catch2 cases pin
that down, and they use a scaled, offset, y-downwards transform on
purpose: under the identity a coordinate transformed twice is
indistinguishable from one transformed once, and an earlier version of
these tests passed with both bounds removed.
One trap found by measuring rather than reading: reserve() asks for an
exact capacity rather than growing geometrically, so reserving exactly
what one polygon needs recopied the whole accumulator once per polygon.
That made polygons 31% slower before it was fixed.
Extension-only, on 20k linestrings to 300k pieces and 4k polygons to 188k
pieces, best of 15 runs, alternating binaries over three rounds:
linestrings 43.4 -> 37.4 ms (-14%), polygons 61.2 -> 57.3 ms (-6%). End to
end through split_linestrings is unchanged, as expected: it is dominated
by geopandas building shapely geometries from the result, which is around
ten times the extension's share and untouched here.
Pieces are bit-identical to before on both geometry types.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SqdWshmD4AUHhrqeMh86GS
0 commit comments