Merge lp:~thomas-voss/location-service/add-ichnaea-provider into lp:location-service/trunk

Proposed by Thomas Voß
Status: Needs review
Proposed branch: lp:~thomas-voss/location-service/add-ichnaea-provider
Merge into: lp:location-service/trunk
Diff against target: 10213 lines (+9973/-0)
39 files modified
3rd-party/ichnaea/CMakeLists.txt (+68/-0)
3rd-party/ichnaea/examples/client.cpp (+101/-0)
3rd-party/ichnaea/include/ichnaea/bluetooth_beacon.h (+33/-0)
3rd-party/ichnaea/include/ichnaea/client.h (+66/-0)
3rd-party/ichnaea/include/ichnaea/error.h (+56/-0)
3rd-party/ichnaea/include/ichnaea/geolocate/fallback.h (+49/-0)
3rd-party/ichnaea/include/ichnaea/geolocate/parameters.h (+48/-0)
3rd-party/ichnaea/include/ichnaea/geolocate/result.h (+45/-0)
3rd-party/ichnaea/include/ichnaea/geosubmit/parameters.h (+34/-0)
3rd-party/ichnaea/include/ichnaea/geosubmit/report.h (+67/-0)
3rd-party/ichnaea/include/ichnaea/geosubmit/result.h (+26/-0)
3rd-party/ichnaea/include/ichnaea/ichnaea.h (+37/-0)
3rd-party/ichnaea/include/ichnaea/radio_cell.h (+60/-0)
3rd-party/ichnaea/include/ichnaea/region/parameters.h (+28/-0)
3rd-party/ichnaea/include/ichnaea/region/result.h (+36/-0)
3rd-party/ichnaea/include/ichnaea/response.h (+86/-0)
3rd-party/ichnaea/include/ichnaea/wifi_access_point.h (+53/-0)
3rd-party/ichnaea/src/ichnaea/client.cpp (+120/-0)
3rd-party/ichnaea/src/ichnaea/codec.h (+371/-0)
3rd-party/ichnaea/src/ichnaea/error.cpp (+30/-0)
3rd-party/ichnaea/src/ichnaea/geolocate/fallback.cpp (+41/-0)
3rd-party/ichnaea/src/ichnaea/geosubmit/report.cpp (+29/-0)
3rd-party/ichnaea/src/ichnaea/radio_cell.cpp (+29/-0)
3rd-party/ichnaea/src/ichnaea/util/json.hpp (+7873/-0)
3rd-party/ichnaea/src/ichnaea/wifi_access_point.cpp (+37/-0)
3rd-party/ichnaea/tests/CMakeLists.txt (+19/-0)
3rd-party/ichnaea/tests/error_test.cpp (+25/-0)
3rd-party/ichnaea/tests/fallback_test.cpp (+38/-0)
3rd-party/ichnaea/tests/radio_cell_test.cpp (+26/-0)
3rd-party/ichnaea/tests/response_test.cpp (+34/-0)
3rd-party/ichnaea/tests/wifi_access_point_test.cpp (+26/-0)
CMakeLists.txt (+3/-0)
src/location_service/com/ubuntu/location/providers/CMakeLists.txt (+1/-0)
src/location_service/com/ubuntu/location/providers/config.cpp (+7/-0)
src/location_service/com/ubuntu/location/providers/mls/CMakeLists.txt (+15/-0)
src/location_service/com/ubuntu/location/providers/mls/delayed_provider.cpp (+42/-0)
src/location_service/com/ubuntu/location/providers/mls/delayed_provider.h (+62/-0)
src/location_service/com/ubuntu/location/providers/mls/provider.cpp (+152/-0)
src/location_service/com/ubuntu/location/providers/mls/provider.h (+100/-0)
To merge this branch: bzr merge lp:~thomas-voss/location-service/add-ichnaea-provider
Reviewer Review Type Date Requested Status
Simon Fels Approve
Scott Sweeny (community) Approve
Review via email: mp+302429@code.launchpad.net

Commit message

Add a provider that talks to Mozilla's location services.

Description of the change

Add a provider that talks to Mozilla's location services.

To post a comment you must log in.
Revision history for this message
Scott Sweeny (ssweeny) wrote :

LGTM

review: Approve
Revision history for this message
Simon Fels (morphis) wrote :

LGTM

review: Approve

Unmerged revisions

265. By Thomas Voß

