1 #pragma once
2 
3 #include <mapbox/geometry.hpp>
4 
5 #include <mapbox/variant.hpp>
6 
7 #include <cstdint>
8 #include <string>
9 #include <vector>
10 #include <unordered_map>
11 
12 namespace mapbox {
13 namespace feature {
14 
15 struct value;
16 
17 struct null_value_t
18 {
19 };
20 
operator ==(const null_value_t &,const null_value_t &)21 constexpr bool operator==(const null_value_t&, const null_value_t&) { return true; }
operator !=(const null_value_t &,const null_value_t &)22 constexpr bool operator!=(const null_value_t&, const null_value_t&) { return false; }
operator <(const null_value_t &,const null_value_t &)23 constexpr bool operator<(const null_value_t&, const null_value_t&) { return false; }
24 
25 constexpr null_value_t null_value = null_value_t();
26 
27 // Multiple numeric types (uint64_t, int64_t, double) are present in order to support
28 // the widest possible range of JSON numbers, which do not have a maximum range.
29 // Implementations that produce `value`s should use that order for type preference,
30 // using uint64_t for positive integers, int64_t for negative integers, and double
31 // for non-integers and integers outside the range of 64 bits.
32 using value_base = mapbox::util::variant<null_value_t, bool, uint64_t, int64_t, double, std::string,
33                                          mapbox::util::recursive_wrapper<std::vector<value>>,
34                                          mapbox::util::recursive_wrapper<std::unordered_map<std::string, value>>>;
35 
36 struct value : value_base
37 {
38     using value_base::value_base;
39 };
40 
41 using property_map = std::unordered_map<std::string, value>;
42 
43 // The same considerations and requirement for numeric types apply as for `value_base`.
44 using identifier = mapbox::util::variant<null_value_t, uint64_t, int64_t, double, std::string>;
45 
46 template <class T>
47 struct feature
48 {
49     using coordinate_type = T;
50     using geometry_type = mapbox::geometry::geometry<T>; // Fully qualified to avoid GCC -fpermissive error.
51 
52     geometry_type geometry;
53     property_map properties;
54     identifier id;
55 
featuremapbox::feature::feature56     feature()
57         : geometry(),
58           properties(),
59           id() {}
featuremapbox::feature::feature60     feature(geometry_type const& geom_)
61         : geometry(geom_),
62           properties(),
63           id() {}
featuremapbox::feature::feature64     feature(geometry_type&& geom_)
65         : geometry(std::move(geom_)),
66           properties(),
67           id() {}
featuremapbox::feature::feature68     feature(geometry_type const& geom_, property_map const& prop_)
69         : geometry(geom_), properties(prop_), id() {}
featuremapbox::feature::feature70     feature(geometry_type&& geom_, property_map&& prop_)
71         : geometry(std::move(geom_)),
72           properties(std::move(prop_)),
73           id() {}
featuremapbox::feature::feature74     feature(geometry_type const& geom_, property_map const& prop_, identifier const& id_)
75         : geometry(geom_),
76           properties(prop_),
77           id(id_) {}
featuremapbox::feature::feature78     feature(geometry_type&& geom_, property_map&& prop_, identifier&& id_)
79         : geometry(std::move(geom_)),
80           properties(std::move(prop_)),
81           id(std::move(id_)) {}
82 };
83 
84 template <class T>
operator ==(feature<T> const & lhs,feature<T> const & rhs)85 constexpr bool operator==(feature<T> const& lhs, feature<T> const& rhs)
86 {
87     return lhs.id == rhs.id && lhs.geometry == rhs.geometry && lhs.properties == rhs.properties;
88 }
89 
90 template <class T>
operator !=(feature<T> const & lhs,feature<T> const & rhs)91 constexpr bool operator!=(feature<T> const& lhs, feature<T> const& rhs)
92 {
93     return !(lhs == rhs);
94 }
95 
96 template <class T, template <typename...> class Cont = std::vector>
97 struct feature_collection : Cont<feature<T>>
98 {
99     using coordinate_type = T;
100     using feature_type = feature<T>;
101     using container_type = Cont<feature_type>;
102     using size_type = typename container_type::size_type;
103 
104     template <class... Args>
feature_collectionmapbox::feature::feature_collection105     feature_collection(Args&&... args) : container_type(std::forward<Args>(args)...)
106     {
107     }
feature_collectionmapbox::feature::feature_collection108     feature_collection(std::initializer_list<feature_type> args)
109         : container_type(std::move(args)) {}
110 };
111 
112 } // namespace feature
113 } // namespace mapbox
114