summaryrefslogtreecommitdiff
path: root/deps/geojson/0.4.2/include/mapbox/geojson_impl.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'deps/geojson/0.4.2/include/mapbox/geojson_impl.hpp')
-rw-r--r--deps/geojson/0.4.2/include/mapbox/geojson_impl.hpp453
1 files changed, 453 insertions, 0 deletions
diff --git a/deps/geojson/0.4.2/include/mapbox/geojson_impl.hpp b/deps/geojson/0.4.2/include/mapbox/geojson_impl.hpp
new file mode 100644
index 0000000000..48d81e4114
--- /dev/null
+++ b/deps/geojson/0.4.2/include/mapbox/geojson_impl.hpp
@@ -0,0 +1,453 @@
+#pragma once
+
+#include <mapbox/geojson.hpp>
+#include <mapbox/geojson/rapidjson.hpp>
+
+#include <rapidjson/document.h>
+#include <rapidjson/writer.h>
+#include <rapidjson/stringbuffer.h>
+#include <rapidjson/error/en.h>
+
+#include <sstream>
+
+namespace mapbox {
+namespace geojson {
+
+using error = std::runtime_error;
+using prop_map = std::unordered_map<std::string, value>;
+
+template <typename T>
+T convert(const rapidjson_value &json);
+
+template <>
+point convert<point>(const rapidjson_value &json) {
+ if (json.Size() < 2)
+ throw error("coordinates array must have at least 2 numbers");
+
+ return point{ json[0].GetDouble(), json[1].GetDouble() };
+}
+
+template <typename Cont>
+Cont convert(const rapidjson_value &json) {
+ Cont points;
+ auto size = json.Size();
+ points.reserve(size);
+
+ for (auto &element : json.GetArray()) {
+ points.push_back(convert<typename Cont::value_type>(element));
+ }
+ return points;
+}
+
+template <>
+geometry convert<geometry>(const rapidjson_value &json) {
+ if (!json.IsObject())
+ throw error("Geometry must be an object");
+
+ const auto &json_end = json.MemberEnd();
+
+ const auto &type_itr = json.FindMember("type");
+ if (type_itr == json_end)
+ throw error("Geometry must have a type property");
+
+ const auto &type = type_itr->value;
+
+ if (type == "GeometryCollection") {
+ const auto &geometries_itr = json.FindMember("geometries");
+ if (geometries_itr == json_end)
+ throw error("GeometryCollection must have a geometries property");
+
+ const auto &json_geometries = geometries_itr->value;
+
+ if (!json_geometries.IsArray())
+ throw error("GeometryCollection geometries property must be an array");
+
+ return geometry{ convert<geometry_collection>(json_geometries) };
+ }
+
+ const auto &coords_itr = json.FindMember("coordinates");
+
+ if (coords_itr == json_end)
+ throw error(std::string(type.GetString()) + " geometry must have a coordinates property");
+
+ const auto &json_coords = coords_itr->value;
+ if (!json_coords.IsArray())
+ throw error("coordinates property must be an array");
+
+ if (type == "Point")
+ return geometry{ convert<point>(json_coords) };
+ if (type == "MultiPoint")
+ return geometry{ convert<multi_point>(json_coords) };
+ if (type == "LineString")
+ return geometry{ convert<line_string>(json_coords) };
+ if (type == "MultiLineString")
+ return geometry{ convert<multi_line_string>(json_coords) };
+ if (type == "Polygon")
+ return geometry{ convert<polygon>(json_coords) };
+ if (type == "MultiPolygon")
+ return geometry{ convert<multi_polygon>(json_coords) };
+
+ throw error(std::string(type.GetString()) + " not yet implemented");
+}
+
+template <>
+value convert<value>(const rapidjson_value &json);
+
+template <>
+prop_map convert(const rapidjson_value &json) {
+ if (!json.IsObject())
+ throw error("properties must be an object");
+
+ prop_map result;
+ for (auto &member : json.GetObject()) {
+ result.emplace(std::string(member.name.GetString(), member.name.GetStringLength()),
+ convert<value>(member.value));
+ }
+ return result;
+}
+
+template <>
+value convert<value>(const rapidjson_value &json) {
+ switch (json.GetType()) {
+ case rapidjson::kNullType:
+ return ::mapbox::geometry::null_value_t{};
+ case rapidjson::kFalseType:
+ return false;
+ case rapidjson::kTrueType:
+ return true;
+ case rapidjson::kObjectType:
+ return convert<prop_map>(json);
+ case rapidjson::kArrayType:
+ return convert<std::vector<value>>(json);
+ case rapidjson::kStringType:
+ return std::string(json.GetString(), json.GetStringLength());
+ default:
+ assert(json.GetType() == rapidjson::kNumberType);
+ if (json.IsUint64())
+ return std::uint64_t(json.GetUint64());
+ if (json.IsInt64())
+ return std::int64_t(json.GetInt64());
+ return json.GetDouble();
+ }
+}
+
+template <>
+identifier convert<identifier>(const rapidjson_value &json) {
+ switch (json.GetType()) {
+ case rapidjson::kStringType:
+ return std::string(json.GetString(), json.GetStringLength());
+ case rapidjson::kNumberType:
+ if (json.IsUint64())
+ return std::uint64_t(json.GetUint64());
+ if (json.IsInt64())
+ return std::int64_t(json.GetInt64());
+ return json.GetDouble();
+ default:
+ throw error("Feature id must be a string or number");
+ }
+}
+
+template <>
+feature convert<feature>(const rapidjson_value &json) {
+ if (!json.IsObject())
+ throw error("Feature must be an object");
+
+ auto const &json_end = json.MemberEnd();
+ auto const &type_itr = json.FindMember("type");
+
+ if (type_itr == json_end)
+ throw error("Feature must have a type property");
+ if (type_itr->value != "Feature")
+ throw error("Feature type must be Feature");
+
+ auto const &geom_itr = json.FindMember("geometry");
+
+ if (geom_itr == json_end)
+ throw error("Feature must have a geometry property");
+
+ feature result{ convert<geometry>(geom_itr->value) };
+
+ auto const &id_itr = json.FindMember("id");
+ if (id_itr != json_end) {
+ result.id = convert<identifier>(id_itr->value);
+ }
+
+ auto const &prop_itr = json.FindMember("properties");
+ if (prop_itr != json_end) {
+ const auto &json_props = prop_itr->value;
+ if (!json_props.IsNull()) {
+ result.properties = convert<prop_map>(json_props);
+ }
+ }
+
+ return result;
+}
+
+template <>
+geojson convert<geojson>(const rapidjson_value &json) {
+ if (!json.IsObject())
+ throw error("GeoJSON must be an object");
+
+ const auto &type_itr = json.FindMember("type");
+ const auto &json_end = json.MemberEnd();
+
+ if (type_itr == json_end)
+ throw error("GeoJSON must have a type property");
+
+ const auto &type = type_itr->value;
+
+ if (type == "FeatureCollection") {
+ const auto &features_itr = json.FindMember("features");
+ if (features_itr == json_end)
+ throw error("FeatureCollection must have features property");
+
+ const auto &json_features = features_itr->value;
+
+ if (!json_features.IsArray())
+ throw error("FeatureCollection features property must be an array");
+
+ feature_collection collection;
+
+ const auto &size = json_features.Size();
+ collection.reserve(size);
+
+ for (auto &feature_obj : json_features.GetArray()) {
+ collection.push_back(convert<feature>(feature_obj));
+ }
+
+ return geojson{ collection };
+ }
+
+ if (type == "Feature")
+ return geojson{ convert<feature>(json) };
+
+ return geojson{ convert<geometry>(json) };
+}
+
+template <class T>
+T parse(const std::string &json) {
+ rapidjson_document d;
+ d.Parse(json.c_str());
+ if (d.HasParseError()) {
+ std::stringstream message;
+ message << d.GetErrorOffset() << " - " << rapidjson::GetParseError_En(d.GetParseError());
+ throw error(message.str());
+ }
+ return convert<T>(d);
+}
+
+template <>
+geometry parse<geometry>(const std::string &);
+template <>
+feature parse<feature>(const std::string &);
+template <>
+feature_collection parse<feature_collection>(const std::string &);
+
+geojson parse(const std::string &json) {
+ return parse<geojson>(json);
+}
+
+geojson convert(const rapidjson_value &json) {
+ return convert<geojson>(json);
+}
+
+template <>
+rapidjson_value convert<geometry>(const geometry&, rapidjson_allocator&);
+
+template <>
+rapidjson_value convert<feature>(const feature&, rapidjson_allocator&);
+
+template <>
+rapidjson_value convert<feature_collection>(const feature_collection&, rapidjson_allocator&);
+
+struct to_type {
+public:
+ const char * operator()(const point&) {
+ return "Point";
+ }
+
+ const char * operator()(const line_string&) {
+ return "LineString";
+ }
+
+ const char * operator()(const polygon&) {
+ return "Polygon";
+ }
+
+ const char * operator()(const multi_point&) {
+ return "MultiPoint";
+ }
+
+ const char * operator()(const multi_line_string&) {
+ return "MultiLineString";
+ }
+
+ const char * operator()(const multi_polygon&) {
+ return "MultiPolygon";
+ }
+
+ const char * operator()(const geometry_collection&) {
+ return "GeometryCollection";
+ }
+};
+
+struct to_coordinates_or_geometries {
+ rapidjson_allocator& allocator;
+
+ // Handles line_string, polygon, multi_point, multi_line_string, multi_polygon, and geometry_collection.
+ template <class E>
+ rapidjson_value operator()(const std::vector<E>& vector) {
+ rapidjson_value result;
+ result.SetArray();
+ for (std::size_t i = 0; i < vector.size(); ++i) {
+ result.PushBack(operator()(vector[i]), allocator);
+ }
+ return result;
+ }
+
+ rapidjson_value operator()(const point& element) {
+ rapidjson_value result;
+ result.SetArray();
+ result.PushBack(element.x, allocator);
+ result.PushBack(element.y, allocator);
+ return result;
+ }
+
+ rapidjson_value operator()(const geometry& element) {
+ return convert(element, allocator);
+ }
+};
+
+struct to_value {
+ rapidjson_allocator& allocator;
+
+ rapidjson_value operator()(null_value_t) {
+ rapidjson_value result;
+ result.SetNull();
+ return result;
+ }
+
+ rapidjson_value operator()(bool t) {
+ rapidjson_value result;
+ result.SetBool(t);
+ return result;
+ }
+
+ rapidjson_value operator()(int64_t t) {
+ rapidjson_value result;
+ result.SetInt64(t);
+ return result;
+ }
+
+ rapidjson_value operator()(uint64_t t) {
+ rapidjson_value result;
+ result.SetUint64(t);
+ return result;
+ }
+
+ rapidjson_value operator()(double t) {
+ rapidjson_value result;
+ result.SetDouble(t);
+ return result;
+ }
+
+ rapidjson_value operator()(const std::string& t) {
+ rapidjson_value result;
+ result.SetString(t.data(), rapidjson::SizeType(t.size()), allocator);
+ return result;
+ }
+
+ rapidjson_value operator()(const std::vector<value>& array) {
+ rapidjson_value result;
+ result.SetArray();
+ for (const auto& item : array) {
+ result.PushBack(value::visit(item, *this), allocator);
+ }
+ return result;
+ }
+
+ rapidjson_value operator()(const std::unordered_map<std::string, value>& map) {
+ rapidjson_value result;
+ result.SetObject();
+ for (const auto& property : map) {
+ result.AddMember(
+ rapidjson::GenericStringRef<char> {
+ property.first.data(),
+ rapidjson::SizeType(property.first.size())
+ },
+ value::visit(property.second, *this),
+ allocator);
+ }
+ return result;
+ }
+};
+
+template <>
+rapidjson_value convert<geometry>(const geometry& element, rapidjson_allocator& allocator) {
+ rapidjson_value result(rapidjson::kObjectType);
+
+ result.AddMember(
+ "type",
+ rapidjson::GenericStringRef<char> { geometry::visit(element, to_type()) },
+ allocator);
+
+ result.AddMember(
+ rapidjson::GenericStringRef<char> { element.is<geometry_collection>() ? "geometries" : "coordinates" },
+ geometry::visit(element, to_coordinates_or_geometries { allocator }),
+ allocator);
+
+ return result;
+}
+
+template <>
+rapidjson_value convert<feature>(const feature& element, rapidjson_allocator& allocator) {
+ rapidjson_value result(rapidjson::kObjectType);
+ result.AddMember("type", "Feature", allocator);
+
+ if (element.id) {
+ result.AddMember("id", identifier::visit(*element.id, to_value { allocator }), allocator);
+ }
+
+ result.AddMember("geometry", convert(element.geometry, allocator), allocator);
+ result.AddMember("properties", to_value { allocator }(element.properties), allocator);
+
+ return result;
+}
+
+template <>
+rapidjson_value convert<feature_collection>(const feature_collection& collection, rapidjson_allocator& allocator) {
+ rapidjson_value result(rapidjson::kObjectType);
+ result.AddMember("type", "FeatureCollection", allocator);
+
+ rapidjson_value features(rapidjson::kArrayType);
+ for (const auto& element : collection) {
+ features.PushBack(convert(element, allocator), allocator);
+ }
+ result.AddMember("features", features, allocator);
+
+ return result;
+}
+
+rapidjson_value convert(const geojson& element, rapidjson_allocator& allocator) {
+ return geojson::visit(element, [&] (const auto& alternative) {
+ return convert(alternative, allocator);
+ });
+}
+
+template <class T>
+std::string stringify(const T& t) {
+ rapidjson_allocator allocator;
+ rapidjson::StringBuffer buffer;
+ rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
+ convert(t, allocator).Accept(writer);
+ return buffer.GetString();
+}
+
+std::string stringify(const geojson& element) {
+ return geojson::visit(element, [] (const auto& alternative) {
+ return stringify(alternative);
+ });
+}
+
+} // namespace geojson
+} // namespace mapbox