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