1 #pragma once
2
3 #include <mapbox/geometry/geometry.hpp>
4
5 #include <mapbox/variant.hpp>
6
7 #include <cstdint>
8 #include <string>
9 #include <vector>
10 #include <unordered_map>
11 #include <experimental/optional>
12
13 namespace mapbox {
14 namespace geometry {
15
16 struct value;
17
18 struct null_value_t
19 {
null_value_tmapbox::geometry::null_value_t20 constexpr null_value_t() {}
null_value_tmapbox::geometry::null_value_t21 constexpr null_value_t(std::nullptr_t) {}
22 };
23
operator ==(const null_value_t &,const null_value_t &)24 constexpr bool operator==(const null_value_t&, const null_value_t&) { return true; }
operator !=(const null_value_t &,const null_value_t &)25 constexpr bool operator!=(const null_value_t&, const null_value_t&) { return false; }
operator <(const null_value_t &,const null_value_t &)26 constexpr bool operator<(const null_value_t&, const null_value_t&) { return false; }
27
28 constexpr null_value_t null_value = null_value_t();
29
30 // Multiple numeric types (uint64_t, int64_t, double) are present in order to support
31 // the widest possible range of JSON numbers, which do not have a maximum range.
32 // Implementations that produce `value`s should use that order for type preference,
33 // using uint64_t for positive integers, int64_t for negative integers, and double
34 // for non-integers and integers outside the range of 64 bits.
35 using value_base = mapbox::util::variant<null_value_t, bool, uint64_t, int64_t, double, std::string,
36 mapbox::util::recursive_wrapper<std::vector<value>>,
37 mapbox::util::recursive_wrapper<std::unordered_map<std::string, value>>>;
38
39 struct value : value_base
40 {
41 using value_base::value_base;
42 };
43
44 using property_map = std::unordered_map<std::string, value>;
45
46 // The same considerations and requirement for numeric types apply as for `value_base`.
47 using identifier = mapbox::util::variant<uint64_t, int64_t, double, std::string>;
48
49 template <class T>
50 struct feature
51 {
52 using coordinate_type = T;
53 using geometry_type = mapbox::geometry::geometry<T>; // Fully qualified to avoid GCC -fpermissive error.
54
55 geometry_type geometry;
56 property_map properties {};
57 std::experimental::optional<identifier> id {};
58
59 // GCC 4.9 does not support C++14 aggregates with non-static data member
60 // initializers.
featuremapbox::geometry::feature61 feature(geometry_type geometry_,
62 property_map properties_ = property_map {},
63 std::experimental::optional<identifier> id_ = std::experimental::optional<identifier> {})
64 : geometry(std::move(geometry_)),
65 properties(std::move(properties_)),
66 id(std::move(id_)) {}
67 };
68
69 template <class T>
operator ==(feature<T> const & lhs,feature<T> const & rhs)70 constexpr bool operator==(feature<T> const& lhs, feature<T> const& rhs)
71 {
72 return lhs.id == rhs.id && lhs.geometry == rhs.geometry && lhs.properties == rhs.properties;
73 }
74
75 template <class T>
operator !=(feature<T> const & lhs,feature<T> const & rhs)76 constexpr bool operator!=(feature<T> const& lhs, feature<T> const& rhs)
77 {
78 return !(lhs == rhs);
79 }
80
81 template <class T, template <typename...> class Cont = std::vector>
82 struct feature_collection : Cont<feature<T>>
83 {
84 using coordinate_type = T;
85 using feature_type = feature<T>;
86 using container_type = Cont<feature_type>;
87 using size_type = typename container_type::size_type;
88
89 template <class... Args>
feature_collectionmapbox::geometry::feature_collection90 feature_collection(Args&&... args) : container_type(std::forward<Args>(args)...) {}
feature_collectionmapbox::geometry::feature_collection91 feature_collection(std::initializer_list<feature_type> args)
92 : container_type(std::move(args)) {}
93 };
94
95 } // namespace geometry
96 } // namespace mapbox
97