Files
tippecanoe/tile.hpp
T
Erica FischerandCursor 65beb3f0d7 Migrate jsonpull to unique_ptr ownership
Replaces the shared_ptr-based json_object_ptr with a unique_ptr that
has a stateless custom deleter dispatching on json_object::type before
calling the right subclass destructor. Eliminates per-node atomic
reference-counting and the control-block allocation that shared_ptr
required for every node in the tree.

API now distinguishes owning and borrowing pointers explicitly:
- json_read / json_read_separators / json_hash_get return raw
  json_object * (borrowed from the parser-owned tree).
- json_read_tree / json_disconnect return json_object_ptr (caller
  takes ownership; back-pointers are cleared so the subtree can
  outlive the parser).
- json_free / json_context / json_stringify take raw pointers.
- The parser's container_stack holds raw pointers; jp->root keeps
  unique_ptr ownership of the most recent top-level value.

Internally, take_from_owner moves the unique_ptr out of whichever
parent vector / hash entry / parser root owned it, which both
json_free and json_disconnect rely on.

In the streaming parsers (parse_feature, parse_layers, the
geojson-loop callback), we are careful to free `j` only after we
have processed a complete Feature: json_read returns each token
as the tree is being built up, and freeing an intermediate node
would splice it out of the surrounding hash and corrupt the
in-progress feature.

Benchmark (tl_2022_us_county.json, -z0 --extend-zooms-if-still-dropping,
median of 5 runs on macOS arm64): 8.5s, vs 10.6s with shared_ptr
and 8.7s on the pre-refactor C baseline.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-30 20:44:25 -07:00

70 lines
2.9 KiB
C++

#ifndef TILE_HPP
#define TILE_HPP
#include <stdio.h>
#include <sqlite3.h>
#include <vector>
#include <atomic>
#include <map>
#include "mbtiles.hpp"
#include "serial.hpp"
#include "attribute.hpp"
#include "jsonpull/jsonpull.h"
struct atomic_strategy {
std::atomic<size_t> dropped_by_rate;
std::atomic<size_t> dropped_by_gamma;
std::atomic<size_t> dropped_as_needed;
std::atomic<size_t> coalesced_as_needed;
std::atomic<size_t> detail_reduced;
std::atomic<size_t> tiny_polygons;
std::atomic<size_t> truncated_zooms;
atomic_strategy()
: dropped_by_rate(0),
dropped_by_gamma(0),
dropped_as_needed(0),
coalesced_as_needed(0),
detail_reduced(0),
tiny_polygons(0),
truncated_zooms(0) {
}
void add_from(struct strategy const &src);
};
struct strategy {
size_t dropped_by_rate = 0;
size_t dropped_by_gamma = 0;
size_t dropped_as_needed = 0;
size_t coalesced_as_needed = 0;
size_t detail_reduced = 0;
size_t tiny_polygons = 0;
size_t truncated_zooms = 0;
size_t tile_size = 0;
size_t feature_count = 0;
strategy(const atomic_strategy &s, size_t ts, size_t fc) {
dropped_by_rate = s.dropped_by_rate;
dropped_by_gamma = s.dropped_by_gamma;
dropped_as_needed = s.dropped_as_needed;
coalesced_as_needed = s.coalesced_as_needed;
detail_reduced = s.detail_reduced;
tile_size = ts;
feature_count = fc;
tiny_polygons = s.tiny_polygons;
truncated_zooms = s.truncated_zooms;
}
strategy() = default;
};
// long long write_tile(char **geom, char *stringpool, unsigned *file_bbox, int z, unsigned x, unsigned y, int detail, int min_detail, int basezoom, sqlite3 *outdb, const char *outdir, double droprate, int buffer, const char *fname, FILE **geomfile, int file_minzoom, int file_maxzoom, double todo, char *geomstart, long long along, double gamma, int nlayers, std::atomic<strategy> *strategy);
int traverse_zooms(int *geomfd, off_t *geom_size, char *stringpool, std::atomic<unsigned> *midx, std::atomic<unsigned> *midy, int &maxzoom, int minzoom, sqlite3 *outdb, const char *outdir, int buffer, const char *fname, const char *tmpdir, double gamma, int full_detail, int low_detail, int min_detail, long long *pool_off, unsigned *initial_x, unsigned *initial_y, double simplification, double maxzoom_simplification, std::vector<std::map<std::string, layermap_entry> > &layermap, const char *prefilter, const char *postfilter, std::unordered_map<std::string, attribute_op> const *attribute_accum, json_object *filter, std::vector<strategy> &strategies, int iz, struct node *shared_nodes_map, size_t nodepos, std::string const &shared_nodes_bloom, int basezoom, double droprate, std::vector<std::string> const &unidecode_data, std::string const *drop_by_attribute_as_needed_attribute, bool drop_by_attribute_descending);
int manage_gap(unsigned long long index, unsigned long long *previndex, double scale, double gamma, double *gap);
#endif