Add a provider that talks to Mozilla's location services.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added directory '3rd-party/ichnaea'
=== added file '3rd-party/ichnaea/CMakeLists.txt'
--- 3rd-party/ichnaea/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ 3rd-party/ichnaea/CMakeLists.txt 2016-08-09 15:10:52 +0000
@@ -0,0 +1,68 @@
1cmake_minimum_required(VERSION 2.8)
2
3project(ichnaea)
4
5set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
6
7include(CTest)
8
9find_package(PkgConfig)
10find_package(Boost)
11find_package(Threads)
12
13pkg_check_modules(NET_CPP net-cpp REQUIRED)
14pkg_check_modules(UBUNTU_LOCATION_SERVICE_CONNECTIVITY ubuntu-location-service-connectivity REQUIRED)
15
16include_directories(
17 include
18 src
19
20 ${NET_CPP_INCLUDE_DIRS}
21 ${UBUNTU_LOCATION_SERVICE_CONNECTIVITY_INCLUDE_DIRS})
22
23add_library(
24 ichnaea
25
26 include/ichnaea/ichnaea.h
27
28 include/ichnaea/bluetooth_beacon.h
29 include/ichnaea/client.h
30 include/ichnaea/error.h
31 include/ichnaea/radio_cell.h
32 include/ichnaea/response.h
33 include/ichnaea/wifi_access_point.h
34 include/ichnaea/geolocate/fallback.h
35 include/ichnaea/geolocate/parameters.h
36 include/ichnaea/geolocate/result.h
37 include/ichnaea/geosubmit/parameters.h
38 include/ichnaea/geosubmit/report.h
39 include/ichnaea/region/parameters.h
40 include/ichnaea/region/result.h
41
42 src/ichnaea/geolocate/fallback.cpp
43 src/ichnaea/geosubmit/report.cpp
44
45 src/ichnaea/codec.h
46 src/ichnaea/client.cpp
47 src/ichnaea/error.cpp
48 src/ichnaea/radio_cell.cpp
49 src/ichnaea/wifi_access_point.cpp)
50
51target_link_libraries(
52 ichnaea
53
54 ${CMAKE_THREAD_LIBS_INIT}
55 ${NET_CPP_LDFLAGS}
56 ${UBUNTU_LOCATION_SERVICE_CONNECTIVITY_LDFLAGS})
57
58add_executable(
59 ichnaea-client
60
61 examples/client.cpp)
62
63target_link_libraries(
64 ichnaea-client
65
66 ichnaea)
67
68add_subdirectory(tests)
069
=== added directory '3rd-party/ichnaea/examples'
=== added file '3rd-party/ichnaea/examples/client.cpp'
--- 3rd-party/ichnaea/examples/client.cpp 1970-01-01 00:00:00 +0000
+++ 3rd-party/ichnaea/examples/client.cpp 2016-08-09 15:10:52 +0000
@@ -0,0 +1,101 @@
1#include <ichnaea/client.h>
2
3#include <com/ubuntu/location/connectivity/manager.h>
4
5#include <core/dbus/macros.h>
6#include <core/dbus/object.h>
7#include <core/dbus/signal.h>
8
9#include <core/net/http/client.h>
10
11#include <thread>
12#include <vector>
13
14namespace connectivity = com::ubuntu::location::connectivity;
15
16int main()
17{
18 auto manager = connectivity::platform_default_manager();
19 auto http_client = core::net::http::make_client();
20
21 std::thread worker1{[http_client]() {http_client->run();}};
22
23 auto client = std::make_shared<ichnaea::Client>("test", http_client);
24
25 manager->wireless_network_scan_finished().connect([manager, client]
26 {
27 std::cout << "Wireless network scan finished" << std::endl;
28
29 std::vector<connectivity::WirelessNetwork::Ptr> wifis;
30
31 manager->enumerate_visible_wireless_networks([&wifis](const connectivity::WirelessNetwork::Ptr& wifi)
32 {
33 wifis.push_back(wifi);
34 });
35
36 ichnaea::geolocate::Parameters params;
37 params.consider_ip = true;
38
39 for (auto wifi : wifis)
40 {
41 ichnaea::WifiAccessPoint ap;
42 ap.bssid = wifi->bssid().get();
43 ap.ssid = wifi->ssid().get();
44 ap.frequency = wifi->frequency().get();
45 ap.signal_strength = wifi->signal_strength().get();
46
47 params.wifi_access_points.insert(ap);
48 }
49
50 try
51 {
52 client->geolocate(params, [client, params](const ichnaea::Response<ichnaea::geolocate::Result>& response)
53 {
54 if (not response.is_error())
55 {
56 std::cout << "Submitting to the service again." << std::endl;
57 ichnaea::geosubmit::Parameters submission;
58 ichnaea::geosubmit::Report report;
59 report.timestamp = std::chrono::system_clock::now();
60 report.position.latitude = response.result().location.lat;
61 report.position.longitude = response.result().location.lon;
62 report.position.accuracy = response.result().accuracy;
63 report.wifi_access_points = params.wifi_access_points;
64 submission.reports.push_back(report);
65
66 client->geosubmit(submission, [](const ichnaea::Response<ichnaea::geosubmit::Result>& response)
67 {
68 if (not response.is_error())
69 std::cout << "Successfully submitted to service." << std::endl;
70 else
71 std::cout << "Error submitting to service: " << response.error() << std::endl;
72 });
73 }
74 else
75 {
76 std::cout << "Error querying service for location: " << response.error() << std::endl;
77 }
78 });
79
80 client->region(params, [](const ichnaea::Response<ichnaea::region::Result>& response)
81 {
82 if (not response.is_error())
83 std::cout << response.result().country_code << ", " << response.result().country_name << std::endl;
84 else
85 std::cout << "Error querying service for region information: " << response.error() << std::endl;
86 });
87 }
88 catch (const std::exception& e)
89 {
90 std::cout << e.what() << std::endl;
91 }
92 });
93
94 while (true)
95 {
96 manager->request_scan_for_wireless_networks();
97 std::this_thread::sleep_for(std::chrono::seconds{15});
98 }
99
100 return 0;
101}
0102
=== added directory '3rd-party/ichnaea/include'
=== added directory '3rd-party/ichnaea/include/ichnaea'
=== added file '3rd-party/ichnaea/include/ichnaea/bluetooth_beacon.h'
--- 3rd-party/ichnaea/include/ichnaea/bluetooth_beacon.h 1970-01-01 00:00:00 +0000
+++ 3rd-party/ichnaea/include/ichnaea/bluetooth_beacon.h 2016-08-09 15:10:52 +0000
@@ -0,0 +1,33 @@
1// Copyright (C) 2016 Canonical Ltd.
2//
3// This library is free software: you can redistribute it and/or modify
4// it under the terms of the GNU Lesser General Public License as published
5// by the Free Software Foundation, either version 3 of the License, or
6// (at your option) any later version.
7//
8// This program is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11// GNU General Public License for more details.
12//
13// You should have received a copy of the GNU Lesser General Public License
14// along with this program. If not, see <http://www.gnu.org/licenses/>.
15#ifndef ICHNAEA_BLUETOOTH_BEACON_H_
16#define ICHNAEA_BLUETOOTH_BEACON_H_
17
18#include <chrono>
19#include <string>
20
21namespace ichnaea
22{
23/// @brief BluetoothBeacon models a visible bluetooth le device.
24struct BluetoothBeacon
25{
26 std::string mac_address; ///< The address of the Bluetooth Low Energy (BLE) beacon.
27 std::string name; ///< The name of the BLE beacon.
28 std::chrono::milliseconds age; ///< The number of milliseconds since this BLE beacon was last seen.
29 double signal_strength; ///< The measured signal strength of the BLE beacon in dBm.
30};
31}
32
33#endif // ICHNAEA_BLUETOOTH_BEACON_H_
034
=== added file '3rd-party/ichnaea/include/ichnaea/client.h'
--- 3rd-party/ichnaea/include/ichnaea/client.h 1970-01-01 00:00:00 +0000
+++ 3rd-party/ichnaea/include/ichnaea/client.h 2016-08-09 15:10:52 +0000
@@ -0,0 +1,66 @@
1// Copyright (C) 2016 Canonical Ltd.
2//
3// This library is free software: you can redistribute it and/or modify
4// it under the terms of the GNU Lesser General Public License as published
5// by the Free Software Foundation, either version 3 of the License, or
6// (at your option) any later version.
7//
8// This program is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11// GNU General Public License for more details.
12//
13// You should have received a copy of the GNU Lesser General Public License
14// along with this program. If not, see <http://www.gnu.org/licenses/>.
15#ifndef ICHNAEA_CLIENT_H_
16#define ICHNAEA_CLIENT_H_
17
18#include <ichnaea/response.h>
19
20#include <ichnaea/geolocate/parameters.h>
21#include <ichnaea/geolocate/result.h>
22
23#include <ichnaea/geosubmit/parameters.h>
24#include <ichnaea/geosubmit/result.h>
25
26#include <ichnaea/region/parameters.h>
27#include <ichnaea/region/result.h>
28
29#include <functional>
30#include <memory>
31#include <string>
32
33namespace core { namespace net { namespace http { class Client; }}}
34
35namespace ichnaea
36{
37/// @brief Client provides access to the ichnaea service offered by Mozilla.
38class Client
39{
40public:
41 /// @brief The default host we talk to.
42 static constexpr const char* default_host{"https://location.services.mozilla.com"};
43
44 /// @brief Client initializes a new instance with host, api_key and http_client.
45 Client(const std::string& host, const std::string& api_key, const std::shared_ptr<core::net::http::Client>& http_client);
46
47 /// @brief Client initializes a new instance with api_key and http_client.
48 Client(const std::string& api_key, const std::shared_ptr<core::net::http::Client>& http_client);
49
50 /// @brief geolocate queries the service instance for a position estimate for parameters,
51 /// reporting the response to cb.
52 void geolocate(const geolocate::Parameters& parameters, const std::function<void(const Response<geolocate::Result>&)>& cb);
53
54 /// @brief geosubmit feeds new location data to the service, reporting the status of the operation to cb.
55 void geosubmit(const geosubmit::Parameters& parameters, const std::function<void(const Response<geosubmit::Result>&)>& cb);
56
57 /// @brief region resolves the country for a given location, reporting the status of the operation to cb.
58 void region(const region::Parameters& parameters, const std::function<void(const Response<region::Result>&)>& cb);
59private:
60 std::string host;
61 std::string api_key;
62 std::shared_ptr<core::net::http::Client> http_client;
63};
64}
65
66#endif // ICHNAEA_CLIENT_H_
067
=== added file '3rd-party/ichnaea/include/ichnaea/error.h'
--- 3rd-party/ichnaea/include/ichnaea/error.h 1970-01-01 00:00:00 +0000
+++ 3rd-party/ichnaea/include/ichnaea/error.h 2016-08-09 15:10:52 +0000
@@ -0,0 +1,56 @@
1// Copyright (C) 2016 Canonical Ltd.
2//
3// This library is free software: you can redistribute it and/or modify
4// it under the terms of the GNU Lesser General Public License as published
5// by the Free Software Foundation, either version 3 of the License, or
6// (at your option) any later version.
7//
8// This program is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11// GNU General Public License for more details.
12//
13// You should have received a copy of the GNU Lesser General Public License
14// along with this program. If not, see <http://www.gnu.org/licenses/>.
15#ifndef ICHNAEA_ERROR_H_
16#define ICHNAEA_ERROR_H_
17
18#include <core/net/http/status.h>
19
20#include <iosfwd>
21#include <stdexcept>
22#include <string>
23#include <vector>
24
25namespace ichnaea
26{
27/// @brief Error models an error response.
28struct Error : public std::runtime_error
29{
30 /// @brief Detail provides further details describing
31 /// an error condition.
32 struct Detail
33 {
34 std::string domain;
35 std::string reason;
36 std::string message;
37 };
38
39 /// @brief Initializes a new instance with code and message.
40 ///
41 /// A human-readable message is generated from code and message,
42 /// handing it to the std::runtime_error ctor such that what invocations
43 /// provide a meaningful summary of the exception.
44 Error(core::net::http::Status code, const std::string& message);
45
46 std::vector<Detail> errors; ///< errors provides further details about the error condition.
47 core::net::http::Status code; ///< code describes the top-level class of the error condition.
48 std::string message; ///< message provides a human-readable error message.
49
50};
51
52/// @brief operator<< inserts error into out.
53std::ostream& operator<<(std::ostream& out, const Error& error);
54}
55
56#endif // ICHNAEA_ERROR_H_
057
=== added directory '3rd-party/ichnaea/include/ichnaea/geolocate'
=== added file '3rd-party/ichnaea/include/ichnaea/geolocate/fallback.h'
--- 3rd-party/ichnaea/include/ichnaea/geolocate/fallback.h 1970-01-01 00:00:00 +0000
+++ 3rd-party/ichnaea/include/ichnaea/geolocate/fallback.h 2016-08-09 15:10:52 +0000
@@ -0,0 +1,49 @@
1// Copyright (C) 2016 Canonical Ltd.
2//
3// This library is free software: you can redistribute it and/or modify
4// it under the terms of the GNU Lesser General Public License as published
5// by the Free Software Foundation, either version 3 of the License, or
6// (at your option) any later version.
7//
8// This program is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11// GNU General Public License for more details.
12//
13// You should have received a copy of the GNU Lesser General Public License
14// along with this program. If not, see <http://www.gnu.org/licenses/>.
15#ifndef ICHNAEA_GEOLOCATE_FALLBACK_H_
16#define ICHNAEA_GEOLOCATE_FALLBACK_H_
17
18#include <iosfwd>
19
20namespace ichnaea
21{
22namespace geolocate
23{
24/// @brief Fallback enumerates all known fallback strategies
25/// for obtaining a position estimate in the case of missing or
26/// contradictory measurements.
27enum class Fallback
28{
29 none = 0,
30 /// If no exact cell match can be found, fall back from exact cell
31 /// position estimates to more coarse grained cell location area estimates,
32 /// rather than going directly to an even worse GeoIP based estimate.
33 lac = 1 << 0,
34 /// If no position can be estimated based on any of the provided data points,
35 /// fall back to an estimate based on a GeoIP database based on the senders IP
36 /// address at the time of the query.
37 ip = 1 << 1
38};
39
40/// @brief operator<< inserts fallback into out.
41std::ostream& operator<<(std::ostream& out, Fallback fallback);
42/// @brief operator| returns the bitwise or of lhs and rhs.
43Fallback operator|(Fallback lhs, Fallback rhs);
44/// @brief operator| returns the bitwise and of lhs and rhs.
45Fallback operator&(Fallback lhs, Fallback rhs);
46}
47}
48
49#endif // ICHNAEA_GEOLOCATE_FALLBACK_H_
050
=== added file '3rd-party/ichnaea/include/ichnaea/geolocate/parameters.h'
--- 3rd-party/ichnaea/include/ichnaea/geolocate/parameters.h 1970-01-01 00:00:00 +0000
+++ 3rd-party/ichnaea/include/ichnaea/geolocate/parameters.h 2016-08-09 15:10:52 +0000
@@ -0,0 +1,48 @@
1// Copyright (C) 2016 Canonical Ltd.
2//
3// This library is free software: you can redistribute it and/or modify
4// it under the terms of the GNU Lesser General Public License as published
5// by the Free Software Foundation, either version 3 of the License, or
6// (at your option) any later version.
7//
8// This program is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11// GNU General Public License for more details.
12//
13// You should have received a copy of the GNU Lesser General Public License
14// along with this program. If not, see <http://www.gnu.org/licenses/>.
15#ifndef ICHNAEA_GEOLOCATE_PARAMETERS_H_
16#define ICHNAEA_GEOLOCATE_PARAMETERS_H_
17
18#include <ichnaea/bluetooth_beacon.h>
19#include <ichnaea/radio_cell.h>
20#include <ichnaea/wifi_access_point.h>
21
22#include <ichnaea/geolocate/fallback.h>
23
24#include <boost/optional.hpp>
25
26#include <set>
27
28namespace ichnaea
29{
30namespace geolocate
31{
32/// @brief Parameters encapsulates all input parameters to a geolocate request.
33struct Parameters
34{
35 boost::optional<std::string> carrier; ///< The clear text name of the cell carrier / operator.
36 boost::optional<bool> consider_ip; ///< Should the clients IP address be used to locate it, defaults to true.
37 boost::optional<RadioCell::MCC> mcc; ///< The mobile country code stored on the SIM card.
38 boost::optional<RadioCell::MNC> mnc; ///< The mobile network code stored on the SIM card.
39 boost::optional<RadioCell::RadioType> radio_type; ///< Same as the radioType entry in each cell record.
40 std::set<BluetoothBeacon> bluetooth_beacons; ///< Visible bluetooth beacons.
41 std::set<WifiAccessPoint> wifi_access_points; ///< Visible access points.
42 std::set<RadioCell> radio_cells; ///< Visible radio cells.
43 boost::optional<Fallback> fallback; ///< Fallback setup.
44};
45}
46}
47
48#endif // ICHNAEA_GEOLOCATE_PARAMETERS_H_
049
=== added file '3rd-party/ichnaea/include/ichnaea/geolocate/result.h'
--- 3rd-party/ichnaea/include/ichnaea/geolocate/result.h 1970-01-01 00:00:00 +0000
+++ 3rd-party/ichnaea/include/ichnaea/geolocate/result.h 2016-08-09 15:10:52 +0000
@@ -0,0 +1,45 @@
1// Copyright (C) 2016 Canonical Ltd.
2//
3// This library is free software: you can redistribute it and/or modify
4// it under the terms of the GNU Lesser General Public License as published
5// by the Free Software Foundation, either version 3 of the License, or
6// (at your option) any later version.
7//
8// This program is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11// GNU General Public License for more details.
12//
13// You should have received a copy of the GNU Lesser General Public License
14// along with this program. If not, see <http://www.gnu.org/licenses/>.
15#ifndef ICHNAEA_GEOLOCATE_RESULT_H_
16#define ICHNAEA_GEOLOCATE_RESULT_H_
17
18#include <ichnaea/geolocate/fallback.h>
19
20#include <boost/optional.hpp>
21
22namespace ichnaea
23{
24namespace geolocate
25{
26/// @brief Result bundles the successful respsone to a
27/// geolocate request.
28///
29/// Please note that we provide accessors for convenience and to
30/// implement a named parameter pattern.
31struct Result
32{
33 struct Location
34 {
35 double lat; ///< lat is the latitude component of the position estimate.
36 double lon; ///< lon is the longitude component of the position estimate.
37 };
38 Location location; ///< location is the position estimate determined by the service.
39 double accuracy; ///< accuracy describes the quality of the estimate in terms of a circle with radious accuracy.
40 boost::optional<Fallback> fallback; ///< fallback contains the fallback strategies that were used to obtain the position estimate.
41};
42}
43}
44
45#endif // ICHNAEA_GEOLOCATE_RESULT_H_
046
=== added directory '3rd-party/ichnaea/include/ichnaea/geosubmit'
=== added file '3rd-party/ichnaea/include/ichnaea/geosubmit/parameters.h'
--- 3rd-party/ichnaea/include/ichnaea/geosubmit/parameters.h 1970-01-01 00:00:00 +0000
+++ 3rd-party/ichnaea/include/ichnaea/geosubmit/parameters.h 2016-08-09 15:10:52 +0000
@@ -0,0 +1,34 @@
1// Copyright (C) 2016 Canonical Ltd.
2//
3// This library is free software: you can redistribute it and/or modify
4// it under the terms of the GNU Lesser General Public License as published
5// by the Free Software Foundation, either version 3 of the License, or
6// (at your option) any later version.
7//
8// This program is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11// GNU General Public License for more details.
12//
13// You should have received a copy of the GNU Lesser General Public License
14// along with this program. If not, see <http://www.gnu.org/licenses/>.
15#ifndef ICHNAEA_GEOSUBMIT_PARAMETERS_H_
16#define ICHNAEA_GEOSUBMIT_PARAMETERS_H_
17
18#include <ichnaea/geosubmit/report.h>
19
20#include <vector>
21
22namespace ichnaea
23{
24namespace geosubmit
25{
26/// @brief Parameters encapsulates all input parameters to a geosubmit request.
27struct Parameters
28{
29 std::vector<Report> reports; ///< Collection of samples to be submitted to the service.
30};
31}
32}
33
34#endif // ICHNAEA_GEOSUBMIT_PARAMETERS_H_
035
=== added file '3rd-party/ichnaea/include/ichnaea/geosubmit/report.h'
--- 3rd-party/ichnaea/include/ichnaea/geosubmit/report.h 1970-01-01 00:00:00 +0000
+++ 3rd-party/ichnaea/include/ichnaea/geosubmit/report.h 2016-08-09 15:10:52 +0000
@@ -0,0 +1,67 @@
1// Copyright (C) 2016 Canonical Ltd.
2//
3// This library is free software: you can redistribute it and/or modify
4// it under the terms of the GNU Lesser General Public License as published
5// by the Free Software Foundation, either version 3 of the License, or
6// (at your option) any later version.
7//
8// This program is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11// GNU General Public License for more details.
12//
13// You should have received a copy of the GNU Lesser General Public License
14// along with this program. If not, see <http://www.gnu.org/licenses/>.
15#ifndef ICHNAEA_GEOSUBMIT_REPORT_H_
16#define ICHNAEA_GEOSUBMIT_REPORT_H_
17
18#include <ichnaea/bluetooth_beacon.h>
19#include <ichnaea/radio_cell.h>
20#include <ichnaea/wifi_access_point.h>
21
22#include <boost/optional.hpp>
23
24#include <chrono>
25#include <set>
26
27namespace ichnaea
28{
29namespace geosubmit
30{
31/// @brief Report encapsulates a set of wifi, cell and bt beacon measurements.
32struct Report
33{
34 struct Position
35 {
36 enum class Source
37 {
38 manual,
39 fusion,
40 gps
41 };
42
43 double latitude; ///< The latitude of the observation (WGS 84).
44 double longitude; ///< The longitude of the observation (WGS 84).
45 boost::optional<double> accuracy; ///< The accuracy of the observed position in meters.
46 boost::optional<std::chrono::milliseconds> age; ///< The age of the position data (in milliseconds).
47 boost::optional<double> altitude; ///< The altitude at which the data was observed in meters above sea-level.
48 boost::optional<double> altitude_accuracy; ///< The accuracy of the altitude estimate in meters.
49 boost::optional<double> heading; ///< The heading field denotes the direction of travel of the device and is specified in degrees, where 0° ≤ heading < 360°, counting clockwise relative to the true north.
50 boost::optional<double> pressure; ///< The air pressure in hPa (millibar).
51 boost::optional<double> speed; ///< The speed field denotes the magnitude of the horizontal component of the device’s current velocity and is specified in meters per second.
52 boost::optional<Source> source; ///< The source of the position information.
53 };
54
55 std::chrono::system_clock::time_point timestamp; ///< The time of observation of the data, measured in milliseconds since the UNIX epoch.
56 Position position; ///< The actual position measurement.
57 std::set<BluetoothBeacon> bluetooth_beacons; ///< Visible bluetooth beacons.
58 std::set<WifiAccessPoint> wifi_access_points; ///< Visible access points.
59 std::set<RadioCell> radio_cells; ///< Visible radio cells.
60};
61
62/// @brief operator<< inserts source into out.
63std::ostream& operator<<(std::ostream& out, Report::Position::Source source);
64}
65}
66
67#endif // ICHNAEA_GEOSUBMIT_REPORT_H_
068
=== added file '3rd-party/ichnaea/include/ichnaea/geosubmit/result.h'
--- 3rd-party/ichnaea/include/ichnaea/geosubmit/result.h 1970-01-01 00:00:00 +0000
+++ 3rd-party/ichnaea/include/ichnaea/geosubmit/result.h 2016-08-09 15:10:52 +0000
@@ -0,0 +1,26 @@
1// Copyright (C) 2016 Canonical Ltd.
2//
3// This library is free software: you can redistribute it and/or modify
4// it under the terms of the GNU Lesser General Public License as published
5// by the Free Software Foundation, either version 3 of the License, or
6// (at your option) any later version.
7//
8// This program is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11// GNU General Public License for more details.
12//
13// You should have received a copy of the GNU Lesser General Public License
14// along with this program. If not, see <http://www.gnu.org/licenses/>.
15#ifndef ICHNAEA_GEOSUBMIT_RESULT_H_
16#define ICHNAEA_GEOSUBMIT_RESULT_H_
17
18namespace ichnaea
19{
20namespace geosubmit
21{
22struct Result {};
23}
24}
25
26#endif // ICHNAEA_GEOSUBMIT_RESULT_H_
027
=== added file '3rd-party/ichnaea/include/ichnaea/ichnaea.h'
--- 3rd-party/ichnaea/include/ichnaea/ichnaea.h 1970-01-01 00:00:00 +0000
+++ 3rd-party/ichnaea/include/ichnaea/ichnaea.h 2016-08-09 15:10:52 +0000
@@ -0,0 +1,37 @@
1// Copyright (C) 2016 Canonical Ltd.
2//
3// This library is free software: you can redistribute it and/or modify
4// it under the terms of the GNU Lesser General Public License as published
5// by the Free Software Foundation, either version 3 of the License, or
6// (at your option) any later version.
7//
8// This program is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11// GNU General Public License for more details.
12//
13// You should have received a copy of the GNU Lesser General Public License
14// along with this program. If not, see <http://www.gnu.org/licenses/>.
15#ifndef ICHNAEA_ICHNAEA_H_
16#define ICHNAEA_ICHNAEA_H_
17
18#include "ichnaea/response.h"
19#include "ichnaea/radio_cell.h"
20#include "ichnaea/client.h"
21#include "ichnaea/error.h"
22#include "ichnaea/geosubmit/parameters.h"
23#include "ichnaea/geosubmit/result.h"
24#include "ichnaea/geosubmit/report.h"
25#include "ichnaea/bluetooth_beacon.h"
26#include "ichnaea/geolocate/fallback.h"
27#include "ichnaea/geolocate/parameters.h"
28#include "ichnaea/geolocate/result.h"
29#include "ichnaea/wifi_access_point.h"
30
31/// @brief ichnaea contains types and functions for using Mozilla's location services:
32///
33/// Please see https://mozilla.github.io/ichnaea/index.html for further details on the server-side
34/// implementation.
35namespace ichnaea{}
36
37#endif // ICHNAEA_ICHNAEA_H_
038
=== added file '3rd-party/ichnaea/include/ichnaea/radio_cell.h'
--- 3rd-party/ichnaea/include/ichnaea/radio_cell.h 1970-01-01 00:00:00 +0000
+++ 3rd-party/ichnaea/include/ichnaea/radio_cell.h 2016-08-09 15:10:52 +0000
@@ -0,0 +1,60 @@
1// Copyright (C) 2016 Canonical Ltd.
2//
3// This library is free software: you can redistribute it and/or modify
4// it under the terms of the GNU Lesser General Public License as published
5// by the Free Software Foundation, either version 3 of the License, or
6// (at your option) any later version.
7//
8// This program is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11// GNU General Public License for more details.
12//
13// You should have received a copy of the GNU Lesser General Public License
14// along with this program. If not, see <http://www.gnu.org/licenses/>.
15#ifndef ICHNAEA_RADIO_CELL_H_
16#define ICHNAEA_RADIO_CELL_H_
17
18#include <boost/optional.hpp>
19
20#include <chrono>
21#include <iosfwd>
22
23namespace ichnaea
24{
25/// @brief CellTower models an individual radio cell tower.
26struct RadioCell
27{
28 enum class RadioType
29 {
30 gsm,
31 wcdma,
32 lte
33 };
34
35 /// @cond
36 typedef unsigned int MCC;
37 typedef unsigned int MNC;
38 typedef unsigned int LAC;
39 typedef unsigned int Id;
40 typedef unsigned int PSC;
41 /// @endcond
42
43 RadioType radio_type; ///< The type of radio network.
44 bool serving; ///< Whether this is the serving or a neighboring cell.
45 MCC mcc; ///< The mobile country code.
46 MNC mnc; ///< The mobile network code.
47 LAC lac; ///< The location area code for GSM and WCDMA networks. The tracking area code for LTE networks.
48 Id id; ///< The cell id or cell identity.
49 std::chrono::milliseconds age; ///< The number of milliseconds since this networks was last detected.
50 PSC psc; ///< The primary scrambling code for WCDMA and physical cell id for LTE.
51 boost::optional<double> asu; ///< The arbitrary strength unit indicating the signal strength if a direct signal strength reading is not available.
52 boost::optional<double> signal_strength; ///< The signal strength for this cell network, either the RSSI or RSCP.
53 double timing_advance; ///< The timing advance value for this cell network.
54};
55
56/// @brief operator<< inserts radio_type into out.
57std::ostream& operator<<(std::ostream& out, RadioCell::RadioType radio_type);
58}
59
60#endif // ICHNAEA_RADIO_CELL_H_
061
=== added directory '3rd-party/ichnaea/include/ichnaea/region'
=== added file '3rd-party/ichnaea/include/ichnaea/region/parameters.h'
--- 3rd-party/ichnaea/include/ichnaea/region/parameters.h 1970-01-01 00:00:00 +0000
+++ 3rd-party/ichnaea/include/ichnaea/region/parameters.h 2016-08-09 15:10:52 +0000
@@ -0,0 +1,28 @@
1// Copyright (C) 2016 Canonical Ltd.
2//
3// This library is free software: you can redistribute it and/or modify
4// it under the terms of the GNU Lesser General Public License as published
5// by the Free Software Foundation, either version 3 of the License, or
6// (at your option) any later version.
7//
8// This program is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11// GNU General Public License for more details.
12//
13// You should have received a copy of the GNU Lesser General Public License
14// along with this program. If not, see <http://www.gnu.org/licenses/>.
15#ifndef ICHNAEA_RESULT_PARAMETERS_H_
16#define ICHNAEA_RESULT_PARAMETERS_H_
17
18#include <ichnaea/geolocate/parameters.h>
19
20namespace ichnaea
21{
22namespace region
23{
24typedef ichnaea::geolocate::Parameters Parameters;
25}
26}
27
28#endif // ICHNAEA_RESULT_PARAMETERS_H_
029
=== added file '3rd-party/ichnaea/include/ichnaea/region/result.h'
--- 3rd-party/ichnaea/include/ichnaea/region/result.h 1970-01-01 00:00:00 +0000
+++ 3rd-party/ichnaea/include/ichnaea/region/result.h 2016-08-09 15:10:52 +0000
@@ -0,0 +1,36 @@
1// Copyright (C) 2016 Canonical Ltd.
2//
3// This library is free software: you can redistribute it and/or modify
4// it under the terms of the GNU Lesser General Public License as published
5// by the Free Software Foundation, either version 3 of the License, or
6// (at your option) any later version.
7//
8// This program is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11// GNU General Public License for more details.
12//
13// You should have received a copy of the GNU Lesser General Public License
14// along with this program. If not, see <http://www.gnu.org/licenses/>.
15#ifndef ICHNAEA_REGION_RESULT_H_
16#define ICHNAEA_REGION_RESULT_H_
17
18#include <ichnaea/geolocate/fallback.h>
19
20namespace ichnaea
21{
22namespace region
23{
24/// @brief Result bundles the result of a region query, reporting back
25/// country code and name using region codes and names from the GENC dataset.
26///
27/// See http://www.gwg.nga.mil/ccwg.php for further details.
28struct Result
29{
30 std::string country_code;
31 std::string country_name;
32};
33}
34}
35
36#endif // ICHNAEA_REGION_RESULT_H_
037
=== added file '3rd-party/ichnaea/include/ichnaea/response.h'
--- 3rd-party/ichnaea/include/ichnaea/response.h 1970-01-01 00:00:00 +0000
+++ 3rd-party/ichnaea/include/ichnaea/response.h 2016-08-09 15:10:52 +0000
@@ -0,0 +1,86 @@
1// Copyright (C) 2016 Canonical Ltd.
2//
3// This library is free software: you can redistribute it and/or modify
4// it under the terms of the GNU Lesser General Public License as published
5// by the Free Software Foundation, either version 3 of the License, or
6// (at your option) any later version.
7//
8// This program is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11// GNU General Public License for more details.
12//
13// You should have received a copy of the GNU Lesser General Public License
14// along with this program. If not, see <http://www.gnu.org/licenses/>.
15#ifndef ICHNAEA_RESPONSE_H_
16#define ICHNAEA_RESPONSE_H_
17
18#include <ichnaea/error.h>
19
20#include <boost/variant.hpp>
21
22#include <type_traits>
23
24namespace ichnaea
25{
26/// @brief Repsonse models a typed variant that either contains the Result of
27/// an operation xor an error if the operation fails.
28template<typename Result>
29class Response
30{
31 public:
32 /// @brief NotAnError is thrown if error() is invoked on a Response<T>
33 /// instance that contains a result.
34 struct NotAnError : public std::runtime_error
35 {
36 NotAnError() : std::runtime_error{"Not an error"}
37 {
38 }
39 };
40
41 /// @brief Response initializes a new instance with result such
42 /// that subsequent invocations of is_error() return false.
43 explicit Response(const Result& result)
44 : result_or_error{result}
45 {
46 }
47
48 /// @brief Response initializes a new instance with error such
49 /// that subsequent invocations of is_error() return true.
50 explicit Response(const Error& error)
51 : result_or_error{error}
52 {
53 }
54
55 /// @brief is_error returns true if the instance contains an error.
56 bool is_error() const
57 {
58 return 1 == result_or_error.which();
59 }
60
61 /// @brief error returns the error response or throws NotAnError
62 /// if no error is contained in the instance.
63 const Error& error() const
64 {
65 if (not is_error())
66 throw NotAnError{};
67
68 return boost::get<Error>(result_or_error);
69 }
70
71 /// @brief result returns the Result instance. Throws the contained
72 /// error if this is an error response.
73 const Result& result() const
74 {
75 if (is_error())
76 throw error();
77
78 return boost::get<Result>(result_or_error);
79 }
80
81 private:
82 boost::variant<Result, Error> result_or_error;
83};
84}
85
86#endif // ICHNAEA_RESPONSE_H_
087
=== added file '3rd-party/ichnaea/include/ichnaea/wifi_access_point.h'
--- 3rd-party/ichnaea/include/ichnaea/wifi_access_point.h 1970-01-01 00:00:00 +0000
+++ 3rd-party/ichnaea/include/ichnaea/wifi_access_point.h 2016-08-09 15:10:52 +0000
@@ -0,0 +1,53 @@
1// Copyright (C) 2016 Canonical Ltd.
2//
3// This library is free software: you can redistribute it and/or modify
4// it under the terms of the GNU Lesser General Public License as published
5// by the Free Software Foundation, either version 3 of the License, or
6// (at your option) any later version.
7//
8// This program is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11// GNU General Public License for more details.
12//
13// You should have received a copy of the GNU Lesser General Public License
14// along with this program. If not, see <http://www.gnu.org/licenses/>.
15#ifndef ICHNAEA_WIFI_ACCESS_POINT_H_
16#define ICHNAEA_WIFI_ACCESS_POINT_H_
17
18#include <boost/optional.hpp>
19
20#include <chrono>
21#include <string>
22
23namespace ichnaea
24{
25struct WifiAccessPoint
26{
27 enum class Type
28 {
29 _802_11_a,
30 _802_11_b,
31 _802_11_g,
32 _802_11_n,
33 _802_11_ac
34 };
35
36 std::string bssid; ///< The BSSID of the WiFi network.
37 boost::optional<Type> type; ///< The Wifi radio type.
38 boost::optional<std::chrono::milliseconds> age; ///< The number of milliseconds since this network was last detected.
39 boost::optional<unsigned int> channel; ///< The WiFi channel, often 1 - 13 for networks in the 2.4GHz range.
40 boost::optional<double> frequency; ///< The frequency in MHz of the channel over which the client is communicating with the access point.
41 boost::optional<double> signal_strength; ///< The received signal strength (RSSI) in dBm.
42 boost::optional<double> signal_to_noise_ratio; ///< The current signal to noise ratio measured in dB.
43 boost::optional<std::string> ssid; ///< The SSID of the Wifi network.
44};
45
46/// @brief operator< returns true if lhs is smaller than rhs.
47bool operator<(const WifiAccessPoint& lhs, const WifiAccessPoint& rhs);
48
49/// @brief operator<< inserts type into out.
50std::ostream& operator<<(std::ostream& out, WifiAccessPoint::Type type);
51}
52
53#endif // ICHNAEA_WIFI_ACCESS_POINT_H_
054
=== added directory '3rd-party/ichnaea/src'
=== added directory '3rd-party/ichnaea/src/ichnaea'
=== added file '3rd-party/ichnaea/src/ichnaea/client.cpp'
--- 3rd-party/ichnaea/src/ichnaea/client.cpp 1970-01-01 00:00:00 +0000
+++ 3rd-party/ichnaea/src/ichnaea/client.cpp 2016-08-09 15:10:52 +0000
@@ -0,0 +1,120 @@
1// Copyright (C) 2016 Canonical Ltd.
2//
3// This library is free software: you can redistribute it and/or modify
4// it under the terms of the GNU Lesser General Public License as published
5// by the Free Software Foundation, either version 3 of the License, or
6// (at your option) any later version.
7//
8// This program is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11// GNU General Public License for more details.
12//
13// You should have received a copy of the GNU Lesser General Public License
14// along with this program. If not, see <http://www.gnu.org/licenses/>.
15#include <ichnaea/client.h>
16#include <ichnaea/codec.h>
17
18#include <ichnaea/util/json.hpp>
19
20#include <core/net/uri.h>
21#include <core/net/http/client.h>
22#include <core/net/http/request.h>
23#include <core/net/http/response.h>
24#include <core/net/http/status.h>
25
26#include <boost/lexical_cast.hpp>
27
28namespace http = core::net::http;
29namespace json = nlohmann;
30
31ichnaea::Client::Client(const std::string& host, const std::string& api_key, const std::shared_ptr<http::Client>& http_client)
32 : host{host}, api_key{api_key}, http_client{http_client}
33{
34}
35
36ichnaea::Client::Client(const std::string& api_key, const std::shared_ptr<http::Client>& http_client)
37 : Client{Client::default_host, api_key, http_client}
38{
39}
40
41void ichnaea::Client::geolocate(const geolocate::Parameters& parameters, const std::function<void(const Response<geolocate::Result>&)>& cb)
42{
43 json::json root; root & parameters;
44
45 http::Request::Configuration config;
46 config.uri = http_client->uri_to_string(core::net::make_uri(host, {"v1", "geolocate"}, {{"key", api_key}}));
47 http::Request::Handler handler;
48 handler.on_response([cb](const http::Response& response)
49 {
50 auto root = json::json::parse(response.body);
51
52 if (response.status != http::Status::ok)
53 {
54 Error e{http::Status::bad_request, ""}; root & std::ref(e);
55 cb(Response<geolocate::Result>{e});
56 }
57 else
58 {
59 geolocate::Result r; root & std::ref(r);
60 cb(Response<geolocate::Result>{r});
61 }
62 });
63
64 http_client->post(config, root.dump(), "application/json")->async_execute(handler);
65}
66
67void ichnaea::Client::geosubmit(const geosubmit::Parameters& parameters, const std::function<void(const Response<geosubmit::Result>&)>& cb)
68{
69 if (parameters.reports.empty())
70 return;
71
72 json::json root; root & parameters;
73
74 http::Request::Configuration config;
75 config.uri = http_client->uri_to_string(core::net::make_uri(host, {"v2", "geosubmit"}, {}));
76 http::Request::Handler handler;
77 handler.on_response([cb](const http::Response& response)
78 {
79 auto root = json::json::parse(response.body);
80
81 if (response.status != http::Status::ok)
82 {
83 Error e{http::Status::bad_request, ""}; root & std::ref(e);
84 cb(Response<geosubmit::Result>{e});
85 }
86 else
87 {
88 geosubmit::Result r; root & std::ref(r);
89 cb(Response<geosubmit::Result>{r});
90 }
91 });
92
93 http_client->post(config, root.dump(), "application/json")->async_execute(handler);
94}
95
96void ichnaea::Client::region(const region::Parameters& parameters, const std::function<void(const Response<region::Result>&)>& cb)
97{
98 json::json root; root & parameters;
99
100 http::Request::Configuration config;
101 config.uri = http_client->uri_to_string(core::net::make_uri(host, {"v1", "country"}, {{"key", api_key}}));
102 http::Request::Handler handler;
103 handler.on_response([cb](const http::Response& response)
104 {
105 auto root = json::json::parse(response.body);
106
107 if (response.status != http::Status::ok)
108 {
109 Error e{http::Status::bad_request, ""}; root & std::ref(e);
110 cb(Response<region::Result>{e});
111 }
112 else
113 {
114 region::Result r; root & std::ref(r);
115 cb(Response<region::Result>{r});
116 }
117 });
118
119 http_client->post(config, root.dump(), "application/json")->async_execute(handler);
120}
0121
=== added file '3rd-party/ichnaea/src/ichnaea/codec.h'
--- 3rd-party/ichnaea/src/ichnaea/codec.h 1970-01-01 00:00:00 +0000
+++ 3rd-party/ichnaea/src/ichnaea/codec.h 2016-08-09 15:10:52 +0000
@@ -0,0 +1,371 @@
1#ifndef ICHNAEA_CODEC_H_
2#define ICHNAEA_CODEC_H_
3
4#include <ichnaea/error.h>
5
6#include <ichnaea/bluetooth_beacon.h>
7#include <ichnaea/radio_cell.h>
8#include <ichnaea/wifi_access_point.h>
9
10#include <ichnaea/geolocate/fallback.h>
11#include <ichnaea/geolocate/parameters.h>
12#include <ichnaea/geolocate/result.h>
13#include <ichnaea/geosubmit/parameters.h>
14#include <ichnaea/geosubmit/report.h>
15#include <ichnaea/geosubmit/result.h>
16#include <ichnaea/region/result.h>
17
18#include <ichnaea/util/json.hpp>
19
20#include <boost/lexical_cast.hpp>
21#include <boost/optional.hpp>
22
23#include <chrono>
24#include <map>
25#include <set>
26#include <vector>
27
28namespace json = nlohmann;
29
30namespace ichnaea
31{
32
33template<typename T>
34struct NVP
35{
36 std::string name;
37 T value;
38};
39
40template<typename T>
41inline NVP<T> make_nvp(const std::string& name, const T& value)
42{
43 return NVP<T>{name, value};
44}
45
46template<typename T>
47struct Codec
48{
49 static void encode(json::json& out, const T& in)
50 {
51 out = in;
52 }
53
54 static void decode(json::json& in, T& out)
55 {
56 out = in;
57 }
58};
59
60template<typename T>
61inline json::json& operator&(json::json& out, const T& in)
62{
63 Codec<T>::encode(out, in);
64 return out;
65}
66
67template<typename T>
68inline json::json& operator&(json::json& out, const std::reference_wrapper<T>& in)
69{
70 Codec<T>::decode(out, in.get());
71 return out;
72}
73
74template<typename T>
75struct Codec<NVP<T>>
76{
77 static void encode(json::json& out, const NVP<T>& in)
78 {
79 Codec<T>::encode(out[in.name], in.value);
80 }
81
82 static void decode(json::json& in, NVP<T>& out)
83 {
84 Codec<T>::decode(in[out.name], out.value);
85 }
86};
87
88template<typename T>
89struct Codec<NVP<boost::optional<T>>>
90{
91 static void encode(json::json& out, const NVP<boost::optional<T>>& in)
92 {
93 if (in.value) out[in.name] & in.value;
94 }
95
96 static void decode(json::json& in, NVP<boost::optional<T>>& out)
97 {
98 if (in) in[out.name] & out.value;
99 }
100};
101
102template<typename T>
103struct Codec<NVP<std::set<T>>>
104{
105 static void encode(json::json& out, const NVP<std::set<T>>& in)
106 {
107 if (not in.value.empty()) out[in.name] & in.value;
108 }
109
110 static void decode(json::json& in, NVP<std::set<T>>& out)
111 {
112 if (in) in[out.name] & out.value;
113 }
114};
115
116template<>
117struct Codec<std::chrono::milliseconds>
118{
119 static void encode(json::json& out, const std::chrono::milliseconds in)
120 {
121 out & in.count();
122 }
123
124 static void decode(json::json& out, std::chrono::milliseconds& in);
125};
126
127template<typename T>
128struct Codec<boost::optional<T>>
129{
130 static void encode(json::json& out, const boost::optional<T>& in)
131 {
132 if (in) Codec<T>::encode(out, *in);
133 }
134
135 static void decode(json::json& out, boost::optional<T>& in)
136 {
137 if (out) Codec<T>::encode(out, *(in = T{}));
138 }
139};
140
141template<typename T>
142struct Codec<std::set<T>>
143{
144 static void encode(json::json& out, const std::set<T>& in)
145 {
146 if (in.empty()) return;
147 for (const auto& element : in)
148 {
149 json::json j; Codec<T>::encode(j, element); out.push_back(j);
150 }
151 }
152
153 static void decode(json::json& out, std::set<T>& in)
154 {
155 for (const auto& element: in)
156 {
157 T t; Codec<T>::decode(element, t); in.insert(t);
158 }
159 }
160};
161
162template<typename T>
163struct Codec<std::vector<T>>
164{
165 static void encode(json::json& out, const std::vector<T>& in)
166 {
167 if (in.empty()) return;
168 for (const auto& element : in)
169 {
170 json::json j; Codec<T>::encode(j, element); out.push_back(j);
171 }
172 }
173
174 static void decode(json::json& out, std::vector<T>& in)
175 {
176 for (const auto& element: in)
177 {
178 T t; Codec<T>::decode(element, t); in.push_back(t);
179 }
180 }
181};
182
183template<>
184struct Codec<Error>
185{
186 static void encode(json::json&, const Error&)
187 {
188 }
189
190 static void decode(json::json& in, Error& error)
191 {
192 Error e{static_cast<core::net::http::Status>(in["error"]["code"].get<unsigned int>()), in["error"]["message"]};
193 for (const auto& element : in["error"]["errors"])
194 e.errors.push_back({element["domain"], element["reason"], element["message"]});
195 error = e;
196 }
197};
198
199template<>
200struct Codec<BluetoothBeacon>
201{
202 static void encode(json::json& out, const BluetoothBeacon& in)
203 {
204 out & make_nvp("macAddress", in.mac_address)
205 & make_nvp("name", in.name)
206 & make_nvp("age", in.age.count())
207 & make_nvp("signalStrength", in.signal_strength);
208 }
209
210 static void decode(json::json& out, BluetoothBeacon& in);
211};
212
213template<>
214struct Codec<WifiAccessPoint::Type>
215{
216 static void encode(json::json& out, WifiAccessPoint::Type in)
217 {
218 out = boost::lexical_cast<std::string>(in);
219 }
220};
221
222template<>
223struct Codec<WifiAccessPoint>
224{
225 static void encode(json::json& out, const WifiAccessPoint& in)
226 {
227 out & make_nvp("macAddress", in.bssid)
228 & make_nvp("age", in.age)
229 & make_nvp("channel", in.channel)
230 & make_nvp("frequency", in.frequency)
231 & make_nvp("signalStrength", in.signal_strength)
232 & make_nvp("signalToNoiseRatio", in.signal_to_noise_ratio)
233 & make_nvp("ssid", in.ssid)
234 & make_nvp("radioType", in.type);
235 }
236
237 static void decode(json::json& out, BluetoothBeacon& in);
238};
239
240template<>
241struct Codec<RadioCell>
242{
243 static void encode(json::json& out, const RadioCell& in)
244 {
245 out & make_nvp("radioType", boost::lexical_cast<std::string>(in.radio_type))
246 & make_nvp("mobileCountryCode", in.mcc)
247 & make_nvp("mobileNetworkCode", in.mnc)
248 & make_nvp("locationAreaCode", in.lac)
249 & make_nvp("cellId", in.id)
250 & make_nvp("age", in.age)
251 & make_nvp("psc", in.psc)
252 & make_nvp("asu", in.asu)
253 & make_nvp("signalStrength", in.signal_strength)
254 & make_nvp("timingAdvance", in.timing_advance);
255 }
256
257 static void decode(json::json& out, RadioCell& in);
258};
259
260template<>
261struct Codec<geolocate::Parameters>
262{
263 static void encode(json::json& out, const geolocate::Parameters& parameters)
264 {
265 out & make_nvp("carrier", parameters.carrier)
266 & make_nvp("considerIp", parameters.consider_ip)
267 & make_nvp("homeMobileCountryCode", parameters.mcc)
268 & make_nvp("homeMobileNetworkCode", parameters.mnc)
269 & make_nvp("bluetoothBeacons", parameters.bluetooth_beacons)
270 & make_nvp("wifiAccessPoints", parameters.wifi_access_points)
271 & make_nvp("cellTowers", parameters.radio_cells)
272 & make_nvp("fallbacks", parameters.fallback);
273 }
274};
275
276template<>
277struct Codec<geolocate::Fallback>
278{
279 static void encode(json::json& out, geolocate::Fallback fb)
280 {
281 if ((fb & geolocate::Fallback::lac) == geolocate::Fallback::lac)
282 out & make_nvp("lacf", true);
283 if ((fb & geolocate::Fallback::ip) == geolocate::Fallback::ip)
284 out & make_nvp("ip", true);
285 }
286};
287
288template<>
289struct Codec<geolocate::Result>
290{
291 static void decode(json::json& in, geolocate::Result& r)
292 {
293 r.location.lat = in["location"]["lat"];
294 r.location.lon = in["location"]["lng"];
295 r.accuracy = in["accuracy"];
296
297 if (in["fallback"] == "ipf")
298 r.fallback = geolocate::Fallback::ip;
299 if (in["fallback"] == "lacf")
300 r.fallback = geolocate::Fallback::lac;
301 }
302};
303
304template<>
305struct Codec<geosubmit::Report::Position::Source>
306{
307 static void encode(json::json& out, const geosubmit::Report::Position::Source& source)
308 {
309 out = boost::lexical_cast<std::string>(source);
310 }
311
312 static void decode(json::json&, geosubmit::Report&);
313};
314
315template<>
316struct Codec<geosubmit::Report>
317{
318 static void encode(json::json& out, const geosubmit::Report& report)
319 {
320 out & make_nvp("timestamp", std::chrono::system_clock::to_time_t(report.timestamp) * 1000);
321
322 out["position"] & make_nvp("latitude", report.position.latitude)
323 & make_nvp("longitude", report.position.longitude)
324 & make_nvp("accuracy", report.position.accuracy)
325 & make_nvp("altitude", report.position.altitude)
326 & make_nvp("altitudeAccuracy", report.position.altitude_accuracy)
327 & make_nvp("age", report.position.age)
328 & make_nvp("heading", report.position.heading)
329 & make_nvp("pressure", report.position.pressure)
330 & make_nvp("speed", report.position.speed)
331 & make_nvp("source", report.position.source);
332 out & make_nvp("bluetoothBeacons", report.bluetooth_beacons)
333 & make_nvp("wifiAccessPoints", report.wifi_access_points)
334 & make_nvp("radioCells", report.radio_cells);
335 }
336
337 static void decode(json::json&, geosubmit::Report&);
338};
339
340template<>
341struct Codec<geosubmit::Parameters>
342{
343 static void encode(json::json& out, const geosubmit::Parameters& params)
344 {
345 out & make_nvp("items", params.reports);
346 }
347
348 static void decode(json::json&, geosubmit::Parameters&);
349};
350
351template<>
352struct Codec<geosubmit::Result>
353{
354 static void decode(json::json&, geosubmit::Result&)
355 {
356 }
357};
358
359template<>
360struct Codec<region::Result>
361{
362 static void decode(json::json& in, region::Result& result)
363 {
364 result.country_code = in["country_code"];
365 result.country_name = in["country_name"];
366
367 }
368};
369}
370
371#endif // ICHNAEA_CODEC_H_
0372
=== added file '3rd-party/ichnaea/src/ichnaea/error.cpp'
--- 3rd-party/ichnaea/src/ichnaea/error.cpp 1970-01-01 00:00:00 +0000
+++ 3rd-party/ichnaea/src/ichnaea/error.cpp 2016-08-09 15:10:52 +0000
@@ -0,0 +1,30 @@
1// Copyright (C) 2016 Canonical Ltd.
2//
3// This library is free software: you can redistribute it and/or modify
4// it under the terms of the GNU Lesser General Public License as published
5// by the Free Software Foundation, either version 3 of the License, or
6// (at your option) any later version.
7//
8// This program is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11// GNU General Public License for more details.
12//
13// You should have received a copy of the GNU Lesser General Public License
14// along with this program. If not, see <http://www.gnu.org/licenses/>.
15#include <ichnaea/error.h>
16
17#include <iostream>
18
19ichnaea::Error::Error(core::net::http::Status code, const std::string& message)
20 : std::runtime_error{message}, code{code}, message{message}
21{
22}
23
24std::ostream& ichnaea::operator<<(std::ostream& out, const Error& error)
25{
26 out << error.code << ", " << error.message << std::endl;
27 for (const Error::Detail& detail : error.errors)
28 out << " " << detail.domain << ", " << detail.message << ", " << detail.reason << std::endl;
29 return out;
30}
031
=== added directory '3rd-party/ichnaea/src/ichnaea/geolocate'
=== added file '3rd-party/ichnaea/src/ichnaea/geolocate/fallback.cpp'
--- 3rd-party/ichnaea/src/ichnaea/geolocate/fallback.cpp 1970-01-01 00:00:00 +0000
+++ 3rd-party/ichnaea/src/ichnaea/geolocate/fallback.cpp 2016-08-09 15:10:52 +0000
@@ -0,0 +1,41 @@
1// Copyright (C) 2016 Canonical Ltd.
2//
3// This library is free software: you can redistribute it and/or modify
4// it under the terms of the GNU Lesser General Public License as published
5// by the Free Software Foundation, either version 3 of the License, or
6// (at your option) any later version.
7//
8// This program is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11// GNU General Public License for more details.
12//
13// You should have received a copy of the GNU Lesser General Public License
14// along with this program. If not, see <http://www.gnu.org/licenses/>.
15#include <ichnaea/geolocate/fallback.h>
16
17#include <iostream>
18#include <type_traits>
19
20std::ostream& ichnaea::geolocate::operator<<(std::ostream& out, Fallback fallback)
21{
22 switch (fallback)
23 {
24 case Fallback::ip: return out << "ipf";
25 case Fallback::lac: return out << "lacf";
26 }
27
28 return out;
29}
30
31ichnaea::geolocate::Fallback ichnaea::geolocate::operator|(ichnaea::geolocate::Fallback lhs, ichnaea::geolocate::Fallback rhs)
32{
33 typedef typename std::underlying_type<Fallback>::type NT;
34 return static_cast<Fallback>(static_cast<NT>(lhs) | static_cast<NT>(rhs));
35}
36
37ichnaea::geolocate::Fallback ichnaea::geolocate::operator&(ichnaea::geolocate::Fallback lhs, ichnaea::geolocate::Fallback rhs)
38{
39 typedef typename std::underlying_type<Fallback>::type NT;
40 return static_cast<Fallback>(static_cast<NT>(lhs) & static_cast<NT>(rhs));
41}
042
=== added directory '3rd-party/ichnaea/src/ichnaea/geosubmit'
=== added file '3rd-party/ichnaea/src/ichnaea/geosubmit/report.cpp'
--- 3rd-party/ichnaea/src/ichnaea/geosubmit/report.cpp 1970-01-01 00:00:00 +0000
+++ 3rd-party/ichnaea/src/ichnaea/geosubmit/report.cpp 2016-08-09 15:10:52 +0000
@@ -0,0 +1,29 @@
1// Copyright (C) 2016 Canonical Ltd.
2//
3// This library is free software: you can redistribute it and/or modify
4// it under the terms of the GNU Lesser General Public License as published
5// by the Free Software Foundation, either version 3 of the License, or
6// (at your option) any later version.
7//
8// This program is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11// GNU General Public License for more details.
12//
13// You should have received a copy of the GNU Lesser General Public License
14// along with this program. If not, see <http://www.gnu.org/licenses/>.
15#include <ichnaea/geosubmit/report.h>
16
17#include <iostream>
18
19std::ostream& ichnaea::geosubmit::operator<<(std::ostream& out, Report::Position::Source source)
20{
21 switch (source)
22 {
23 case Report::Position::Source::fusion: return out << "fusion";
24 case Report::Position::Source::gps: return out << "gps";
25 case Report::Position::Source::manual: return out << "manual";
26 }
27
28 return out;
29}
030
=== added file '3rd-party/ichnaea/src/ichnaea/radio_cell.cpp'
--- 3rd-party/ichnaea/src/ichnaea/radio_cell.cpp 1970-01-01 00:00:00 +0000
+++ 3rd-party/ichnaea/src/ichnaea/radio_cell.cpp 2016-08-09 15:10:52 +0000
@@ -0,0 +1,29 @@
1// Copyright (C) 2016 Canonical Ltd.
2//
3// This library is free software: you can redistribute it and/or modify
4// it under the terms of the GNU Lesser General Public License as published
5// by the Free Software Foundation, either version 3 of the License, or
6// (at your option) any later version.
7//
8// This program is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11// GNU General Public License for more details.
12//
13// You should have received a copy of the GNU Lesser General Public License
14// along with this program. If not, see <http://www.gnu.org/licenses/>.
15#include <ichnaea/radio_cell.h>
16
17#include <iostream>
18
19std::ostream& ichnaea::operator<<(std::ostream& out, ichnaea::RadioCell::RadioType radio_type)
20{
21 switch (radio_type)
22 {
23 case ichnaea::RadioCell::RadioType::gsm: return out << "gsm";
24 case ichnaea::RadioCell::RadioType::lte: return out << "lte";
25 case ichnaea::RadioCell::RadioType::wcdma: return out << "wcdma";
26 }
27
28 return out;
29}
030
=== added directory '3rd-party/ichnaea/src/ichnaea/util'
=== added file '3rd-party/ichnaea/src/ichnaea/util/json.hpp'
--- 3rd-party/ichnaea/src/ichnaea/util/json.hpp 1970-01-01 00:00:00 +0000
+++ 3rd-party/ichnaea/src/ichnaea/util/json.hpp 2016-08-09 15:10:52 +0000
@@ -0,0 +1,7873 @@
1/*!
2@mainpage
3
4These pages contain the API documentation of JSON for Modern C++, a C++11
5header-only JSON class.
6
7Class @ref nlohmann::basic_json is a good entry point for the documentation.
8
9@copyright The code is licensed under the [MIT
10 License](http://opensource.org/licenses/MIT):
11 <br>
12 Copyright &copy; 2013-2015 Niels Lohmann.
13 <br>
14 Permission is hereby granted, free of charge, to any person obtaining a copy
15 of this software and associated documentation files (the "Software"), to deal
16 in the Software without restriction, including without limitation the rights
17 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18 copies of the Software, and to permit persons to whom the Software is
19 furnished to do so, subject to the following conditions:
20 <br>
21 The above copyright notice and this permission notice shall be included in
22 all copies or substantial portions of the Software.
23 <br>
24 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 SOFTWARE.
31
32@author [Niels Lohmann](http://nlohmann.me)
33@see https://github.com/nlohmann/json to download the source code
34
35@version 1.0.0
36*/
37
38#ifndef NLOHMANN_JSON_HPP
39#define NLOHMANN_JSON_HPP
40
41#include <algorithm>
42#include <array>
43#include <ciso646>
44#include <cmath>
45#include <cstdio>
46#include <functional>
47#include <initializer_list>
48#include <iomanip>
49#include <iostream>
50#include <iterator>
51#include <limits>
52#include <map>
53#include <memory>
54#include <sstream>
55#include <string>
56#include <type_traits>
57#include <utility>
58#include <vector>
59
60// enable ssize_t on MinGW
61#ifdef __GNUC__
62 #ifdef __MINGW32__
63 #include <sys/types.h>
64 #endif
65#endif
66
67// enable ssize_t for MSVC
68#ifdef _MSC_VER
69 #include <basetsd.h>
70 using ssize_t = SSIZE_T;
71#endif
72
73/*!
74@brief namespace for Niels Lohmann
75@see https://github.com/nlohmann
76@since version 1.0.0
77*/
78namespace nlohmann
79{
80
81
82/*!
83@brief unnamed namespace with internal helper functions
84@since version 1.0.0
85*/
86namespace
87{
88/*!
89@brief Helper to determine whether there's a key_type for T.
90@sa http://stackoverflow.com/a/7728728/266378
91*/
92template<typename T>
93struct has_mapped_type
94{
95 private:
96 template<typename C> static char test(typename C::mapped_type*);
97 template<typename C> static int test(...);
98 public:
99 enum { value = sizeof(test<T>(0)) == sizeof(char) };
100};
101
102/// "equality" comparison for floating point numbers
103template<typename T>
104static bool approx(const T a, const T b)
105{
106 return not (a > b or a < b);
107}
108}
109
110/*!
111@brief a class to store JSON values
112
113@tparam ObjectType type for JSON objects (@c std::map by default; will be used
114in @ref object_t)
115@tparam ArrayType type for JSON arrays (@c std::vector by default; will be used
116in @ref array_t)
117@tparam StringType type for JSON strings and object keys (@c std::string by
118default; will be used in @ref string_t)
119@tparam BooleanType type for JSON booleans (@c `bool` by default; will be used
120in @ref boolean_t)
121@tparam NumberIntegerType type for JSON integer numbers (@c `int64_t` by
122default; will be used in @ref number_integer_t)
123@tparam NumberFloatType type for JSON floating-point numbers (@c `double` by
124default; will be used in @ref number_float_t)
125@tparam AllocatorType type of the allocator to use (@c `std::allocator` by
126default)
127
128@requirement The class satisfies the following concept requirements:
129- Basic
130 - [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible):
131 JSON values can be default constructed. The result will be a JSON null value.
132 - [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible):
133 A JSON value can be constructed from an rvalue argument.
134 - [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible):
135 A JSON value can be copy-constrcuted from an lvalue expression.
136 - [MoveAssignable](http://en.cppreference.com/w/cpp/concept/MoveAssignable):
137 A JSON value van be assigned from an rvalue argument.
138 - [CopyAssignable](http://en.cppreference.com/w/cpp/concept/CopyAssignable):
139 A JSON value can be copy-assigned from an lvalue expression.
140 - [Destructible](http://en.cppreference.com/w/cpp/concept/Destructible):
141 JSON values can be destructed.
142- Layout
143 - [StandardLayoutType](http://en.cppreference.com/w/cpp/concept/StandardLayoutType):
144 JSON values have
145 [standard layout](http://en.cppreference.com/w/cpp/language/data_members#Standard_layout):
146 All non-static data members are private and standard layout types, the class
147 has no virtual functions or (virtual) base classes.
148- Library-wide
149 - [EqualityComparable](http://en.cppreference.com/w/cpp/concept/EqualityComparable):
150 JSON values can be compared with `==`, see @ref
151 operator==(const_reference,const_reference).
152 - [LessThanComparable](http://en.cppreference.com/w/cpp/concept/LessThanComparable):
153 JSON values can be compared with `<`, see @ref
154 operator<(const_reference,const_reference).
155 - [Swappable](http://en.cppreference.com/w/cpp/concept/Swappable):
156 Any JSON lvalue or rvalue of can be swapped with any lvalue or rvalue of
157 other compatible types, using unqualified function call @ref swap().
158 - [NullablePointer](http://en.cppreference.com/w/cpp/concept/NullablePointer):
159 JSON values can be compared against `std::nullptr_t` objects which are used
160 to model the `null` value.
161- Container
162 - [Container](http://en.cppreference.com/w/cpp/concept/Container):
163 JSON values can be used like STL containers and provide iterator access.
164 - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer);
165 JSON values can be used like STL containers and provide reverse iterator
166 access.
167
168@internal
169@note ObjectType trick from http://stackoverflow.com/a/9860911
170@endinternal
171
172@see RFC 7159 <http://rfc7159.net/rfc7159>
173
174@since version 1.0.0
175
176@nosubgrouping
177*/
178template <
179 template<typename U, typename V, typename... Args> class ObjectType = std::map,
180 template<typename U, typename... Args> class ArrayType = std::vector,
181 class StringType = std::string,
182 class BooleanType = bool,
183 class NumberIntegerType = int64_t,
184 class NumberFloatType = double,
185 template<typename U> class AllocatorType = std::allocator
186 >
187class basic_json
188{
189 private:
190 /// workaround type for MSVC
191 using basic_json_t = basic_json<ObjectType,
192 ArrayType,
193 StringType,
194 BooleanType,
195 NumberIntegerType,
196 NumberFloatType,
197 AllocatorType>;
198
199 public:
200
201 /////////////////////
202 // container types //
203 /////////////////////
204
205 /// @name container types
206 /// @{
207
208 /// the type of elements in a basic_json container
209 using value_type = basic_json;
210
211 /// the type of an element reference
212 using reference = value_type&;
213
214 /// the type of an element const reference
215 using const_reference = const value_type&;
216
217 /// a type to represent differences between iterators
218 using difference_type = std::ptrdiff_t;
219
220 /// a type to represent container sizes
221 using size_type = std::size_t;
222
223 /// the allocator type
224 using allocator_type = AllocatorType<basic_json>;
225
226 /// the type of an element pointer
227 using pointer = typename std::allocator_traits<allocator_type>::pointer;
228 /// the type of an element const pointer
229 using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer;
230
231 // forward declaration
232 template<typename Base> class json_reverse_iterator;
233
234 /// an iterator for a basic_json container
235 class iterator;
236 /// a const iterator for a basic_json container
237 class const_iterator;
238 /// a reverse iterator for a basic_json container
239 using reverse_iterator = json_reverse_iterator<typename basic_json::iterator>;
240 /// a const reverse iterator for a basic_json container
241 using const_reverse_iterator = json_reverse_iterator<typename basic_json::const_iterator>;
242
243 /// @}
244
245
246 /*!
247 @brief returns the allocator associated with the container
248 */
249 static allocator_type get_allocator()
250 {
251 return allocator_type();
252 }
253
254
255 ///////////////////////////
256 // JSON value data types //
257 ///////////////////////////
258
259 /// @name JSON value data types
260 /// @{
261
262 /*!
263 @brief a type for an object
264
265 [RFC 7159](http://rfc7159.net/rfc7159) describes JSON objects as follows:
266 > An object is an unordered collection of zero or more name/value pairs,
267 > where a name is a string and a value is a string, number, boolean, null,
268 > object, or array.
269
270 To store objects in C++, a type is defined by the template parameters
271 described below.
272
273 @tparam ObjectType the container to store objects (e.g., `std::map` or
274 `std::unordered_map`)
275 @tparam StringType the type of the keys or names (e.g., `std::string`). The
276 comparison function `std::less<StringType>` is used to order elements
277 inside the container.
278 @tparam AllocatorType the allocator to use for objects (e.g.,
279 `std::allocator`)
280
281 #### Default type
282
283 With the default values for @a ObjectType (`std::map`), @a StringType
284 (`std::string`), and @a AllocatorType (`std::allocator`), the default value
285 for @a object_t is:
286
287 @code {.cpp}
288 std::map<
289 std::string, // key_type
290 basic_json, // value_type
291 std::less<std::string>, // key_compare
292 std::allocator<std::pair<const std::string, basic_json>> // allocator_type
293 >
294 @endcode
295
296 #### Behavior
297
298 The choice of @a object_t influences the behavior of the JSON class. With
299 the default type, objects have the following behavior:
300
301 - When all names are unique, objects will be interoperable in the sense
302 that all software implementations receiving that object will agree on the
303 name-value mappings.
304 - When the names within an object are not unique, later stored name/value
305 pairs overwrite previously stored name/value pairs, leaving the used
306 names unique. For instance, `{"key": 1}` and `{"key": 2, "key": 1}` will
307 be treated as equal and both stored as `{"key": 1}`.
308 - Internally, name/value pairs are stored in lexicographical order of the
309 names. Objects will also be serialized (see @ref dump) in this order. For
310 instance, `{"b": 1, "a": 2}` and `{"a": 2, "b": 1}` will be stored and
311 serialized as `{"a": 2, "b": 1}`.
312 - When comparing objects, the order of the name/value pairs is irrelevant.
313 This makes objects interoperable in the sense that they will not be
314 affected by these differences. For instance, `{"b": 1, "a": 2}` and
315 `{"a": 2, "b": 1}` will be treated as equal.
316
317 #### Limits
318
319 [RFC 7159](http://rfc7159.net/rfc7159) specifies:
320 > An implementation may set limits on the maximum depth of nesting.
321
322 In this class, the object's limit of nesting is not constraint explicitly.
323 However, a maximum depth of nesting may be introduced by the compiler or
324 runtime environment. A theoretical limit can be queried by calling the @ref
325 max_size function of a JSON object.
326
327 #### Storage
328
329 Objects are stored as pointers in a @ref basic_json type. That is, for any
330 access to object values, a pointer of type `object_t*` must be dereferenced.
331
332 @sa @ref array_t -- type for an array value
333
334 @since version 1.0.0
335 */
336 using object_t = ObjectType<StringType,
337 basic_json,
338 std::less<StringType>,
339 AllocatorType<std::pair<const StringType,
340 basic_json>>>;
341
342 /*!
343 @brief a type for an array
344
345 [RFC 7159](http://rfc7159.net/rfc7159) describes JSON arrays as follows:
346 > An array is an ordered sequence of zero or more values.
347
348 To store objects in C++, a type is defined by the template parameters
349 explained below.
350
351 @tparam ArrayType container type to store arrays (e.g., `std::vector` or
352 `std::list`)
353 @tparam AllocatorType allocator to use for arrays (e.g., `std::allocator`)
354
355 #### Default type
356
357 With the default values for @a ArrayType (`std::vector`) and @a
358 AllocatorType (`std::allocator`), the default value for @a array_t is:
359
360 @code {.cpp}
361 std::vector<
362 basic_json, // value_type
363 std::allocator<basic_json> // allocator_type
364 >
365 @endcode
366
367 #### Limits
368
369 [RFC 7159](http://rfc7159.net/rfc7159) specifies:
370 > An implementation may set limits on the maximum depth of nesting.
371
372 In this class, the array's limit of nesting is not constraint explicitly.
373 However, a maximum depth of nesting may be introduced by the compiler or
374 runtime environment. A theoretical limit can be queried by calling the @ref
375 max_size function of a JSON array.
376
377 #### Storage
378
379 Arrays are stored as pointers in a @ref basic_json type. That is, for any
380 access to array values, a pointer of type `array_t*` must be dereferenced.
381
382 @sa @ref object_t -- type for an object value
383
384 @since version 1.0.0
385 */
386 using array_t = ArrayType<basic_json, AllocatorType<basic_json>>;
387
388 /*!
389 @brief a type for a string
390
391 [RFC 7159](http://rfc7159.net/rfc7159) describes JSON strings as follows:
392 > A string is a sequence of zero or more Unicode characters.
393
394 To store objects in C++, a type is defined by the template parameter
395 described below. Unicode values are split by the JSON class into byte-sized
396 characters during deserialization.
397
398 @tparam StringType the container to store strings (e.g., `std::string`).
399 Note this container is used for keys/names in objects, see @ref object_t.
400
401 #### Default type
402
403 With the default values for @a StringType (`std::string`), the default
404 value for @a string_t is:
405
406 @code {.cpp}
407 std::string
408 @endcode
409
410 #### String comparison
411
412 [RFC 7159](http://rfc7159.net/rfc7159) states:
413 > Software implementations are typically required to test names of object
414 > members for equality. Implementations that transform the textual
415 > representation into sequences of Unicode code units and then perform the
416 > comparison numerically, code unit by code unit, are interoperable in the
417 > sense that implementations will agree in all cases on equality or
418 > inequality of two strings. For example, implementations that compare
419 > strings with escaped characters unconverted may incorrectly find that
420 > `"a\\b"` and `"a\u005Cb"` are not equal.
421
422 This implementation is interoperable as it does compare strings code unit
423 by code unit.
424
425 #### Storage
426
427 String values are stored as pointers in a @ref basic_json type. That is,
428 for any access to string values, a pointer of type `string_t*` must be
429 dereferenced.
430
431 @since version 1.0.0
432 */
433 using string_t = StringType;
434
435 /*!
436 @brief a type for a boolean
437
438 [RFC 7159](http://rfc7159.net/rfc7159) implicitly describes a boolean as a
439 type which differentiates the two literals `true` and `false`.
440
441 To store objects in C++, a type is defined by the template parameter @a
442 BooleanType which chooses the type to use.
443
444 #### Default type
445
446 With the default values for @a BooleanType (`bool`), the default value for
447 @a boolean_t is:
448
449 @code {.cpp}
450 bool
451 @endcode
452
453 #### Storage
454
455 Boolean values are stored directly inside a @ref basic_json type.
456
457 @since version 1.0.0
458 */
459 using boolean_t = BooleanType;
460
461 /*!
462 @brief a type for a number (integer)
463
464 [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows:
465 > The representation of numbers is similar to that used in most programming
466 > languages. A number is represented in base 10 using decimal digits. It
467 > contains an integer component that may be prefixed with an optional minus
468 > sign, which may be followed by a fraction part and/or an exponent part.
469 > Leading zeros are not allowed. (...) Numeric values that cannot be
470 > represented in the grammar below (such as Infinity and NaN) are not
471 > permitted.
472
473 This description includes both integer and floating-point numbers. However,
474 C++ allows more precise storage if it is known whether the number is an
475 integer or a floating-point number. Therefore, two different types, @ref
476 number_integer_t and @ref number_float_t are used.
477
478 To store integer numbers in C++, a type is defined by the template
479 parameter @a NumberIntegerType which chooses the type to use.
480
481 #### Default type
482
483 With the default values for @a NumberIntegerType (`int64_t`), the default
484 value for @a number_integer_t is:
485
486 @code {.cpp}
487 int64_t
488 @endcode
489
490 #### Default behavior
491
492 - The restrictions about leading zeros is not enforced in C++. Instead,
493 leading zeros in integer literals lead to an interpretation as octal
494 number. Internally, the value will be stored as decimal number. For
495 instance, the C++ integer literal `010` will be serialized to `8`. During
496 deserialization, leading zeros yield an error.
497 - Not-a-number (NaN) values will be serialized to `null`.
498
499 #### Limits
500
501 [RFC 7159](http://rfc7159.net/rfc7159) specifies:
502 > An implementation may set limits on the range and precision of numbers.
503
504 When the default type is used, the maximal integer number that can be
505 stored is `9223372036854775807` (INT64_MAX) and the minimal integer number
506 that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers
507 that are out of range will yield over/underflow when used in a constructor.
508 During deserialization, too large or small integer numbers will be
509 automatically be stored as @ref number_float_t.
510
511 [RFC 7159](http://rfc7159.net/rfc7159) further states:
512 > Note that when such software is used, numbers that are integers and are
513 > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense
514 > that implementations will agree exactly on their numeric values.
515
516 As this range is a subrange of the exactly supported range [INT64_MIN,
517 INT64_MAX], this class's integer type is interoperable.
518
519 #### Storage
520
521 Integer number values are stored directly inside a @ref basic_json type.
522
523 @sa @ref number_float_t -- type for number values (floating-point)
524
525 @since version 1.0.0
526 */
527 using number_integer_t = NumberIntegerType;
528
529 /*!
530 @brief a type for a number (floating-point)
531
532 [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows:
533 > The representation of numbers is similar to that used in most programming
534 > languages. A number is represented in base 10 using decimal digits. It
535 > contains an integer component that may be prefixed with an optional minus
536 > sign, which may be followed by a fraction part and/or an exponent part.
537 > Leading zeros are not allowed. (...) Numeric values that cannot be
538 > represented in the grammar below (such as Infinity and NaN) are not
539 > permitted.
540
541 This description includes both integer and floating-point numbers. However,
542 C++ allows more precise storage if it is known whether the number is an
543 integer or a floating-point number. Therefore, two different types, @ref
544 number_integer_t and @ref number_float_t are used.
545
546 To store floating-point numbers in C++, a type is defined by the template
547 parameter @a NumberFloatType which chooses the type to use.
548
549 #### Default type
550
551 With the default values for @a NumberFloatType (`double`), the default
552 value for @a number_float_t is:
553
554 @code {.cpp}
555 double
556 @endcode
557
558 #### Default behavior
559
560 - The restrictions about leading zeros is not enforced in C++. Instead,
561 leading zeros in floating-point literals will be ignored. Internally, the
562 value will be stored as decimal number. For instance, the C++
563 floating-point literal `01.2` will be serialized to `1.2`. During
564 deserialization, leading zeros yield an error.
565 - Not-a-number (NaN) values will be serialized to `null`.
566
567 #### Limits
568
569 [RFC 7159](http://rfc7159.net/rfc7159) states:
570 > This specification allows implementations to set limits on the range and
571 > precision of numbers accepted. Since software that implements IEEE
572 > 754-2008 binary64 (double precision) numbers is generally available and
573 > widely used, good interoperability can be achieved by implementations that
574 > expect no more precision or range than these provide, in the sense that
575 > implementations will approximate JSON numbers within the expected
576 > precision.
577
578 This implementation does exactly follow this approach, as it uses double
579 precision floating-point numbers. Note values smaller than
580 `-1.79769313486232e+308` and values greather than `1.79769313486232e+308`
581 will be stored as NaN internally and be serialized to `null`.
582
583 #### Storage
584
585 Floating-point number values are stored directly inside a @ref basic_json
586 type.
587
588 @sa @ref number_integer_t -- type for number values (integer)
589
590 @since version 1.0.0
591 */
592 using number_float_t = NumberFloatType;
593
594 /// @}
595
596
597 ///////////////////////////
598 // JSON type enumeration //
599 ///////////////////////////
600
601 /*!
602 @brief the JSON type enumeration
603
604 This enumeration collects the different JSON types. It is internally used
605 to distinguish the stored values, and the functions @ref is_null(), @ref
606 is_object(), @ref is_array(), @ref is_string(), @ref is_boolean(), @ref
607 is_number(), and @ref is_discarded() rely on it.
608
609 @since version 1.0.0
610 */
611 enum class value_t : uint8_t
612 {
613 null, ///< null value
614 object, ///< object (unordered set of name/value pairs)
615 array, ///< array (ordered collection of values)
616 string, ///< string value
617 boolean, ///< boolean value
618 number_integer, ///< number value (integer)
619 number_float, ///< number value (floating-point)
620 discarded ///< discarded by the the parser callback function
621 };
622
623
624 private:
625 /// helper for exception-safe object creation
626 template<typename T, typename... Args>
627 static T* create(Args&& ... args)
628 {
629 AllocatorType<T> alloc;
630 auto deleter = [&](T * object)
631 {
632 alloc.deallocate(object, 1);
633 };
634 std::unique_ptr<T, decltype(deleter)> object(alloc.allocate(1), deleter);
635 alloc.construct(object.get(), std::forward<Args>(args)...);
636 return object.release();
637 }
638
639 ////////////////////////
640 // JSON value storage //
641 ////////////////////////
642
643 /*!
644 @brief a JSON value
645
646 The actual storage for a JSON value of the @ref basic_json class.
647
648 @since version 1.0.0
649 */
650 union json_value
651 {
652 /// object (stored with pointer to save storage)
653 object_t* object;
654 /// array (stored with pointer to save storage)
655 array_t* array;
656 /// string (stored with pointer to save storage)
657 string_t* string;
658 /// boolean
659 boolean_t boolean;
660 /// number (integer)
661 number_integer_t number_integer;
662 /// number (floating-point)
663 number_float_t number_float;
664
665 /// default constructor (for null values)
666 json_value() noexcept = default;
667 /// constructor for booleans
668 json_value(boolean_t v) noexcept : boolean(v) {}
669 /// constructor for numbers (integer)
670 json_value(number_integer_t v) noexcept : number_integer(v) {}
671 /// constructor for numbers (floating-point)
672 json_value(number_float_t v) noexcept : number_float(v) {}
673 /// constructor for empty values of a given type
674 json_value(value_t t)
675 {
676 switch (t)
677 {
678 case value_t::object:
679 {
680 object = create<object_t>();
681 break;
682 }
683
684 case value_t::array:
685 {
686 array = create<array_t>();
687 break;
688 }
689
690 case value_t::string:
691 {
692 string = create<string_t>("");
693 break;
694 }
695
696 case value_t::boolean:
697 {
698 boolean = boolean_t(false);
699 break;
700 }
701
702 case value_t::number_integer:
703 {
704 number_integer = number_integer_t(0);
705 break;
706 }
707
708 case value_t::number_float:
709 {
710 number_float = number_float_t(0.0);
711 break;
712 }
713
714 default:
715 {
716 break;
717 }
718 }
719 }
720
721 /// constructor for strings
722 json_value(const string_t& value)
723 {
724 string = create<string_t>(value);
725 }
726
727 /// constructor for objects
728 json_value(const object_t& value)
729 {
730 object = create<object_t>(value);
731 }
732
733 /// constructor for arrays
734 json_value(const array_t& value)
735 {
736 array = create<array_t>(value);
737 }
738 };
739
740
741 public:
742 //////////////////////////
743 // JSON parser callback //
744 //////////////////////////
745
746 /*!
747 @brief JSON callback events
748
749 This enumeration lists the parser events that can trigger calling a
750 callback function of type @ref parser_callback_t during parsing.
751
752 @since version 1.0.0
753 */
754 enum class parse_event_t : uint8_t
755 {
756 /// the parser read `{` and started to process a JSON object
757 object_start,
758 /// the parser read `}` and finished processing a JSON object
759 object_end,
760 /// the parser read `[` and started to process a JSON array
761 array_start,
762 /// the parser read `]` and finished processing a JSON array
763 array_end,
764 /// the parser read a key of a value in an object
765 key,
766 /// the parser finished reading a JSON value
767 value
768 };
769
770 /*!
771 @brief per-element parser callback type
772
773 With a parser callback function, the result of parsing a JSON text can be
774 influenced. When passed to @ref parse(std::istream&, parser_callback_t) or
775 @ref parse(const string_t&, parser_callback_t), it is called on certain
776 events (passed as @ref parse_event_t via parameter @a event) with a set
777 recursion depth @a depth and context JSON value @a parsed. The return value
778 of the callback function is a boolean indicating whether the element that
779 emitted the callback shall be kept or not.
780
781 We distinguish six scenarios (determined by the event type) in which the
782 callback function can be called. The following table describes the values
783 of the parameters @a depth, @a event, and @a parsed.
784
785 parameter @a event | description | parameter @a depth | parameter @a parsed
786 ------------------ | ----------- | ------------------ | -------------------
787 parse_event_t::object_start | the parser read `{` and started to process a JSON object | depth of the parent of the JSON object | a JSON value with type discarded
788 parse_event_t::key | the parser read a key of a value in an object | depth of the currently parsed JSON object | a JSON string containing the key
789 parse_event_t::object_end | the parser read `}` and finished processing a JSON object | depth of the parent of the JSON object | the parsed JSON object
790 parse_event_t::array_start | the parser read `[` and started to process a JSON array | depth of the parent of the JSON array | a JSON value with type discarded
791 parse_event_t::array_end | the parser read `]` and finished processing a JSON array | depth of the parent of the JSON array | the parsed JSON array
792 parse_event_t::value | the parser finished reading a JSON value | depth of the value | the parsed JSON value
793
794 Discarding a value (i.e., returning `false`) has different effects
795 depending on the context in which function was called:
796
797 - Discarded values in structured types are skipped. That is, the parser
798 will behave as if the discarded value was never read.
799 - In case a value outside a structured type is skipped, it is replaced with
800 `null`. This case happens if the top-level element is skipped.
801
802 @param[in] depth the depth of the recursion during parsing
803
804 @param[in] event an event of type parse_event_t indicating the context in
805 the callback function has been called
806
807 @param[in,out] parsed the current intermediate parse result; note that
808 writing to this value has no effect for parse_event_t::key events
809
810 @return Whether the JSON value which called the function during parsing
811 should be kept (`true`) or not (`false`). In the latter case, it is either
812 skipped completely or replaced by an empty discarded object.
813
814 @sa @ref parse(std::istream&, parser_callback_t) or
815 @ref parse(const string_t&, parser_callback_t) for examples
816
817 @since version 1.0.0
818 */
819 using parser_callback_t = std::function<bool(int depth, parse_event_t event, basic_json& parsed)>;
820
821
822 //////////////////
823 // constructors //
824 //////////////////
825
826 /// @name constructors and destructors
827 /// @{
828
829 /*!
830 @brief create an empty value with a given type
831
832 Create an empty JSON value with a given type. The value will be default
833 initialized with an empty value which depends on the type:
834
835 Value type | initial value
836 ----------- | -------------
837 null | `null`
838 boolean | `false`
839 string | `""`
840 number | `0`
841 object | `{}`
842 array | `[]`
843
844 @param[in] value_type the type of the value to create
845
846 @complexity Constant.
847
848 @throw std::bad_alloc if allocation for object, array, or string value
849 fails
850
851 @liveexample{The following code shows the constructor for different @ref
852 value_t values,basic_json__value_t}
853
854 @sa @ref basic_json(std::nullptr_t) -- create a `null` value
855 @sa @ref basic_json(boolean_t value) -- create a boolean value
856 @sa @ref basic_json(const string_t&) -- create a string value
857 @sa @ref basic_json(const object_t&) -- create a object value
858 @sa @ref basic_json(const array_t&) -- create a array value
859 @sa @ref basic_json(const number_float_t) -- create a number
860 (floating-point) value
861 @sa @ref basic_json(const number_integer_t) -- create a number (integer)
862 value
863
864 @since version 1.0.0
865 */
866 basic_json(const value_t value_type)
867 : m_type(value_type), m_value(value_type)
868 {}
869
870 /*!
871 @brief create a null object (implicitly)
872
873 Create a `null` JSON value. This is the implicit version of the `null`
874 value constructor as it takes no parameters.
875
876 @complexity Constant.
877
878 @requirement This function satisfies the Container requirements:
879 - The complexity is constant.
880 - As postcondition, it holds: `basic_json().empty() == true`.
881
882 @liveexample{The following code shows the constructor for a `null` JSON
883 value.,basic_json}
884
885 @sa @ref basic_json(std::nullptr_t) -- create a `null` value
886
887 @since version 1.0.0
888 */
889 basic_json() noexcept = default;
890
891 /*!
892 @brief create a null object (explicitly)
893
894 Create a `null` JSON value. This is the explicitly version of the `null`
895 value constructor as it takes a null pointer as parameter. It allows to
896 create `null` values by explicitly assigning a @c nullptr to a JSON value.
897 The passed null pointer itself is not read -- it is only used to choose the
898 right constructor.
899
900 @complexity Constant.
901
902 @liveexample{The following code shows the constructor with null pointer
903 parameter.,basic_json__nullptr_t}
904
905 @sa @ref basic_json() -- default constructor (implicitly creating a `null`
906 value)
907
908 @since version 1.0.0
909 */
910 basic_json(std::nullptr_t) noexcept
911 : basic_json(value_t::null)
912 {}
913
914 /*!
915 @brief create an object (explicit)
916
917 Create an object JSON value with a given content.
918
919 @param[in] val a value for the object
920
921 @complexity Linear in the size of the passed @a val.
922
923 @throw std::bad_alloc if allocation for object value fails
924
925 @liveexample{The following code shows the constructor with an @ref object_t
926 parameter.,basic_json__object_t}
927
928 @sa @ref basic_json(const CompatibleObjectType&) -- create an object value
929 from a compatible STL container
930
931 @since version 1.0.0
932 */
933 basic_json(const object_t& val)
934 : m_type(value_t::object), m_value(val)
935 {}
936
937 /*!
938 @brief create an object (implicit)
939
940 Create an object JSON value with a given content. This constructor allows
941 any type that can be used to construct values of type @ref object_t.
942 Examples include the types `std::map` and `std::unordered_map`.
943
944 @tparam CompatibleObjectType an object type whose `key_type` and
945 `value_type` is compatible to @ref object_t
946
947 @param[in] val a value for the object
948
949 @complexity Linear in the size of the passed @a val.
950
951 @throw std::bad_alloc if allocation for object value fails
952
953 @liveexample{The following code shows the constructor with several
954 compatible object type parameters.,basic_json__CompatibleObjectType}
955
956 @sa @ref basic_json(const object_t&) -- create an object value
957
958 @since version 1.0.0
959 */
960 template <class CompatibleObjectType, typename
961 std::enable_if<
962 std::is_constructible<typename object_t::key_type, typename CompatibleObjectType::key_type>::value and
963 std::is_constructible<basic_json, typename CompatibleObjectType::mapped_type>::value, int>::type
964 = 0>
965 basic_json(const CompatibleObjectType& val)
966 : m_type(value_t::object)
967 {
968 using std::begin;
969 using std::end;
970 m_value.object = create<object_t>(begin(val), end(val));
971 }
972
973 /*!
974 @brief create an array (explicit)
975
976 Create an array JSON value with a given content.
977
978 @param[in] val a value for the array
979
980 @complexity Linear in the size of the passed @a val.
981
982 @throw std::bad_alloc if allocation for array value fails
983
984 @liveexample{The following code shows the constructor with an @ref array_t
985 parameter.,basic_json__array_t}
986
987 @sa @ref basic_json(const CompatibleArrayType&) -- create an array value
988 from a compatible STL containers
989
990 @since version 1.0.0
991 */
992 basic_json(const array_t& val)
993 : m_type(value_t::array), m_value(val)
994 {}
995
996 /*!
997 @brief create an array (implicit)
998
999 Create an array JSON value with a given content. This constructor allows
1000 any type that can be used to construct values of type @ref array_t.
1001 Examples include the types `std::vector`, `std::list`, and `std::set`.
1002
1003 @tparam CompatibleArrayType an object type whose `value_type` is compatible
1004 to @ref array_t
1005
1006 @param[in] val a value for the array
1007
1008 @complexity Linear in the size of the passed @a val.
1009
1010 @throw std::bad_alloc if allocation for array value fails
1011
1012 @liveexample{The following code shows the constructor with several
1013 compatible array type parameters.,basic_json__CompatibleArrayType}
1014
1015 @sa @ref basic_json(const array_t&) -- create an array value
1016
1017 @since version 1.0.0
1018 */
1019 template <class CompatibleArrayType, typename
1020 std::enable_if<
1021 not std::is_same<CompatibleArrayType, typename basic_json_t::iterator>::value and
1022 not std::is_same<CompatibleArrayType, typename basic_json_t::const_iterator>::value and
1023 not std::is_same<CompatibleArrayType, typename basic_json_t::reverse_iterator>::value and
1024 not std::is_same<CompatibleArrayType, typename basic_json_t::const_reverse_iterator>::value and
1025 not std::is_same<CompatibleArrayType, typename array_t::iterator>::value and
1026 not std::is_same<CompatibleArrayType, typename array_t::const_iterator>::value and
1027 std::is_constructible<basic_json, typename CompatibleArrayType::value_type>::value, int>::type
1028 = 0>
1029 basic_json(const CompatibleArrayType& val)
1030 : m_type(value_t::array)
1031 {
1032 using std::begin;
1033 using std::end;
1034 m_value.array = create<array_t>(begin(val), end(val));
1035 }
1036
1037 /*!
1038 @brief create a string (explicit)
1039
1040 Create an string JSON value with a given content.
1041
1042 @param[in] val a value for the string
1043
1044 @complexity Linear in the size of the passed @a val.
1045
1046 @throw std::bad_alloc if allocation for string value fails
1047
1048 @liveexample{The following code shows the constructor with an @ref string_t
1049 parameter.,basic_json__string_t}
1050
1051 @sa @ref basic_json(const typename string_t::value_type*) -- create a
1052 string value from a character pointer
1053 @sa @ref basic_json(const CompatibleStringType&) -- create a string value
1054 from a compatible string container
1055
1056 @since version 1.0.0
1057 */
1058 basic_json(const string_t& val)
1059 : m_type(value_t::string), m_value(val)
1060 {}
1061
1062 /*!
1063 @brief create a string (explicit)
1064
1065 Create a string JSON value with a given content.
1066
1067 @param[in] val a literal value for the string
1068
1069 @complexity Linear in the size of the passed @a val.
1070
1071 @throw std::bad_alloc if allocation for string value fails
1072
1073 @liveexample{The following code shows the constructor with string literal
1074 parameter.,basic_json__string_t_value_type}
1075
1076 @sa @ref basic_json(const string_t&) -- create a string value
1077 @sa @ref basic_json(const CompatibleStringType&) -- create a string value
1078 from a compatible string container
1079
1080 @since version 1.0.0
1081 */
1082 basic_json(const typename string_t::value_type* val)
1083 : basic_json(string_t(val))
1084 {}
1085
1086 /*!
1087 @brief create a string (implicit)
1088
1089 Create a string JSON value with a given content.
1090
1091 @param[in] val a value for the string
1092
1093 @tparam CompatibleStringType an string type which is compatible to @ref
1094 string_t
1095
1096 @complexity Linear in the size of the passed @a val.
1097
1098 @throw std::bad_alloc if allocation for string value fails
1099
1100 @liveexample{The following code shows the construction of a string value
1101 from a compatible type.,basic_json__CompatibleStringType}
1102
1103 @sa @ref basic_json(const string_t&) -- create a string value
1104 @sa @ref basic_json(const typename string_t::value_type*) -- create a
1105 string value from a character pointer
1106
1107 @since version 1.0.0
1108 */
1109 template <class CompatibleStringType, typename
1110 std::enable_if<
1111 std::is_constructible<string_t, CompatibleStringType>::value, int>::type
1112 = 0>
1113 basic_json(const CompatibleStringType& val)
1114 : basic_json(string_t(val))
1115 {}
1116
1117 /*!
1118 @brief create a boolean (explicit)
1119
1120 Creates a JSON boolean type from a given value.
1121
1122 @param[in] val a boolean value to store
1123
1124 @complexity Constant.
1125
1126 @liveexample{The example below demonstrates boolean
1127 values.,basic_json__boolean_t}
1128
1129 @since version 1.0.0
1130 */
1131 basic_json(boolean_t val)
1132 : m_type(value_t::boolean), m_value(val)
1133 {}
1134
1135 /*!
1136 @brief create an integer number (explicit)
1137
1138 Create an interger number JSON value with a given content.
1139
1140 @tparam T helper type to compare number_integer_t and int (not visible in)
1141 the interface.
1142
1143 @param[in] val an integer to create a JSON number from
1144
1145 @note This constructor would have the same signature as @ref
1146 basic_json(const int value), so we need to switch this one off in case
1147 number_integer_t is the same as int. This is done via the helper type @a T.
1148
1149 @complexity Constant.
1150
1151 @liveexample{The example below shows the construction of a JSON integer
1152 number value.,basic_json__number_integer_t}
1153
1154 @sa @ref basic_json(const int) -- create a number value (integer)
1155 @sa @ref basic_json(const CompatibleNumberIntegerType) -- create a number
1156 value (integer) from a compatible number type
1157
1158 @since version 1.0.0
1159 */
1160 template<typename T,
1161 typename std::enable_if<
1162 not (std::is_same<T, int>::value)
1163 and std::is_same<T, number_integer_t>::value
1164 , int>::type = 0>
1165 basic_json(const number_integer_t val)
1166 : m_type(value_t::number_integer), m_value(val)
1167 {}
1168
1169 /*!
1170 @brief create an integer number from an enum type (explicit)
1171
1172 Create an integer number JSON value with a given content.
1173
1174 @param[in] val an integer to create a JSON number from
1175
1176 @note This constructor allows to pass enums directly to a constructor. As
1177 C++ has no way of specifying the type of an anonymous enum explicitly, we
1178 can only rely on the fact that such values implicitly convert to int. As
1179 int may already be the same type of number_integer_t, we may need to switch
1180 off the constructor @ref basic_json(const number_integer_t).
1181
1182 @complexity Constant.
1183
1184 @liveexample{The example below shows the construction of a JSON integer
1185 number value from an anonymous enum.,basic_json__const_int}
1186
1187 @sa @ref basic_json(const number_integer_t) -- create a number value
1188 (integer)
1189 @sa @ref basic_json(const CompatibleNumberIntegerType) -- create a number
1190 value (integer) from a compatible number type
1191
1192 @since version 1.0.0
1193 */
1194 basic_json(const int val)
1195 : m_type(value_t::number_integer),
1196 m_value(static_cast<number_integer_t>(val))
1197 {}
1198
1199 /*!
1200 @brief create an integer number (implicit)
1201
1202 Create an integer number JSON value with a given content. This constructor
1203 allows any type that can be used to construct values of type @ref
1204 number_integer_t. Examples may include the types `int`, `int32_t`, or
1205 `short`.
1206
1207 @tparam CompatibleNumberIntegerType an integer type which is compatible to
1208 @ref number_integer_t.
1209
1210 @param[in] val an integer to create a JSON number from
1211
1212 @complexity Constant.
1213
1214 @liveexample{The example below shows the construction of several JSON
1215 integer number values from compatible
1216 types.,basic_json__CompatibleIntegerNumberType}
1217
1218 @sa @ref basic_json(const number_integer_t) -- create a number value
1219 (integer)
1220 @sa @ref basic_json(const int) -- create a number value (integer)
1221
1222 @since version 1.0.0
1223 */
1224 template<typename CompatibleNumberIntegerType, typename
1225 std::enable_if<
1226 std::is_constructible<number_integer_t, CompatibleNumberIntegerType>::value and
1227 std::numeric_limits<CompatibleNumberIntegerType>::is_integer, CompatibleNumberIntegerType>::type
1228 = 0>
1229 basic_json(const CompatibleNumberIntegerType val) noexcept
1230 : m_type(value_t::number_integer),
1231 m_value(static_cast<number_integer_t>(val))
1232 {}
1233
1234 /*!
1235 @brief create a floating-point number (explicit)
1236
1237 Create a floating-point number JSON value with a given content.
1238
1239 @param[in] val a floating-point value to create a JSON number from
1240
1241 @note RFC 7159 <http://www.rfc-editor.org/rfc/rfc7159.txt>, section 6
1242 disallows NaN values:
1243 > Numeric values that cannot be represented in the grammar below (such
1244 > as Infinity and NaN) are not permitted.
1245 In case the parameter @a val is not a number, a JSON null value is
1246 created instead.
1247
1248 @complexity Constant.
1249
1250 @liveexample{The following example creates several floating-point
1251 values.,basic_json__number_float_t}
1252
1253 @sa @ref basic_json(const CompatibleNumberFloatType) -- create a number
1254 value (floating-point) from a compatible number type
1255
1256 @since version 1.0.0
1257 */
1258 basic_json(const number_float_t val)
1259 : m_type(value_t::number_float), m_value(val)
1260 {
1261 // replace infinity and NAN by null
1262 if (not std::isfinite(val))
1263 {
1264 m_type = value_t::null;
1265 m_value = json_value();
1266 }
1267 }
1268
1269 /*!
1270 @brief create an floating-point number (implicit)
1271
1272 Create an floating-point number JSON value with a given content. This
1273 constructor allows any type that can be used to construct values of type
1274 @ref number_float_t. Examples may include the types `float`.
1275
1276 @tparam CompatibleNumberFloatType a floating-point type which is compatible
1277 to @ref number_float_t.
1278
1279 @param[in] val a floating-point to create a JSON number from
1280
1281 @note RFC 7159 <http://www.rfc-editor.org/rfc/rfc7159.txt>, section 6
1282 disallows NaN values:
1283 > Numeric values that cannot be represented in the grammar below (such
1284 > as Infinity and NaN) are not permitted.
1285 In case the parameter @a val is not a number, a JSON null value is
1286 created instead.
1287
1288 @complexity Constant.
1289
1290 @liveexample{The example below shows the construction of several JSON
1291 floating-point number values from compatible
1292 types.,basic_json__CompatibleNumberFloatType}
1293
1294 @sa @ref basic_json(const number_float_t) -- create a number value
1295 (floating-point)
1296
1297 @since version 1.0.0
1298 */
1299 template<typename CompatibleNumberFloatType, typename = typename
1300 std::enable_if<
1301 std::is_constructible<number_float_t, CompatibleNumberFloatType>::value and
1302 std::is_floating_point<CompatibleNumberFloatType>::value>::type
1303 >
1304 basic_json(const CompatibleNumberFloatType val) noexcept
1305 : basic_json(number_float_t(val))
1306 {}
1307
1308 /*!
1309 @brief create a container (array or object) from an initializer list
1310
1311 Creates a JSON value of type array or object from the passed initializer
1312 list @a init. In case @a type_deduction is `true` (default), the type of
1313 the JSON value to be created is deducted from the initializer list @a init
1314 according to the following rules:
1315
1316 1. If the list is empty, an empty JSON object value `{}` is created.
1317 2. If the list consists of pairs whose first element is a string, a JSON
1318 object value is created where the first elements of the pairs are treated
1319 as keys and the second elements are as values.
1320 3. In all other cases, an array is created.
1321
1322 The rules aim to create the best fit between a C++ initializer list and
1323 JSON values. The ratioinale is as follows:
1324
1325 1. The empty initializer list is written as `{}` which is exactly an empty
1326 JSON object.
1327 2. C++ has now way of describing mapped types other than to list a list of
1328 pairs. As JSON requires that keys must be of type string, rule 2 is the
1329 weakest constraint one can pose on initializer lists to interpret them as
1330 an object.
1331 3. In all other cases, the initializer list could not be interpreted as
1332 JSON object type, so interpreting it as JSON array type is safe.
1333
1334 With the rules described above, the following JSON values cannot be
1335 expressed by an initializer list:
1336
1337 - the empty array (`[]`): use @ref array(std::initializer_list<basic_json>)
1338 with an empty initializer list in this case
1339 - arrays whose elements satisfy rule 2: use @ref
1340 array(std::initializer_list<basic_json>) with the same initializer list
1341 in this case
1342
1343 @note When used without parentheses around an empty initializer list, @ref
1344 basic_json() is called instead of this function, yielding the JSON null
1345 value.
1346
1347 @param[in] init initializer list with JSON values
1348
1349 @param[in] type_deduction internal parameter; when set to `true`, the type
1350 of the JSON value is deducted from the initializer list @a init; when set
1351 to `false`, the type provided via @a manual_type is forced. This mode is
1352 used by the functions @ref array(std::initializer_list<basic_json>) and
1353 @ref object(std::initializer_list<basic_json>).
1354
1355 @param[in] manual_type internal parameter; when @a type_deduction is set to
1356 `false`, the created JSON value will use the provided type (only @ref
1357 value_t::array and @ref value_t::object are valid); when @a type_deduction
1358 is set to `true`, this parameter has no effect
1359
1360 @throw std::domain_error if @a type_deduction is `false`, @a manual_type is
1361 `value_t::object`, but @a init contains an element which is not a pair
1362 whose first element is a string; example: `"cannot create object from
1363 initializer list"`
1364
1365 @complexity Linear in the size of the initializer list @a init.
1366
1367 @liveexample{The example below shows how JSON values are created from
1368 initializer lists,basic_json__list_init_t}
1369
1370 @sa @ref array(std::initializer_list<basic_json>) -- create a JSON array
1371 value from an initializer list
1372 @sa @ref object(std::initializer_list<basic_json>) -- create a JSON object
1373 value from an initializer list
1374
1375 @since version 1.0.0
1376 */
1377 basic_json(std::initializer_list<basic_json> init,
1378 bool type_deduction = true,
1379 value_t manual_type = value_t::array)
1380 {
1381 // the initializer list could describe an object
1382 bool is_an_object = true;
1383
1384 // check if each element is an array with two elements whose first
1385 // element is a string
1386 for (const auto& element : init)
1387 {
1388 if (not element.is_array() or element.size() != 2
1389 or not element[0].is_string())
1390 {
1391 // we found an element that makes it impossible to use the
1392 // initializer list as object
1393 is_an_object = false;
1394 break;
1395 }
1396 }
1397
1398 // adjust type if type deduction is not wanted
1399 if (not type_deduction)
1400 {
1401 // if array is wanted, do not create an object though possible
1402 if (manual_type == value_t::array)
1403 {
1404 is_an_object = false;
1405 }
1406
1407 // if object is wanted but impossible, throw an exception
1408 if (manual_type == value_t::object and not is_an_object)
1409 {
1410 throw std::domain_error("cannot create object from initializer list");
1411 }
1412 }
1413
1414 if (is_an_object)
1415 {
1416 // the initializer list is a list of pairs -> create object
1417 m_type = value_t::object;
1418 m_value = value_t::object;
1419
1420 for (auto& element : init)
1421 {
1422 m_value.object->emplace(std::move(*(element[0].m_value.string)), std::move(element[1]));
1423 }
1424 }
1425 else
1426 {
1427 // the initializer list describes an array -> create array
1428 m_type = value_t::array;
1429 m_value.array = create<array_t>(std::move(init));
1430 }
1431 }
1432
1433 /*!
1434 @brief explicitly create an array from an initializer list
1435
1436 Creates a JSON array value from a given initializer list. That is, given a
1437 list of values `a, b, c`, creates the JSON value `[a, b, c]`. If the
1438 initializer list is empty, the empty array `[]` is created.
1439
1440 @note This function is only needed to express two edge cases that cannot be
1441 realized with the initializer list constructor (@ref
1442 basic_json(std::initializer_list<basic_json>, bool, value_t)). These cases
1443 are:
1444 1. creating an array whose elements are all pairs whose first element is a
1445 string -- in this case, the initializer list constructor would create an
1446 object, taking the first elements as keys
1447 2. creating an empty array -- passing the empty initializer list to the
1448 initializer list constructor yields an empty object
1449
1450 @param[in] init initializer list with JSON values to create an array from
1451 (optional)
1452
1453 @return JSON array value
1454
1455 @complexity Linear in the size of @a init.
1456
1457 @liveexample{The following code shows an example for the @ref array
1458 function.,array}
1459
1460 @sa @ref basic_json(std::initializer_list<basic_json>, bool, value_t) --
1461 create a JSON value from an initializer list
1462 @sa @ref object(std::initializer_list<basic_json>) -- create a JSON object
1463 value from an initializer list
1464
1465 @since version 1.0.0
1466 */
1467 static basic_json array(std::initializer_list<basic_json> init =
1468 std::initializer_list<basic_json>())
1469 {
1470 return basic_json(init, false, value_t::array);
1471 }
1472
1473 /*!
1474 @brief explicitly create an object from an initializer list
1475
1476 Creates a JSON object value from a given initializer list. The initializer
1477 lists elements must be pairs, and their first elments must be strings. If
1478 the initializer list is empty, the empty object `{}` is created.
1479
1480 @note This function is only added for symmetry reasons. In contrast to the
1481 related function @ref array(std::initializer_list<basic_json>), there are
1482 no cases which can only be expressed by this function. That is, any
1483 initializer list @a init can also be passed to the initializer list
1484 constructor
1485 @ref basic_json(std::initializer_list<basic_json>, bool, value_t).
1486
1487 @param[in] init initializer list to create an object from (optional)
1488
1489 @return JSON object value
1490
1491 @throw std::domain_error if @a init is not a pair whose first elements are
1492 strings; thrown by
1493 @ref basic_json(std::initializer_list<basic_json>, bool, value_t)
1494
1495 @complexity Linear in the size of @a init.
1496
1497 @liveexample{The following code shows an example for the @ref object
1498 function.,object}
1499
1500 @sa @ref basic_json(std::initializer_list<basic_json>, bool, value_t) --
1501 create a JSON value from an initializer list
1502 @sa @ref array(std::initializer_list<basic_json>) -- create a JSON array
1503 value from an initializer list
1504
1505 @since version 1.0.0
1506 */
1507 static basic_json object(std::initializer_list<basic_json> init =
1508 std::initializer_list<basic_json>())
1509 {
1510 return basic_json(init, false, value_t::object);
1511 }
1512
1513 /*!
1514 @brief construct an array with count copies of given value
1515
1516 Constructs a JSON array value by creating @a cnt copies of a passed
1517 value. In case @a cnt is `0`, an empty array is created. As postcondition,
1518 `std::distance(begin(),end()) == cnt` holds.
1519
1520 @param[in] cnt the number of JSON copies of @a val to create
1521 @param[in] val the JSON value to copy
1522
1523 @complexity Linear in @a cnt.
1524
1525 @liveexample{The following code shows examples for the @ref
1526 basic_json(size_type\, const basic_json&)
1527 constructor.,basic_json__size_type_basic_json}
1528
1529 @since version 1.0.0
1530 */
1531 basic_json(size_type cnt, const basic_json& val)
1532 : m_type(value_t::array)
1533 {
1534 m_value.array = create<array_t>(cnt, val);
1535 }
1536
1537 /*!
1538 @brief construct a JSON container given an iterator range
1539
1540 Constructs the JSON value with the contents of the range `[first, last)`.
1541 The semantics depends on the different types a JSON value can have:
1542 - In case of primitive types (number, boolean, or string), @a first must
1543 be `begin()` and @a last must be `end()`. In this case, the value is
1544 copied. Otherwise, std::out_of_range is thrown.
1545 - In case of structured types (array, object), the constructor behaves
1546 as similar versions for `std::vector`.
1547 - In case of a null type, std::domain_error is thrown.
1548
1549 @tparam InputIT an input iterator type (@ref iterator or @ref
1550 const_iterator)
1551
1552 @param[in] first begin of the range to copy from (included)
1553 @param[in] last end of the range to copy from (excluded)
1554
1555 @throw std::domain_error if iterators are not compatible; that is, do not
1556 belong to the same JSON value; example: `"iterators are not compatible"`
1557 @throw std::out_of_range if iterators are for a primitive type (number,
1558 boolean, or string) where an out of range error can be detected easily;
1559 example: `"iterators out of range"`
1560 @throw std::bad_alloc if allocation for object, array, or string fails
1561 @throw std::domain_error if called with a null value; example: `"cannot use
1562 construct with iterators from null"`
1563
1564 @complexity Linear in distance between @a first and @a last.
1565
1566 @liveexample{The example below shows several ways to create JSON values by
1567 specifying a subrange with iterators.,basic_json__InputIt_InputIt}
1568
1569 @since version 1.0.0
1570 */
1571 template <class InputIT, typename
1572 std::enable_if<
1573 std::is_same<InputIT, typename basic_json_t::iterator>::value or
1574 std::is_same<InputIT, typename basic_json_t::const_iterator>::value
1575 , int>::type
1576 = 0>
1577 basic_json(InputIT first, InputIT last) : m_type(first.m_object->m_type)
1578 {
1579 // make sure iterator fits the current value
1580 if (first.m_object != last.m_object)
1581 {
1582 throw std::domain_error("iterators are not compatible");
1583 }
1584
1585 // check if iterator range is complete for primitive values
1586 switch (m_type)
1587 {
1588 case value_t::boolean:
1589 case value_t::number_float:
1590 case value_t::number_integer:
1591 case value_t::string:
1592 {
1593 if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end())
1594 {
1595 throw std::out_of_range("iterators out of range");
1596 }
1597 break;
1598 }
1599
1600 default:
1601 {
1602 break;
1603 }
1604 }
1605
1606 switch (m_type)
1607 {
1608 case value_t::number_integer:
1609 {
1610 m_value.number_integer = first.m_object->m_value.number_integer;
1611 break;
1612 }
1613
1614 case value_t::number_float:
1615 {
1616 m_value.number_float = first.m_object->m_value.number_float;
1617 break;
1618 }
1619
1620 case value_t::boolean:
1621 {
1622 m_value.boolean = first.m_object->m_value.boolean;
1623 break;
1624 }
1625
1626 case value_t::string:
1627 {
1628 m_value = *first.m_object->m_value.string;
1629 break;
1630 }
1631
1632 case value_t::object:
1633 {
1634 m_value.object = create<object_t>(first.m_it.object_iterator, last.m_it.object_iterator);
1635 break;
1636 }
1637
1638 case value_t::array:
1639 {
1640 m_value.array = create<array_t>(first.m_it.array_iterator, last.m_it.array_iterator);
1641 break;
1642 }
1643
1644 default:
1645 {
1646 throw std::domain_error("cannot use construct with iterators from " + first.m_object->type_name());
1647 }
1648 }
1649 }
1650
1651 ///////////////////////////////////////
1652 // other constructors and destructor //
1653 ///////////////////////////////////////
1654
1655 /*!
1656 @brief copy constructor
1657
1658 Creates a copy of a given JSON value.
1659
1660 @param[in] other the JSON value to copy
1661
1662 @complexity Linear in the size of @a other.
1663
1664 @requirement This function satisfies the Container requirements:
1665 - The complexity is linear.
1666 - As postcondition, it holds: `other == basic_json(other)`.
1667
1668 @throw std::bad_alloc if allocation for object, array, or string fails.
1669
1670 @liveexample{The following code shows an example for the copy
1671 constructor.,basic_json__basic_json}
1672
1673 @since version 1.0.0
1674 */
1675 basic_json(const basic_json& other)
1676 : m_type(other.m_type)
1677 {
1678 switch (m_type)
1679 {
1680 case value_t::object:
1681 {
1682 m_value = *other.m_value.object;
1683 break;
1684 }
1685
1686 case value_t::array:
1687 {
1688 m_value = *other.m_value.array;
1689 break;
1690 }
1691
1692 case value_t::string:
1693 {
1694 m_value = *other.m_value.string;
1695 break;
1696 }
1697
1698 case value_t::boolean:
1699 {
1700 m_value = other.m_value.boolean;
1701 break;
1702 }
1703
1704 case value_t::number_integer:
1705 {
1706 m_value = other.m_value.number_integer;
1707 break;
1708 }
1709
1710 case value_t::number_float:
1711 {
1712 m_value = other.m_value.number_float;
1713 break;
1714 }
1715
1716 default:
1717 {
1718 break;
1719 }
1720 }
1721 }
1722
1723 /*!
1724 @brief move constructor
1725
1726 Move constructor. Constructs a JSON value with the contents of the given
1727 value @a other using move semantics. It "steals" the resources from @a
1728 other and leaves it as JSON null value.
1729
1730 @param[in,out] other value to move to this object
1731
1732 @post @a other is a JSON null value
1733
1734 @complexity Constant.
1735
1736 @liveexample{The code below shows the move constructor explicitly called
1737 via std::move.,basic_json__moveconstructor}
1738
1739 @since version 1.0.0
1740 */
1741 basic_json(basic_json&& other) noexcept
1742 : m_type(std::move(other.m_type)),
1743 m_value(std::move(other.m_value))
1744 {
1745 // invalidate payload
1746 other.m_type = value_t::null;
1747 other.m_value = {};
1748 }
1749
1750 /*!
1751 @brief copy assignment
1752
1753 Copy assignment operator. Copies a JSON value via the "copy and swap"
1754 strategy: It is expressed in terms of the copy constructor, destructor, and
1755 the swap() member function.
1756
1757 @param[in] other value to copy from
1758
1759 @complexity Linear.
1760
1761 @requirement This function satisfies the Container requirements:
1762 - The complexity is linear.
1763
1764 @liveexample{The code below shows and example for the copy assignment. It
1765 creates a copy of value `a` which is then swapped with `b`. Finally\, the
1766 copy of `a` (which is the null value after the swap) is
1767 destroyed.,basic_json__copyassignment}
1768
1769 @since version 1.0.0
1770 */
1771 reference& operator=(basic_json other) noexcept (
1772 std::is_nothrow_move_constructible<value_t>::value and
1773 std::is_nothrow_move_assignable<value_t>::value and
1774 std::is_nothrow_move_constructible<json_value>::value and
1775 std::is_nothrow_move_assignable<json_value>::value
1776 )
1777 {
1778 using std::swap;
1779 swap(m_type, other.m_type);
1780 swap(m_value, other.m_value);
1781 return *this;
1782 }
1783
1784 /*!
1785 @brief destructor
1786
1787 Destroys the JSON value and frees all allocated memory.
1788
1789 @complexity Linear.
1790
1791 @requirement This function satisfies the Container requirements:
1792 - The complexity is linear.
1793 - All stored elements are destroyed and all memory is freed.
1794
1795 @since version 1.0.0
1796 */
1797 ~basic_json()
1798 {
1799 switch (m_type)
1800 {
1801 case value_t::object:
1802 {
1803 AllocatorType<object_t> alloc;
1804 alloc.destroy(m_value.object);
1805 alloc.deallocate(m_value.object, 1);
1806 break;
1807 }
1808
1809 case value_t::array:
1810 {
1811 AllocatorType<array_t> alloc;
1812 alloc.destroy(m_value.array);
1813 alloc.deallocate(m_value.array, 1);
1814 break;
1815 }
1816
1817 case value_t::string:
1818 {
1819 AllocatorType<string_t> alloc;
1820 alloc.destroy(m_value.string);
1821 alloc.deallocate(m_value.string, 1);
1822 break;
1823 }
1824
1825 default:
1826 {
1827 // all other types need no specific destructor
1828 break;
1829 }
1830 }
1831 }
1832
1833 /// @}
1834
1835 public:
1836 ///////////////////////
1837 // object inspection //
1838 ///////////////////////
1839
1840 /// @name object inspection
1841 /// @{
1842
1843 /*!
1844 @brief serialization
1845
1846 Serialization function for JSON values. The function tries to mimick
1847 Python's @p json.dumps() function, and currently supports its @p indent
1848 parameter.
1849
1850 @param[in] indent if indent is nonnegative, then array elements and object
1851 members will be pretty-printed with that indent level. An indent level of 0
1852 will only insert newlines. -1 (the default) selects the most compact
1853 representation
1854
1855 @return string containing the serialization of the JSON value
1856
1857 @complexity Linear.
1858
1859 @liveexample{The following example shows the effect of different @a indent
1860 parameters to the result of the serializaion.,dump}
1861
1862 @see https://docs.python.org/2/library/json.html#json.dump
1863
1864 @since version 1.0.0
1865 */
1866 string_t dump(const int indent = -1) const
1867 {
1868 std::stringstream ss;
1869
1870 if (indent >= 0)
1871 {
1872 dump(ss, true, static_cast<unsigned int>(indent));
1873 }
1874 else
1875 {
1876 dump(ss, false, 0);
1877 }
1878
1879 return ss.str();
1880 }
1881
1882 /*!
1883 @brief return the type of the JSON value (explicit)
1884
1885 Return the type of the JSON value as a value from the @ref value_t
1886 enumeration.
1887
1888 @return the type of the JSON value
1889
1890 @complexity Constant.
1891
1892 @liveexample{The following code exemplifies @ref type() for all JSON
1893 types.,type}
1894
1895 @since version 1.0.0
1896 */
1897 value_t type() const noexcept
1898 {
1899 return m_type;
1900 }
1901
1902 /*!
1903 @brief return whether type is primitive
1904
1905 This function returns true iff the JSON type is primitive (string, number,
1906 boolean, or null).
1907
1908 @return `true` if type is primitive (string, number, boolean, or null),
1909 `false` otherwise.
1910
1911 @complexity Constant.
1912
1913 @liveexample{The following code exemplifies @ref is_primitive for all JSON
1914 types.,is_primitive}
1915
1916 @since version 1.0.0
1917 */
1918 bool is_primitive() const noexcept
1919 {
1920 return is_null() or is_string() or is_boolean() or is_number();
1921 }
1922
1923 /*!
1924 @brief return whether type is structured
1925
1926 This function returns true iff the JSON type is structured (array or
1927 object).
1928
1929 @return `true` if type is structured (array or object), `false` otherwise.
1930
1931 @complexity Constant.
1932
1933 @liveexample{The following code exemplifies @ref is_structured for all JSON
1934 types.,is_structured}
1935
1936 @since version 1.0.0
1937 */
1938 bool is_structured() const noexcept
1939 {
1940 return is_array() or is_object();
1941 }
1942
1943 /*!
1944 @brief return whether value is null
1945
1946 This function returns true iff the JSON value is null.
1947
1948 @return `true` if type is null, `false` otherwise.
1949
1950 @complexity Constant.
1951
1952 @liveexample{The following code exemplifies @ref is_null for all JSON
1953 types.,is_null}
1954
1955 @since version 1.0.0
1956 */
1957 bool is_null() const noexcept
1958 {
1959 return m_type == value_t::null;
1960 }
1961
1962 /*!
1963 @brief return whether value is a boolean
1964
1965 This function returns true iff the JSON value is a boolean.
1966
1967 @return `true` if type is boolean, `false` otherwise.
1968
1969 @complexity Constant.
1970
1971 @liveexample{The following code exemplifies @ref is_boolean for all JSON
1972 types.,is_boolean}
1973
1974 @since version 1.0.0
1975 */
1976 bool is_boolean() const noexcept
1977 {
1978 return m_type == value_t::boolean;
1979 }
1980
1981 /*!
1982 @brief return whether value is a number
1983
1984 This function returns true iff the JSON value is a number. This includes
1985 both integer and floating-point values.
1986
1987 @return `true` if type is number (regardless whether integer or
1988 floating-type), `false` otherwise.
1989
1990 @complexity Constant.
1991
1992 @liveexample{The following code exemplifies @ref is_number for all JSON
1993 types.,is_number}
1994
1995 @sa @ref is_number_integer() -- check if value is an integer number
1996 @sa @ref is_number_float() -- check if value is a floating-point number
1997
1998 @since version 1.0.0
1999 */
2000 bool is_number() const noexcept
2001 {
2002 return is_number_integer() or is_number_float();
2003 }
2004
2005 /*!
2006 @brief return whether value is an integer number
2007
2008 This function returns true iff the JSON value is an integer number. This
2009 excludes floating-point values.
2010
2011 @return `true` if type is an integer number, `false` otherwise.
2012
2013 @complexity Constant.
2014
2015 @liveexample{The following code exemplifies @ref is_number_integer for all
2016 JSON types.,is_number_integer}
2017
2018 @sa @ref is_number() -- check if value is a number
2019 @sa @ref is_number_float() -- check if value is a floating-point number
2020
2021 @since version 1.0.0
2022 */
2023 bool is_number_integer() const noexcept
2024 {
2025 return m_type == value_t::number_integer;
2026 }
2027
2028 /*!
2029 @brief return whether value is a floating-point number
2030
2031 This function returns true iff the JSON value is a floating-point number.
2032 This excludes integer values.
2033
2034 @return `true` if type is a floating-point number, `false` otherwise.
2035
2036 @complexity Constant.
2037
2038 @liveexample{The following code exemplifies @ref is_number_float for all
2039 JSON types.,is_number_float}
2040
2041 @sa @ref is_number() -- check if value is number
2042 @sa @ref is_number_integer() -- check if value is an integer number
2043
2044 @since version 1.0.0
2045 */
2046 bool is_number_float() const noexcept
2047 {
2048 return m_type == value_t::number_float;
2049 }
2050
2051 /*!
2052 @brief return whether value is an object
2053
2054 This function returns true iff the JSON value is an object.
2055
2056 @return `true` if type is object, `false` otherwise.
2057
2058 @complexity Constant.
2059
2060 @liveexample{The following code exemplifies @ref is_object for all JSON
2061 types.,is_object}
2062
2063 @since version 1.0.0
2064 */
2065 bool is_object() const noexcept
2066 {
2067 return m_type == value_t::object;
2068 }
2069
2070 /*!
2071 @brief return whether value is an array
2072
2073 This function returns true iff the JSON value is an array.
2074
2075 @return `true` if type is array, `false` otherwise.
2076
2077 @complexity Constant.
2078
2079 @liveexample{The following code exemplifies @ref is_array for all JSON
2080 types.,is_array}
2081
2082 @since version 1.0.0
2083 */
2084 bool is_array() const noexcept
2085 {
2086 return m_type == value_t::array;
2087 }
2088
2089 /*!
2090 @brief return whether value is a string
2091
2092 This function returns true iff the JSON value is a string.
2093
2094 @return `true` if type is string, `false` otherwise.
2095
2096 @complexity Constant.
2097
2098 @liveexample{The following code exemplifies @ref is_string for all JSON
2099 types.,is_string}
2100
2101 @since version 1.0.0
2102 */
2103 bool is_string() const noexcept
2104 {
2105 return m_type == value_t::string;
2106 }
2107
2108 /*!
2109 @brief return whether value is discarded
2110
2111 This function returns true iff the JSON value was discarded during parsing
2112 with a callback function (see @ref parser_callback_t).
2113
2114 @note This function will always be `false` for JSON values after parsing.
2115 That is, discarded values can only occur during parsing, but will be
2116 removed when inside a structured value or replaced by null in other cases.
2117
2118 @return `true` if type is discarded, `false` otherwise.
2119
2120 @complexity Constant.
2121
2122 @liveexample{The following code exemplifies @ref is_discarded for all JSON
2123 types.,is_discarded}
2124
2125 @since version 1.0.0
2126 */
2127 bool is_discarded() const noexcept
2128 {
2129 return m_type == value_t::discarded;
2130 }
2131
2132 /*!
2133 @brief return the type of the JSON value (implicit)
2134
2135 Implicitly return the type of the JSON value as a value from the @ref
2136 value_t enumeration.
2137
2138 @return the type of the JSON value
2139
2140 @complexity Constant.
2141
2142 @liveexample{The following code exemplifies the value_t operator for all
2143 JSON types.,operator__value_t}
2144
2145 @since version 1.0.0
2146 */
2147 operator value_t() const noexcept
2148 {
2149 return m_type;
2150 }
2151
2152 /// @}
2153
2154 private:
2155 //////////////////
2156 // value access //
2157 //////////////////
2158
2159 /// get an object (explicit)
2160 template <class T, typename
2161 std::enable_if<
2162 std::is_convertible<typename object_t::key_type, typename T::key_type>::value and
2163 std::is_convertible<basic_json_t, typename T::mapped_type>::value
2164 , int>::type = 0>
2165 T get_impl(T*) const
2166 {
2167 if (is_object())
2168 {
2169 return T(m_value.object->begin(), m_value.object->end());
2170 }
2171 else
2172 {
2173 throw std::domain_error("type must be object, but is " + type_name());
2174 }
2175 }
2176
2177 /// get an object (explicit)
2178 object_t get_impl(object_t*) const
2179 {
2180 if (is_object())
2181 {
2182 return *(m_value.object);
2183 }
2184 else
2185 {
2186 throw std::domain_error("type must be object, but is " + type_name());
2187 }
2188 }
2189
2190 /// get an array (explicit)
2191 template <class T, typename
2192 std::enable_if<
2193 std::is_convertible<basic_json_t, typename T::value_type>::value and
2194 not std::is_same<basic_json_t, typename T::value_type>::value and
2195 not std::is_arithmetic<T>::value and
2196 not std::is_convertible<std::string, T>::value and
2197 not has_mapped_type<T>::value
2198 , int>::type = 0>
2199 T get_impl(T*) const
2200 {
2201 if (is_array())
2202 {
2203 T to_vector;
2204 std::transform(m_value.array->begin(), m_value.array->end(),
2205 std::inserter(to_vector, to_vector.end()), [](basic_json i)
2206 {
2207 return i.get<typename T::value_type>();
2208 });
2209 return to_vector;
2210 }
2211 else
2212 {
2213 throw std::domain_error("type must be array, but is " + type_name());
2214 }
2215 }
2216
2217 /// get an array (explicit)
2218 template <class T, typename
2219 std::enable_if<
2220 std::is_convertible<basic_json_t, T>::value and
2221 not std::is_same<basic_json_t, T>::value
2222 , int>::type = 0>
2223 std::vector<T> get_impl(std::vector<T>*) const
2224 {
2225 if (is_array())
2226 {
2227 std::vector<T> to_vector;
2228 to_vector.reserve(m_value.array->size());
2229 std::transform(m_value.array->begin(), m_value.array->end(),
2230 std::inserter(to_vector, to_vector.end()), [](basic_json i)
2231 {
2232 return i.get<T>();
2233 });
2234 return to_vector;
2235 }
2236 else
2237 {
2238 throw std::domain_error("type must be array, but is " + type_name());
2239 }
2240 }
2241
2242 /// get an array (explicit)
2243 template <class T, typename
2244 std::enable_if<
2245 std::is_same<basic_json, typename T::value_type>::value and
2246 not has_mapped_type<T>::value
2247 , int>::type = 0>
2248 T get_impl(T*) const
2249 {
2250 if (is_array())
2251 {
2252 return T(m_value.array->begin(), m_value.array->end());
2253 }
2254 else
2255 {
2256 throw std::domain_error("type must be array, but is " + type_name());
2257 }
2258 }
2259
2260 /// get an array (explicit)
2261 array_t get_impl(array_t*) const
2262 {
2263 if (is_array())
2264 {
2265 return *(m_value.array);
2266 }
2267 else
2268 {
2269 throw std::domain_error("type must be array, but is " + type_name());
2270 }
2271 }
2272
2273 /// get a string (explicit)
2274 template <typename T, typename
2275 std::enable_if<
2276 std::is_convertible<string_t, T>::value
2277 , int>::type = 0>
2278 T get_impl(T*) const
2279 {
2280 if (is_string())
2281 {
2282 return *m_value.string;
2283 }
2284 else
2285 {
2286 throw std::domain_error("type must be string, but is " + type_name());
2287 }
2288 }
2289
2290 /// get a number (explicit)
2291 template<typename T, typename
2292 std::enable_if<
2293 std::is_arithmetic<T>::value
2294 , int>::type = 0>
2295 T get_impl(T*) const
2296 {
2297 switch (m_type)
2298 {
2299 case value_t::number_integer:
2300 {
2301 return static_cast<T>(m_value.number_integer);
2302 }
2303
2304 case value_t::number_float:
2305 {
2306 return static_cast<T>(m_value.number_float);
2307 }
2308
2309 default:
2310 {
2311 throw std::domain_error("type must be number, but is " + type_name());
2312 }
2313 }
2314 }
2315
2316 /// get a boolean (explicit)
2317 boolean_t get_impl(boolean_t*) const
2318 {
2319 if (is_boolean())
2320 {
2321 return m_value.boolean;
2322 }
2323 else
2324 {
2325 throw std::domain_error("type must be boolean, but is " + type_name());
2326 }
2327 }
2328
2329 /// get a pointer to the value (object)
2330 object_t* get_impl_ptr(object_t*) noexcept
2331 {
2332 return is_object() ? m_value.object : nullptr;
2333 }
2334
2335 /// get a pointer to the value (object)
2336 const object_t* get_impl_ptr(const object_t*) const noexcept
2337 {
2338 return is_object() ? m_value.object : nullptr;
2339 }
2340
2341 /// get a pointer to the value (array)
2342 array_t* get_impl_ptr(array_t*) noexcept
2343 {
2344 return is_array() ? m_value.array : nullptr;
2345 }
2346
2347 /// get a pointer to the value (array)
2348 const array_t* get_impl_ptr(const array_t*) const noexcept
2349 {
2350 return is_array() ? m_value.array : nullptr;
2351 }
2352
2353 /// get a pointer to the value (string)
2354 string_t* get_impl_ptr(string_t*) noexcept
2355 {
2356 return is_string() ? m_value.string : nullptr;
2357 }
2358
2359 /// get a pointer to the value (string)
2360 const string_t* get_impl_ptr(const string_t*) const noexcept
2361 {
2362 return is_string() ? m_value.string : nullptr;
2363 }
2364
2365 /// get a pointer to the value (boolean)
2366 boolean_t* get_impl_ptr(boolean_t*) noexcept
2367 {
2368 return is_boolean() ? &m_value.boolean : nullptr;
2369 }
2370
2371 /// get a pointer to the value (boolean)
2372 const boolean_t* get_impl_ptr(const boolean_t*) const noexcept
2373 {
2374 return is_boolean() ? &m_value.boolean : nullptr;
2375 }
2376
2377 /// get a pointer to the value (integer number)
2378 number_integer_t* get_impl_ptr(number_integer_t*) noexcept
2379 {
2380 return is_number_integer() ? &m_value.number_integer : nullptr;
2381 }
2382
2383 /// get a pointer to the value (integer number)
2384 const number_integer_t* get_impl_ptr(const number_integer_t*) const noexcept
2385 {
2386 return is_number_integer() ? &m_value.number_integer : nullptr;
2387 }
2388
2389 /// get a pointer to the value (floating-point number)
2390 number_float_t* get_impl_ptr(number_float_t*) noexcept
2391 {
2392 return is_number_float() ? &m_value.number_float : nullptr;
2393 }
2394
2395 /// get a pointer to the value (floating-point number)
2396 const number_float_t* get_impl_ptr(const number_float_t*) const noexcept
2397 {
2398 return is_number_float() ? &m_value.number_float : nullptr;
2399 }
2400
2401 public:
2402
2403 /// @name value access
2404 /// @{
2405
2406 /*!
2407 @brief get a value (explicit)
2408
2409 Explicit type conversion between the JSON value and a compatible value.
2410
2411 @tparam ValueType non-pointer type compatible to the JSON value, for
2412 instance `int` for JSON integer numbers, `bool` for JSON booleans, or
2413 `std::vector` types for JSON arrays
2414
2415 @return copy of the JSON value, converted to type @a ValueType
2416
2417 @throw std::domain_error in case passed type @a ValueType is incompatible
2418 to JSON; example: `"type must be object, but is null"`
2419
2420 @complexity Linear in the size of the JSON value.
2421
2422 @liveexample{The example below shows serveral conversions from JSON values
2423 to other types. There a few things to note: (1) Floating-point numbers can
2424 be converted to integers\, (2) A JSON array can be converted to a standard
2425 `std::vector<short>`\, (3) A JSON object can be converted to C++
2426 assiciative containers such as `std::unordered_map<std::string\,
2427 json>`.,get__ValueType_const}
2428
2429 @internal
2430 The idea of using a casted null pointer to choose the correct
2431 implementation is from <http://stackoverflow.com/a/8315197/266378>.
2432 @endinternal
2433
2434 @sa @ref operator ValueType() const for implicit conversion
2435 @sa @ref get() for pointer-member access
2436
2437 @since version 1.0.0
2438 */
2439 template<typename ValueType, typename
2440 std::enable_if<
2441 not std::is_pointer<ValueType>::value
2442 , int>::type = 0>
2443 ValueType get() const
2444 {
2445 return get_impl(static_cast<ValueType*>(nullptr));
2446 }
2447
2448 /*!
2449 @brief get a pointer value (explicit)
2450
2451 Explicit pointer access to the internally stored JSON value. No copies are
2452 made.
2453
2454 @warning The pointer becomes invalid if the underlying JSON object changes.
2455
2456 @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref
2457 object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or @ref
2458 number_float_t.
2459
2460 @return pointer to the internally stored JSON value if the requested
2461 pointer type @a PointerType fits to the JSON value; `nullptr` otherwise
2462
2463 @complexity Constant.
2464
2465 @liveexample{The example below shows how pointers to internal values of a
2466 JSON value can be requested. Note that no type conversions are made and a
2467 `nullptr` is returned if the value and the requested pointer type does not
2468 match.,get__PointerType}
2469
2470 @sa @ref get_ptr() for explicit pointer-member access
2471
2472 @since version 1.0.0
2473 */
2474 template<typename PointerType, typename
2475 std::enable_if<
2476 std::is_pointer<PointerType>::value
2477 , int>::type = 0>
2478 PointerType get() noexcept
2479 {
2480 // delegate the call to get_ptr
2481 return get_ptr<PointerType>();
2482 }
2483
2484 /*!
2485 @brief get a pointer value (explicit)
2486 @copydoc get()
2487 */
2488 template<typename PointerType, typename
2489 std::enable_if<
2490 std::is_pointer<PointerType>::value
2491 , int>::type = 0>
2492 const PointerType get() const noexcept
2493 {
2494 // delegate the call to get_ptr
2495 return get_ptr<PointerType>();
2496 }
2497
2498 /*!
2499 @brief get a pointer value (implicit)
2500
2501 Implict pointer access to the internally stored JSON value. No copies are
2502 made.
2503
2504 @warning Writing data to the pointee of the result yields an undefined
2505 state.
2506
2507 @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref
2508 object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or @ref
2509 number_float_t.
2510
2511 @return pointer to the internally stored JSON value if the requested
2512 pointer type @a PointerType fits to the JSON value; `nullptr` otherwise
2513
2514 @complexity Constant.
2515
2516 @liveexample{The example below shows how pointers to internal values of a
2517 JSON value can be requested. Note that no type conversions are made and a
2518 `nullptr` is returned if the value and the requested pointer type does not
2519 match.,get_ptr}
2520
2521 @since version 1.0.0
2522 */
2523 template<typename PointerType, typename
2524 std::enable_if<
2525 std::is_pointer<PointerType>::value
2526 , int>::type = 0>
2527 PointerType get_ptr() noexcept
2528 {
2529 // delegate the call to get_impl_ptr<>()
2530 return get_impl_ptr(static_cast<PointerType>(nullptr));
2531 }
2532
2533 /*!
2534 @brief get a pointer value (implicit)
2535 @copydoc get_ptr()
2536 */
2537 template<typename PointerType, typename
2538 std::enable_if<
2539 std::is_pointer<PointerType>::value
2540 and std::is_const<typename std::remove_pointer<PointerType>::type>::value
2541 , int>::type = 0>
2542 const PointerType get_ptr() const noexcept
2543 {
2544 // delegate the call to get_impl_ptr<>() const
2545 return get_impl_ptr(static_cast<const PointerType>(nullptr));
2546 }
2547
2548 /*!
2549 @brief get a value (implicit)
2550
2551 Implict type conversion between the JSON value and a compatible value. The
2552 call is realized by calling @ref get() const.
2553
2554 @tparam ValueType non-pointer type compatible to the JSON value, for
2555 instance `int` for JSON integer numbers, `bool` for JSON booleans, or
2556 `std::vector` types for JSON arrays. The character type of @ref string_t
2557 as well as an initializer list of this type is excluded to avoid
2558 ambiguities as these types implicitly convert to `std::string`.
2559
2560 @return copy of the JSON value, converted to type @a ValueType
2561
2562 @throw std::domain_error in case passed type @a ValueType is incompatible
2563 to JSON, thrown by @ref get() const
2564
2565 @complexity Linear in the size of the JSON value.
2566
2567 @liveexample{The example below shows serveral conversions from JSON values
2568 to other types. There a few things to note: (1) Floating-point numbers can
2569 be converted to integers\, (2) A JSON array can be converted to a standard
2570 `std::vector<short>`\, (3) A JSON object can be converted to C++
2571 assiciative containers such as `std::unordered_map<std::string\,
2572 json>`.,operator__ValueType}
2573
2574 @since version 1.0.0
2575 */
2576 template<typename ValueType, typename
2577 std::enable_if<
2578 not std::is_pointer<ValueType>::value
2579 and not std::is_same<ValueType, typename string_t::value_type>::value
2580 and not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value
2581 , int>::type = 0>
2582 operator ValueType() const
2583 {
2584 // delegate the call to get<>() const
2585 return get<ValueType>();
2586 }
2587
2588 /// @}
2589
2590
2591 ////////////////////
2592 // element access //
2593 ////////////////////
2594
2595 /// @name element access
2596 /// @{
2597
2598 /*!
2599 @brief access specified array element with bounds checking
2600
2601 Returns a reference to the element at specified location @a idx, with
2602 bounds checking.
2603
2604 @param[in] idx index of the element to access
2605
2606 @return reference to the element at index @a idx
2607
2608 @throw std::domain_error if the JSON value is not an array; example:
2609 `"cannot use at() with string"`
2610 @throw std::out_of_range if the index @a idx is out of range of the array;
2611 that is, `idx >= size()`; example: `"array index 7 is out of range"`
2612
2613 @complexity Constant.
2614
2615 @liveexample{The example below shows how array elements can be read and
2616 written using at.,at__size_type}
2617
2618 @since version 1.0.0
2619 */
2620 reference at(size_type idx)
2621 {
2622 // at only works for arrays
2623 if (is_array())
2624 {
2625 try
2626 {
2627 return m_value.array->at(idx);
2628 }
2629 catch (std::out_of_range& e)
2630 {
2631 // create better exception explanation
2632 throw std::out_of_range("array index " + std::to_string(idx) + " is out of range");
2633 }
2634 }
2635 else
2636 {
2637 throw std::domain_error("cannot use at() with " + type_name());
2638 }
2639 }
2640
2641 /*!
2642 @brief access specified array element with bounds checking
2643
2644 Returns a const reference to the element at specified location @a idx, with
2645 bounds checking.
2646
2647 @param[in] idx index of the element to access
2648
2649 @return const reference to the element at index @a idx
2650
2651 @throw std::domain_error if the JSON value is not an array; example:
2652 `"cannot use at() with string"`
2653 @throw std::out_of_range if the index @a idx is out of range of the array;
2654 that is, `idx >= size()`; example: `"array index 7 is out of range"`
2655
2656 @complexity Constant.
2657
2658 @liveexample{The example below shows how array elements can be read using
2659 at.,at__size_type_const}
2660
2661 @since version 1.0.0
2662 */
2663 const_reference at(size_type idx) const
2664 {
2665 // at only works for arrays
2666 if (is_array())
2667 {
2668 try
2669 {
2670 return m_value.array->at(idx);
2671 }
2672 catch (std::out_of_range& e)
2673 {
2674 // create better exception explanation
2675 throw std::out_of_range("array index " + std::to_string(idx) + " is out of range");
2676 }
2677 }
2678 else
2679 {
2680 throw std::domain_error("cannot use at() with " + type_name());
2681 }
2682 }
2683
2684 /*!
2685 @brief access specified object element with bounds checking
2686
2687 Returns a reference to the element at with specified key @a key, with
2688 bounds checking.
2689
2690 @param[in] key key of the element to access
2691
2692 @return reference to the element at key @a key
2693
2694 @throw std::domain_error if the JSON value is not an object; example:
2695 `"cannot use at() with boolean"`
2696 @throw std::out_of_range if the key @a key is is not stored in the object;
2697 that is, `find(key) == end()`; example: `"key "the fast" not found"`
2698
2699 @complexity Logarithmic in the size of the container.
2700
2701 @liveexample{The example below shows how object elements can be read and
2702 written using at.,at__object_t_key_type}
2703
2704 @sa @ref operator[](const typename object_t::key_type&) for unchecked
2705 access by reference
2706 @sa @ref value() for access by value with a default value
2707
2708 @since version 1.0.0
2709 */
2710 reference at(const typename object_t::key_type& key)
2711 {
2712 // at only works for objects
2713 if (is_object())
2714 {
2715 try
2716 {
2717 return m_value.object->at(key);
2718 }
2719 catch (std::out_of_range& e)
2720 {
2721 // create better exception explanation
2722 throw std::out_of_range("key '" + key + "' not found");
2723 }
2724 }
2725 else
2726 {
2727 throw std::domain_error("cannot use at() with " + type_name());
2728 }
2729 }
2730
2731 /*!
2732 @brief access specified object element with bounds checking
2733
2734 Returns a const reference to the element at with specified key @a key, with
2735 bounds checking.
2736
2737 @param[in] key key of the element to access
2738
2739 @return const reference to the element at key @a key
2740
2741 @throw std::domain_error if the JSON value is not an object; example:
2742 `"cannot use at() with boolean"`
2743 @throw std::out_of_range if the key @a key is is not stored in the object;
2744 that is, `find(key) == end()`; example: `"key "the fast" not found"`
2745
2746 @complexity Logarithmic in the size of the container.
2747
2748 @liveexample{The example below shows how object elements can be read using
2749 at.,at__object_t_key_type_const}
2750
2751 @sa @ref operator[](const typename object_t::key_type&) for unchecked
2752 access by reference
2753 @sa @ref value() for access by value with a default value
2754
2755 @since version 1.0.0
2756 */
2757 const_reference at(const typename object_t::key_type& key) const
2758 {
2759 // at only works for objects
2760 if (is_object())
2761 {
2762 try
2763 {
2764 return m_value.object->at(key);
2765 }
2766 catch (std::out_of_range& e)
2767 {
2768 // create better exception explanation
2769 throw std::out_of_range("key '" + key + "' not found");
2770 }
2771 }
2772 else
2773 {
2774 throw std::domain_error("cannot use at() with " + type_name());
2775 }
2776 }
2777
2778 /*!
2779 @brief access specified array element
2780
2781 Returns a reference to the element at specified location @a idx.
2782
2783 @note If @a idx is beyond the range of the array (i.e., `idx >= size()`),
2784 then the array is silently filled up with `null` values to make `idx` a
2785 valid reference to the last stored element.
2786
2787 @param[in] idx index of the element to access
2788
2789 @return reference to the element at index @a idx
2790
2791 @throw std::domain_error if JSON is not an array or null; example: `"cannot
2792 use operator[] with null"`
2793
2794 @complexity Constant if @a idx is in the range of the array. Otherwise
2795 linear in `idx - size()`.
2796
2797 @liveexample{The example below shows how array elements can be read and
2798 written using [] operator. Note the addition of `null`
2799 values.,operatorarray__size_type}
2800
2801 @since version 1.0.0
2802 */
2803 reference operator[](size_type idx)
2804 {
2805 // implicitly convert null to object
2806 if (is_null())
2807 {
2808 m_type = value_t::array;
2809 m_value.array = create<array_t>();
2810 }
2811
2812 // [] only works for arrays
2813 if (is_array())
2814 {
2815 for (size_t i = m_value.array->size(); i <= idx; ++i)
2816 {
2817 m_value.array->push_back(basic_json());
2818 }
2819
2820 return m_value.array->operator[](idx);
2821 }
2822 else
2823 {
2824 throw std::domain_error("cannot use operator[] with " + type_name());
2825 }
2826 }
2827
2828 /*!
2829 @brief access specified array element
2830
2831 Returns a const reference to the element at specified location @a idx.
2832
2833 @param[in] idx index of the element to access
2834
2835 @return const reference to the element at index @a idx
2836
2837 @throw std::domain_error if JSON is not an array; example: `"cannot use
2838 operator[] with null"`
2839
2840 @complexity Constant.
2841
2842 @liveexample{The example below shows how array elements can be read using
2843 the [] operator.,operatorarray__size_type_const}
2844
2845 @since version 1.0.0
2846 */
2847 const_reference operator[](size_type idx) const
2848 {
2849 // at only works for arrays
2850 if (is_array())
2851 {
2852 return m_value.array->operator[](idx);
2853 }
2854 else
2855 {
2856 throw std::domain_error("cannot use operator[] with " + type_name());
2857 }
2858 }
2859
2860 /*!
2861 @brief access specified object element
2862
2863 Returns a reference to the element at with specified key @a key.
2864
2865 @note If @a key is not found in the object, then it is silently added to
2866 the object and filled with a `null` value to make `key` a valid reference.
2867 In case the value was `null` before, it is converted to an object.
2868
2869 @param[in] key key of the element to access
2870
2871 @return reference to the element at key @a key
2872
2873 @throw std::domain_error if JSON is not an object or null; example:
2874 `"cannot use operator[] with null"`
2875
2876 @complexity Logarithmic in the size of the container.
2877
2878 @liveexample{The example below shows how object elements can be read and
2879 written using the [] operator.,operatorarray__key_type}
2880
2881 @sa @ref at(const typename object_t::key_type&) for access by reference
2882 with range checking
2883 @sa @ref value() for access by value with a default value
2884
2885 @since version 1.0.0
2886 */
2887 reference operator[](const typename object_t::key_type& key)
2888 {
2889 // implicitly convert null to object
2890 if (is_null())
2891 {
2892 m_type = value_t::object;
2893 m_value.object = create<object_t>();
2894 }
2895
2896 // [] only works for objects
2897 if (is_object())
2898 {
2899 return m_value.object->operator[](key);
2900 }
2901 else
2902 {
2903 throw std::domain_error("cannot use operator[] with " + type_name());
2904 }
2905 }
2906
2907 /*!
2908 @brief read-only access specified object element
2909
2910 Returns a const reference to the element at with specified key @a key. No
2911 bounds checking is performed.
2912
2913 @warning If the element with key @a key does not exist, the behavior is
2914 undefined.
2915
2916 @param[in] key key of the element to access
2917
2918 @return const reference to the element at key @a key
2919
2920 @throw std::domain_error if JSON is not an object; example: `"cannot use
2921 operator[] with null"`
2922
2923 @complexity Logarithmic in the size of the container.
2924
2925 @liveexample{The example below shows how object elements can be read using
2926 the [] operator.,operatorarray__key_type_const}
2927
2928 @sa @ref at(const typename object_t::key_type&) for access by reference
2929 with range checking
2930 @sa @ref value() for access by value with a default value
2931
2932 @since version 1.0.0
2933 */
2934 const_reference operator[](const typename object_t::key_type& key) const
2935 {
2936 // [] only works for objects
2937 if (is_object())
2938 {
2939 return m_value.object->find(key)->second;
2940 }
2941 else
2942 {
2943 throw std::domain_error("cannot use operator[] with " + type_name());
2944 }
2945 }
2946
2947 /*!
2948 @brief access specified object element
2949
2950 Returns a reference to the element at with specified key @a key.
2951
2952 @note If @a key is not found in the object, then it is silently added to
2953 the object and filled with a `null` value to make `key` a valid reference.
2954 In case the value was `null` before, it is converted to an object.
2955
2956 @note This function is required for compatibility reasons with Clang.
2957
2958 @param[in] key key of the element to access
2959
2960 @return reference to the element at key @a key
2961
2962 @throw std::domain_error if JSON is not an object or null; example:
2963 `"cannot use operator[] with null"`
2964
2965 @complexity Logarithmic in the size of the container.
2966
2967 @liveexample{The example below shows how object elements can be read and
2968 written using the [] operator.,operatorarray__key_type}
2969
2970 @sa @ref at(const typename object_t::key_type&) for access by reference
2971 with range checking
2972 @sa @ref value() for access by value with a default value
2973
2974 @since version 1.0.0
2975 */
2976 template<typename T, std::size_t n>
2977 reference operator[](const T (&key)[n])
2978 {
2979 // implicitly convert null to object
2980 if (is_null())
2981 {
2982 m_type = value_t::object;
2983 m_value = value_t::object;
2984 }
2985
2986 // at only works for objects
2987 if (is_object())
2988 {
2989 return m_value.object->operator[](key);
2990 }
2991 else
2992 {
2993 throw std::domain_error("cannot use operator[] with " + type_name());
2994 }
2995 }
2996
2997 /*!
2998 @brief read-only access specified object element
2999
3000 Returns a const reference to the element at with specified key @a key. No
3001 bounds checking is performed.
3002
3003 @warning If the element with key @a key does not exist, the behavior is
3004 undefined.
3005
3006 @note This function is required for compatibility reasons with Clang.
3007
3008 @param[in] key key of the element to access
3009
3010 @return const reference to the element at key @a key
3011
3012 @throw std::domain_error if JSON is not an object; example: `"cannot use
3013 operator[] with null"`
3014
3015 @complexity Logarithmic in the size of the container.
3016
3017 @liveexample{The example below shows how object elements can be read using
3018 the [] operator.,operatorarray__key_type_const}
3019
3020 @sa @ref at(const typename object_t::key_type&) for access by reference
3021 with range checking
3022 @sa @ref value() for access by value with a default value
3023
3024 @since version 1.0.0
3025 */
3026 template<typename T, std::size_t n>
3027 const_reference operator[](const T (&key)[n]) const
3028 {
3029 // at only works for objects
3030 if (is_object())
3031 {
3032 return m_value.object->find(key)->second;
3033 }
3034 else
3035 {
3036 throw std::domain_error("cannot use operator[] with " + type_name());
3037 }
3038 }
3039
3040 /*!
3041 @brief access specified object element with default value
3042
3043 Returns either a copy of an object's element at the specified key @a key or
3044 a given default value if no element with key @a key exists.
3045
3046 The function is basically equivalent to executing
3047 @code {.cpp}
3048 try {
3049 return at(key);
3050 } catch(std::out_of_range) {
3051 return default_value;
3052 }
3053 @endcode
3054
3055 @note Unlike @ref at(const typename object_t::key_type&), this function
3056 does not throw if the given key @a key was not found.
3057
3058 @note Unlike @ref operator[](const typename object_t::key_type& key), this
3059 function does not implicitly add an element to the position defined by @a
3060 key. This function is furthermore also applicable to const objects.
3061
3062 @param[in] key key of the element to access
3063 @param[in] default_value the value to return if @a key is not found
3064
3065 @tparam ValueType type compatible to JSON values, for instance `int` for
3066 JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for
3067 JSON arrays. Note the type of the expected value at @a key and the default
3068 value @a default_value must be compatible.
3069
3070 @return copy of the element at key @a key or @a default_value if @a key
3071 is not found
3072
3073 @throw std::domain_error if JSON is not an object; example: `"cannot use
3074 value() with null"`
3075
3076 @complexity Logarithmic in the size of the container.
3077
3078 @liveexample{The example below shows how object elements can be queried
3079 with a default value.,basic_json__value}
3080
3081 @sa @ref at(const typename object_t::key_type&) for access by reference
3082 with range checking
3083 @sa @ref operator[](const typename object_t::key_type&) for unchecked
3084 access by reference
3085
3086 @since version 1.0.0
3087 */
3088 template <class ValueType, typename
3089 std::enable_if<
3090 std::is_convertible<basic_json_t, ValueType>::value
3091 , int>::type = 0>
3092 ValueType value(const typename object_t::key_type& key, ValueType default_value) const
3093 {
3094 // at only works for objects
3095 if (is_object())
3096 {
3097 // if key is found, return value and given default value otherwise
3098 const auto it = find(key);
3099 if (it != end())
3100 {
3101 return *it;
3102 }
3103 else
3104 {
3105 return default_value;
3106 }
3107 }
3108 else
3109 {
3110 throw std::domain_error("cannot use value() with " + type_name());
3111 }
3112 }
3113
3114 /*!
3115 @brief overload for a default value of type const char*
3116 @copydoc basic_json::value()
3117 */
3118 string_t value(const typename object_t::key_type& key, const char* default_value) const
3119 {
3120 return value(key, string_t(default_value));
3121 }
3122
3123 /*!
3124 @brief access the first element
3125
3126 Returns a reference to the first element in the container. For a JSON
3127 container `c`, the expression `c.front()` is equivalent to `*c.begin()`.
3128
3129 @return In case of a structured type (array or object), a reference to the
3130 first element is returned. In cast of number, string, or boolean values, a
3131 reference to the value is returned.
3132
3133 @complexity Constant.
3134
3135 @note Calling `front` on an empty container is undefined.
3136
3137 @throw std::out_of_range when called on null value
3138
3139 @liveexample{The following code shows an example for @ref front.,front}
3140
3141 @since version 1.0.0
3142 */
3143 reference front()
3144 {
3145 return *begin();
3146 }
3147
3148 /*!
3149 @copydoc basic_json::front()
3150 */
3151 const_reference front() const
3152 {
3153 return *cbegin();
3154 }
3155
3156 /*!
3157 @brief access the last element
3158
3159 Returns a reference to the last element in the container. For a JSON
3160 container `c`, the expression `c.back()` is equivalent to `{ auto tmp =
3161 c.end(); --tmp; return *tmp; }`.
3162
3163 @return In case of a structured type (array or object), a reference to the
3164 last element is returned. In cast of number, string, or boolean values, a
3165 reference to the value is returned.
3166
3167 @complexity Constant.
3168
3169 @note Calling `back` on an empty container is undefined.
3170
3171 @throw std::out_of_range when called on null value.
3172
3173 @liveexample{The following code shows an example for @ref back.,back}
3174
3175 @since version 1.0.0
3176 */
3177 reference back()
3178 {
3179 auto tmp = end();
3180 --tmp;
3181 return *tmp;
3182 }
3183
3184 /*!
3185 @copydoc basic_json::back()
3186 */
3187 const_reference back() const
3188 {
3189 auto tmp = cend();
3190 --tmp;
3191 return *tmp;
3192 }
3193
3194 /*!
3195 @brief remove element given an iterator
3196
3197 Removes the element specified by iterator @a pos. Invalidates iterators and
3198 references at or after the point of the erase, including the end()
3199 iterator. The iterator @a pos must be valid and dereferenceable. Thus the
3200 end() iterator (which is valid, but is not dereferencable) cannot be used
3201 as a value for @a pos.
3202
3203 If called on a primitive type other than null, the resulting JSON value
3204 will be `null`.
3205
3206 @param[in] pos iterator to the element to remove
3207 @return Iterator following the last removed element. If the iterator @a pos
3208 refers to the last element, the end() iterator is returned.
3209
3210 @tparam InteratorType an @ref iterator or @ref const_iterator
3211
3212 @throw std::domain_error if called on a `null` value; example: `"cannot use
3213 erase() with null"`
3214 @throw std::domain_error if called on an iterator which does not belong to
3215 the current JSON value; example: `"iterator does not fit current value"`
3216 @throw std::out_of_range if called on a primitive type with invalid
3217 iterator (i.e., any iterator which is not end()); example: `"iterator out
3218 of range"`
3219
3220 @complexity The complexity depends on the type:
3221 - objects: amortized constant
3222 - arrays: linear in distance between pos and the end of the container
3223 - strings: linear in the length of the string
3224 - other types: constant
3225
3226 @liveexample{The example shows the result of erase for different JSON
3227 types.,erase__IteratorType}
3228
3229 @sa @ref erase(InteratorType, InteratorType) -- removes the elements in the
3230 given range
3231 @sa @ref erase(const typename object_t::key_type&) -- remvoes the element
3232 from an object at the given key
3233 @sa @ref erase(const size_type) -- removes the element from an array at the
3234 given index
3235
3236 @since version 1.0.0
3237 */
3238 template <class InteratorType, typename
3239 std::enable_if<
3240 std::is_same<InteratorType, typename basic_json_t::iterator>::value or
3241 std::is_same<InteratorType, typename basic_json_t::const_iterator>::value
3242 , int>::type
3243 = 0>
3244 InteratorType erase(InteratorType pos)
3245 {
3246 // make sure iterator fits the current value
3247 if (this != pos.m_object)
3248 {
3249 throw std::domain_error("iterator does not fit current value");
3250 }
3251
3252 InteratorType result = end();
3253
3254 switch (m_type)
3255 {
3256 case value_t::boolean:
3257 case value_t::number_float:
3258 case value_t::number_integer:
3259 case value_t::string:
3260 {
3261 if (not pos.m_it.primitive_iterator.is_begin())
3262 {
3263 throw std::out_of_range("iterator out of range");
3264 }
3265
3266 if (is_string())
3267 {
3268 delete m_value.string;
3269 m_value.string = nullptr;
3270 }
3271
3272 m_type = value_t::null;
3273 break;
3274 }
3275
3276 case value_t::object:
3277 {
3278 result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator);
3279 break;
3280 }
3281
3282 case value_t::array:
3283 {
3284 result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator);
3285 break;
3286 }
3287
3288 default:
3289 {
3290 throw std::domain_error("cannot use erase() with " + type_name());
3291 }
3292 }
3293
3294 return result;
3295 }
3296
3297 /*!
3298 @brief remove elements given an iterator range
3299
3300 Removes the element specified by the range `[first; last)`. Invalidates
3301 iterators and references at or after the point of the erase, including the
3302 end() iterator. The iterator @a first does not need to be dereferenceable
3303 if `first == last`: erasing an empty range is a no-op.
3304
3305 If called on a primitive type other than null, the resulting JSON value
3306 will be `null`.
3307
3308 @param[in] first iterator to the beginning of the range to remove
3309 @param[in] last iterator past the end of the range to remove
3310 @return Iterator following the last removed element. If the iterator @a
3311 second refers to the last element, the end() iterator is returned.
3312
3313 @tparam InteratorType an @ref iterator or @ref const_iterator
3314
3315 @throw std::domain_error if called on a `null` value; example: `"cannot use
3316 erase() with null"`
3317 @throw std::domain_error if called on iterators which does not belong to
3318 the current JSON value; example: `"iterators do not fit current value"`
3319 @throw std::out_of_range if called on a primitive type with invalid
3320 iterators (i.e., if `first != begin()` and `last != end()`); example:
3321 `"iterators out of range"`
3322
3323 @complexity The complexity depends on the type:
3324 - objects: `log(size()) + std::distance(first, last)`
3325 - arrays: linear in the distance between @a first and @a last, plus linear
3326 in the distance between @a last and end of the container
3327 - strings: linear in the length of the string
3328 - other types: constant
3329
3330 @liveexample{The example shows the result of erase for different JSON
3331 types.,erase__IteratorType_IteratorType}
3332
3333 @sa @ref erase(InteratorType) -- removes the element at a given position
3334 @sa @ref erase(const typename object_t::key_type&) -- remvoes the element
3335 from an object at the given key
3336 @sa @ref erase(const size_type) -- removes the element from an array at the
3337 given index
3338
3339 @since version 1.0.0
3340 */
3341 template <class InteratorType, typename
3342 std::enable_if<
3343 std::is_same<InteratorType, typename basic_json_t::iterator>::value or
3344 std::is_same<InteratorType, typename basic_json_t::const_iterator>::value
3345 , int>::type
3346 = 0>
3347 InteratorType erase(InteratorType first, InteratorType last)
3348 {
3349 // make sure iterator fits the current value
3350 if (this != first.m_object or this != last.m_object)
3351 {
3352 throw std::domain_error("iterators do not fit current value");
3353 }
3354
3355 InteratorType result = end();
3356
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches