mirror of
https://github.com/felt/tippecanoe.git
synced 2026-10-02 08:25:40 +02:00
Subclass json_object so primitives shrink from 168 to 24 bytes
The previous "every member in a struct" layout cost 168 bytes per json_object, even for JSON_NULL / JSON_TRUE / JSON_FALSE nodes that have no payload. Splitting json_object into a small base class plus json_number / json_string / json_array / json_hash subclasses brings each instance down to just the size of its actual contents: json_object (base, TRUE / FALSE / NULL) 24 bytes json_number 48 bytes json_string 48 bytes json_array (empty) 48 bytes json_hash (empty) 72 bytes Other size wins along the way: * Drop enable_shared_from_this<json_object> (its embedded weak_ptr was 16 bytes per node). json_pull now keeps an explicit container_stack and the parser no longer needs to resurrect a shared_ptr from a raw `parent` walk. * Remove the unused `refcon` slot from the string variant. * No virtual destructor: shared_ptr keeps the deleter from the original std::make_shared<json_xxx> call, so destroying a shared_ptr<json_object> still runs the right subclass dtor. The base class exposes type-tagged accessors (o->string(), o->number(), o->array(), o->keys(), o->values(), o->large_signed(), o->large_unsigned()) that assert the type matches and downcast to the appropriate subclass storage. All call sites were swept from the old `o->value.X.Y` field paths to these accessors. A raw-pointer overload of json_hash_get() replaces the few external uses of shared_from_this() that survived in geojson-loop.cpp. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+4
-4
@@ -55,9 +55,9 @@ void set_attribute_accum(std::unordered_map<std::string, attribute_op> &attribut
|
||||
exit(EXIT_JSON);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < o->value.object.keys.size(); i++) {
|
||||
json_object_ptr k = o->value.object.keys[i];
|
||||
json_object_ptr v = o->value.object.values[i];
|
||||
for (size_t i = 0; i < o->keys().size(); i++) {
|
||||
json_object_ptr k = o->keys()[i];
|
||||
json_object_ptr v = o->values()[i];
|
||||
|
||||
if (k->type != JSON_STRING) {
|
||||
fprintf(stderr, "%s: -E%s: key %zu not a string\n", *argv, arg, i);
|
||||
@@ -68,7 +68,7 @@ void set_attribute_accum(std::unordered_map<std::string, attribute_op> &attribut
|
||||
exit(EXIT_JSON);
|
||||
}
|
||||
|
||||
set_attribute_accum(attribute_accum, k->value.string.string.c_str(), v->value.string.string.c_str());
|
||||
set_attribute_accum(attribute_accum, k->string().c_str(), v->string().c_str());
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
+4
-4
@@ -260,14 +260,14 @@ sqlite3 *dirmeta2tmp(const char *fname) {
|
||||
exit(EXIT_JSON);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < o->value.object.keys.size(); i++) {
|
||||
if (o->value.object.keys[i]->type != JSON_STRING || o->value.object.values[i]->type != JSON_STRING) {
|
||||
for (size_t i = 0; i < o->keys().size(); i++) {
|
||||
if (o->keys()[i]->type != JSON_STRING || o->values()[i]->type != JSON_STRING) {
|
||||
fprintf(stderr, "%s: non-string in metadata\n", name.c_str());
|
||||
}
|
||||
|
||||
char *sql = sqlite3_mprintf("INSERT INTO metadata (name, value) VALUES (%Q, %Q);", o->value.object.keys[i]->value.string.string.c_str(), o->value.object.values[i]->value.string.string.c_str());
|
||||
char *sql = sqlite3_mprintf("INSERT INTO metadata (name, value) VALUES (%Q, %Q);", o->keys()[i]->string().c_str(), o->values()[i]->string().c_str());
|
||||
if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
|
||||
fprintf(stderr, "set %s in metadata: %s\n", o->value.object.keys[i]->value.string.string.c_str(), err);
|
||||
fprintf(stderr, "set %s in metadata: %s\n", o->keys()[i]->string().c_str(), err);
|
||||
}
|
||||
sqlite3_free(sql);
|
||||
}
|
||||
|
||||
+28
-28
@@ -17,7 +17,7 @@ int compare(mvt_value const &one, json_object_ptr two, bool &fail) {
|
||||
return false; // string vs non-string
|
||||
}
|
||||
|
||||
return strcmp(one.c_str(), two->value.string.string.c_str());
|
||||
return strcmp(one.c_str(), two->string().c_str());
|
||||
|
||||
case mvt_double:
|
||||
case mvt_float:
|
||||
@@ -52,9 +52,9 @@ int compare(mvt_value const &one, json_object_ptr two, bool &fail) {
|
||||
exit(EXIT_IMPOSSIBLE);
|
||||
}
|
||||
|
||||
if (v < two->value.number.number) {
|
||||
if (v < two->number()) {
|
||||
return -1;
|
||||
} else if (v > two->value.number.number) {
|
||||
} else if (v > two->number()) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
@@ -102,7 +102,7 @@ static int eval(std::function<mvt_value(std::string const &)> feature, json_obje
|
||||
}
|
||||
|
||||
if (f->type == JSON_NUMBER) {
|
||||
if (f->value.number.number == 0) {
|
||||
if (f->number() == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
@@ -110,7 +110,7 @@ static int eval(std::function<mvt_value(std::string const &)> feature, json_obje
|
||||
}
|
||||
|
||||
if (f->type == JSON_STRING) {
|
||||
if (f->value.string.string.empty()) {
|
||||
if (f->string().empty()) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
@@ -123,39 +123,39 @@ static int eval(std::function<mvt_value(std::string const &)> feature, json_obje
|
||||
exit(EXIT_FILTER);
|
||||
}
|
||||
|
||||
if (f->value.array.array.size() < 1) {
|
||||
if (f->array().size() < 1) {
|
||||
fprintf(stderr, "Array too small in filter: %s\n", json_stringify(f).c_str());
|
||||
exit(EXIT_FILTER);
|
||||
}
|
||||
|
||||
if (f->value.array.array[0]->type != JSON_STRING) {
|
||||
if (f->array()[0]->type != JSON_STRING) {
|
||||
fprintf(stderr, "Filter operation is not a string: %s\n", json_stringify(f).c_str());
|
||||
exit(EXIT_FILTER);
|
||||
}
|
||||
|
||||
const std::string &op = f->value.array.array[0]->value.string.string;
|
||||
const std::string &op = f->array()[0]->string();
|
||||
|
||||
if (op == "has" ||
|
||||
op == "!has") {
|
||||
if (f->value.array.array.size() != 2) {
|
||||
if (f->array().size() != 2) {
|
||||
fprintf(stderr, "Wrong number of array elements in filter: %s\n", json_stringify(f).c_str());
|
||||
exit(EXIT_FILTER);
|
||||
}
|
||||
|
||||
if (op == "has") {
|
||||
if (f->value.array.array[1]->type != JSON_STRING) {
|
||||
if (f->array()[1]->type != JSON_STRING) {
|
||||
fprintf(stderr, "\"has\" key is not a string: %s\n", json_stringify(f).c_str());
|
||||
exit(EXIT_FILTER);
|
||||
}
|
||||
return feature(f->value.array.array[1]->value.string.string).type != mvt_no_such_key;
|
||||
return feature(f->array()[1]->string()).type != mvt_no_such_key;
|
||||
}
|
||||
|
||||
if (op == "!has") {
|
||||
if (f->value.array.array[1]->type != JSON_STRING) {
|
||||
if (f->array()[1]->type != JSON_STRING) {
|
||||
fprintf(stderr, "\"!has\" key is not a string: %s\n", json_stringify(f).c_str());
|
||||
exit(EXIT_FILTER);
|
||||
}
|
||||
return feature(f->value.array.array[1]->value.string.string).type == mvt_no_such_key;
|
||||
return feature(f->array()[1]->string()).type == mvt_no_such_key;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,16 +165,16 @@ static int eval(std::function<mvt_value(std::string const &)> feature, json_obje
|
||||
op == ">=" ||
|
||||
op == "<" ||
|
||||
op == "<=") {
|
||||
if (f->value.array.array.size() != 3) {
|
||||
if (f->array().size() != 3) {
|
||||
fprintf(stderr, "Wrong number of array elements in filter: %s\n", json_stringify(f).c_str());
|
||||
exit(EXIT_FILTER);
|
||||
}
|
||||
if (f->value.array.array[1]->type != JSON_STRING) {
|
||||
if (f->array()[1]->type != JSON_STRING) {
|
||||
fprintf(stderr, "comparison key is not a string: %s\n", json_stringify(f).c_str());
|
||||
exit(EXIT_FILTER);
|
||||
}
|
||||
|
||||
mvt_value ff = feature(f->value.array.array[1]->value.string.string);
|
||||
mvt_value ff = feature(f->array()[1]->string());
|
||||
if (ff.type == mvt_no_such_key) {
|
||||
static bool warned = false;
|
||||
if (!warned) {
|
||||
@@ -188,7 +188,7 @@ static int eval(std::function<mvt_value(std::string const &)> feature, json_obje
|
||||
}
|
||||
|
||||
bool fail = false;
|
||||
int cmp = compare(ff, f->value.array.array[2], fail);
|
||||
int cmp = compare(ff, f->array()[2], fail);
|
||||
|
||||
if (fail) {
|
||||
static bool warned = false;
|
||||
@@ -236,8 +236,8 @@ static int eval(std::function<mvt_value(std::string const &)> feature, json_obje
|
||||
v = false;
|
||||
}
|
||||
|
||||
for (size_t i = 1; i < f->value.array.array.size(); i++) {
|
||||
int out = eval(feature, f->value.array.array[i], exclude_attributes, unidecode_data);
|
||||
for (size_t i = 1; i < f->array().size(); i++) {
|
||||
int out = eval(feature, f->array()[i], exclude_attributes, unidecode_data);
|
||||
|
||||
if (out >= 0) { // nulls are ignored in boolean and/or expressions
|
||||
if (op == "all") {
|
||||
@@ -263,17 +263,17 @@ static int eval(std::function<mvt_value(std::string const &)> feature, json_obje
|
||||
|
||||
if (op == "in" ||
|
||||
op == "!in") {
|
||||
if (f->value.array.array.size() < 2) {
|
||||
if (f->array().size() < 2) {
|
||||
fprintf(stderr, "Array too small in filter: %s\n", json_stringify(f).c_str());
|
||||
exit(EXIT_FILTER);
|
||||
}
|
||||
|
||||
if (f->value.array.array[1]->type != JSON_STRING) {
|
||||
if (f->array()[1]->type != JSON_STRING) {
|
||||
fprintf(stderr, "\"!in\" key is not a string: %s\n", json_stringify(f).c_str());
|
||||
exit(EXIT_FILTER);
|
||||
}
|
||||
|
||||
mvt_value ff = feature(f->value.array.array[1]->value.string.string);
|
||||
mvt_value ff = feature(f->array()[1]->string());
|
||||
if (ff.type == mvt_no_such_key) {
|
||||
static bool warned = false;
|
||||
if (!warned) {
|
||||
@@ -287,9 +287,9 @@ static int eval(std::function<mvt_value(std::string const &)> feature, json_obje
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
for (size_t i = 2; i < f->value.array.array.size(); i++) {
|
||||
for (size_t i = 2; i < f->array().size(); i++) {
|
||||
bool fail = false;
|
||||
int cmp = compare(ff, f->value.array.array[i], fail);
|
||||
int cmp = compare(ff, f->array()[i], fail);
|
||||
|
||||
if (fail) {
|
||||
static bool warned = false;
|
||||
@@ -314,19 +314,19 @@ static int eval(std::function<mvt_value(std::string const &)> feature, json_obje
|
||||
}
|
||||
|
||||
if (op == "attribute-filter") {
|
||||
if (f->value.array.array.size() != 3) {
|
||||
if (f->array().size() != 3) {
|
||||
fprintf(stderr, "Wrong number of array elements in filter: %s\n", json_stringify(f).c_str());
|
||||
exit(EXIT_FILTER);
|
||||
}
|
||||
|
||||
if (f->value.array.array[1]->type != JSON_STRING) {
|
||||
if (f->array()[1]->type != JSON_STRING) {
|
||||
fprintf(stderr, "\"attribute-filter\" key is not a string: %s\n", json_stringify(f).c_str());
|
||||
exit(EXIT_FILTER);
|
||||
}
|
||||
|
||||
bool ok = eval(feature, f->value.array.array[2], exclude_attributes, unidecode_data) > 0;
|
||||
bool ok = eval(feature, f->array()[2], exclude_attributes, unidecode_data) > 0;
|
||||
if (!ok) {
|
||||
exclude_attributes.insert(f->value.array.array[1]->value.string.string);
|
||||
exclude_attributes.insert(f->array()[1]->string());
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
+3
-3
@@ -400,17 +400,17 @@ void readFeature(protozero::pbf_reader &pbf, size_t dim, double e, std::vector<s
|
||||
if (o != nullptr) {
|
||||
json_object_ptr min = json_hash_get(o, "minzoom");
|
||||
if (min != nullptr && (min->type == JSON_NUMBER)) {
|
||||
sf.tippecanoe_minzoom = integer_zoom(sst->fname, milo::dtoa_milo(min->value.number.number));
|
||||
sf.tippecanoe_minzoom = integer_zoom(sst->fname, milo::dtoa_milo(min->number()));
|
||||
}
|
||||
|
||||
json_object_ptr max = json_hash_get(o, "maxzoom");
|
||||
if (max != nullptr && (max->type == JSON_NUMBER)) {
|
||||
sf.tippecanoe_maxzoom = integer_zoom(sst->fname, milo::dtoa_milo(max->value.number.number));
|
||||
sf.tippecanoe_maxzoom = integer_zoom(sst->fname, milo::dtoa_milo(max->number()));
|
||||
}
|
||||
|
||||
json_object_ptr tlayer = json_hash_get(o, "layer");
|
||||
if (tlayer != nullptr && (tlayer->type == JSON_STRING)) {
|
||||
layername = tlayer->value.string.string;
|
||||
layername = tlayer->string();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-7
@@ -74,7 +74,7 @@ void parse_json(json_feature_action *jfa, json_pull_ptr jp) {
|
||||
int i;
|
||||
int is_geometry = 0;
|
||||
for (i = 0; i < GEOM_TYPES; i++) {
|
||||
if (type->value.string.string == geometry_names[i]) {
|
||||
if (type->string() == geometry_names[i]) {
|
||||
is_geometry = 1;
|
||||
break;
|
||||
}
|
||||
@@ -84,14 +84,14 @@ void parse_json(json_feature_action *jfa, json_pull_ptr jp) {
|
||||
if (j->parent != nullptr) {
|
||||
if (j->parent->type == JSON_ARRAY && j->parent->parent != nullptr) {
|
||||
if (j->parent->parent->type == JSON_HASH) {
|
||||
json_object_ptr geometries = json_hash_get(j->parent->parent->shared_from_this(), "geometries");
|
||||
json_object_ptr geometries = json_hash_get(j->parent->parent, "geometries");
|
||||
if (geometries != nullptr) {
|
||||
// Parent of Parent must be a GeometryCollection
|
||||
is_geometry = 0;
|
||||
}
|
||||
}
|
||||
} else if (j->parent->type == JSON_HASH) {
|
||||
json_object_ptr geometry = json_hash_get(j->parent->shared_from_this(), "geometry");
|
||||
json_object_ptr geometry = json_hash_get(j->parent, "geometry");
|
||||
if (geometry != nullptr) {
|
||||
// Parent must be a Feature
|
||||
is_geometry = 0;
|
||||
@@ -104,7 +104,7 @@ void parse_json(json_feature_action *jfa, json_pull_ptr jp) {
|
||||
json_object *jo = j.get();
|
||||
while (jo != nullptr) {
|
||||
if (jo->parent != nullptr && jo->parent->type == JSON_HASH) {
|
||||
if (json_hash_get(jo->parent->shared_from_this(), "properties").get() == jo) {
|
||||
if (json_hash_get(jo->parent, "properties").get() == jo) {
|
||||
// Ancestor is the value corresponding to a properties key
|
||||
is_geometry = 0;
|
||||
break;
|
||||
@@ -126,8 +126,8 @@ void parse_json(json_feature_action *jfa, json_pull_ptr jp) {
|
||||
}
|
||||
}
|
||||
|
||||
if (type->value.string.string != "Feature") {
|
||||
if (type->value.string.string == "FeatureCollection") {
|
||||
if (type->string() != "Feature") {
|
||||
if (type->string() == "FeatureCollection") {
|
||||
jfa->check_crs(j);
|
||||
json_free(j);
|
||||
}
|
||||
@@ -161,7 +161,7 @@ void parse_json(json_feature_action *jfa, json_pull_ptr jp) {
|
||||
json_object *jo = j.get();
|
||||
while (jo != nullptr) {
|
||||
if (jo->parent != nullptr && jo->parent->type == JSON_HASH) {
|
||||
if (json_hash_get(jo->parent->shared_from_this(), "properties").get() == jo) {
|
||||
if (json_hash_get(jo->parent, "properties").get() == jo) {
|
||||
// Ancestor is the value corresponding to a properties key
|
||||
is_feature = false;
|
||||
break;
|
||||
|
||||
+25
-25
@@ -68,12 +68,12 @@ int serialize_geojson_feature(struct serialization_state *sst, json_object_ptr g
|
||||
|
||||
int t;
|
||||
for (t = 0; t < GEOM_TYPES; t++) {
|
||||
if (geometry_type->value.string.string == geometry_names[t]) {
|
||||
if (geometry_type->string() == geometry_names[t]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (t >= GEOM_TYPES) {
|
||||
fprintf(stderr, "%s:%d: Can't handle geometry type %s: ", sst->fname, sst->line, geometry_type->value.string.string.c_str());
|
||||
fprintf(stderr, "%s:%d: Can't handle geometry type %s: ", sst->fname, sst->line, geometry_type->string().c_str());
|
||||
json_context(feature);
|
||||
return 0;
|
||||
}
|
||||
@@ -85,17 +85,17 @@ int serialize_geojson_feature(struct serialization_state *sst, json_object_ptr g
|
||||
if (tippecanoe != nullptr) {
|
||||
json_object_ptr min = json_hash_get(tippecanoe, "minzoom");
|
||||
if (min != nullptr && (min->type == JSON_NUMBER)) {
|
||||
tippecanoe_minzoom = integer_zoom(sst->fname, milo::dtoa_milo(min->value.number.number));
|
||||
tippecanoe_minzoom = integer_zoom(sst->fname, milo::dtoa_milo(min->number()));
|
||||
}
|
||||
|
||||
json_object_ptr max = json_hash_get(tippecanoe, "maxzoom");
|
||||
if (max != nullptr && (max->type == JSON_NUMBER)) {
|
||||
tippecanoe_maxzoom = integer_zoom(sst->fname, milo::dtoa_milo(max->value.number.number));
|
||||
tippecanoe_maxzoom = integer_zoom(sst->fname, milo::dtoa_milo(max->number()));
|
||||
}
|
||||
|
||||
json_object_ptr ln = json_hash_get(tippecanoe, "layer");
|
||||
if (ln != nullptr && (ln->type == JSON_STRING)) {
|
||||
tippecanoe_layername = ln->value.string.string;
|
||||
tippecanoe_layername = ln->string();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,27 +103,27 @@ int serialize_geojson_feature(struct serialization_state *sst, json_object_ptr g
|
||||
unsigned long long id_value = 0;
|
||||
if (id != nullptr) {
|
||||
if (id->type == JSON_NUMBER) {
|
||||
if (id->value.number.number >= 0) {
|
||||
if (id->number() >= 0) {
|
||||
char *err = NULL;
|
||||
std::string id_number = milo::dtoa_milo(id->value.number.number);
|
||||
std::string id_number = milo::dtoa_milo(id->number());
|
||||
id_value = strtoull(id_number.c_str(), &err, 10);
|
||||
|
||||
if (id->value.number.large_unsigned != 0) {
|
||||
id_value = id->value.number.large_unsigned;
|
||||
if (id->large_unsigned() != 0) {
|
||||
id_value = id->large_unsigned();
|
||||
}
|
||||
|
||||
if (err != NULL && *err != '\0') {
|
||||
static bool warned_frac = false;
|
||||
|
||||
if (!warned_frac) {
|
||||
fprintf(stderr, "Warning: Can't represent non-integer feature ID %s\n", milo::dtoa_milo(id->value.number.number).c_str());
|
||||
fprintf(stderr, "Warning: Can't represent non-integer feature ID %s\n", milo::dtoa_milo(id->number()).c_str());
|
||||
warned_frac = true;
|
||||
}
|
||||
} else if (id->value.number.large_unsigned == 0 && std::to_string(id_value) != milo::dtoa_milo(id->value.number.number)) {
|
||||
} else if (id->large_unsigned() == 0 && std::to_string(id_value) != milo::dtoa_milo(id->number())) {
|
||||
static bool warned = false;
|
||||
|
||||
if (!warned) {
|
||||
fprintf(stderr, "Warning: Can't represent too-large feature ID %s\n", milo::dtoa_milo(id->value.number.number).c_str());
|
||||
fprintf(stderr, "Warning: Can't represent too-large feature ID %s\n", milo::dtoa_milo(id->number()).c_str());
|
||||
warned = true;
|
||||
}
|
||||
} else {
|
||||
@@ -133,7 +133,7 @@ int serialize_geojson_feature(struct serialization_state *sst, json_object_ptr g
|
||||
static bool warned_neg = false;
|
||||
|
||||
if (!warned_neg) {
|
||||
fprintf(stderr, "Warning: Can't represent negative feature ID %s\n", milo::dtoa_milo(id->value.number.number).c_str());
|
||||
fprintf(stderr, "Warning: Can't represent negative feature ID %s\n", milo::dtoa_milo(id->number()).c_str());
|
||||
warned_neg = true;
|
||||
}
|
||||
}
|
||||
@@ -142,20 +142,20 @@ int serialize_geojson_feature(struct serialization_state *sst, json_object_ptr g
|
||||
|
||||
if (additional[A_CONVERT_NUMERIC_IDS] && id->type == JSON_STRING) {
|
||||
char *err = NULL;
|
||||
id_value = strtoull(id->value.string.string.c_str(), &err, 10);
|
||||
id_value = strtoull(id->string().c_str(), &err, 10);
|
||||
|
||||
if (err != NULL && *err != '\0') {
|
||||
static bool warned_frac = false;
|
||||
|
||||
if (!warned_frac) {
|
||||
fprintf(stderr, "Warning: Can't represent non-integer feature ID %s\n", id->value.string.string.c_str());
|
||||
fprintf(stderr, "Warning: Can't represent non-integer feature ID %s\n", id->string().c_str());
|
||||
warned_frac = true;
|
||||
}
|
||||
} else if (std::to_string(id_value) != id->value.string.string) {
|
||||
} else if (std::to_string(id_value) != id->string()) {
|
||||
static bool warned = false;
|
||||
|
||||
if (!warned) {
|
||||
fprintf(stderr, "Warning: Can't represent too-large feature ID %s\n", id->value.string.string.c_str());
|
||||
fprintf(stderr, "Warning: Can't represent too-large feature ID %s\n", id->string().c_str());
|
||||
warned = true;
|
||||
}
|
||||
} else {
|
||||
@@ -177,7 +177,7 @@ int serialize_geojson_feature(struct serialization_state *sst, json_object_ptr g
|
||||
|
||||
size_t nprop = 0;
|
||||
if (properties != nullptr && properties->type == JSON_HASH) {
|
||||
nprop = properties->value.object.keys.size();
|
||||
nprop = properties->keys().size();
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<std::string>> full_keys;
|
||||
@@ -188,10 +188,10 @@ int serialize_geojson_feature(struct serialization_state *sst, json_object_ptr g
|
||||
key_pool key_pool;
|
||||
|
||||
for (size_t i = 0; i < nprop; i++) {
|
||||
if (properties->value.object.keys[i]->type == JSON_STRING) {
|
||||
serial_val sv = stringify_value(properties->value.object.values[i], sst->fname, sst->line, feature);
|
||||
if (properties->keys()[i]->type == JSON_STRING) {
|
||||
serial_val sv = stringify_value(properties->values()[i], sst->fname, sst->line, feature);
|
||||
|
||||
full_keys.emplace_back(key_pool.pool(properties->value.object.keys[i]->value.string.string.c_str()));
|
||||
full_keys.emplace_back(key_pool.pool(properties->keys()[i]->string().c_str()));
|
||||
values.push_back(std::move(sv));
|
||||
}
|
||||
}
|
||||
@@ -223,9 +223,9 @@ void check_crs(json_object_ptr j, const char *reading) {
|
||||
if (properties != nullptr) {
|
||||
json_object_ptr name = json_hash_get(properties, "name");
|
||||
if (name != nullptr && name->type == JSON_STRING) {
|
||||
if (name->value.string.string != projection->alias) {
|
||||
if (name->string() != projection->alias) {
|
||||
if (!quiet) {
|
||||
fprintf(stderr, "%s: Warning: GeoJSON specified projection \"%s\", not the expected \"%s\".\n", reading, name->value.string.string.c_str(), projection->alias);
|
||||
fprintf(stderr, "%s: Warning: GeoJSON specified projection \"%s\", not the expected \"%s\".\n", reading, name->string().c_str(), projection->alias);
|
||||
fprintf(stderr, "%s: If \"%s\" is not the expected projection, use -s to specify the right one.\n", reading, projection->alias);
|
||||
}
|
||||
}
|
||||
@@ -243,8 +243,8 @@ struct json_serialize_action : json_feature_action {
|
||||
sst->line = geometry->parser->line;
|
||||
if (geometrycollection) {
|
||||
int ret = 1;
|
||||
for (size_t g = 0; g < geometry->value.array.array.size(); g++) {
|
||||
ret &= serialize_geojson_feature(sst, geometry->value.array.array[g], properties, id, layer, tippecanoe, feature, layername);
|
||||
for (size_t g = 0; g < geometry->array().size(); g++) {
|
||||
ret &= serialize_geojson_feature(sst, geometry->array()[g], properties, id, layer, tippecanoe, feature, layername);
|
||||
}
|
||||
return ret;
|
||||
} else {
|
||||
|
||||
+112
-83
@@ -86,22 +86,47 @@ static inline int read_wrap(json_pull *j) {
|
||||
return c;
|
||||
}
|
||||
|
||||
static json_object_ptr fabricate_object(json_pull *jp, json_object *parent, json_type type) {
|
||||
auto o = std::make_shared<json_object>();
|
||||
o->type = type;
|
||||
o->parent = parent;
|
||||
o->parser = jp;
|
||||
// Construct an instance of the right subclass for the given type.
|
||||
// JSON_TRUE / JSON_FALSE / JSON_NULL and the parse-token types are bare
|
||||
// json_objects; the value-bearing types each get their own subclass.
|
||||
static json_object_ptr make_object(json_type type, json_object *parent, json_pull *jp) {
|
||||
json_object_ptr o;
|
||||
switch (type) {
|
||||
case JSON_NUMBER:
|
||||
o = std::make_shared<json_number>(parent, jp);
|
||||
break;
|
||||
case JSON_STRING:
|
||||
o = std::make_shared<json_string>(parent, jp);
|
||||
break;
|
||||
case JSON_ARRAY:
|
||||
o = std::make_shared<json_array>(parent, jp);
|
||||
break;
|
||||
case JSON_HASH:
|
||||
o = std::make_shared<json_hash>(parent, jp);
|
||||
break;
|
||||
default:
|
||||
o = std::make_shared<json_object>(type, parent, jp);
|
||||
break;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
static json_object_ptr fabricate_object(json_pull *jp, json_object *parent, json_type type) {
|
||||
return make_object(type, parent, jp);
|
||||
}
|
||||
|
||||
static inline json_object *current_container(json_pull *j) {
|
||||
return j->container_stack.empty() ? nullptr : j->container_stack.back().get();
|
||||
}
|
||||
|
||||
static json_object_ptr add_object(json_pull *j, json_type type) {
|
||||
json_object *c = j->container.get();
|
||||
json_object_ptr o = fabricate_object(j, c, type);
|
||||
json_object *c = current_container(j);
|
||||
json_object_ptr o = make_object(type, c, j);
|
||||
|
||||
if (c != nullptr) {
|
||||
if (c->type == JSON_ARRAY) {
|
||||
if (c->expect == JSON_ITEM) {
|
||||
c->value.array.array.push_back(o);
|
||||
c->array().push_back(o);
|
||||
c->expect = JSON_COMMA;
|
||||
} else {
|
||||
j->error = "Expected a comma, not a list item";
|
||||
@@ -109,7 +134,7 @@ static json_object_ptr add_object(json_pull *j, json_type type) {
|
||||
}
|
||||
} else if (c->type == JSON_HASH) {
|
||||
if (c->expect == JSON_VALUE) {
|
||||
c->value.object.values.back() = o;
|
||||
c->values().back() = o;
|
||||
c->expect = JSON_COMMA;
|
||||
} else if (c->expect == JSON_KEY) {
|
||||
if (type != JSON_STRING) {
|
||||
@@ -117,8 +142,8 @@ static json_object_ptr add_object(json_pull *j, json_type type) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
c->value.object.keys.push_back(o);
|
||||
c->value.object.values.push_back(nullptr);
|
||||
c->keys().push_back(o);
|
||||
c->values().push_back(nullptr);
|
||||
c->expect = JSON_COLON;
|
||||
} else {
|
||||
j->error = "Expected a comma or colon";
|
||||
@@ -134,16 +159,18 @@ static json_object_ptr add_object(json_pull *j, json_type type) {
|
||||
return o;
|
||||
}
|
||||
|
||||
json_object_ptr json_hash_get(json_object_ptr o, const char *s) {
|
||||
json_object_ptr json_hash_get(json_object *o, const char *s) {
|
||||
if (o == nullptr || o->type != JSON_HASH) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < o->value.object.keys.size(); i++) {
|
||||
const auto &key = o->value.object.keys[i];
|
||||
const auto &keys = o->keys();
|
||||
const auto &vals = o->values();
|
||||
for (size_t i = 0; i < keys.size(); i++) {
|
||||
const auto &key = keys[i];
|
||||
if (key != nullptr && key->type == JSON_STRING) {
|
||||
if (key->value.string.string == s) {
|
||||
return o->value.object.values[i];
|
||||
if (key->string() == s) {
|
||||
return vals[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -151,19 +178,23 @@ json_object_ptr json_hash_get(json_object_ptr o, const char *s) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
json_object_ptr json_hash_get(json_object_ptr o, const char *s) {
|
||||
return json_hash_get(o.get(), s);
|
||||
}
|
||||
|
||||
json_object_ptr json_read_separators(json_pull_ptr jp, json_separator_callback cb, void *state) {
|
||||
int c;
|
||||
json_pull *j = jp.get();
|
||||
|
||||
// In case there is an error at the top level
|
||||
if (j->container == nullptr) {
|
||||
if (j->container_stack.empty()) {
|
||||
j->root.reset();
|
||||
}
|
||||
|
||||
again:
|
||||
c = read_wrap(j);
|
||||
if (c == EOF) {
|
||||
if (j->container != nullptr) {
|
||||
if (!j->container_stack.empty()) {
|
||||
j->error = "Reached EOF without all containers being closed";
|
||||
}
|
||||
|
||||
@@ -204,8 +235,8 @@ again:
|
||||
if (o == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
j->container = o;
|
||||
j->container->expect = JSON_ITEM;
|
||||
o->expect = JSON_ITEM;
|
||||
j->container_stack.push_back(o);
|
||||
|
||||
if (cb != nullptr) {
|
||||
cb(JSON_ARRAY, j, state);
|
||||
@@ -215,32 +246,26 @@ again:
|
||||
}
|
||||
|
||||
case ']': {
|
||||
if (j->container == nullptr) {
|
||||
json_object *cc = current_container(j);
|
||||
if (cc == nullptr) {
|
||||
j->error = "Found ] at top level";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (j->container->type != JSON_ARRAY) {
|
||||
if (cc->type != JSON_ARRAY) {
|
||||
j->error = "Found ] not in an array";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (j->container->expect != JSON_COMMA) {
|
||||
if (!(j->container->expect == JSON_ITEM && j->container->value.array.array.size() == 0)) {
|
||||
if (cc->expect != JSON_COMMA) {
|
||||
if (!(cc->expect == JSON_ITEM && cc->array().size() == 0)) {
|
||||
j->error = "Found ] without final element";
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
json_object_ptr ret = j->container;
|
||||
// Walk up to the parent container. The parent (if any) still owns
|
||||
// `ret` via its own array vector, so the raw `parent` pointer is
|
||||
// still valid and we can resurrect a shared_ptr to it.
|
||||
if (ret->parent != nullptr) {
|
||||
j->container = ret->parent->shared_from_this();
|
||||
} else {
|
||||
j->container.reset();
|
||||
}
|
||||
json_object_ptr ret = j->container_stack.back();
|
||||
j->container_stack.pop_back();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -251,8 +276,8 @@ again:
|
||||
if (o == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
j->container = o;
|
||||
j->container->expect = JSON_KEY;
|
||||
o->expect = JSON_KEY;
|
||||
j->container_stack.push_back(o);
|
||||
|
||||
if (cb != nullptr) {
|
||||
cb(JSON_HASH, j, state);
|
||||
@@ -262,29 +287,26 @@ again:
|
||||
}
|
||||
|
||||
case '}': {
|
||||
if (j->container == nullptr) {
|
||||
json_object *cc = current_container(j);
|
||||
if (cc == nullptr) {
|
||||
j->error = "Found } at top level";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (j->container->type != JSON_HASH) {
|
||||
if (cc->type != JSON_HASH) {
|
||||
j->error = "Found } not in a hash";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (j->container->expect != JSON_COMMA) {
|
||||
if (!(j->container->expect == JSON_KEY && j->container->value.object.keys.size() == 0)) {
|
||||
if (cc->expect != JSON_COMMA) {
|
||||
if (!(cc->expect == JSON_KEY && cc->keys().size() == 0)) {
|
||||
j->error = "Found } without final element";
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
json_object_ptr ret = j->container;
|
||||
if (ret->parent != nullptr) {
|
||||
j->container = ret->parent->shared_from_this();
|
||||
} else {
|
||||
j->container.reset();
|
||||
}
|
||||
json_object_ptr ret = j->container_stack.back();
|
||||
j->container_stack.pop_back();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -350,16 +372,17 @@ again:
|
||||
/////////////////////////// Comma
|
||||
|
||||
case ',': {
|
||||
if (j->container != nullptr) {
|
||||
if (j->container->expect != JSON_COMMA) {
|
||||
json_object *cc = current_container(j);
|
||||
if (cc != nullptr) {
|
||||
if (cc->expect != JSON_COMMA) {
|
||||
j->error = "Found unexpected comma";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (j->container->type == JSON_HASH) {
|
||||
j->container->expect = JSON_KEY;
|
||||
if (cc->type == JSON_HASH) {
|
||||
cc->expect = JSON_KEY;
|
||||
} else {
|
||||
j->container->expect = JSON_ITEM;
|
||||
cc->expect = JSON_ITEM;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -373,17 +396,18 @@ again:
|
||||
/////////////////////////// Colon
|
||||
|
||||
case ':': {
|
||||
if (j->container == nullptr) {
|
||||
json_object *cc = current_container(j);
|
||||
if (cc == nullptr) {
|
||||
j->error = "Found colon at top level";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (j->container->expect != JSON_COLON) {
|
||||
if (cc->expect != JSON_COLON) {
|
||||
j->error = "Found unexpected colon";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
j->container->expect = JSON_VALUE;
|
||||
cc->expect = JSON_VALUE;
|
||||
|
||||
if (cb != nullptr) {
|
||||
cb(JSON_COLON, j, state);
|
||||
@@ -463,27 +487,27 @@ again:
|
||||
|
||||
json_object_ptr n = add_object(j, JSON_NUMBER);
|
||||
if (n != nullptr) {
|
||||
n->value.number.number = atof(j->number_buffer.c_str());
|
||||
n->value.number.large_signed = 0;
|
||||
n->value.number.large_unsigned = 0;
|
||||
n->number() = atof(j->number_buffer.c_str());
|
||||
n->large_signed() = 0;
|
||||
n->large_unsigned() = 0;
|
||||
|
||||
#define MAX_SAFE_INTEGER 9007199254740991.0
|
||||
#define MIN_SAFE_INTEGER -9007199254740991.0
|
||||
|
||||
if (!decimal && n->value.number.number > MAX_SAFE_INTEGER) {
|
||||
if (!decimal && n->number() > MAX_SAFE_INTEGER) {
|
||||
errno = 0;
|
||||
char *err = nullptr;
|
||||
unsigned long long ull = strtoull(j->number_buffer.c_str(), &err, 10);
|
||||
if (errno == 0 && (err == nullptr || *err == '\0')) {
|
||||
n->value.number.large_unsigned = ull;
|
||||
n->large_unsigned() = ull;
|
||||
}
|
||||
}
|
||||
if (!decimal && n->value.number.number < MIN_SAFE_INTEGER) {
|
||||
if (!decimal && n->number() < MIN_SAFE_INTEGER) {
|
||||
errno = 0;
|
||||
char *err = nullptr;
|
||||
long long ll = strtoll(j->number_buffer.c_str(), &err, 10);
|
||||
if (errno == 0 && (err == nullptr || *err == '\0')) {
|
||||
n->value.number.large_signed = ll;
|
||||
n->large_signed() = ll;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -614,8 +638,7 @@ again:
|
||||
|
||||
json_object_ptr s = add_object(j, JSON_STRING);
|
||||
if (s != nullptr) {
|
||||
s->value.string.string = std::move(val);
|
||||
s->value.string.refcon = nullptr;
|
||||
s->string() = std::move(val);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
@@ -653,13 +676,16 @@ static void clear_back_pointers(json_object *o) {
|
||||
}
|
||||
|
||||
if (o->type == JSON_HASH) {
|
||||
for (size_t i = 0; i < o->value.object.keys.size(); i++) {
|
||||
clear_back_pointers(o->value.object.keys[i].get());
|
||||
clear_back_pointers(o->value.object.values[i].get());
|
||||
const auto &keys = o->keys();
|
||||
const auto &vals = o->values();
|
||||
for (size_t i = 0; i < keys.size(); i++) {
|
||||
clear_back_pointers(keys[i].get());
|
||||
clear_back_pointers(vals[i].get());
|
||||
}
|
||||
} else if (o->type == JSON_ARRAY) {
|
||||
for (size_t i = 0; i < o->value.array.array.size(); i++) {
|
||||
clear_back_pointers(o->value.array.array[i].get());
|
||||
const auto &arr = o->array();
|
||||
for (size_t i = 0; i < arr.size(); i++) {
|
||||
clear_back_pointers(arr[i].get());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -679,7 +705,7 @@ void json_disconnect(json_object_ptr o) {
|
||||
json_object *parent = o->parent;
|
||||
if (parent != nullptr) {
|
||||
if (parent->type == JSON_ARRAY) {
|
||||
auto &arr = parent->value.array.array;
|
||||
auto &arr = parent->array();
|
||||
for (size_t i = 0; i < arr.size(); i++) {
|
||||
if (arr[i].get() == o.get()) {
|
||||
arr.erase(arr.begin() + i);
|
||||
@@ -687,8 +713,8 @@ void json_disconnect(json_object_ptr o) {
|
||||
}
|
||||
}
|
||||
} else if (parent->type == JSON_HASH) {
|
||||
auto &keys = parent->value.object.keys;
|
||||
auto &vals = parent->value.object.values;
|
||||
auto &keys = parent->keys();
|
||||
auto &vals = parent->values();
|
||||
|
||||
for (size_t i = 0; i < keys.size(); i++) {
|
||||
if (keys[i].get() == o.get()) {
|
||||
@@ -739,7 +765,7 @@ static void json_print_one(std::string &val, json_object *o) {
|
||||
} else if (o->type == JSON_STRING) {
|
||||
string_append_c(val, '\"');
|
||||
|
||||
for (const char *cp = o->value.string.string.c_str(); *cp != '\0'; cp++) {
|
||||
for (const char *cp = o->string().c_str(); *cp != '\0'; cp++) {
|
||||
if (*cp == '\\' || *cp == '"') {
|
||||
string_append_c(val, '\\');
|
||||
string_append_c(val, *cp);
|
||||
@@ -756,16 +782,16 @@ static void json_print_one(std::string &val, json_object *o) {
|
||||
|
||||
string_append_c(val, '\"');
|
||||
} else if (o->type == JSON_NUMBER) {
|
||||
if (o->value.number.large_signed != 0) {
|
||||
if (o->large_signed() != 0) {
|
||||
char s[65];
|
||||
snprintf(s, sizeof(s), "%lld", o->value.number.large_signed);
|
||||
snprintf(s, sizeof(s), "%lld", o->large_signed());
|
||||
string_append(val, s);
|
||||
} else if (o->value.number.large_unsigned != 0) {
|
||||
} else if (o->large_unsigned() != 0) {
|
||||
char s[65];
|
||||
snprintf(s, sizeof(s), "%llu", o->value.number.large_unsigned);
|
||||
snprintf(s, sizeof(s), "%llu", o->large_unsigned());
|
||||
string_append(val, s);
|
||||
} else {
|
||||
char *s = dtoa_milo(o->value.number.number);
|
||||
char *s = dtoa_milo(o->number());
|
||||
string_append(val, s);
|
||||
free(s);
|
||||
}
|
||||
@@ -789,20 +815,23 @@ static void json_print(std::string &val, json_object *o) {
|
||||
} else if (o->type == JSON_HASH) {
|
||||
string_append_c(val, '{');
|
||||
|
||||
for (size_t i = 0; i < o->value.object.keys.size(); i++) {
|
||||
json_print(val, o->value.object.keys[i].get());
|
||||
const auto &keys = o->keys();
|
||||
const auto &vals = o->values();
|
||||
for (size_t i = 0; i < keys.size(); i++) {
|
||||
json_print(val, keys[i].get());
|
||||
string_append_c(val, ':');
|
||||
json_print(val, o->value.object.values[i].get());
|
||||
if (i + 1 < o->value.object.keys.size()) {
|
||||
json_print(val, vals[i].get());
|
||||
if (i + 1 < keys.size()) {
|
||||
string_append_c(val, ',');
|
||||
}
|
||||
}
|
||||
string_append_c(val, '}');
|
||||
} else if (o->type == JSON_ARRAY) {
|
||||
string_append_c(val, '[');
|
||||
for (size_t i = 0; i < o->value.array.array.size(); i++) {
|
||||
json_print(val, o->value.array.array[i].get());
|
||||
if (i + 1 < o->value.array.array.size()) {
|
||||
const auto &arr = o->array();
|
||||
for (size_t i = 0; i < arr.size(); i++) {
|
||||
json_print(val, arr[i].get());
|
||||
if (i + 1 < arr.size()) {
|
||||
string_append_c(val, ',');
|
||||
}
|
||||
}
|
||||
|
||||
+143
-33
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -33,48 +34,152 @@ struct json_pull;
|
||||
typedef std::shared_ptr<json_object> json_object_ptr;
|
||||
typedef std::shared_ptr<json_pull> json_pull_ptr;
|
||||
|
||||
// json_object owns its descendants via std::shared_ptr in std::vector<>s,
|
||||
// and keeps raw back-pointers to its parent and to the parser. The back-pointers
|
||||
// remain valid as long as the node is attached to the tree (the parent is kept
|
||||
// alive by holding a shared_ptr to this child, and the parser is kept alive by
|
||||
// the caller's json_pull_ptr). json_disconnect() splices a node out of its
|
||||
// parent and clears those back-pointers in the detached subtree, so the
|
||||
// detached subtree can outlive the original parser.
|
||||
// json_object is a small base type that just records the JSON type and
|
||||
// the back-pointers to its parent and parser. The actual value payload
|
||||
// lives in a type-specific subclass (json_number, json_string, json_array,
|
||||
// json_hash), so that JSON_TRUE / JSON_FALSE / JSON_NULL nodes pay only
|
||||
// the base-class cost and a JSON_HASH does not also drag along a string
|
||||
// or a number field. Type-tagged accessor methods on the base class
|
||||
// downcast and return references to the underlying subclass storage.
|
||||
//
|
||||
// Children are owned by their parent (via std::vector<json_object_ptr>
|
||||
// inside json_array / json_hash); the raw `parent` and `parser`
|
||||
// back-pointers stay valid as long as the node is attached to the tree.
|
||||
// json_disconnect() splices a node out of its parent and walks the
|
||||
// detached subtree clearing those back-pointers so the subtree can
|
||||
// outlive the original parser.
|
||||
//
|
||||
// json_object intentionally has no virtual functions and no virtual
|
||||
// destructor: subclasses are constructed via std::make_shared<json_xxx>(),
|
||||
// and std::shared_ptr remembers the deleter from the original type, so
|
||||
// destroying a shared_ptr<json_object> that actually points at a
|
||||
// json_string still runs ~json_string(). Dispatch on `type` is what the
|
||||
// rest of the code already does. The accessor methods assert at debug
|
||||
// time that the type matches before downcasting.
|
||||
|
||||
struct json_object : public std::enable_shared_from_this<json_object> {
|
||||
struct json_object {
|
||||
json_object *parent = nullptr;
|
||||
json_pull *parser = nullptr;
|
||||
|
||||
json_type type = JSON_NULL;
|
||||
int expect = 0;
|
||||
json_type type;
|
||||
int expect = 0; // used by the parser on JSON_ARRAY / JSON_HASH nodes
|
||||
|
||||
// Members named to match the previous C union layout so that existing
|
||||
// access paths like `o->value.string.string` and `o->value.array.array[i]`
|
||||
// continue to work. This is no longer a union because std::string and
|
||||
// std::vector have non-trivial destructors.
|
||||
struct value_t {
|
||||
struct {
|
||||
double number = 0;
|
||||
unsigned long long large_unsigned = 0;
|
||||
long long large_signed = 0;
|
||||
} number;
|
||||
json_object(json_type t) : type(t) {}
|
||||
json_object(json_type t, json_object *p, json_pull *pl) : parent(p), parser(pl), type(t) {}
|
||||
|
||||
struct {
|
||||
std::string string;
|
||||
void *refcon = nullptr; // reference constant for caller's use
|
||||
} string;
|
||||
// Type-tagged accessors. Each one asserts that the receiver is of
|
||||
// the right kind, then downcasts to the storage in the appropriate
|
||||
// subclass. Inline so the assert and cast disappear at -O.
|
||||
inline std::string &string();
|
||||
inline const std::string &string() const;
|
||||
|
||||
struct {
|
||||
std::vector<json_object_ptr> array;
|
||||
} array;
|
||||
inline double &number();
|
||||
inline double number() const;
|
||||
inline unsigned long long &large_unsigned();
|
||||
inline unsigned long long large_unsigned() const;
|
||||
inline long long &large_signed();
|
||||
inline long long large_signed() const;
|
||||
|
||||
struct {
|
||||
std::vector<json_object_ptr> keys;
|
||||
std::vector<json_object_ptr> values;
|
||||
} object;
|
||||
} value;
|
||||
inline std::vector<json_object_ptr> &array();
|
||||
inline const std::vector<json_object_ptr> &array() const;
|
||||
|
||||
inline std::vector<json_object_ptr> &keys();
|
||||
inline const std::vector<json_object_ptr> &keys() const;
|
||||
inline std::vector<json_object_ptr> &values();
|
||||
inline const std::vector<json_object_ptr> &values() const;
|
||||
};
|
||||
|
||||
struct json_number : json_object {
|
||||
double number_value = 0;
|
||||
unsigned long long large_unsigned_value = 0;
|
||||
long long large_signed_value = 0;
|
||||
|
||||
json_number() : json_object(JSON_NUMBER) {}
|
||||
json_number(json_object *p, json_pull *pl) : json_object(JSON_NUMBER, p, pl) {}
|
||||
};
|
||||
|
||||
struct json_string : json_object {
|
||||
std::string string_value;
|
||||
|
||||
json_string() : json_object(JSON_STRING) {}
|
||||
json_string(json_object *p, json_pull *pl) : json_object(JSON_STRING, p, pl) {}
|
||||
};
|
||||
|
||||
struct json_array : json_object {
|
||||
std::vector<json_object_ptr> array_value;
|
||||
|
||||
json_array() : json_object(JSON_ARRAY) {}
|
||||
json_array(json_object *p, json_pull *pl) : json_object(JSON_ARRAY, p, pl) {}
|
||||
};
|
||||
|
||||
struct json_hash : json_object {
|
||||
std::vector<json_object_ptr> keys_value;
|
||||
std::vector<json_object_ptr> values_value;
|
||||
|
||||
json_hash() : json_object(JSON_HASH) {}
|
||||
json_hash(json_object *p, json_pull *pl) : json_object(JSON_HASH, p, pl) {}
|
||||
};
|
||||
|
||||
inline std::string &json_object::string() {
|
||||
assert(type == JSON_STRING);
|
||||
return static_cast<json_string *>(this)->string_value;
|
||||
}
|
||||
inline const std::string &json_object::string() const {
|
||||
assert(type == JSON_STRING);
|
||||
return static_cast<const json_string *>(this)->string_value;
|
||||
}
|
||||
|
||||
inline double &json_object::number() {
|
||||
assert(type == JSON_NUMBER);
|
||||
return static_cast<json_number *>(this)->number_value;
|
||||
}
|
||||
inline double json_object::number() const {
|
||||
assert(type == JSON_NUMBER);
|
||||
return static_cast<const json_number *>(this)->number_value;
|
||||
}
|
||||
inline unsigned long long &json_object::large_unsigned() {
|
||||
assert(type == JSON_NUMBER);
|
||||
return static_cast<json_number *>(this)->large_unsigned_value;
|
||||
}
|
||||
inline unsigned long long json_object::large_unsigned() const {
|
||||
assert(type == JSON_NUMBER);
|
||||
return static_cast<const json_number *>(this)->large_unsigned_value;
|
||||
}
|
||||
inline long long &json_object::large_signed() {
|
||||
assert(type == JSON_NUMBER);
|
||||
return static_cast<json_number *>(this)->large_signed_value;
|
||||
}
|
||||
inline long long json_object::large_signed() const {
|
||||
assert(type == JSON_NUMBER);
|
||||
return static_cast<const json_number *>(this)->large_signed_value;
|
||||
}
|
||||
|
||||
inline std::vector<json_object_ptr> &json_object::array() {
|
||||
assert(type == JSON_ARRAY);
|
||||
return static_cast<json_array *>(this)->array_value;
|
||||
}
|
||||
inline const std::vector<json_object_ptr> &json_object::array() const {
|
||||
assert(type == JSON_ARRAY);
|
||||
return static_cast<const json_array *>(this)->array_value;
|
||||
}
|
||||
|
||||
inline std::vector<json_object_ptr> &json_object::keys() {
|
||||
assert(type == JSON_HASH);
|
||||
return static_cast<json_hash *>(this)->keys_value;
|
||||
}
|
||||
inline const std::vector<json_object_ptr> &json_object::keys() const {
|
||||
assert(type == JSON_HASH);
|
||||
return static_cast<const json_hash *>(this)->keys_value;
|
||||
}
|
||||
inline std::vector<json_object_ptr> &json_object::values() {
|
||||
assert(type == JSON_HASH);
|
||||
return static_cast<json_hash *>(this)->values_value;
|
||||
}
|
||||
inline const std::vector<json_object_ptr> &json_object::values() const {
|
||||
assert(type == JSON_HASH);
|
||||
return static_cast<const json_hash *>(this)->values_value;
|
||||
}
|
||||
|
||||
struct json_pull {
|
||||
const char *error = nullptr; // points at a string literal; no allocation
|
||||
int line = 1;
|
||||
@@ -85,7 +190,11 @@ struct json_pull {
|
||||
ssize_t buffer_tail = 0;
|
||||
ssize_t buffer_head = 0;
|
||||
|
||||
json_object_ptr container;
|
||||
// Stack of currently-open containers; the top is the innermost container
|
||||
// being parsed. Replaces the previous single `container` pointer / parent
|
||||
// walk, which previously required enable_shared_from_this<json_object>
|
||||
// on every json_object instance (16 extra bytes per node).
|
||||
std::vector<json_object_ptr> container_stack;
|
||||
json_object_ptr root;
|
||||
|
||||
std::string number_buffer;
|
||||
@@ -118,6 +227,7 @@ void json_free(json_object_ptr &j);
|
||||
void json_disconnect(json_object_ptr j);
|
||||
|
||||
json_object_ptr json_hash_get(json_object_ptr o, const char *s);
|
||||
json_object_ptr json_hash_get(json_object *o, const char *s);
|
||||
|
||||
std::string json_stringify(json_object_ptr o);
|
||||
|
||||
|
||||
+16
-22
@@ -149,7 +149,7 @@ void out(std::string const &s, int type, json_object_ptr properties) {
|
||||
if (o != nullptr) {
|
||||
found = true;
|
||||
if (o->type == JSON_STRING || o->type == JSON_NUMBER) {
|
||||
extracted = sort_quote(o->value.string.string.c_str());
|
||||
extracted = sort_quote(o->string().c_str());
|
||||
} else {
|
||||
extracted = sort_quote(json_stringify(o).c_str());
|
||||
}
|
||||
@@ -244,9 +244,9 @@ void join_csv(json_object_ptr j) {
|
||||
|
||||
std::string joinkey;
|
||||
if (key->type == JSON_STRING) {
|
||||
joinkey = key->value.string.string;
|
||||
joinkey = key->string();
|
||||
} else if (key->type == JSON_NUMBER) {
|
||||
joinkey = milo::dtoa_milo(key->value.number.number);
|
||||
joinkey = milo::dtoa_milo(key->number());
|
||||
} else {
|
||||
joinkey = json_stringify(key);
|
||||
}
|
||||
@@ -298,8 +298,8 @@ void join_csv(json_object_ptr j) {
|
||||
}
|
||||
|
||||
if (fields.size() > 0 && joinkey == fields[0]) {
|
||||
properties->value.object.keys.reserve(properties->value.object.keys.size() + fields.size());
|
||||
properties->value.object.values.reserve(properties->value.object.values.size() + fields.size());
|
||||
properties->keys().reserve(properties->keys().size() + fields.size());
|
||||
properties->values().reserve(properties->values().size() + fields.size());
|
||||
|
||||
for (size_t i = 1; i < fields.size(); i++) {
|
||||
std::string k = header[i];
|
||||
@@ -317,30 +317,24 @@ void join_csv(json_object_ptr j) {
|
||||
}
|
||||
|
||||
if (attr_type != JSON_NULL) {
|
||||
auto ko = std::make_shared<json_object>();
|
||||
auto vo = std::make_shared<json_object>();
|
||||
|
||||
ko->type = JSON_STRING;
|
||||
ko->parent = properties.get();
|
||||
ko->parser = properties->parser;
|
||||
ko->value.string.string = k;
|
||||
|
||||
vo->type = attr_type;
|
||||
vo->parent = properties.get();
|
||||
vo->parser = properties->parser;
|
||||
auto ko = std::make_shared<json_string>(properties.get(), properties->parser);
|
||||
ko->string_value = k;
|
||||
|
||||
json_object_ptr vo;
|
||||
if (attr_type == JSON_STRING) {
|
||||
vo->value.string.string = v;
|
||||
auto s = std::make_shared<json_string>(properties.get(), properties->parser);
|
||||
s->string_value = v;
|
||||
vo = s;
|
||||
} else if (attr_type == JSON_NUMBER) {
|
||||
vo->value.number.number = atof(v.c_str());
|
||||
vo->value.number.large_unsigned = 0;
|
||||
vo->value.number.large_signed = 0;
|
||||
auto n = std::make_shared<json_number>(properties.get(), properties->parser);
|
||||
n->number_value = atof(v.c_str());
|
||||
vo = n;
|
||||
} else {
|
||||
abort();
|
||||
}
|
||||
|
||||
properties->value.object.keys.push_back(ko);
|
||||
properties->value.object.values.push_back(vo);
|
||||
properties->keys().push_back(ko);
|
||||
properties->values().push_back(vo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2885,9 +2885,9 @@ void set_attribute_value(const char *arg) {
|
||||
exit(EXIT_JSON);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < o->value.object.keys.size(); i++) {
|
||||
json_object_ptr k = o->value.object.keys[i];
|
||||
json_object_ptr v = o->value.object.values[i];
|
||||
for (size_t i = 0; i < o->keys().size(); i++) {
|
||||
json_object_ptr k = o->keys()[i];
|
||||
json_object_ptr v = o->values()[i];
|
||||
|
||||
if (k->type != JSON_STRING) {
|
||||
fprintf(stderr, "%s: --set-attribute %s: key %zu not a string\n", *av, arg, i);
|
||||
@@ -2895,7 +2895,7 @@ void set_attribute_value(const char *arg) {
|
||||
}
|
||||
|
||||
serial_val val = stringify_value(v, "json", 1, o);
|
||||
set_attributes.emplace(k->value.string.string, val);
|
||||
set_attributes.emplace(k->string(), val);
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -2941,21 +2941,21 @@ void parse_json_source(const char *arg, struct source &src) {
|
||||
exit(EXIT_JSON);
|
||||
}
|
||||
|
||||
src.file = fname->value.string.string;
|
||||
src.file = fname->string();
|
||||
|
||||
json_object_ptr layer = json_hash_get(o, "layer");
|
||||
if (layer != nullptr && layer->type == JSON_STRING) {
|
||||
src.layer = layer->value.string.string;
|
||||
src.layer = layer->string();
|
||||
}
|
||||
|
||||
json_object_ptr description = json_hash_get(o, "description");
|
||||
if (description != nullptr && description->type == JSON_STRING) {
|
||||
src.description = description->value.string.string;
|
||||
src.description = description->string();
|
||||
}
|
||||
|
||||
json_object_ptr format = json_hash_get(o, "format");
|
||||
if (format != nullptr && format->type == JSON_STRING) {
|
||||
src.format = format->value.string.string;
|
||||
src.format = format->string();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+14
-14
@@ -168,7 +168,7 @@ serial_feature parse_feature(json_pull_ptr jp, int z, unsigned x, unsigned y, st
|
||||
if (type == nullptr || type->type != JSON_STRING) {
|
||||
continue;
|
||||
}
|
||||
if (type->value.string.string != "Feature") {
|
||||
if (type->string() != "Feature") {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -208,12 +208,12 @@ serial_feature parse_feature(json_pull_ptr jp, int z, unsigned x, unsigned y, st
|
||||
|
||||
int t;
|
||||
for (t = 0; t < GEOM_TYPES; t++) {
|
||||
if (geometry_type->value.string.string == geometry_names[t]) {
|
||||
if (geometry_type->string() == geometry_names[t]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (t >= GEOM_TYPES) {
|
||||
fprintf(stderr, "Filter output:%d: Can't handle geometry type %s: ", jp->line, geometry_type->value.string.string.c_str());
|
||||
fprintf(stderr, "Filter output:%d: Can't handle geometry type %s: ", jp->line, geometry_type->string().c_str());
|
||||
json_context(j);
|
||||
exit(EXIT_JSON);
|
||||
}
|
||||
@@ -252,22 +252,22 @@ serial_feature parse_feature(json_pull_ptr jp, int z, unsigned x, unsigned y, st
|
||||
if (tippecanoe != nullptr) {
|
||||
json_object_ptr layer = json_hash_get(tippecanoe, "layer");
|
||||
if (layer != nullptr && layer->type == JSON_STRING) {
|
||||
layername = layer->value.string.string;
|
||||
layername = layer->string();
|
||||
}
|
||||
|
||||
json_object_ptr index = json_hash_get(tippecanoe, "index");
|
||||
if (index != nullptr && index->type == JSON_NUMBER) {
|
||||
sf.index = index->value.number.number;
|
||||
sf.index = index->number();
|
||||
}
|
||||
|
||||
json_object_ptr sequence = json_hash_get(tippecanoe, "sequence");
|
||||
if (sequence != nullptr && sequence->type == JSON_NUMBER) {
|
||||
sf.seq = sequence->value.number.number;
|
||||
sf.seq = sequence->number();
|
||||
}
|
||||
|
||||
json_object_ptr extent = json_hash_get(tippecanoe, "extent");
|
||||
if (extent != nullptr && extent->type == JSON_NUMBER) {
|
||||
sf.extent = extent->value.number.number;
|
||||
sf.extent = extent->number();
|
||||
}
|
||||
|
||||
json_object_ptr dropped = json_hash_get(tippecanoe, "dropped");
|
||||
@@ -297,9 +297,9 @@ serial_feature parse_feature(json_pull_ptr jp, int z, unsigned x, unsigned y, st
|
||||
|
||||
json_object_ptr id = json_hash_get(j, "id");
|
||||
if (id != nullptr && id->type == JSON_NUMBER) {
|
||||
sf.id = id->value.number.number;
|
||||
if (id->value.number.large_unsigned > 0) {
|
||||
sf.id = id->value.number.large_unsigned;
|
||||
sf.id = id->number();
|
||||
if (id->large_unsigned() > 0) {
|
||||
sf.id = id->large_unsigned();
|
||||
}
|
||||
sf.has_id = true;
|
||||
}
|
||||
@@ -343,18 +343,18 @@ serial_feature parse_feature(json_pull_ptr jp, int z, unsigned x, unsigned y, st
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < properties->value.object.keys.size(); i++) {
|
||||
serial_val v = stringify_value(properties->value.object.values[i], "Filter output", jp->line, j);
|
||||
for (size_t i = 0; i < properties->keys().size(); i++) {
|
||||
serial_val v = stringify_value(properties->values()[i], "Filter output", jp->line, j);
|
||||
|
||||
// Nulls can be excluded here because the expression evaluation filter
|
||||
// would have already run before prefiltering
|
||||
|
||||
if (v.type != mvt_null) {
|
||||
sf.full_keys.push_back(key_pool.pool(properties->value.object.keys[i]->value.string.string));
|
||||
sf.full_keys.push_back(key_pool.pool(properties->keys()[i]->string()));
|
||||
sf.full_values.push_back(v);
|
||||
|
||||
if (!postfilter) {
|
||||
add_to_tilestats(ts->second.tilestats, properties->value.object.keys[i]->value.string.string, v);
|
||||
add_to_tilestats(ts->second.tilestats, properties->keys()[i]->string(), v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+12
-12
@@ -415,37 +415,37 @@ sqlite3 *pmtilesmeta2tmp(const char *fname, const char *pmtiles_map) {
|
||||
state.nospace = true;
|
||||
state.json_write_hash();
|
||||
|
||||
for (size_t i = 0; i < o->value.object.keys.size(); i++) {
|
||||
const std::string &key = o->value.object.keys[i]->value.string.string;
|
||||
if (key == "vector_layers" && o->value.object.values[i]->type == JSON_ARRAY) {
|
||||
for (size_t i = 0; i < o->keys().size(); i++) {
|
||||
const std::string &key = o->keys()[i]->string();
|
||||
if (key == "vector_layers" && o->values()[i]->type == JSON_ARRAY) {
|
||||
has_json = true;
|
||||
state.nospace = true;
|
||||
state.json_write_string("vector_layers");
|
||||
state.nospace = true;
|
||||
state.json_write_json(json_stringify(o->value.object.values[i]));
|
||||
} else if (key == "tilestats" && o->value.object.values[i]->type == JSON_HASH) {
|
||||
state.json_write_json(json_stringify(o->values()[i]));
|
||||
} else if (key == "tilestats" && o->values()[i]->type == JSON_HASH) {
|
||||
has_json = true;
|
||||
state.nospace = true;
|
||||
state.json_write_string("tilestats");
|
||||
state.nospace = true;
|
||||
state.json_write_json(json_stringify(o->value.object.values[i]));
|
||||
} else if (key == "strategies" && o->value.object.values[i]->type == JSON_ARRAY) {
|
||||
sql = sqlite3_mprintf("INSERT INTO metadata (name, value) VALUES ('strategies', %Q);", json_stringify(o->value.object.values[i]).c_str());
|
||||
state.json_write_json(json_stringify(o->values()[i]));
|
||||
} else if (key == "strategies" && o->values()[i]->type == JSON_ARRAY) {
|
||||
sql = sqlite3_mprintf("INSERT INTO metadata (name, value) VALUES ('strategies', %Q);", json_stringify(o->values()[i]).c_str());
|
||||
if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
|
||||
fprintf(stderr, "set %s in metadata: %s\n", key.c_str(), err);
|
||||
}
|
||||
sqlite3_free(sql);
|
||||
} else if (key == "tippecanoe_decisions" && o->value.object.values[i]->type == JSON_HASH) {
|
||||
sql = sqlite3_mprintf("INSERT INTO metadata (name, value) VALUES ('tippecanoe_decisions', %Q);", json_stringify(o->value.object.values[i]).c_str());
|
||||
} else if (key == "tippecanoe_decisions" && o->values()[i]->type == JSON_HASH) {
|
||||
sql = sqlite3_mprintf("INSERT INTO metadata (name, value) VALUES ('tippecanoe_decisions', %Q);", json_stringify(o->values()[i]).c_str());
|
||||
if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
|
||||
fprintf(stderr, "set %s in metadata: %s\n", key.c_str(), err);
|
||||
}
|
||||
sqlite3_free(sql);
|
||||
} else if (o->value.object.keys[i]->type != JSON_STRING || o->value.object.values[i]->type != JSON_STRING) {
|
||||
} else if (o->keys()[i]->type != JSON_STRING || o->values()[i]->type != JSON_STRING) {
|
||||
fprintf(stderr, "%s\n", key.c_str());
|
||||
fprintf(stderr, "%s: non-string in metadata\n", fname);
|
||||
} else {
|
||||
sql = sqlite3_mprintf("INSERT INTO metadata (name, value) VALUES (%Q, %Q);", key.c_str(), o->value.object.values[i]->value.string.string.c_str());
|
||||
sql = sqlite3_mprintf("INSERT INTO metadata (name, value) VALUES (%Q, %Q);", key.c_str(), o->values()[i]->string().c_str());
|
||||
if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
|
||||
fprintf(stderr, "set %s in metadata: %s\n", key.c_str(), err);
|
||||
}
|
||||
|
||||
+22
-22
@@ -63,7 +63,7 @@ void parse_coordinates(int t, json_object_ptr j, drawvec &out, int op, const cha
|
||||
int within = geometry_within[t];
|
||||
if (within >= 0) {
|
||||
size_t i;
|
||||
for (i = 0; i < j->value.array.array.size(); i++) {
|
||||
for (i = 0; i < j->array().size(); i++) {
|
||||
if (within == GEOM_POINT) {
|
||||
if (i == 0 || mb_geometry[t] == VT_POINT) {
|
||||
op = VT_MOVETO;
|
||||
@@ -72,16 +72,16 @@ void parse_coordinates(int t, json_object_ptr j, drawvec &out, int op, const cha
|
||||
}
|
||||
}
|
||||
|
||||
parse_coordinates(within, j->value.array.array[i], out, op, fname, line, feature);
|
||||
parse_coordinates(within, j->array()[i], out, op, fname, line, feature);
|
||||
}
|
||||
} else {
|
||||
if (j->value.array.array.size() >= 2 && j->value.array.array[0]->type == JSON_NUMBER && j->value.array.array[1]->type == JSON_NUMBER) {
|
||||
if (j->array().size() >= 2 && j->array()[0]->type == JSON_NUMBER && j->array()[1]->type == JSON_NUMBER) {
|
||||
long long x, y;
|
||||
double lon = j->value.array.array[0]->value.number.number;
|
||||
double lat = j->value.array.array[1]->value.number.number;
|
||||
double lon = j->array()[0]->number();
|
||||
double lat = j->array()[1]->number();
|
||||
projection->project(lon, lat, 32, &x, &y);
|
||||
|
||||
if (j->value.array.array.size() > 2) {
|
||||
if (j->array().size() > 2) {
|
||||
static int warned = 0;
|
||||
|
||||
if (!warned) {
|
||||
@@ -129,7 +129,7 @@ serial_val stringify_value(json_object_ptr value, const char *reading, int line,
|
||||
|
||||
if (vt == JSON_STRING) {
|
||||
sv.type = mvt_string;
|
||||
sv.s = value->value.string.string;
|
||||
sv.s = value->string();
|
||||
|
||||
std::string err = check_utf8(sv.s);
|
||||
if (err.size() > 0) {
|
||||
@@ -140,12 +140,12 @@ serial_val stringify_value(json_object_ptr value, const char *reading, int line,
|
||||
} else if (vt == JSON_NUMBER) {
|
||||
sv.type = mvt_double;
|
||||
|
||||
if (value->value.number.large_unsigned != 0) {
|
||||
sv.s = std::to_string(value->value.number.large_unsigned);
|
||||
} else if (value->value.number.large_signed != 0) {
|
||||
sv.s = std::to_string(value->value.number.large_signed);
|
||||
if (value->large_unsigned() != 0) {
|
||||
sv.s = std::to_string(value->large_unsigned());
|
||||
} else if (value->large_signed() != 0) {
|
||||
sv.s = std::to_string(value->large_signed());
|
||||
} else {
|
||||
sv.s = milo::dtoa_milo(value->value.number.number);
|
||||
sv.s = milo::dtoa_milo(value->number());
|
||||
}
|
||||
} else if (vt == JSON_TRUE) {
|
||||
sv.type = mvt_bool;
|
||||
@@ -200,12 +200,12 @@ std::pair<int, drawvec> parse_geometry(json_object_ptr geometry, json_pull_ptr j
|
||||
|
||||
int t;
|
||||
for (t = 0; t < GEOM_TYPES; t++) {
|
||||
if (geometry_type->value.string.string == geometry_names[t]) {
|
||||
if (geometry_type->string() == geometry_names[t]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (t >= GEOM_TYPES) {
|
||||
fprintf(stderr, "Filter output:%d: Can't handle geometry type %s: ", jp->line, geometry_type->value.string.string.c_str());
|
||||
fprintf(stderr, "Filter output:%d: Can't handle geometry type %s: ", jp->line, geometry_type->string().c_str());
|
||||
json_context(j);
|
||||
exit(EXIT_JSON);
|
||||
}
|
||||
@@ -325,7 +325,7 @@ std::vector<mvt_layer> parse_layers(FILE *fp, int z, unsigned x, unsigned y, int
|
||||
if (type == nullptr || type->type != JSON_STRING) {
|
||||
continue;
|
||||
}
|
||||
if (type->value.string.string != "Feature") {
|
||||
if (type->string() != "Feature") {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -342,7 +342,7 @@ std::vector<mvt_layer> parse_layers(FILE *fp, int z, unsigned x, unsigned y, int
|
||||
if (tippecanoe != nullptr) {
|
||||
layer = json_hash_get(tippecanoe, "layer");
|
||||
if (layer != nullptr && layer->type == JSON_STRING) {
|
||||
layername = layer->value.string.string;
|
||||
layername = layer->string();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -375,22 +375,22 @@ std::vector<mvt_layer> parse_layers(FILE *fp, int z, unsigned x, unsigned y, int
|
||||
|
||||
json_object_ptr id = json_hash_get(j, "id");
|
||||
if (id != nullptr && id->type == JSON_NUMBER) {
|
||||
feature.id = id->value.number.number;
|
||||
if (id->value.number.large_unsigned > 0) {
|
||||
feature.id = id->value.number.large_unsigned;
|
||||
feature.id = id->number();
|
||||
if (id->large_unsigned() > 0) {
|
||||
feature.id = id->large_unsigned();
|
||||
}
|
||||
feature.has_id = true;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < properties->value.object.keys.size(); i++) {
|
||||
serial_val sv = stringify_value(properties->value.object.values[i], "Filter output", jp->line, j);
|
||||
for (size_t i = 0; i < properties->keys().size(); i++) {
|
||||
serial_val sv = stringify_value(properties->values()[i], "Filter output", jp->line, j);
|
||||
|
||||
// Nulls can be excluded here because this is the postfilter
|
||||
// and it is nearly time to create the vector representation
|
||||
|
||||
if (sv.type != mvt_null) {
|
||||
mvt_value v = stringified_to_mvt_value(sv.type, sv.s.c_str(), tile_stringpool);
|
||||
l->second.tag(feature, properties->value.object.keys[i]->value.string.string, v);
|
||||
l->second.tag(feature, properties->keys()[i]->string(), v);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+26
-26
@@ -969,12 +969,12 @@ void handle_strategies(const unsigned char *s, std::vector<strategy> *st) {
|
||||
json_object_ptr o = json_read_tree(jp);
|
||||
|
||||
if (o != nullptr && o->type == JSON_ARRAY) {
|
||||
for (size_t i = 0; i < o->value.array.array.size(); i++) {
|
||||
json_object_ptr h = o->value.array.array[i];
|
||||
for (size_t i = 0; i < o->array().size(); i++) {
|
||||
json_object_ptr h = o->array()[i];
|
||||
if (h->type == JSON_HASH) {
|
||||
for (size_t j = 0; j < h->value.object.keys.size(); j++) {
|
||||
json_object_ptr k = h->value.object.keys[j];
|
||||
json_object_ptr v = h->value.object.values[j];
|
||||
for (size_t j = 0; j < h->keys().size(); j++) {
|
||||
json_object_ptr k = h->keys()[j];
|
||||
json_object_ptr v = h->values()[j];
|
||||
|
||||
if (k->type != JSON_STRING) {
|
||||
fprintf(stderr, "Key %zu of %zu is not a string: %s\n", j, i, s);
|
||||
@@ -985,25 +985,25 @@ void handle_strategies(const unsigned char *s, std::vector<strategy> *st) {
|
||||
st->resize(i + 1);
|
||||
}
|
||||
|
||||
const std::string &key = k->value.string.string;
|
||||
const std::string &key = k->string();
|
||||
if (key == "dropped_by_rate") {
|
||||
(*st)[i].dropped_by_rate += v->value.number.number;
|
||||
(*st)[i].dropped_by_rate += v->number();
|
||||
} else if (key == "dropped_by_gamma") {
|
||||
(*st)[i].dropped_by_gamma += v->value.number.number;
|
||||
(*st)[i].dropped_by_gamma += v->number();
|
||||
} else if (key == "dropped_as_needed") {
|
||||
(*st)[i].dropped_as_needed += v->value.number.number;
|
||||
(*st)[i].dropped_as_needed += v->number();
|
||||
} else if (key == "coalesced_as_needed") {
|
||||
(*st)[i].coalesced_as_needed += v->value.number.number;
|
||||
(*st)[i].coalesced_as_needed += v->number();
|
||||
} else if (key == "truncated_zooms") {
|
||||
(*st)[i].truncated_zooms += v->value.number.number;
|
||||
(*st)[i].truncated_zooms += v->number();
|
||||
} else if (key == "detail_reduced") {
|
||||
(*st)[i].detail_reduced += v->value.number.number;
|
||||
(*st)[i].detail_reduced += v->number();
|
||||
} else if (key == "tiny_polygons") {
|
||||
(*st)[i].tiny_polygons += v->value.number.number;
|
||||
(*st)[i].tiny_polygons += v->number();
|
||||
} else if (key == "tile_size_desired") {
|
||||
(*st)[i].tile_size += v->value.number.number;
|
||||
(*st)[i].tile_size += v->number();
|
||||
} else if (key == "feature_count_desired") {
|
||||
(*st)[i].feature_count += v->value.number.number;
|
||||
(*st)[i].feature_count += v->number();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1016,14 +1016,14 @@ void handle_strategies(const unsigned char *s, std::vector<strategy> *st) {
|
||||
|
||||
void handle_vector_layers(json_object_ptr vector_layers, std::map<std::string, layermap_entry> &layermap, std::map<std::string, std::string> &attribute_descriptions) {
|
||||
if (vector_layers != nullptr && vector_layers->type == JSON_ARRAY) {
|
||||
for (size_t i = 0; i < vector_layers->value.array.array.size(); i++) {
|
||||
if (vector_layers->value.array.array[i]->type == JSON_HASH) {
|
||||
json_object_ptr id = json_hash_get(vector_layers->value.array.array[i], "id");
|
||||
json_object_ptr desc = json_hash_get(vector_layers->value.array.array[i], "description");
|
||||
for (size_t i = 0; i < vector_layers->array().size(); i++) {
|
||||
if (vector_layers->array()[i]->type == JSON_HASH) {
|
||||
json_object_ptr id = json_hash_get(vector_layers->array()[i], "id");
|
||||
json_object_ptr desc = json_hash_get(vector_layers->array()[i], "description");
|
||||
|
||||
if (id != nullptr && desc != nullptr && id->type == JSON_STRING && desc->type == JSON_STRING) {
|
||||
const std::string &sid = id->value.string.string;
|
||||
const std::string &sdesc = desc->value.string.string;
|
||||
const std::string &sid = id->string();
|
||||
const std::string &sdesc = desc->string();
|
||||
|
||||
if (sdesc.size() != 0) {
|
||||
auto f = layermap.find(sid);
|
||||
@@ -1033,17 +1033,17 @@ void handle_vector_layers(json_object_ptr vector_layers, std::map<std::string, l
|
||||
}
|
||||
}
|
||||
|
||||
json_object_ptr fields = json_hash_get(vector_layers->value.array.array[i], "fields");
|
||||
json_object_ptr fields = json_hash_get(vector_layers->array()[i], "fields");
|
||||
if (fields != nullptr && fields->type == JSON_HASH) {
|
||||
for (size_t j = 0; j < fields->value.object.keys.size(); j++) {
|
||||
if (fields->value.object.keys[j]->type == JSON_STRING && fields->value.object.values[j]->type) {
|
||||
const std::string &desc2 = fields->value.object.values[j]->value.string.string;
|
||||
for (size_t j = 0; j < fields->keys().size(); j++) {
|
||||
if (fields->keys()[j]->type == JSON_STRING && fields->values()[j]->type) {
|
||||
const std::string &desc2 = fields->values()[j]->string();
|
||||
|
||||
if (desc2 != "Number" &&
|
||||
desc2 != "String" &&
|
||||
desc2 != "Boolean" &&
|
||||
desc2 != "Mixed") {
|
||||
attribute_descriptions.insert(std::pair<std::string, std::string>(fields->value.object.keys[j]->value.string.string, desc2));
|
||||
attribute_descriptions.insert(std::pair<std::string, std::string>(fields->keys()[j]->string(), desc2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user