summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt3
-rw-r--r--generator/CMakeLists.txt4
-rw-r--r--generator/frame.h1
-rw-r--r--generator/generator.cpp82
-rw-r--r--generator/generator.h3
-rw-r--r--generator/group.cpp27
-rw-r--r--generator/group.h1
-rw-r--r--generator/part.cpp18
-rw-r--r--generator/part.h7
-rw-r--r--generator/role.h8
-rw-r--r--generator/schema.sql8
-rw-r--r--generator/vn.diff340
-rw-r--r--lib/database.cpp32
-rw-r--r--lib/database.h2
-rw-r--r--lib/part.cpp41
-rw-r--r--lib/part.h22
-rw-r--r--lib/selrestr.cpp309
-rw-r--r--lib/selrestr.h90
-rw-r--r--lib/verbly.h1
-rw-r--r--vendor/json/json.hpp12201
20 files changed, 468 insertions, 12732 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 32c73c1..0ea601e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt
@@ -6,8 +6,7 @@ pkg_check_modules(sqlite3 sqlite3>=3.8.3 REQUIRED)
6 6
7set(CMAKE_BUILD_TYPE Debug) 7set(CMAKE_BUILD_TYPE Debug)
8 8
9include_directories(vendor/json) 9add_library(verbly lib/filter.cpp lib/field.cpp lib/notion.cpp lib/word.cpp lib/frame.cpp lib/part.cpp lib/lemma.cpp lib/form.cpp lib/pronunciation.cpp lib/statement.cpp lib/binding.cpp lib/database.cpp lib/token.cpp lib/part.cpp)
10add_library(verbly lib/filter.cpp lib/field.cpp lib/notion.cpp lib/word.cpp lib/frame.cpp lib/part.cpp lib/lemma.cpp lib/form.cpp lib/pronunciation.cpp lib/statement.cpp lib/binding.cpp lib/database.cpp lib/token.cpp lib/selrestr.cpp lib/part.cpp)
11set_property(TARGET verbly PROPERTY CXX_STANDARD 11) 10set_property(TARGET verbly PROPERTY CXX_STANDARD 11)
12set_property(TARGET verbly PROPERTY CXX_STANDARD_REQUIRED ON) 11set_property(TARGET verbly PROPERTY CXX_STANDARD_REQUIRED ON)
13target_link_libraries(verbly ${sqlite3_LIBRARIES}) 12target_link_libraries(verbly ${sqlite3_LIBRARIES})
diff --git a/generator/CMakeLists.txt b/generator/CMakeLists.txt index 5bbd82d..95a11b5 100644 --- a/generator/CMakeLists.txt +++ b/generator/CMakeLists.txt
@@ -5,8 +5,8 @@ find_package(PkgConfig)
5pkg_check_modules(sqlite3 sqlite3 REQUIRED) 5pkg_check_modules(sqlite3 sqlite3 REQUIRED)
6find_package(libxml2 REQUIRED) 6find_package(libxml2 REQUIRED)
7 7
8include_directories(${sqlite3_INCLUDE_DIR} ${LIBXML2_INCLUDE_DIR} ../vendor/json) 8include_directories(${sqlite3_INCLUDE_DIR} ${LIBXML2_INCLUDE_DIR})
9add_executable(generator notion.cpp word.cpp lemma.cpp form.cpp pronunciation.cpp group.cpp frame.cpp part.cpp ../lib/selrestr.cpp database.cpp field.cpp generator.cpp main.cpp) 9add_executable(generator notion.cpp word.cpp lemma.cpp form.cpp pronunciation.cpp group.cpp frame.cpp part.cpp database.cpp field.cpp generator.cpp main.cpp)
10set_property(TARGET generator PROPERTY CXX_STANDARD 11) 10set_property(TARGET generator PROPERTY CXX_STANDARD 11)
11set_property(TARGET generator PROPERTY CXX_STANDARD_REQUIRED ON) 11set_property(TARGET generator PROPERTY CXX_STANDARD_REQUIRED ON)
12target_link_libraries(generator ${sqlite3_LIBRARIES} ${LIBXML2_LIBRARIES}) 12target_link_libraries(generator ${sqlite3_LIBRARIES} ${LIBXML2_LIBRARIES})
diff --git a/generator/frame.h b/generator/frame.h index ba266f0..d26d500 100644 --- a/generator/frame.h +++ b/generator/frame.h
@@ -2,6 +2,7 @@
2#define FRAME_H_26770FF1 2#define FRAME_H_26770FF1
3 3
4#include <list> 4#include <list>
5#include <vector>
5#include "part.h" 6#include "part.h"
6 7
7namespace verbly { 8namespace verbly {
diff --git a/generator/generator.cpp b/generator/generator.cpp index 4cc9f64..e125b4a 100644 --- a/generator/generator.cpp +++ b/generator/generator.cpp
@@ -7,7 +7,6 @@
7#include <fstream> 7#include <fstream>
8#include "../lib/enums.h" 8#include "../lib/enums.h"
9#include "progress.h" 9#include "progress.h"
10#include "../lib/selrestr.h"
11#include "role.h" 10#include "role.h"
12#include "part.h" 11#include "part.h"
13#include "field.h" 12#include "field.h"
@@ -1303,12 +1302,20 @@ namespace verbly {
1303 std::string roleName = reinterpret_cast<const char*>(key); 1302 std::string roleName = reinterpret_cast<const char*>(key);
1304 xmlFree(key); 1303 xmlFree(key);
1305 1304
1306 selrestr roleSelrestrs; 1305 std::set<std::string> roleSelrestrs;
1307 for (xmlNodePtr rolenode = roletopnode->xmlChildrenNode; rolenode != nullptr; rolenode = rolenode->next) 1306 for (xmlNodePtr rolenode = roletopnode->xmlChildrenNode; rolenode != nullptr; rolenode = rolenode->next)
1308 { 1307 {
1309 if (!xmlStrcmp(rolenode->name, reinterpret_cast<const xmlChar*>("SELRESTRS"))) 1308 if (!xmlStrcmp(rolenode->name, reinterpret_cast<const xmlChar*>("SELRESTRS")))
1310 { 1309 {
1311 roleSelrestrs = parseSelrestr(rolenode); 1310 for (xmlNodePtr selrestrnode = rolenode->xmlChildrenNode; selrestrnode != nullptr; selrestrnode = selrestrnode->next)
1311 {
1312 if (!xmlStrcmp(selrestrnode->name, reinterpret_cast<const xmlChar*>("SELRESTR")))
1313 {
1314 key = xmlGetProp(selrestrnode, reinterpret_cast<const xmlChar*>("type"));
1315 roleSelrestrs.insert(std::string(reinterpret_cast<const char*>(key)));
1316 xmlFree(key);
1317 }
1318 }
1312 } 1319 }
1313 } 1320 }
1314 1321
@@ -1335,7 +1342,7 @@ namespace verbly {
1335 std::string partRole = reinterpret_cast<const char*>(key); 1342 std::string partRole = reinterpret_cast<const char*>(key);
1336 xmlFree(key); 1343 xmlFree(key);
1337 1344
1338 selrestr partSelrestrs; 1345 std::set<std::string> partSelrestrs;
1339 std::set<std::string> partSynrestrs; 1346 std::set<std::string> partSynrestrs;
1340 1347
1341 for (xmlNodePtr npnode = syntaxnode->xmlChildrenNode; npnode != nullptr; npnode = npnode->next) 1348 for (xmlNodePtr npnode = syntaxnode->xmlChildrenNode; npnode != nullptr; npnode = npnode->next)
@@ -1351,11 +1358,17 @@ namespace verbly {
1351 xmlFree(key); 1358 xmlFree(key);
1352 } 1359 }
1353 } 1360 }
1354 } 1361 } else if (!xmlStrcmp(npnode->name, reinterpret_cast<const xmlChar*>("SELRESTRS")))
1355
1356 if (!xmlStrcmp(npnode->name, reinterpret_cast<const xmlChar*>("SELRESTRS")))
1357 { 1362 {
1358 partSelrestrs = parseSelrestr(npnode); 1363 for (xmlNodePtr selrestrnode = npnode->xmlChildrenNode; selrestrnode != nullptr; selrestrnode = selrestrnode->next)
1364 {
1365 if (!xmlStrcmp(selrestrnode->name, reinterpret_cast<const xmlChar*>("SELRESTR")))
1366 {
1367 key = xmlGetProp(selrestrnode, reinterpret_cast<const xmlChar*>("type"));
1368 partSelrestrs.insert(std::string(reinterpret_cast<const char*>(key)));
1369 xmlFree(key);
1370 }
1371 }
1359 } 1372 }
1360 } 1373 }
1361 1374
@@ -1434,58 +1447,5 @@ namespace verbly {
1434 } 1447 }
1435 } 1448 }
1436 1449
1437 selrestr generator::parseSelrestr(xmlNodePtr top)
1438 {
1439 xmlChar* key;
1440
1441 if (!xmlStrcmp(top->name, reinterpret_cast<const xmlChar*>("SELRESTRS")))
1442 {
1443 if (xmlChildElementCount(top) == 0)
1444 {
1445 return {};
1446 } else if (xmlChildElementCount(top) == 1)
1447 {
1448 return parseSelrestr(xmlFirstElementChild(top));
1449 } else {
1450 bool orlogic = false;
1451 if (xmlHasProp(top, reinterpret_cast<const xmlChar*>("logic")))
1452 {
1453 key = xmlGetProp(top, reinterpret_cast<const xmlChar*>("logic"));
1454 if (!xmlStrcmp(key, reinterpret_cast<const xmlChar*>("or")))
1455 {
1456 orlogic = true;
1457 }
1458
1459 xmlFree(key);
1460 }
1461
1462 std::list<selrestr> children;
1463 for (xmlNodePtr selrestr = top->xmlChildrenNode; selrestr != nullptr; selrestr = selrestr->next)
1464 {
1465 if (!xmlStrcmp(selrestr->name, reinterpret_cast<const xmlChar*>("SELRESTRS"))
1466 || !xmlStrcmp(selrestr->name, reinterpret_cast<const xmlChar*>("SELRESTR")))
1467 {
1468 children.push_back(parseSelrestr(selrestr));
1469 }
1470 }
1471
1472 return selrestr(children, orlogic);
1473 }
1474 } else if (!xmlStrcmp(top->name, reinterpret_cast<const xmlChar*>("SELRESTR")))
1475 {
1476 key = xmlGetProp(top, reinterpret_cast<const xmlChar*>("Value"));
1477 bool selPos = (std::string(reinterpret_cast<const char*>(key)) == "+");
1478 xmlFree(key);
1479
1480 key = xmlGetProp(top, reinterpret_cast<const xmlChar*>("type"));
1481 std::string selRestriction = reinterpret_cast<const char*>(key);
1482 xmlFree(key);
1483
1484 return selrestr(selRestriction, selPos);
1485 } else {
1486 throw std::logic_error("Badly formatted selrestr");
1487 }
1488 }
1489
1490 }; 1450 };
1491}; 1451};
diff --git a/generator/generator.h b/generator/generator.h index bc9b3c7..43b3272 100644 --- a/generator/generator.h +++ b/generator/generator.h
@@ -18,7 +18,6 @@
18namespace verbly { 18namespace verbly {
19 19
20 enum class part_of_speech; 20 enum class part_of_speech;
21 class selrestr;
22 21
23 namespace generator { 22 namespace generator {
24 23
@@ -107,8 +106,6 @@ namespace verbly {
107 106
108 void createGroup(xmlNodePtr top, const group* parent = nullptr); 107 void createGroup(xmlNodePtr top, const group* parent = nullptr);
109 108
110 selrestr parseSelrestr(xmlNodePtr top);
111
112 // Input 109 // Input
113 110
114 std::string verbNetPath_; 111 std::string verbNetPath_;
diff --git a/generator/group.cpp b/generator/group.cpp index aa28d42..5b23578 100644 --- a/generator/group.cpp +++ b/generator/group.cpp
@@ -1,10 +1,10 @@
1#include "group.h" 1#include "group.h"
2#include <stdexcept> 2#include <stdexcept>
3#include <list> 3#include <list>
4#include <json.hpp>
5#include "database.h" 4#include "database.h"
6#include "field.h" 5#include "field.h"
7#include "frame.h" 6#include "frame.h"
7#include "../lib/util.h"
8 8
9namespace verbly { 9namespace verbly {
10 namespace generator { 10 namespace generator {
@@ -83,16 +83,22 @@ namespace verbly {
83 { 83 {
84 fields.emplace_back("role", p.getNounRole()); 84 fields.emplace_back("role", p.getNounRole());
85 85
86 selrestr partSelrestr; 86 // Short interlude to serialize the selrestrs
87 if (p.getNounSelrestrs().getType() != selrestr::type::empty) 87 std::set<std::string> partSelrestrs = p.getNounSelrestrs();
88 if (partSelrestrs.empty() && arg.hasRole(p.getNounRole()))
88 { 89 {
89 partSelrestr = p.getNounSelrestrs(); 90 partSelrestrs = arg.getRole(p.getNounRole()).getSelrestrs();
90 } else if (arg.hasRole(p.getNounRole()))
91 {
92 partSelrestr = arg.getRole(p.getNounRole()).getSelrestrs();
93 } 91 }
94 92
95 fields.emplace_back("selrestrs", partSelrestr.toJson().dump()); 93 for (const std::string& s : partSelrestrs)
94 {
95 std::list<field> selrestrFields;
96
97 selrestrFields.emplace_back("part_id", p.getId());
98 selrestrFields.emplace_back("selrestr", s);
99
100 db.insertIntoTable("selrestrs", std::move(selrestrFields));
101 }
96 102
97 // Short interlude to serialize the synrestrs 103 // Short interlude to serialize the synrestrs
98 for (const std::string& s : p.getNounSynrestrs()) 104 for (const std::string& s : p.getNounSynrestrs())
@@ -110,7 +116,10 @@ namespace verbly {
110 116
111 case part::type::preposition: 117 case part::type::preposition:
112 { 118 {
113 fields.emplace_back("prepositions", nlohmann::json(p.getPrepositionChoices()).dump()); 119 std::set<std::string> setChoices = p.getPrepositionChoices();
120 std::string serializedChoices = implode(std::begin(setChoices), std::end(setChoices), ",");
121
122 fields.emplace_back("prepositions", std::move(serializedChoices));
114 fields.emplace_back("preposition_literality", p.isPrepositionLiteral() ? 1 : 0); 123 fields.emplace_back("preposition_literality", p.isPrepositionLiteral() ? 1 : 0);
115 124
116 break; 125 break;
diff --git a/generator/group.h b/generator/group.h index 5486fbe..a7f3a17 100644 --- a/generator/group.h +++ b/generator/group.h
@@ -5,6 +5,7 @@
5#include <set> 5#include <set>
6#include <string> 6#include <string>
7#include <cassert> 7#include <cassert>
8#include <list>
8#include "role.h" 9#include "role.h"
9 10
10namespace verbly { 11namespace verbly {
diff --git a/generator/part.cpp b/generator/part.cpp index 07618a8..d3e6656 100644 --- a/generator/part.cpp +++ b/generator/part.cpp
@@ -6,12 +6,12 @@ namespace verbly {
6 6
7 int part::nextId_ = 0; 7 int part::nextId_ = 0;
8 8
9 part part::createNounPhrase(std::string role, selrestr selrestrs, std::set<std::string> synrestrs) 9 part part::createNounPhrase(std::string role, std::set<std::string> selrestrs, std::set<std::string> synrestrs)
10 { 10 {
11 part p(type::noun_phrase); 11 part p(type::noun_phrase);
12 12
13 new(&p.noun_phrase_.role) std::string(std::move(role)); 13 new(&p.noun_phrase_.role) std::string(std::move(role));
14 new(&p.noun_phrase_.selrestrs) selrestr(std::move(selrestrs)); 14 new(&p.noun_phrase_.selrestrs) std::set<std::string>(std::move(selrestrs));
15 new(&p.noun_phrase_.synrestrs) std::set<std::string>(std::move(synrestrs)); 15 new(&p.noun_phrase_.synrestrs) std::set<std::string>(std::move(synrestrs));
16 16
17 return p; 17 return p;
@@ -60,7 +60,7 @@ namespace verbly {
60 case type::noun_phrase: 60 case type::noun_phrase:
61 { 61 {
62 new(&result.noun_phrase_.role) std::string(other.noun_phrase_.role); 62 new(&result.noun_phrase_.role) std::string(other.noun_phrase_.role);
63 new(&result.noun_phrase_.selrestrs) selrestr(other.noun_phrase_.selrestrs); 63 new(&result.noun_phrase_.selrestrs) std::set<std::string>(other.noun_phrase_.selrestrs);
64 new(&result.noun_phrase_.synrestrs) std::set<std::string>(other.noun_phrase_.synrestrs); 64 new(&result.noun_phrase_.synrestrs) std::set<std::string>(other.noun_phrase_.synrestrs);
65 65
66 break; 66 break;
@@ -103,7 +103,7 @@ namespace verbly {
103 case type::noun_phrase: 103 case type::noun_phrase:
104 { 104 {
105 new(&noun_phrase_.role) std::string(other.noun_phrase_.role); 105 new(&noun_phrase_.role) std::string(other.noun_phrase_.role);
106 new(&noun_phrase_.selrestrs) selrestr(other.noun_phrase_.selrestrs); 106 new(&noun_phrase_.selrestrs) std::set<std::string>(other.noun_phrase_.selrestrs);
107 new(&noun_phrase_.synrestrs) std::set<std::string>(other.noun_phrase_.synrestrs); 107 new(&noun_phrase_.synrestrs) std::set<std::string>(other.noun_phrase_.synrestrs);
108 108
109 break; 109 break;
@@ -153,7 +153,7 @@ namespace verbly {
153 type tempType = first.type_; 153 type tempType = first.type_;
154 int tempId = first.id_; 154 int tempId = first.id_;
155 std::string tempRole; 155 std::string tempRole;
156 selrestr tempSelrestrs; 156 std::set<std::string> tempSelrestrs;
157 std::set<std::string> tempSynrestrs; 157 std::set<std::string> tempSynrestrs;
158 std::set<std::string> tempChoices; 158 std::set<std::string> tempChoices;
159 bool tempPrepLiteral; 159 bool tempPrepLiteral;
@@ -204,7 +204,7 @@ namespace verbly {
204 case type::noun_phrase: 204 case type::noun_phrase:
205 { 205 {
206 new(&first.noun_phrase_.role) std::string(std::move(second.noun_phrase_.role)); 206 new(&first.noun_phrase_.role) std::string(std::move(second.noun_phrase_.role));
207 new(&first.noun_phrase_.selrestrs) selrestr(std::move(second.noun_phrase_.selrestrs)); 207 new(&first.noun_phrase_.selrestrs) std::set<std::string>(std::move(second.noun_phrase_.selrestrs));
208 new(&first.noun_phrase_.synrestrs) std::set<std::string>(std::move(second.noun_phrase_.synrestrs)); 208 new(&first.noun_phrase_.synrestrs) std::set<std::string>(std::move(second.noun_phrase_.synrestrs));
209 209
210 break; 210 break;
@@ -244,7 +244,7 @@ namespace verbly {
244 case type::noun_phrase: 244 case type::noun_phrase:
245 { 245 {
246 new(&second.noun_phrase_.role) std::string(std::move(tempRole)); 246 new(&second.noun_phrase_.role) std::string(std::move(tempRole));
247 new(&second.noun_phrase_.selrestrs) selrestr(std::move(tempSelrestrs)); 247 new(&second.noun_phrase_.selrestrs) std::set<std::string>(std::move(tempSelrestrs));
248 new(&second.noun_phrase_.synrestrs) std::set<std::string>(std::move(tempSynrestrs)); 248 new(&second.noun_phrase_.synrestrs) std::set<std::string>(std::move(tempSynrestrs));
249 249
250 break; 250 break;
@@ -285,7 +285,7 @@ namespace verbly {
285 using set_type = std::set<std::string>; 285 using set_type = std::set<std::string>;
286 286
287 noun_phrase_.role.~string_type(); 287 noun_phrase_.role.~string_type();
288 noun_phrase_.selrestrs.~selrestr(); 288 noun_phrase_.selrestrs.~set_type();
289 noun_phrase_.synrestrs.~set_type(); 289 noun_phrase_.synrestrs.~set_type();
290 290
291 break; 291 break;
@@ -329,7 +329,7 @@ namespace verbly {
329 } 329 }
330 } 330 }
331 331
332 selrestr part::getNounSelrestrs() const 332 std::set<std::string> part::getNounSelrestrs() const
333 { 333 {
334 if (type_ == type::noun_phrase) 334 if (type_ == type::noun_phrase)
335 { 335 {
diff --git a/generator/part.h b/generator/part.h index 39ba1e7..01791f5 100644 --- a/generator/part.h +++ b/generator/part.h
@@ -3,7 +3,6 @@
3 3
4#include <string> 4#include <string>
5#include <set> 5#include <set>
6#include "../lib/selrestr.h"
7#include "../lib/enums.h" 6#include "../lib/enums.h"
8 7
9namespace verbly { 8namespace verbly {
@@ -17,7 +16,7 @@ namespace verbly {
17 16
18 // Static factories 17 // Static factories
19 18
20 static part createNounPhrase(std::string role, selrestr selrestrs, std::set<std::string> synrestrs); 19 static part createNounPhrase(std::string role, std::set<std::string> selrestrs, std::set<std::string> synrestrs);
21 20
22 static part createVerb(); 21 static part createVerb();
23 22
@@ -67,7 +66,7 @@ namespace verbly {
67 66
68 std::string getNounRole() const; 67 std::string getNounRole() const;
69 68
70 selrestr getNounSelrestrs() const; 69 std::set<std::string> getNounSelrestrs() const;
71 70
72 std::set<std::string> getNounSynrestrs() const; 71 std::set<std::string> getNounSynrestrs() const;
73 72
@@ -104,7 +103,7 @@ namespace verbly {
104 union { 103 union {
105 struct { 104 struct {
106 std::string role; 105 std::string role;
107 selrestr selrestrs; 106 std::set<std::string> selrestrs;
108 std::set<std::string> synrestrs; 107 std::set<std::string> synrestrs;
109 } noun_phrase_; 108 } noun_phrase_;
110 struct { 109 struct {
diff --git a/generator/role.h b/generator/role.h index 4884ef3..fccfa98 100644 --- a/generator/role.h +++ b/generator/role.h
@@ -3,7 +3,7 @@
3 3
4#include <stdexcept> 4#include <stdexcept>
5#include <string> 5#include <string>
6#include "../lib/selrestr.h" 6#include <set>
7 7
8namespace verbly { 8namespace verbly {
9 9
@@ -18,7 +18,7 @@ namespace verbly {
18 18
19 role( 19 role(
20 std::string name, 20 std::string name,
21 selrestr selrestrs = {}) : 21 std::set<std::string> selrestrs = {}) :
22 valid_(true), 22 valid_(true),
23 name_(name), 23 name_(name),
24 selrestrs_(selrestrs) 24 selrestrs_(selrestrs)
@@ -37,7 +37,7 @@ namespace verbly {
37 return name_; 37 return name_;
38 } 38 }
39 39
40 const selrestr& getSelrestrs() const 40 const std::set<std::string>& getSelrestrs() const
41 { 41 {
42 if (!valid_) 42 if (!valid_)
43 { 43 {
@@ -51,7 +51,7 @@ namespace verbly {
51 51
52 bool valid_ = false; 52 bool valid_ = false;
53 std::string name_; 53 std::string name_;
54 selrestr selrestrs_; 54 std::set<std::string> selrestrs_;
55 55
56 }; 56 };
57 57
diff --git a/generator/schema.sql b/generator/schema.sql index 33ebc28..2ac658c 100644 --- a/generator/schema.sql +++ b/generator/schema.sql
@@ -200,7 +200,6 @@ CREATE TABLE `parts` (
200 `part_index` INTEGER NOT NULL, 200 `part_index` INTEGER NOT NULL,
201 `type` INTEGER NOT NULL, 201 `type` INTEGER NOT NULL,
202 `role` VARCHAR(16), 202 `role` VARCHAR(16),
203 `selrestrs` BLOB,
204 `prepositions` BLOB, 203 `prepositions` BLOB,
205 `preposition_literality` SMALLINT, 204 `preposition_literality` SMALLINT,
206 `literal_value` VARCHAR(64) 205 `literal_value` VARCHAR(64)
@@ -215,3 +214,10 @@ CREATE TABLE `synrestrs` (
215); 214);
216 215
217CREATE INDEX `synrestrs_for` ON `synrestrs`(`part_id`); 216CREATE INDEX `synrestrs_for` ON `synrestrs`(`part_id`);
217
218CREATE TABLE `selrestrs` (
219 `part_id` INTEGER NOT NULL,
220 `selrestr` VARCHAR(32) NOT NULL
221);
222
223CREATE INDEX `selrestrs_for` ON `selrestrs`(`part_id`);
diff --git a/generator/vn.diff b/generator/vn.diff index 5d5e2f3..bbfd6cf 100644 --- a/generator/vn.diff +++ b/generator/vn.diff
@@ -1,8 +1,11 @@
1diff /Users/hatkirby/Downloads/new_vn 2/admit-65.xml datadir/vn/admit-65.xml 1diff /Users/hatkirby/Downloads/new_vn 2/admit-65.xml datadir/vn/admit-65.xml
2104c104 2104,106c104,105
3< <SELRESTRS logic="or"> 3< <SELRESTRS logic="or">
4< <SELRESTR Value="+" type="location"/>
5< <SELRESTR Value="-" type="region"/>
4--- 6---
5> <SELRESTRS> 7> <SELRESTRS>
8> <SELRESTR Value="+" type="non_region_location"/>
6diff /Users/hatkirby/Downloads/new_vn 2/amuse-31.1.xml datadir/vn/amuse-31.1.xml 9diff /Users/hatkirby/Downloads/new_vn 2/amuse-31.1.xml datadir/vn/amuse-31.1.xml
7270a271,273 10270a271,273
8> <THEMROLE type="Cause"> 11> <THEMROLE type="Cause">
@@ -30,6 +33,18 @@ diff /Users/hatkirby/Downloads/new_vn 2/animal_sounds-38.xml datadir/vn/animal_s
30diff /Users/hatkirby/Downloads/new_vn 2/assessment-34.1.xml datadir/vn/assessment-34.1.xml 33diff /Users/hatkirby/Downloads/new_vn 2/assessment-34.1.xml datadir/vn/assessment-34.1.xml
31103d102 34103d102
32< <LEX value="'s"/> 35< <LEX value="'s"/>
36diff /Users/hatkirby/Downloads/new_vn 2/assuming_position-50.xml datadir/vn/assuming_position-50.xml
3741,42c41
38< <SELRESTR Value="+" type="location"/>
39< <SELRESTR Value="-" type="region"/>
40---
41> <SELRESTR Value="+" type="non_region_location"/>
42diff /Users/hatkirby/Downloads/new_vn 2/banish-10.2.xml datadir/vn/banish-10.2.xml
4335,36c35
44< <SELRESTR Value="+" type="location"/>
45< <SELRESTR Value="-" type="region"/>
46---
47> <SELRESTR Value="+" type="non_region_location"/>
33diff /Users/hatkirby/Downloads/new_vn 2/battle-36.4.xml datadir/vn/battle-36.4.xml 48diff /Users/hatkirby/Downloads/new_vn 2/battle-36.4.xml datadir/vn/battle-36.4.xml
3496c96 4996c96
35< <SYNRESTR Value="+" type="what_extract"/> 50< <SYNRESTR Value="+" type="what_extract"/>
@@ -85,6 +100,20 @@ diff /Users/hatkirby/Downloads/new_vn 2/break-45.1.xml datadir/vn/break-45.1.xml
85> <SYNRESTRS> 100> <SYNRESTRS>
86> <SYNRESTR Value="+" type="adjp"/> 101> <SYNRESTR Value="+" type="adjp"/>
87> </SYNRESTRS> 102> </SYNRESTRS>
103diff /Users/hatkirby/Downloads/new_vn 2/bring-11.3.xml datadir/vn/bring-11.3.xml
10427,30c27
105< <SELRESTRS>
106< <SELRESTR Value="+" type="location"/>
107< <SELRESTR Value="-" type="region"/>
108< </SELRESTRS>
109---
110> <SELRESTR Value="+" type="non_region_location"/>
111diff /Users/hatkirby/Downloads/new_vn 2/butter-9.9.xml datadir/vn/butter-9.9.xml
112155,156c155
113< <SELRESTR Value="+" type="location"/>
114< <SELRESTR Value="-" type="region"/>
115---
116> <SELRESTR Value="+" type="non_region_location"/>
88diff /Users/hatkirby/Downloads/new_vn 2/characterize-29.2.xml datadir/vn/characterize-29.2.xml 117diff /Users/hatkirby/Downloads/new_vn 2/characterize-29.2.xml datadir/vn/characterize-29.2.xml
89107c107 118107c107
90< <LEX value="as"/> 119< <LEX value="as"/>
@@ -104,6 +133,31 @@ diff /Users/hatkirby/Downloads/new_vn 2/characterize-29.2.xml datadir/vn/charact
104> <SYNRESTR Value="+" type="adjp"/> 133> <SYNRESTR Value="+" type="adjp"/>
105> </SYNRESTRS> 134> </SYNRESTRS>
106> </NP> 135> </NP>
136diff /Users/hatkirby/Downloads/new_vn 2/cheat-10.6.xml datadir/vn/cheat-10.6.xml
13756,59c56
138< <SELRESTRS>
139< <SELRESTR Value="+" type="location"/>
140< <SELRESTR Value="-" type="region"/>
141< </SELRESTRS>
142---
143> <SELRESTR Value="+" type="non_region_location"/>
144diff /Users/hatkirby/Downloads/new_vn 2/chew-39.2.xml datadir/vn/chew-39.2.xml
14537,38c37
146< <SELRESTR Value="+" type="comestible"/>
147< <SELRESTR Value="+" type="solid"/>
148---
149> <SELRESTR Value="+" type="solid_food"/>
150155,156c154
151< <SELRESTR Value="+" type="comestible"/>
152< <SELRESTR Value="-" type="solid"/>
153---
154> <SELRESTR Value="+" type="non_solid_food"/>
155diff /Users/hatkirby/Downloads/new_vn 2/coil-9.6.xml datadir/vn/coil-9.6.xml
15622,23c22
157< <SELRESTR Value="+" type="nonrigid"/>
158< <SELRESTR Value="+" type="elongated"/>
159---
160> <SELRESTR Value="+" type="slinky"/>
107diff /Users/hatkirby/Downloads/new_vn 2/coloring-24.xml datadir/vn/coloring-24.xml 161diff /Users/hatkirby/Downloads/new_vn 2/coloring-24.xml datadir/vn/coloring-24.xml
10889c89,91 16289c89,91
109< <SYNRESTRS/> 163< <SYNRESTRS/>
@@ -118,6 +172,11 @@ diff /Users/hatkirby/Downloads/new_vn 2/confess-37.10.xml datadir/vn/confess-37.
118> <SYNRESTR Value="+" type="adjp"/> 172> <SYNRESTR Value="+" type="adjp"/>
119> </SYNRESTRS> 173> </SYNRESTRS>
120> </NP> 174> </NP>
175diff /Users/hatkirby/Downloads/new_vn 2/confine-92.xml datadir/vn/confine-92.xml
17618c18
177< <SELRESTRS>
178---
179> <SELRESTRS logic="or">
121diff /Users/hatkirby/Downloads/new_vn 2/consider-29.9.xml datadir/vn/consider-29.9.xml 180diff /Users/hatkirby/Downloads/new_vn 2/consider-29.9.xml datadir/vn/consider-29.9.xml
122191,193c191,193 181191,193c191,193
123< <SYNRESTRS> 182< <SYNRESTRS>
@@ -195,6 +254,47 @@ diff /Users/hatkirby/Downloads/new_vn 2/declare-29.4.xml datadir/vn/declare-29.4
195> <SYNRESTRS> 254> <SYNRESTRS>
196> <SYNRESTR Value="+" type="adjp"/> 255> <SYNRESTR Value="+" type="adjp"/>
197> </SYNRESTRS> 256> </SYNRESTRS>
257diff /Users/hatkirby/Downloads/new_vn 2/devour-39.4.xml datadir/vn/devour-39.4.xml
25826,27c26
259< <SELRESTR Value="+" type="comestible"/>
260< <SELRESTR Value="+" type="solid"/>
261---
262> <SELRESTR Value="+" type="solid_food"/>
26367,68c66
264< <SELRESTR Value="+" type="comestible"/>
265< <SELRESTR Value="-" type="solid"/>
266---
267> <SELRESTR Value="+" type="non_solid_food"/>
268diff /Users/hatkirby/Downloads/new_vn 2/drive-11.5.xml datadir/vn/drive-11.5.xml
26937,40c37
270< <SELRESTRS>
271< <SELRESTR Value="+" type="location"/>
272< <SELRESTR Value="-" type="region"/>
273< </SELRESTRS>
274---
275> <SELRESTR Value="+" type="non_region_location"/>
276diff /Users/hatkirby/Downloads/new_vn 2/eat-39.1.xml datadir/vn/eat-39.1.xml
27724,25c24
278< <SELRESTR Value="+" type="comestible"/>
279< <SELRESTR Value="+" type="solid"/>
280---
281> <SELRESTR Value="+" type="solid_food"/>
282148,149c147
283< <SELRESTR Value="+" type="comestible"/>
284< <SELRESTR Value="-" type="solid"/>
285---
286> <SELRESTR Value="+" type="non_solid_food"/>
287diff /Users/hatkirby/Downloads/new_vn 2/enforce-63.xml datadir/vn/enforce-63.xml
28811c11
289< <SELRESTRS>
290---
291> <SELRESTRS logic="or">
292diff /Users/hatkirby/Downloads/new_vn 2/entity_specific_modes_being-47.2.xml datadir/vn/entity_specific_modes_being-47.2.xml
29335,36c35
294< <SELRESTR Value="+" type="location"/>
295< <SELRESTR Value="-" type="region"/>
296---
297> <SELRESTR Value="+" type="non_region_location"/>
198diff /Users/hatkirby/Downloads/new_vn 2/estimate-34.2.xml datadir/vn/estimate-34.2.xml 298diff /Users/hatkirby/Downloads/new_vn 2/estimate-34.2.xml datadir/vn/estimate-34.2.xml
199123a124 299123a124
200> <LEX value="to be"/> 300> <LEX value="to be"/>
@@ -206,12 +306,53 @@ diff /Users/hatkirby/Downloads/new_vn 2/estimate-34.2.xml datadir/vn/estimate-34
206> <SYNRESTRS> 306> <SYNRESTRS>
207> <SYNRESTR Value="+" type="adjp"/> 307> <SYNRESTR Value="+" type="adjp"/>
208> </SYNRESTRS> 308> </SYNRESTRS>
309diff /Users/hatkirby/Downloads/new_vn 2/exchange-13.6.xml datadir/vn/exchange-13.6.xml
310329,330c329
311< <SELRESTR Value="+" type="location"/>
312< <SELRESTR Value="-" type="region"/>
313---
314> <SELRESTR Value="+" type="non_region_location"/>
315diff /Users/hatkirby/Downloads/new_vn 2/exist-47.1.xml datadir/vn/exist-47.1.xml
31613,14c13
317< <SELRESTR Value="+" type="location"/>
318< <SELRESTR Value="-" type="region"/>
319---
320> <SELRESTR Value="+" type="non_region_location"/>
321diff /Users/hatkirby/Downloads/new_vn 2/fill-9.8.xml datadir/vn/fill-9.8.xml
322132,133c132
323< <SELRESTR Value="+" type="location"/>
324< <SELRESTR Value="-" type="region"/>
325---
326> <SELRESTR Value="+" type="non_region_location"/>
327diff /Users/hatkirby/Downloads/new_vn 2/funnel-9.3.xml datadir/vn/funnel-9.3.xml
32830,31c30
329< <SELRESTR Value="+" type="location"/>
330< <SELRESTR Value="-" type="region"/>
331---
332> <SELRESTR Value="+" type="non_region_location"/>
209diff /Users/hatkirby/Downloads/new_vn 2/get-13.5.1.xml datadir/vn/get-13.5.1.xml 333diff /Users/hatkirby/Downloads/new_vn 2/get-13.5.1.xml datadir/vn/get-13.5.1.xml
21055,56c55 33455,56c55
211< <SELRESTR Value="-" type="location"/> 335< <SELRESTR Value="-" type="location"/>
212< <SELRESTR Value="-" type="region"/> 336< <SELRESTR Value="-" type="region"/>
213--- 337---
214> <SELRESTR Value="+" type="currency"/> 338> <SELRESTR Value="+" type="currency"/>
339diff /Users/hatkirby/Downloads/new_vn 2/gobble-39.3.xml datadir/vn/gobble-39.3.xml
34023,24c23
341< <SELRESTR Value="+" type="comestible"/>
342< <SELRESTR Value="+" type="solid"/>
343---
344> <SELRESTR Value="+" type="solid_food"/>
345118,119c117
346< <SELRESTR Value="+" type="comestible"/>
347< <SELRESTR Value="-" type="solid"/>
348---
349> <SELRESTR Value="+" type="non_solid_food"/>
350diff /Users/hatkirby/Downloads/new_vn 2/herd-47.5.2.xml datadir/vn/herd-47.5.2.xml
35129,30c29
352< <SELRESTR Value="+" type="concrete"/>
353< <SELRESTR Value="+" type="plural"/>
354---
355> <SELRESTR Value="+" type="group"/>
215diff /Users/hatkirby/Downloads/new_vn 2/hit-18.1.xml datadir/vn/hit-18.1.xml 356diff /Users/hatkirby/Downloads/new_vn 2/hit-18.1.xml datadir/vn/hit-18.1.xml
216234c234,236 357234c234,236
217< <SYNRESTRS/> 358< <SYNRESTRS/>
@@ -257,6 +398,23 @@ diff /Users/hatkirby/Downloads/new_vn 2/judgment-33.xml datadir/vn/judgment-33.x
257< </SYNRESTRS> 398< </SYNRESTRS>
258--- 399---
259> <SYNRESTRS/> 400> <SYNRESTRS/>
401diff /Users/hatkirby/Downloads/new_vn 2/keep-15.2.xml datadir/vn/keep-15.2.xml
40224,25c24
403< <SELRESTR Value="+" type="location"/>
404< <SELRESTR Value="-" type="region"/>
405---
406> <SELRESTR Value="+" type="non_region_location"/>
407diff /Users/hatkirby/Downloads/new_vn 2/leave-51.2.xml datadir/vn/leave-51.2.xml
40816,17c16
409< <SELRESTR Value="+" type="location"/>
410< <SELRESTR Value="-" type="region"/>
411---
412> <SELRESTR Value="+" type="non_region_location"/>
413diff /Users/hatkirby/Downloads/new_vn 2/light_emission-43.1.xml datadir/vn/light_emission-43.1.xml
41431c31
415< <SELRESTR Value="-" type="animate"/>
416---
417> <SELRESTR Value="+" type="inanimate"/>
260diff /Users/hatkirby/Downloads/new_vn 2/manner_speaking-37.3.xml datadir/vn/manner_speaking-37.3.xml 418diff /Users/hatkirby/Downloads/new_vn 2/manner_speaking-37.3.xml datadir/vn/manner_speaking-37.3.xml
261264c264,266 419264c264,266
262< <SYNRESTRS/> 420< <SYNRESTRS/>
@@ -270,6 +428,17 @@ diff /Users/hatkirby/Downloads/new_vn 2/manner_speaking-37.3.xml datadir/vn/mann
270> <SYNRESTRS> 428> <SYNRESTRS>
271> <SYNRESTR Value="+" type="quotation"/> 429> <SYNRESTR Value="+" type="quotation"/>
272> </SYNRESTRS> 430> </SYNRESTRS>
431diff /Users/hatkirby/Downloads/new_vn 2/matter-91.xml datadir/vn/matter-91.xml
43210c10
433< <SELRESTRS>
434---
435> <SELRESTRS logic="or">
436diff /Users/hatkirby/Downloads/new_vn 2/modes_of_being_with_motion-47.3.xml datadir/vn/modes_of_being_with_motion-47.3.xml
43764,65c64
438< <SELRESTR Value="+" type="location"/>
439< <SELRESTR Value="-" type="region"/>
440---
441> <SELRESTR Value="+" type="non_region_location"/>
273diff /Users/hatkirby/Downloads/new_vn 2/other_cos-45.4.xml datadir/vn/other_cos-45.4.xml 442diff /Users/hatkirby/Downloads/new_vn 2/other_cos-45.4.xml datadir/vn/other_cos-45.4.xml
274534c534,536 443534c534,536
275< <SYNRESTRS/> 444< <SYNRESTRS/>
@@ -277,6 +446,11 @@ diff /Users/hatkirby/Downloads/new_vn 2/other_cos-45.4.xml datadir/vn/other_cos-
277> <SYNRESTRS> 446> <SYNRESTRS>
278> <SYNRESTR Value="+" type="adjp"/> 447> <SYNRESTR Value="+" type="adjp"/>
279> </SYNRESTRS> 448> </SYNRESTRS>
449diff /Users/hatkirby/Downloads/new_vn 2/pay-68.xml datadir/vn/pay-68.xml
45013c13
451< <SELRESTRS>
452---
453> <SELRESTRS logic="or">
280diff /Users/hatkirby/Downloads/new_vn 2/pocket-9.10.xml datadir/vn/pocket-9.10.xml 454diff /Users/hatkirby/Downloads/new_vn 2/pocket-9.10.xml datadir/vn/pocket-9.10.xml
281256c256,258 455256c256,258
282< <SYNRESTRS/> 456< <SYNRESTRS/>
@@ -292,7 +466,24 @@ diff /Users/hatkirby/Downloads/new_vn 2/poison-42.2.xml datadir/vn/poison-42.2.x
292> <SYNRESTR Value="+" type="adjp"/> 466> <SYNRESTR Value="+" type="adjp"/>
293> </SYNRESTRS> 467> </SYNRESTRS>
294diff /Users/hatkirby/Downloads/new_vn 2/pour-9.5.xml datadir/vn/pour-9.5.xml 468diff /Users/hatkirby/Downloads/new_vn 2/pour-9.5.xml datadir/vn/pour-9.5.xml
29559,61c59,62 46924,27c24
470< <SELRESTRS>
471< <SELRESTR Value="+" type="concrete"/>
472< <SELRESTR Value="+" type="plural"/>
473< </SELRESTRS>
474---
475> <SELRESTR Value="+" type="group"/>
47632,33c29
477< <SELRESTR Value="+" type="location"/>
478< <SELRESTR Value="-" type="region"/>
479---
480> <SELRESTR Value="+" type="non_region_location"/>
48139,40c35
482< <SELRESTR Value="+" type="location"/>
483< <SELRESTR Value="-" type="region"/>
484---
485> <SELRESTR Value="+" type="non_region_location"/>
48659,61c54,57
296< <SELRESTRS> 487< <SELRESTRS>
297< <SELRESTR Value="+" type="path"/> 488< <SELRESTR Value="+" type="path"/>
298< <SELRESTR Value="-" type="dest_dir"/> 489< <SELRESTR Value="-" type="dest_dir"/>
@@ -301,7 +492,7 @@ diff /Users/hatkirby/Downloads/new_vn 2/pour-9.5.xml datadir/vn/pour-9.5.xml
301> <SELRESTR Value="+" type="dir"/> 492> <SELRESTR Value="+" type="dir"/>
302> <SELRESTR Value="+" type="src"/> 493> <SELRESTR Value="+" type="src"/>
303> <SELRESTR Value="+" type="dest_conf"/> 494> <SELRESTR Value="+" type="dest_conf"/>
304157,160c158,162 495157,160c153,157
305< <SELRESTRS> 496< <SELRESTRS>
306< <SELRESTR Value="+" type="path"/> 497< <SELRESTR Value="+" type="path"/>
307< <SELRESTR Value="-" type="dest_dir"/> 498< <SELRESTR Value="-" type="dest_dir"/>
@@ -319,6 +510,31 @@ diff /Users/hatkirby/Downloads/new_vn 2/push-12.xml datadir/vn/push-12.xml
319> <SYNRESTRS> 510> <SYNRESTRS>
320> <SYNRESTR Value="+" type="adjp"/> 511> <SYNRESTR Value="+" type="adjp"/>
321> </SYNRESTRS> 512> </SYNRESTRS>
513diff /Users/hatkirby/Downloads/new_vn 2/put-9.1.xml datadir/vn/put-9.1.xml
51435,36c35
515< <SELRESTR Value="+" type="location"/>
516< <SELRESTR Value="-" type="region"/>
517---
518> <SELRESTR Value="+" type="non_region_location"/>
519diff /Users/hatkirby/Downloads/new_vn 2/put_direction-9.4.xml datadir/vn/put_direction-9.4.xml
52030,31c30
521< <SELRESTR Value="+" type="location"/>
522< <SELRESTR Value="-" type="region"/>
523---
524> <SELRESTR Value="+" type="non_region_location"/>
525diff /Users/hatkirby/Downloads/new_vn 2/put_spatial-9.2.xml datadir/vn/put_spatial-9.2.xml
52625,26c25
527< <SELRESTR Value="+" type="location"/>
528< <SELRESTR Value="-" type="region"/>
529---
530> <SELRESTR Value="+" type="non_region_location"/>
531diff /Users/hatkirby/Downloads/new_vn 2/reach-51.8.xml datadir/vn/reach-51.8.xml
53212,13c12,13
533< <SELRESTRS>
534< <SELRESTR Value="+" type="concrete"/>
535---
536> <SELRESTRS logic="or">
537> <SELRESTR Value="+" type="animate"/>
322diff /Users/hatkirby/Downloads/new_vn 2/roll-51.3.1.xml datadir/vn/roll-51.3.1.xml 538diff /Users/hatkirby/Downloads/new_vn 2/roll-51.3.1.xml datadir/vn/roll-51.3.1.xml
323190c190,192 539190c190,192
324< <SYNRESTRS/> 540< <SYNRESTRS/>
@@ -357,8 +573,23 @@ diff /Users/hatkirby/Downloads/new_vn 2/seem-109.xml datadir/vn/seem-109.xml
357> <SYNRESTRS> 573> <SYNRESTRS>
358> <SYNRESTR Value="+" type="adjp"/> 574> <SYNRESTR Value="+" type="adjp"/>
359> </SYNRESTRS> 575> </SYNRESTRS>
576diff /Users/hatkirby/Downloads/new_vn 2/send-11.1.xml datadir/vn/send-11.1.xml
57741,44c41
578< <SELRESTRS>
579< <SELRESTR Value="+" type="location"/>
580< <SELRESTR Value="-" type="region"/>
581< </SELRESTRS>
582---
583> <SELRESTR Value="+" type="non_region_location"/>
360diff /Users/hatkirby/Downloads/new_vn 2/slide-11.2.xml datadir/vn/slide-11.2.xml 584diff /Users/hatkirby/Downloads/new_vn 2/slide-11.2.xml datadir/vn/slide-11.2.xml
36169,72c69,73 58527,30c27
586< <SELRESTRS>
587< <SELRESTR Value="+" type="location"/>
588< <SELRESTR Value="-" type="region"/>
589< </SELRESTRS>
590---
591> <SELRESTR Value="+" type="non_region_location"/>
59269,72c66,70
362< <SELRESTRS> 593< <SELRESTRS>
363< <SELRESTR Value="+" type="path"/> 594< <SELRESTR Value="+" type="path"/>
364< <SELRESTR Value="-" type="dest_dir"/> 595< <SELRESTR Value="-" type="dest_dir"/>
@@ -369,7 +600,7 @@ diff /Users/hatkirby/Downloads/new_vn 2/slide-11.2.xml datadir/vn/slide-11.2.xml
369> <SELRESTR Value="+" type="src"/> 600> <SELRESTR Value="+" type="src"/>
370> <SELRESTR Value="+" type="dest_conf"/> 601> <SELRESTR Value="+" type="dest_conf"/>
371> </SELRESTRS> 602> </SELRESTRS>
372218,221c219,223 603218,221c216,220
373< <SELRESTRS> 604< <SELRESTRS>
374< <SELRESTR Value="+" type="path"/> 605< <SELRESTR Value="+" type="path"/>
375< <SELRESTR Value="-" type="dest_dir"/> 606< <SELRESTR Value="-" type="dest_dir"/>
@@ -380,6 +611,22 @@ diff /Users/hatkirby/Downloads/new_vn 2/slide-11.2.xml datadir/vn/slide-11.2.xml
380> <SELRESTR Value="+" type="src"/> 611> <SELRESTR Value="+" type="src"/>
381> <SELRESTR Value="+" type="dest_conf"/> 612> <SELRESTR Value="+" type="dest_conf"/>
382> </SELRESTRS> 613> </SELRESTRS>
614diff /Users/hatkirby/Downloads/new_vn 2/smell_emission-43.3.xml datadir/vn/smell_emission-43.3.xml
61512c12
616< <SELRESTR Value="-" type="animate"/>
617---
618> <SELRESTR Value="+" type="inanimate"/>
619diff /Users/hatkirby/Downloads/new_vn 2/sound_emission-43.2.xml datadir/vn/sound_emission-43.2.xml
620138c138
621< <SELRESTR Value="-" type="animate"/>
622---
623> <SELRESTR Value="+" type="inanimate"/>
624diff /Users/hatkirby/Downloads/new_vn 2/sound_existence-47.4.xml datadir/vn/sound_existence-47.4.xml
62521,22c21
626< <SELRESTR Value="+" type="location"/>
627< <SELRESTR Value="-" type="region"/>
628---
629> <SELRESTR Value="+" type="non_region_location"/>
383diff /Users/hatkirby/Downloads/new_vn 2/spank-18.3.xml datadir/vn/spank-18.3.xml 630diff /Users/hatkirby/Downloads/new_vn 2/spank-18.3.xml datadir/vn/spank-18.3.xml
38469a70,72 63169a70,72
385> <THEMROLE type="Recipient"> 632> <THEMROLE type="Recipient">
@@ -405,6 +652,12 @@ diff /Users/hatkirby/Downloads/new_vn 2/spank-18.3.xml datadir/vn/spank-18.3.xml
405> <SYNRESTRS> 652> <SYNRESTRS>
406> <SYNRESTR Value="+" type="body_part"/> 653> <SYNRESTR Value="+" type="body_part"/>
407> </SYNRESTRS> 654> </SYNRESTRS>
655diff /Users/hatkirby/Downloads/new_vn 2/spatial_configuration-47.6.xml datadir/vn/spatial_configuration-47.6.xml
65666,67c66
657< <SELRESTR Value="+" type="location"/>
658< <SELRESTR Value="-" type="region"/>
659---
660> <SELRESTR Value="+" type="non_region_location"/>
408diff /Users/hatkirby/Downloads/new_vn 2/split-23.2.xml datadir/vn/split-23.2.xml 661diff /Users/hatkirby/Downloads/new_vn 2/split-23.2.xml datadir/vn/split-23.2.xml
40959c59 66259c59
410< <PREP value="off off of from"> 663< <PREP value="off off of from">
@@ -418,6 +671,41 @@ diff /Users/hatkirby/Downloads/new_vn 2/split-23.2.xml datadir/vn/split-23.2.xml
418< <PREP value="off off of from"> 671< <PREP value="off off of from">
419--- 672---
420> <PREP value="off off_of from"> 673> <PREP value="off off_of from">
674diff /Users/hatkirby/Downloads/new_vn 2/spray-9.7.xml datadir/vn/spray-9.7.xml
67519,20c19
676< <SELRESTR Value="+" type="location"/>
677< <SELRESTR Value="-" type="region"/>
678---
679> <SELRESTR Value="+" type="non_region_location"/>
680254,255c253
681< <SELRESTR Value="+" type="concrete"/>
682< <SELRESTR Value="+" type="plural"/>
683---
684> <SELRESTR Value="+" type="group"/>
685diff /Users/hatkirby/Downloads/new_vn 2/steal-10.5.xml datadir/vn/steal-10.5.xml
68655,58c55
687< <SELRESTRS>
688< <SELRESTR Value="+" type="location"/>
689< <SELRESTR Value="-" type="region"/>
690< </SELRESTRS>
691---
692> <SELRESTR Value="+" type="non_region_location"/>
693diff /Users/hatkirby/Downloads/new_vn 2/substance_emission-43.4.xml datadir/vn/substance_emission-43.4.xml
69440c40
695< <SELRESTR Value="-" type="animate"/>
696---
697> <SELRESTR Value="+" type="inanimate"/>
698diff /Users/hatkirby/Downloads/new_vn 2/swarm-47.5.1.xml datadir/vn/swarm-47.5.1.xml
6998,9c8
700< <SELRESTR Value="+" type="concrete"/>
701< <SELRESTR Value="+" type="plural"/>
702---
703> <SELRESTR Value="+" type="group"/>
70414,15c13
705< <SELRESTR Value="+" type="location"/>
706< <SELRESTR Value="-" type="region"/>
707---
708> <SELRESTR Value="+" type="non_region_location"/>
421diff /Users/hatkirby/Downloads/new_vn 2/swat-18.2.xml datadir/vn/swat-18.2.xml 709diff /Users/hatkirby/Downloads/new_vn 2/swat-18.2.xml datadir/vn/swat-18.2.xml
422264c264,266 710264c264,266
423< <SYNRESTRS/> 711< <SYNRESTRS/>
@@ -432,12 +720,25 @@ diff /Users/hatkirby/Downloads/new_vn 2/swat-18.2.xml datadir/vn/swat-18.2.xml
432> <SYNRESTR Value="+" type="adjp"/> 720> <SYNRESTR Value="+" type="adjp"/>
433> </SYNRESTRS> 721> </SYNRESTRS>
434diff /Users/hatkirby/Downloads/new_vn 2/tape-22.4.xml datadir/vn/tape-22.4.xml 722diff /Users/hatkirby/Downloads/new_vn 2/tape-22.4.xml datadir/vn/tape-22.4.xml
435364c364,366 72393,94c93
724< <SELRESTR Value="+" type="concrete"/>
725< <SELRESTR Value="-" type="animate"/>
726---
727> <SELRESTR Value="+" type="concrete_inanimate"/>
728364c363,365
436< <SYNRESTRS/> 729< <SYNRESTRS/>
437--- 730---
438> <SYNRESTRS> 731> <SYNRESTRS>
439> <SYNRESTR Value="+" type="adjp"/> 732> <SYNRESTR Value="+" type="adjp"/>
440> </SYNRESTRS> 733> </SYNRESTRS>
734diff /Users/hatkirby/Downloads/new_vn 2/throw-17.1.xml datadir/vn/throw-17.1.xml
73527,30c27
736< <SELRESTRS>
737< <SELRESTR Value="+" type="location"/>
738< <SELRESTR Value="-" type="region"/>
739< </SELRESTRS>
740---
741> <SELRESTR Value="+" type="non_region_location"/>
441diff /Users/hatkirby/Downloads/new_vn 2/vehicle-51.4.1.xml datadir/vn/vehicle-51.4.1.xml 742diff /Users/hatkirby/Downloads/new_vn 2/vehicle-51.4.1.xml datadir/vn/vehicle-51.4.1.xml
442227c227,229 743227c227,229
443< <SYNRESTRS/> 744< <SYNRESTRS/>
@@ -468,18 +769,32 @@ diff /Users/hatkirby/Downloads/new_vn 2/want-32.1.xml datadir/vn/want-32.1.xml
468> <SYNRESTR Value="+" type="adjp"/> 769> <SYNRESTR Value="+" type="adjp"/>
469> </SYNRESTRS> 770> </SYNRESTRS>
470diff /Users/hatkirby/Downloads/new_vn 2/wipe_instr-10.4.2.xml datadir/vn/wipe_instr-10.4.2.xml 771diff /Users/hatkirby/Downloads/new_vn 2/wipe_instr-10.4.2.xml datadir/vn/wipe_instr-10.4.2.xml
471178c178,180 77226,27c26
773< <SELRESTR Value="+" type="concrete"/>
774< <SELRESTR Value="-" type="animate"/>
775---
776> <SELRESTR Value="+" type="concrete_inanimate"/>
77737,38c36
778< <SELRESTR Value="+" type="concrete"/>
779< <SELRESTR Value="-" type="animate"/>
780---
781> <SELRESTR Value="+" type="concrete_inanimate"/>
782178c176,178
472< <SYNRESTRS/> 783< <SYNRESTRS/>
473--- 784---
474> <SYNRESTRS> 785> <SYNRESTRS>
475> <SYNRESTR Value="+" type="adjp"/> 786> <SYNRESTR Value="+" type="adjp"/>
476> </SYNRESTRS> 787> </SYNRESTRS>
477diff /Users/hatkirby/Downloads/new_vn 2/wipe_manner-10.4.1.xml datadir/vn/wipe_manner-10.4.1.xml 788diff /Users/hatkirby/Downloads/new_vn 2/wipe_manner-10.4.1.xml datadir/vn/wipe_manner-10.4.1.xml
478198c198,199 78937,38c37
790< <SELRESTR Value="+" type="concrete"/>
791< <SELRESTR Value="-" type="animate"/>
792---
793> <SELRESTR Value="+" type="concrete_inanimate"/>
794198c197
479< <SELRESTR Value="-" type="region"/> 795< <SELRESTR Value="-" type="region"/>
480--- 796---
481> <SELRESTR Value="+" type="location"/> 797> <SELRESTR Value="+" type="non_region_location"/>
482> <SELRESTR Value="-" type="region"/>
483diff /Users/hatkirby/Downloads/new_vn 2/wish-62.xml datadir/vn/wish-62.xml 798diff /Users/hatkirby/Downloads/new_vn 2/wish-62.xml datadir/vn/wish-62.xml
48491a92 79991a92
485> <LEX value="to be"/> 800> <LEX value="to be"/>
@@ -493,3 +808,8 @@ diff /Users/hatkirby/Downloads/new_vn 2/wish-62.xml datadir/vn/wish-62.xml
493> </SYNRESTRS> 808> </SYNRESTRS>
494122a124 809122a124
495> <ADJ/> 810> <ADJ/>
811diff /Users/hatkirby/Downloads/new_vn 2/withdraw-82.xml datadir/vn/withdraw-82.xml
8127c7
813< <SELRESTRS>
814---
815> <SELRESTRS logic="or">
diff --git a/lib/database.cpp b/lib/database.cpp index 563ec31..c7b37ec 100644 --- a/lib/database.cpp +++ b/lib/database.cpp
@@ -76,6 +76,38 @@ namespace verbly {
76 return query<pronunciation>(*this, ppdb_, std::move(where), std::move(sortOrder), limit); 76 return query<pronunciation>(*this, ppdb_, std::move(where), std::move(sortOrder), limit);
77 } 77 }
78 78
79 std::set<std::string> database::selrestrs(int partId) const
80 {
81 std::string queryString = "SELECT selrestr FROM selrestrs WHERE part_id = ?";
82
83 sqlite3_stmt* ppstmt;
84 if (sqlite3_prepare_v2(ppdb_, queryString.c_str(), queryString.length(), &ppstmt, NULL) != SQLITE_OK)
85 {
86 std::string errorMsg = sqlite3_errmsg(ppdb_);
87 sqlite3_finalize(ppstmt);
88
89 throw database_error("Error preparing query", errorMsg);
90 }
91
92 if (sqlite3_bind_int(ppstmt, 1, partId) != SQLITE_OK)
93 {
94 std::string errorMsg = sqlite3_errmsg(ppdb_);
95 sqlite3_finalize(ppstmt);
96
97 throw database_error("Error binding value to query", errorMsg);
98 }
99
100 std::set<std::string> result;
101 while (sqlite3_step(ppstmt) == SQLITE_ROW)
102 {
103 result.insert(reinterpret_cast<const char*>(sqlite3_column_blob(ppstmt, 0)));
104 }
105
106 sqlite3_finalize(ppstmt);
107
108 return result;
109 }
110
79 std::set<std::string> database::synrestrs(int partId) const 111 std::set<std::string> database::synrestrs(int partId) const
80 { 112 {
81 std::string queryString = "SELECT synrestr FROM synrestrs WHERE part_id = ?"; 113 std::string queryString = "SELECT synrestr FROM synrestrs WHERE part_id = ?";
diff --git a/lib/database.h b/lib/database.h index 0b10eba..5567061 100644 --- a/lib/database.h +++ b/lib/database.h
@@ -62,6 +62,8 @@ namespace verbly {
62 62
63 query<pronunciation> pronunciations(filter where, order sortOrder = {}, int limit = 1) const; 63 query<pronunciation> pronunciations(filter where, order sortOrder = {}, int limit = 1) const;
64 64
65 std::set<std::string> selrestrs(int partId) const;
66
65 std::set<std::string> synrestrs(int partId) const; 67 std::set<std::string> synrestrs(int partId) const;
66 68
67 private: 69 private:
diff --git a/lib/part.cpp b/lib/part.cpp index cbd951b..341d4bb 100644 --- a/lib/part.cpp +++ b/lib/part.cpp
@@ -1,14 +1,14 @@
1#include "part.h" 1#include "part.h"
2#include <stdexcept> 2#include <stdexcept>
3#include <sqlite3.h> 3#include <sqlite3.h>
4#include "selrestr.h"
5#include "database.h" 4#include "database.h"
5#include "util.h"
6 6
7namespace verbly { 7namespace verbly {
8 8
9 const object part::objectType = object::part; 9 const object part::objectType = object::part;
10 10
11 const std::list<std::string> part::select = {"part_id", "frame_id", "part_index", "type", "role", "selrestrs", "prepositions", "preposition_literality", "literal_value"}; 11 const std::list<std::string> part::select = {"part_id", "frame_id", "part_index", "type", "role", "prepositions", "preposition_literality", "literal_value"};
12 12
13 const field part::index = field::integerField(object::part, "part_index"); 13 const field part::index = field::integerField(object::part, "part_index");
14 const field part::type = field::integerField(object::part, "type"); 14 const field part::type = field::integerField(object::part, "type");
@@ -17,17 +17,21 @@ namespace verbly {
17 17
18 const field part::frames = field::joinField(object::part, "frame_id", object::frame); 18 const field part::frames = field::joinField(object::part, "frame_id", object::frame);
19 19
20 const field part::selrestr_field::selrestrJoin = field::joinField(object::part, "part_id", "selrestrs");
21 const field part::selrestr_field::selrestrField = field::stringField("selrestrs", "selrestr");
22
20 const field part::synrestr_field::synrestrJoin = field::joinField(object::part, "part_id", "synrestrs"); 23 const field part::synrestr_field::synrestrJoin = field::joinField(object::part, "part_id", "synrestrs");
21 const field part::synrestr_field::synrestrField = field::stringField("synrestrs", "synrestr"); 24 const field part::synrestr_field::synrestrField = field::stringField("synrestrs", "synrestr");
22 25
26 const part::selrestr_field part::selrestrs = {};
23 const part::synrestr_field part::synrestrs = {}; 27 const part::synrestr_field part::synrestrs = {};
24 28
25 part part::createNounPhrase(std::string role, selrestr selrestrs, std::set<std::string> synrestrs) 29 part part::createNounPhrase(std::string role, std::set<std::string> selrestrs, std::set<std::string> synrestrs)
26 { 30 {
27 part p(part_type::noun_phrase); 31 part p(part_type::noun_phrase);
28 32
29 new(&p.noun_phrase_.role) std::string(std::move(role)); 33 new(&p.noun_phrase_.role) std::string(std::move(role));
30 new(&p.noun_phrase_.selrestrs) selrestr(std::move(selrestrs)); 34 new(&p.noun_phrase_.selrestrs) std::set<std::string>(std::move(selrestrs));
31 new(&p.noun_phrase_.synrestrs) std::set<std::string>(std::move(synrestrs)); 35 new(&p.noun_phrase_.synrestrs) std::set<std::string>(std::move(synrestrs));
32 36
33 return p; 37 return p;
@@ -78,7 +82,7 @@ namespace verbly {
78 case part_type::noun_phrase: 82 case part_type::noun_phrase:
79 { 83 {
80 new(&noun_phrase_.role) std::string(reinterpret_cast<const char*>(sqlite3_column_blob(row, 4))); 84 new(&noun_phrase_.role) std::string(reinterpret_cast<const char*>(sqlite3_column_blob(row, 4)));
81 new(&noun_phrase_.selrestrs) selrestr(nlohmann::json::parse(reinterpret_cast<const char*>(sqlite3_column_blob(row, 5)))); 85 new(&noun_phrase_.selrestrs) std::set<std::string>(db.selrestrs(id));
82 new(&noun_phrase_.synrestrs) std::set<std::string>(db.synrestrs(id)); 86 new(&noun_phrase_.synrestrs) std::set<std::string>(db.synrestrs(id));
83 87
84 break; 88 break;
@@ -86,22 +90,17 @@ namespace verbly {
86 90
87 case part_type::preposition: 91 case part_type::preposition:
88 { 92 {
89 new(&preposition_.choices) std::vector<std::string>(); 93 std::string serializedChoices(reinterpret_cast<const char*>(sqlite3_column_blob(row, 5)));
90 preposition_.literal = (sqlite3_column_int(row, 7) == 1); 94 new(&preposition_.choices) std::vector<std::string>(split<std::vector<std::string>>(serializedChoices, ","));
91 95
92 std::string choicesJsonStr(reinterpret_cast<const char*>(sqlite3_column_blob(row, 6))); 96 preposition_.literal = (sqlite3_column_int(row, 6) == 1);
93 nlohmann::json choicesJson = nlohmann::json::parse(std::move(choicesJsonStr));
94 for (const nlohmann::json& choiceJson : choicesJson)
95 {
96 preposition_.choices.push_back(choiceJson.get<std::string>());
97 }
98 97
99 break; 98 break;
100 } 99 }
101 100
102 case part_type::literal: 101 case part_type::literal:
103 { 102 {
104 new(&literal_) std::string(reinterpret_cast<const char*>(sqlite3_column_blob(row, 8))); 103 new(&literal_) std::string(reinterpret_cast<const char*>(sqlite3_column_blob(row, 7)));
105 104
106 break; 105 break;
107 } 106 }
@@ -125,7 +124,7 @@ namespace verbly {
125 case part_type::noun_phrase: 124 case part_type::noun_phrase:
126 { 125 {
127 new(&noun_phrase_.role) std::string(other.noun_phrase_.role); 126 new(&noun_phrase_.role) std::string(other.noun_phrase_.role);
128 new(&noun_phrase_.selrestrs) selrestr(other.noun_phrase_.selrestrs); 127 new(&noun_phrase_.selrestrs) std::set<std::string>(other.noun_phrase_.selrestrs);
129 new(&noun_phrase_.synrestrs) std::set<std::string>(other.noun_phrase_.synrestrs); 128 new(&noun_phrase_.synrestrs) std::set<std::string>(other.noun_phrase_.synrestrs);
130 129
131 break; 130 break;
@@ -174,7 +173,7 @@ namespace verbly {
174 173
175 type tempType = first.type_; 174 type tempType = first.type_;
176 std::string tempRole; 175 std::string tempRole;
177 selrestr tempSelrestrs; 176 std::set<std::string> tempSelrestrs;
178 std::set<std::string> tempSynrestrs; 177 std::set<std::string> tempSynrestrs;
179 std::vector<std::string> tempChoices; 178 std::vector<std::string> tempChoices;
180 bool tempPrepLiteral; 179 bool tempPrepLiteral;
@@ -224,7 +223,7 @@ namespace verbly {
224 case type::noun_phrase: 223 case type::noun_phrase:
225 { 224 {
226 new(&first.noun_phrase_.role) std::string(std::move(second.noun_phrase_.role)); 225 new(&first.noun_phrase_.role) std::string(std::move(second.noun_phrase_.role));
227 new(&first.noun_phrase_.selrestrs) selrestr(std::move(second.noun_phrase_.selrestrs)); 226 new(&first.noun_phrase_.selrestrs) std::set<std::string>(std::move(second.noun_phrase_.selrestrs));
228 new(&first.noun_phrase_.synrestrs) std::set<std::string>(std::move(second.noun_phrase_.synrestrs)); 227 new(&first.noun_phrase_.synrestrs) std::set<std::string>(std::move(second.noun_phrase_.synrestrs));
229 228
230 break; 229 break;
@@ -263,7 +262,7 @@ namespace verbly {
263 case type::noun_phrase: 262 case type::noun_phrase:
264 { 263 {
265 new(&second.noun_phrase_.role) std::string(std::move(tempRole)); 264 new(&second.noun_phrase_.role) std::string(std::move(tempRole));
266 new(&second.noun_phrase_.selrestrs) selrestr(std::move(tempSelrestrs)); 265 new(&second.noun_phrase_.selrestrs) std::set<std::string>(std::move(tempSelrestrs));
267 new(&second.noun_phrase_.synrestrs) std::set<std::string>(std::move(tempSynrestrs)); 266 new(&second.noun_phrase_.synrestrs) std::set<std::string>(std::move(tempSynrestrs));
268 267
269 break; 268 break;
@@ -304,7 +303,7 @@ namespace verbly {
304 using set_type = std::set<std::string>; 303 using set_type = std::set<std::string>;
305 304
306 noun_phrase_.role.~string_type(); 305 noun_phrase_.role.~string_type();
307 noun_phrase_.selrestrs.~selrestr(); 306 noun_phrase_.selrestrs.~set_type();
308 noun_phrase_.synrestrs.~set_type(); 307 noun_phrase_.synrestrs.~set_type();
309 308
310 break; 309 break;
@@ -348,7 +347,7 @@ namespace verbly {
348 } 347 }
349 } 348 }
350 349
351 selrestr part::getNounSelrestrs() const 350 std::set<std::string> part::getNounSelrestrs() const
352 { 351 {
353 if (type_ == part_type::noun_phrase) 352 if (type_ == part_type::noun_phrase)
354 { 353 {
diff --git a/lib/part.h b/lib/part.h index 7180f57..450db3d 100644 --- a/lib/part.h +++ b/lib/part.h
@@ -5,7 +5,6 @@
5#include <vector> 5#include <vector>
6#include <set> 6#include <set>
7#include <list> 7#include <list>
8#include "selrestr.h"
9#include "field.h" 8#include "field.h"
10#include "filter.h" 9#include "filter.h"
11#include "enums.h" 10#include "enums.h"
@@ -21,7 +20,7 @@ namespace verbly {
21 20
22 // Static factories 21 // Static factories
23 22
24 static part createNounPhrase(std::string role, selrestr selrestrs, std::set<std::string> synrestrs); 23 static part createNounPhrase(std::string role, std::set<std::string> selrestrs, std::set<std::string> synrestrs);
25 24
26 static part createVerb(); 25 static part createVerb();
27 26
@@ -77,7 +76,7 @@ namespace verbly {
77 76
78 std::string getNounRole() const; 77 std::string getNounRole() const;
79 78
80 selrestr getNounSelrestrs() const; 79 std::set<std::string> getNounSelrestrs() const;
81 80
82 std::set<std::string> getNounSynrestrs() const; 81 std::set<std::string> getNounSynrestrs() const;
83 82
@@ -110,8 +109,21 @@ namespace verbly {
110 109
111 static const field frames; 110 static const field frames;
112 111
113 // Noun synrestr relationship 112 // Noun selrestr and synrestr relationships
114 113
114 class selrestr_field {
115 public:
116
117 filter operator%=(std::string selrestr) const;
118
119 private:
120
121 static const field selrestrJoin;
122 static const field selrestrField;
123 };
124
125 static const selrestr_field selrestrs;
126
115 class synrestr_field { 127 class synrestr_field {
116 public: 128 public:
117 129
@@ -138,7 +150,7 @@ namespace verbly {
138 union { 150 union {
139 struct { 151 struct {
140 std::string role; 152 std::string role;
141 selrestr selrestrs; 153 std::set<std::string> selrestrs;
142 std::set<std::string> synrestrs; 154 std::set<std::string> synrestrs;
143 } noun_phrase_; 155 } noun_phrase_;
144 struct { 156 struct {
diff --git a/lib/selrestr.cpp b/lib/selrestr.cpp deleted file mode 100644 index 8646871..0000000 --- a/lib/selrestr.cpp +++ /dev/null
@@ -1,309 +0,0 @@
1#include "selrestr.h"
2
3namespace verbly {
4
5 selrestr::selrestr(nlohmann::json data)
6 {
7 if (data.find("children") != data.end())
8 {
9 type_ = type::group;
10 new(&group_.children) std::list<selrestr>();
11
12 for (const nlohmann::json& child : data["children"])
13 {
14 group_.children.emplace_back(child);
15 }
16
17 group_.orlogic = (data["logic"] == "or");
18 } else if (data.find("type") != data.end())
19 {
20 type_ = type::singleton;
21 singleton_.pos = data["pos"].get<bool>();
22 new(&singleton_.restriction) std::string(data["type"].get<std::string>());
23 } else {
24 type_ = type::empty;
25 }
26 }
27
28 selrestr::selrestr(const selrestr& other)
29 {
30 type_ = other.type_;
31
32 switch (type_)
33 {
34 case type::singleton:
35 {
36 singleton_.pos = other.singleton_.pos;
37 new(&singleton_.restriction) std::string(other.singleton_.restriction);
38
39 break;
40 }
41
42 case type::group:
43 {
44 new(&group_.children) std::list<selrestr>(other.group_.children);
45 group_.orlogic = other.group_.orlogic;
46
47 break;
48 }
49
50 case type::empty:
51 {
52 break;
53 }
54 }
55 }
56
57 selrestr::selrestr(selrestr&& other) : selrestr()
58 {
59 swap(*this, other);
60 }
61
62 selrestr& selrestr::operator=(selrestr other)
63 {
64 swap(*this, other);
65
66 return *this;
67 }
68
69 void swap(selrestr& first, selrestr& second)
70 {
71 using type = selrestr::type;
72
73 type tempType = first.type_;
74 int tempPos;
75 std::string tempRestriction;
76 std::list<selrestr> tempChildren;
77 bool tempOrlogic;
78
79 switch (tempType)
80 {
81 case type::singleton:
82 {
83 tempPos = first.singleton_.pos;
84 tempRestriction = std::move(first.singleton_.restriction);
85
86 break;
87 }
88
89 case type::group:
90 {
91 tempChildren = std::move(first.group_.children);
92 tempOrlogic = first.group_.orlogic;
93
94 break;
95 }
96
97 case type::empty:
98 {
99 break;
100 }
101 }
102
103 first.~selrestr();
104
105 first.type_ = second.type_;
106
107 switch (first.type_)
108 {
109 case type::singleton:
110 {
111 first.singleton_.pos = second.singleton_.pos;
112 new(&first.singleton_.restriction) std::string(std::move(second.singleton_.restriction));
113
114 break;
115 }
116
117 case type::group:
118 {
119 new(&first.group_.children) std::list<selrestr>(std::move(second.group_.children));
120 first.group_.orlogic = second.group_.orlogic;
121
122 break;
123 }
124
125 case type::empty:
126 {
127 break;
128 }
129 }
130
131 second.~selrestr();
132
133 second.type_ = tempType;
134
135 switch (second.type_)
136 {
137 case type::singleton:
138 {
139 second.singleton_.pos = tempPos;
140 new(&second.singleton_.restriction) std::string(std::move(tempRestriction));
141
142 break;
143 }
144
145 case type::group:
146 {
147 new(&second.group_.children) std::list<selrestr>(std::move(tempChildren));
148 second.group_.orlogic = tempOrlogic;
149
150 break;
151 }
152
153 case type::empty:
154 {
155 break;
156 }
157 }
158 }
159
160 selrestr::~selrestr()
161 {
162 switch (type_)
163 {
164 case type::singleton:
165 {
166 using string_type = std::string;
167 singleton_.restriction.~string_type();
168
169 break;
170 }
171
172 case type::group:
173 {
174 using list_type = std::list<selrestr>;
175 group_.children.~list_type();
176
177 break;
178 }
179
180 case type::empty:
181 {
182 break;
183 }
184 }
185 }
186
187 selrestr::selrestr() : type_(type::empty)
188 {
189 }
190
191 selrestr::selrestr(
192 std::string restriction,
193 bool pos) :
194 type_(type::singleton)
195 {
196 new(&singleton_.restriction) std::string(std::move(restriction));
197 singleton_.pos = pos;
198 }
199
200 std::string selrestr::getRestriction() const
201 {
202 if (type_ == type::singleton)
203 {
204 return singleton_.restriction;
205 } else {
206 throw std::domain_error("Only singleton selrestrs have restrictions");
207 }
208 }
209
210 bool selrestr::getPos() const
211 {
212 if (type_ == type::singleton)
213 {
214 return singleton_.pos;
215 } else {
216 throw std::domain_error("Only singleton selrestrs have positivity flags");
217 }
218 }
219
220 selrestr::selrestr(
221 std::list<selrestr> children,
222 bool orlogic) :
223 type_(type::group)
224 {
225 new(&group_.children) std::list<selrestr>(std::move(children));
226 group_.orlogic = orlogic;
227 }
228
229 std::list<selrestr> selrestr::getChildren() const
230 {
231 if (type_ == type::group)
232 {
233 return group_.children;
234 } else {
235 throw std::domain_error("Only group selrestrs have children");
236 }
237 }
238
239 std::list<selrestr>::const_iterator selrestr::begin() const
240 {
241 if (type_ == type::group)
242 {
243 return std::begin(group_.children);
244 } else {
245 throw std::domain_error("Only group selrestrs have children");
246 }
247 }
248
249 std::list<selrestr>::const_iterator selrestr::end() const
250 {
251 if (type_ == type::group)
252 {
253 return std::end(group_.children);
254 } else {
255 throw std::domain_error("Only group selrestrs have children");
256 }
257 }
258
259 bool selrestr::getOrlogic() const
260 {
261 if (type_ == type::group)
262 {
263 return group_.orlogic;
264 } else {
265 throw std::domain_error("Only group selrestrs have logic");
266 }
267 }
268
269 nlohmann::json selrestr::toJson() const
270 {
271 switch (type_)
272 {
273 case type::empty:
274 {
275 return {};
276 }
277
278 case type::singleton:
279 {
280 return {
281 {"type", singleton_.restriction},
282 {"pos", singleton_.pos}
283 };
284 }
285
286 case type::group:
287 {
288 std::string logic;
289 if (group_.orlogic)
290 {
291 logic = "or";
292 } else {
293 logic = "and";
294 }
295
296 std::list<nlohmann::json> children;
297 std::transform(std::begin(group_.children), std::end(group_.children), std::back_inserter(children), [] (const selrestr& child) {
298 return child.toJson();
299 });
300
301 return {
302 {"logic", logic},
303 {"children", children}
304 };
305 }
306 }
307 }
308
309};
diff --git a/lib/selrestr.h b/lib/selrestr.h deleted file mode 100644 index a7cde0a..0000000 --- a/lib/selrestr.h +++ /dev/null
@@ -1,90 +0,0 @@
1#ifndef SELRESTR_H_50652FB7
2#define SELRESTR_H_50652FB7
3
4#include <list>
5#include <string>
6#include "../vendor/json/json.hpp"
7
8namespace verbly {
9
10 class selrestr {
11 public:
12 enum class type {
13 empty,
14 singleton,
15 group
16 };
17
18 // Construct from json
19
20 explicit selrestr(nlohmann::json json);
21
22 // Copy and move constructors
23
24 selrestr(const selrestr& other);
25 selrestr(selrestr&& other);
26
27 // Assignment
28
29 selrestr& operator=(selrestr other);
30
31 // Swap
32
33 friend void swap(selrestr& first, selrestr& second);
34
35 // Destructor
36
37 ~selrestr();
38
39 // Generic accessors
40
41 type getType() const
42 {
43 return type_;
44 }
45
46 // Empty
47
48 selrestr();
49
50 // Singleton
51
52 selrestr(std::string restriction, bool pos);
53
54 std::string getRestriction() const;
55
56 bool getPos() const;
57
58 // Group
59
60 selrestr(std::list<selrestr> children, bool orlogic);
61
62 std::list<selrestr> getChildren() const;
63
64 std::list<selrestr>::const_iterator begin() const;
65
66 std::list<selrestr>::const_iterator end() const;
67
68 bool getOrlogic() const;
69
70 // Helpers
71
72 nlohmann::json toJson() const;
73
74 private:
75 union {
76 struct {
77 bool pos;
78 std::string restriction;
79 } singleton_;
80 struct {
81 std::list<selrestr> children;
82 bool orlogic;
83 } group_;
84 };
85 type type_;
86 };
87
88};
89
90#endif /* end of include guard: SELRESTR_H_50652FB7 */
diff --git a/lib/verbly.h b/lib/verbly.h index 112907b..0f48a8c 100644 --- a/lib/verbly.h +++ b/lib/verbly.h
@@ -15,6 +15,5 @@
15#include "form.h" 15#include "form.h"
16#include "pronunciation.h" 16#include "pronunciation.h"
17#include "token.h" 17#include "token.h"
18#include "selrestr.h"
19 18
20#endif /* end of include guard: VERBLY_H_5B39CE50 */ 19#endif /* end of include guard: VERBLY_H_5B39CE50 */
diff --git a/vendor/json/json.hpp b/vendor/json/json.hpp deleted file mode 100644 index 23058be..0000000 --- a/vendor/json/json.hpp +++ /dev/null
@@ -1,12201 +0,0 @@
1/*
2 __ _____ _____ _____
3 __| | __| | | | JSON for Modern C++
4| | |__ | | | | | | version 2.0.9
5|_____|_____|_____|_|___| https://github.com/nlohmann/json
6
7Licensed under the MIT License <http://opensource.org/licenses/MIT>.
8Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
9
10Permission is hereby granted, free of charge, to any person obtaining a copy
11of this software and associated documentation files (the "Software"), to deal
12in the Software without restriction, including without limitation the rights
13to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14copies of the Software, and to permit persons to whom the Software is
15furnished to do so, subject to the following conditions:
16
17The above copyright notice and this permission notice shall be included in all
18copies or substantial portions of the Software.
19
20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26SOFTWARE.
27*/
28
29#ifndef NLOHMANN_JSON_HPP
30#define NLOHMANN_JSON_HPP
31
32#include <algorithm> // all_of, for_each, transform
33#include <array> // array
34#include <cassert> // assert
35#include <cctype> // isdigit
36#include <ciso646> // and, not, or
37#include <cmath> // isfinite, ldexp, signbit
38#include <cstddef> // nullptr_t, ptrdiff_t, size_t
39#include <cstdint> // int64_t, uint64_t
40#include <cstdlib> // strtod, strtof, strtold, strtoul
41#include <cstring> // strlen
42#include <functional> // function, hash, less
43#include <initializer_list> // initializer_list
44#include <iomanip> // setw
45#include <iostream> // istream, ostream
46#include <iterator> // advance, begin, bidirectional_iterator_tag, distance, end, inserter, iterator, iterator_traits, next, random_access_iterator_tag, reverse_iterator
47#include <limits> // numeric_limits
48#include <locale> // locale
49#include <map> // map
50#include <memory> // addressof, allocator, allocator_traits, unique_ptr
51#include <numeric> // accumulate
52#include <sstream> // stringstream
53#include <stdexcept> // domain_error, invalid_argument, out_of_range
54#include <string> // getline, stoi, string, to_string
55#include <type_traits> // add_pointer, enable_if, is_arithmetic, is_base_of, is_const, is_constructible, is_convertible, is_floating_point, is_integral, is_nothrow_move_assignable, std::is_nothrow_move_constructible, std::is_pointer, std::is_reference, std::is_same, remove_const, remove_pointer, remove_reference
56#include <utility> // declval, forward, make_pair, move, pair, swap
57#include <vector> // vector
58
59// exclude unsupported compilers
60#if defined(__clang__)
61 #define CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__)
62 #if CLANG_VERSION < 30400
63 #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers"
64 #endif
65#elif defined(__GNUC__)
66 #define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
67 #if GCC_VERSION < 40900
68 #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers"
69 #endif
70#endif
71
72// disable float-equal warnings on GCC/clang
73#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
74 #pragma GCC diagnostic push
75 #pragma GCC diagnostic ignored "-Wfloat-equal"
76#endif
77
78// disable documentation warnings on clang
79#if defined(__clang__)
80 #pragma GCC diagnostic push
81 #pragma GCC diagnostic ignored "-Wdocumentation"
82#endif
83
84// allow for portable deprecation warnings
85#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
86 #define JSON_DEPRECATED __attribute__((deprecated))
87#elif defined(_MSC_VER)
88 #define JSON_DEPRECATED __declspec(deprecated)
89#else
90 #define JSON_DEPRECATED
91#endif
92
93/*!
94@brief namespace for Niels Lohmann
95@see https://github.com/nlohmann
96@since version 1.0.0
97*/
98namespace nlohmann
99{
100
101
102/*!
103@brief unnamed namespace with internal helper functions
104@since version 1.0.0
105*/
106namespace
107{
108/*!
109@brief Helper to determine whether there's a key_type for T.
110
111Thus helper is used to tell associative containers apart from other containers
112such as sequence containers. For instance, `std::map` passes the test as it
113contains a `mapped_type`, whereas `std::vector` fails the test.
114
115@sa http://stackoverflow.com/a/7728728/266378
116@since version 1.0.0, overworked in version 2.0.6
117*/
118template<typename T>
119struct has_mapped_type
120{
121 private:
122 template <typename U, typename = typename U::mapped_type>
123 static int detect(U&&);
124
125 static void detect(...);
126 public:
127 static constexpr bool value =
128 std::is_integral<decltype(detect(std::declval<T>()))>::value;
129};
130
131}
132
133/*!
134@brief a class to store JSON values
135
136@tparam ObjectType type for JSON objects (`std::map` by default; will be used
137in @ref object_t)
138@tparam ArrayType type for JSON arrays (`std::vector` by default; will be used
139in @ref array_t)
140@tparam StringType type for JSON strings and object keys (`std::string` by
141default; will be used in @ref string_t)
142@tparam BooleanType type for JSON booleans (`bool` by default; will be used
143in @ref boolean_t)
144@tparam NumberIntegerType type for JSON integer numbers (`int64_t` by
145default; will be used in @ref number_integer_t)
146@tparam NumberUnsignedType type for JSON unsigned integer numbers (@c
147`uint64_t` by default; will be used in @ref number_unsigned_t)
148@tparam NumberFloatType type for JSON floating-point numbers (`double` by
149default; will be used in @ref number_float_t)
150@tparam AllocatorType type of the allocator to use (`std::allocator` by
151default)
152
153@requirement The class satisfies the following concept requirements:
154- Basic
155 - [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible):
156 JSON values can be default constructed. The result will be a JSON null value.
157 - [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible):
158 A JSON value can be constructed from an rvalue argument.
159 - [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible):
160 A JSON value can be copy-constructed from an lvalue expression.
161 - [MoveAssignable](http://en.cppreference.com/w/cpp/concept/MoveAssignable):
162 A JSON value van be assigned from an rvalue argument.
163 - [CopyAssignable](http://en.cppreference.com/w/cpp/concept/CopyAssignable):
164 A JSON value can be copy-assigned from an lvalue expression.
165 - [Destructible](http://en.cppreference.com/w/cpp/concept/Destructible):
166 JSON values can be destructed.
167- Layout
168 - [StandardLayoutType](http://en.cppreference.com/w/cpp/concept/StandardLayoutType):
169 JSON values have
170 [standard layout](http://en.cppreference.com/w/cpp/language/data_members#Standard_layout):
171 All non-static data members are private and standard layout types, the class
172 has no virtual functions or (virtual) base classes.
173- Library-wide
174 - [EqualityComparable](http://en.cppreference.com/w/cpp/concept/EqualityComparable):
175 JSON values can be compared with `==`, see @ref
176 operator==(const_reference,const_reference).
177 - [LessThanComparable](http://en.cppreference.com/w/cpp/concept/LessThanComparable):
178 JSON values can be compared with `<`, see @ref
179 operator<(const_reference,const_reference).
180 - [Swappable](http://en.cppreference.com/w/cpp/concept/Swappable):
181 Any JSON lvalue or rvalue of can be swapped with any lvalue or rvalue of
182 other compatible types, using unqualified function call @ref swap().
183 - [NullablePointer](http://en.cppreference.com/w/cpp/concept/NullablePointer):
184 JSON values can be compared against `std::nullptr_t` objects which are used
185 to model the `null` value.
186- Container
187 - [Container](http://en.cppreference.com/w/cpp/concept/Container):
188 JSON values can be used like STL containers and provide iterator access.
189 - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer);
190 JSON values can be used like STL containers and provide reverse iterator
191 access.
192
193@invariant The member variables @a m_value and @a m_type have the following
194relationship:
195- If `m_type == value_t::object`, then `m_value.object != nullptr`.
196- If `m_type == value_t::array`, then `m_value.array != nullptr`.
197- If `m_type == value_t::string`, then `m_value.string != nullptr`.
198The invariants are checked by member function assert_invariant().
199
200@internal
201@note ObjectType trick from http://stackoverflow.com/a/9860911
202@endinternal
203
204@see [RFC 7159: The JavaScript Object Notation (JSON) Data Interchange
205Format](http://rfc7159.net/rfc7159)
206
207@since version 1.0.0
208
209@nosubgrouping
210*/
211template <
212 template<typename U, typename V, typename... Args> class ObjectType = std::map,
213 template<typename U, typename... Args> class ArrayType = std::vector,
214 class StringType = std::string,
215 class BooleanType = bool,
216 class NumberIntegerType = std::int64_t,
217 class NumberUnsignedType = std::uint64_t,
218 class NumberFloatType = double,
219 template<typename U> class AllocatorType = std::allocator
220 >
221class basic_json
222{
223 private:
224 /// workaround type for MSVC
225 using basic_json_t = basic_json<ObjectType, ArrayType, StringType,
226 BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType,
227 AllocatorType>;
228
229 public:
230 // forward declarations
231 template<typename U> class iter_impl;
232 template<typename Base> class json_reverse_iterator;
233 class json_pointer;
234
235 /////////////////////
236 // container types //
237 /////////////////////
238
239 /// @name container types
240 /// The canonic container types to use @ref basic_json like any other STL
241 /// container.
242 /// @{
243
244 /// the type of elements in a basic_json container
245 using value_type = basic_json;
246
247 /// the type of an element reference
248 using reference = value_type&;
249 /// the type of an element const reference
250 using const_reference = const value_type&;
251
252 /// a type to represent differences between iterators
253 using difference_type = std::ptrdiff_t;
254 /// a type to represent container sizes
255 using size_type = std::size_t;
256
257 /// the allocator type
258 using allocator_type = AllocatorType<basic_json>;
259
260 /// the type of an element pointer
261 using pointer = typename std::allocator_traits<allocator_type>::pointer;
262 /// the type of an element const pointer
263 using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer;
264
265 /// an iterator for a basic_json container
266 using iterator = iter_impl<basic_json>;
267 /// a const iterator for a basic_json container
268 using const_iterator = iter_impl<const basic_json>;
269 /// a reverse iterator for a basic_json container
270 using reverse_iterator = json_reverse_iterator<typename basic_json::iterator>;
271 /// a const reverse iterator for a basic_json container
272 using const_reverse_iterator = json_reverse_iterator<typename basic_json::const_iterator>;
273
274 /// @}
275
276
277 /*!
278 @brief returns the allocator associated with the container
279 */
280 static allocator_type get_allocator()
281 {
282 return allocator_type();
283 }
284
285
286 ///////////////////////////
287 // JSON value data types //
288 ///////////////////////////
289
290 /// @name JSON value data types
291 /// The data types to store a JSON value. These types are derived from
292 /// the template arguments passed to class @ref basic_json.
293 /// @{
294
295 /*!
296 @brief a type for an object
297
298 [RFC 7159](http://rfc7159.net/rfc7159) describes JSON objects as follows:
299 > An object is an unordered collection of zero or more name/value pairs,
300 > where a name is a string and a value is a string, number, boolean, null,
301 > object, or array.
302
303 To store objects in C++, a type is defined by the template parameters
304 described below.
305
306 @tparam ObjectType the container to store objects (e.g., `std::map` or
307 `std::unordered_map`)
308 @tparam StringType the type of the keys or names (e.g., `std::string`).
309 The comparison function `std::less<StringType>` is used to order elements
310 inside the container.
311 @tparam AllocatorType the allocator to use for objects (e.g.,
312 `std::allocator`)
313
314 #### Default type
315
316 With the default values for @a ObjectType (`std::map`), @a StringType
317 (`std::string`), and @a AllocatorType (`std::allocator`), the default
318 value for @a object_t is:
319
320 @code {.cpp}
321 std::map<
322 std::string, // key_type
323 basic_json, // value_type
324 std::less<std::string>, // key_compare
325 std::allocator<std::pair<const std::string, basic_json>> // allocator_type
326 >
327 @endcode
328
329 #### Behavior
330
331 The choice of @a object_t influences the behavior of the JSON class. With
332 the default type, objects have the following behavior:
333
334 - When all names are unique, objects will be interoperable in the sense
335 that all software implementations receiving that object will agree on
336 the name-value mappings.
337 - When the names within an object are not unique, later stored name/value
338 pairs overwrite previously stored name/value pairs, leaving the used
339 names unique. For instance, `{"key": 1}` and `{"key": 2, "key": 1}` will
340 be treated as equal and both stored as `{"key": 1}`.
341 - Internally, name/value pairs are stored in lexicographical order of the
342 names. Objects will also be serialized (see @ref dump) in this order.
343 For instance, `{"b": 1, "a": 2}` and `{"a": 2, "b": 1}` will be stored
344 and serialized as `{"a": 2, "b": 1}`.
345 - When comparing objects, the order of the name/value pairs is irrelevant.
346 This makes objects interoperable in the sense that they will not be
347 affected by these differences. For instance, `{"b": 1, "a": 2}` and
348 `{"a": 2, "b": 1}` will be treated as equal.
349
350 #### Limits
351
352 [RFC 7159](http://rfc7159.net/rfc7159) specifies:
353 > An implementation may set limits on the maximum depth of nesting.
354
355 In this class, the object's limit of nesting is not constraint explicitly.
356 However, a maximum depth of nesting may be introduced by the compiler or
357 runtime environment. A theoretical limit can be queried by calling the
358 @ref max_size function of a JSON object.
359
360 #### Storage
361
362 Objects are stored as pointers in a @ref basic_json type. That is, for any
363 access to object values, a pointer of type `object_t*` must be
364 dereferenced.
365
366 @sa @ref array_t -- type for an array value
367
368 @since version 1.0.0
369
370 @note The order name/value pairs are added to the object is *not*
371 preserved by the library. Therefore, iterating an object may return
372 name/value pairs in a different order than they were originally stored. In
373 fact, keys will be traversed in alphabetical order as `std::map` with
374 `std::less` is used by default. Please note this behavior conforms to [RFC
375 7159](http://rfc7159.net/rfc7159), because any order implements the
376 specified "unordered" nature of JSON objects.
377 */
378 using object_t = ObjectType<StringType,
379 basic_json,
380 std::less<StringType>,
381 AllocatorType<std::pair<const StringType,
382 basic_json>>>;
383
384 /*!
385 @brief a type for an array
386
387 [RFC 7159](http://rfc7159.net/rfc7159) describes JSON arrays as follows:
388 > An array is an ordered sequence of zero or more values.
389
390 To store objects in C++, a type is defined by the template parameters
391 explained below.
392
393 @tparam ArrayType container type to store arrays (e.g., `std::vector` or
394 `std::list`)
395 @tparam AllocatorType allocator to use for arrays (e.g., `std::allocator`)
396
397 #### Default type
398
399 With the default values for @a ArrayType (`std::vector`) and @a
400 AllocatorType (`std::allocator`), the default value for @a array_t is:
401
402 @code {.cpp}
403 std::vector<
404 basic_json, // value_type
405 std::allocator<basic_json> // allocator_type
406 >
407 @endcode
408
409 #### Limits
410
411 [RFC 7159](http://rfc7159.net/rfc7159) specifies:
412 > An implementation may set limits on the maximum depth of nesting.
413
414 In this class, the array's limit of nesting is not constraint explicitly.
415 However, a maximum depth of nesting may be introduced by the compiler or
416 runtime environment. A theoretical limit can be queried by calling the
417 @ref max_size function of a JSON array.
418
419 #### Storage
420
421 Arrays are stored as pointers in a @ref basic_json type. That is, for any
422 access to array values, a pointer of type `array_t*` must be dereferenced.
423
424 @sa @ref object_t -- type for an object value
425
426 @since version 1.0.0
427 */
428 using array_t = ArrayType<basic_json, AllocatorType<basic_json>>;
429
430 /*!
431 @brief a type for a string
432
433 [RFC 7159](http://rfc7159.net/rfc7159) describes JSON strings as follows:
434 > A string is a sequence of zero or more Unicode characters.
435
436 To store objects in C++, a type is defined by the template parameter
437 described below. Unicode values are split by the JSON class into
438 byte-sized characters during deserialization.
439
440 @tparam StringType the container to store strings (e.g., `std::string`).
441 Note this container is used for keys/names in objects, see @ref object_t.
442
443 #### Default type
444
445 With the default values for @a StringType (`std::string`), the default
446 value for @a string_t is:
447
448 @code {.cpp}
449 std::string
450 @endcode
451
452 #### String comparison
453
454 [RFC 7159](http://rfc7159.net/rfc7159) states:
455 > Software implementations are typically required to test names of object
456 > members for equality. Implementations that transform the textual
457 > representation into sequences of Unicode code units and then perform the
458 > comparison numerically, code unit by code unit, are interoperable in the
459 > sense that implementations will agree in all cases on equality or
460 > inequality of two strings. For example, implementations that compare
461 > strings with escaped characters unconverted may incorrectly find that
462 > `"a\\b"` and `"a\u005Cb"` are not equal.
463
464 This implementation is interoperable as it does compare strings code unit
465 by code unit.
466
467 #### Storage
468
469 String values are stored as pointers in a @ref basic_json type. That is,
470 for any access to string values, a pointer of type `string_t*` must be
471 dereferenced.
472
473 @since version 1.0.0
474 */
475 using string_t = StringType;
476
477 /*!
478 @brief a type for a boolean
479
480 [RFC 7159](http://rfc7159.net/rfc7159) implicitly describes a boolean as a
481 type which differentiates the two literals `true` and `false`.
482
483 To store objects in C++, a type is defined by the template parameter @a
484 BooleanType which chooses the type to use.
485
486 #### Default type
487
488 With the default values for @a BooleanType (`bool`), the default value for
489 @a boolean_t is:
490
491 @code {.cpp}
492 bool
493 @endcode
494
495 #### Storage
496
497 Boolean values are stored directly inside a @ref basic_json type.
498
499 @since version 1.0.0
500 */
501 using boolean_t = BooleanType;
502
503 /*!
504 @brief a type for a number (integer)
505
506 [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows:
507 > The representation of numbers is similar to that used in most
508 > programming languages. A number is represented in base 10 using decimal
509 > digits. It contains an integer component that may be prefixed with an
510 > optional minus sign, which may be followed by a fraction part and/or an
511 > exponent part. Leading zeros are not allowed. (...) Numeric values that
512 > cannot be represented in the grammar below (such as Infinity and NaN)
513 > are not permitted.
514
515 This description includes both integer and floating-point numbers.
516 However, C++ allows more precise storage if it is known whether the number
517 is a signed integer, an unsigned integer or a floating-point number.
518 Therefore, three different types, @ref number_integer_t, @ref
519 number_unsigned_t and @ref number_float_t are used.
520
521 To store integer numbers in C++, a type is defined by the template
522 parameter @a NumberIntegerType which chooses the type to use.
523
524 #### Default type
525
526 With the default values for @a NumberIntegerType (`int64_t`), the default
527 value for @a number_integer_t is:
528
529 @code {.cpp}
530 int64_t
531 @endcode
532
533 #### Default behavior
534
535 - The restrictions about leading zeros is not enforced in C++. Instead,
536 leading zeros in integer literals lead to an interpretation as octal
537 number. Internally, the value will be stored as decimal number. For
538 instance, the C++ integer literal `010` will be serialized to `8`.
539 During deserialization, leading zeros yield an error.
540 - Not-a-number (NaN) values will be serialized to `null`.
541
542 #### Limits
543
544 [RFC 7159](http://rfc7159.net/rfc7159) specifies:
545 > An implementation may set limits on the range and precision of numbers.
546
547 When the default type is used, the maximal integer number that can be
548 stored is `9223372036854775807` (INT64_MAX) and the minimal integer number
549 that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers
550 that are out of range will yield over/underflow when used in a
551 constructor. During deserialization, too large or small integer numbers
552 will be automatically be stored as @ref number_unsigned_t or @ref
553 number_float_t.
554
555 [RFC 7159](http://rfc7159.net/rfc7159) further states:
556 > Note that when such software is used, numbers that are integers and are
557 > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense
558 > that implementations will agree exactly on their numeric values.
559
560 As this range is a subrange of the exactly supported range [INT64_MIN,
561 INT64_MAX], this class's integer type is interoperable.
562
563 #### Storage
564
565 Integer number values are stored directly inside a @ref basic_json type.
566
567 @sa @ref number_float_t -- type for number values (floating-point)
568
569 @sa @ref number_unsigned_t -- type for number values (unsigned integer)
570
571 @since version 1.0.0
572 */
573 using number_integer_t = NumberIntegerType;
574
575 /*!
576 @brief a type for a number (unsigned)
577
578 [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows:
579 > The representation of numbers is similar to that used in most
580 > programming languages. A number is represented in base 10 using decimal
581 > digits. It contains an integer component that may be prefixed with an
582 > optional minus sign, which may be followed by a fraction part and/or an
583 > exponent part. Leading zeros are not allowed. (...) Numeric values that
584 > cannot be represented in the grammar below (such as Infinity and NaN)
585 > are not permitted.
586
587 This description includes both integer and floating-point numbers.
588 However, C++ allows more precise storage if it is known whether the number
589 is a signed integer, an unsigned integer or a floating-point number.
590 Therefore, three different types, @ref number_integer_t, @ref
591 number_unsigned_t and @ref number_float_t are used.
592
593 To store unsigned integer numbers in C++, a type is defined by the
594 template parameter @a NumberUnsignedType which chooses the type to use.
595
596 #### Default type
597
598 With the default values for @a NumberUnsignedType (`uint64_t`), the
599 default value for @a number_unsigned_t is:
600
601 @code {.cpp}
602 uint64_t
603 @endcode
604
605 #### Default behavior
606
607 - The restrictions about leading zeros is not enforced in C++. Instead,
608 leading zeros in integer literals lead to an interpretation as octal
609 number. Internally, the value will be stored as decimal number. For
610 instance, the C++ integer literal `010` will be serialized to `8`.
611 During deserialization, leading zeros yield an error.
612 - Not-a-number (NaN) values will be serialized to `null`.
613
614 #### Limits
615
616 [RFC 7159](http://rfc7159.net/rfc7159) specifies:
617 > An implementation may set limits on the range and precision of numbers.
618
619 When the default type is used, the maximal integer number that can be
620 stored is `18446744073709551615` (UINT64_MAX) and the minimal integer
621 number that can be stored is `0`. Integer numbers that are out of range
622 will yield over/underflow when used in a constructor. During
623 deserialization, too large or small integer numbers will be automatically
624 be stored as @ref number_integer_t or @ref number_float_t.
625
626 [RFC 7159](http://rfc7159.net/rfc7159) further states:
627 > Note that when such software is used, numbers that are integers and are
628 > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense
629 > that implementations will agree exactly on their numeric values.
630
631 As this range is a subrange (when considered in conjunction with the
632 number_integer_t type) of the exactly supported range [0, UINT64_MAX],
633 this class's integer type is interoperable.
634
635 #### Storage
636
637 Integer number values are stored directly inside a @ref basic_json type.
638
639 @sa @ref number_float_t -- type for number values (floating-point)
640 @sa @ref number_integer_t -- type for number values (integer)
641
642 @since version 2.0.0
643 */
644 using number_unsigned_t = NumberUnsignedType;
645
646 /*!
647 @brief a type for a number (floating-point)
648
649 [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows:
650 > The representation of numbers is similar to that used in most
651 > programming languages. A number is represented in base 10 using decimal
652 > digits. It contains an integer component that may be prefixed with an
653 > optional minus sign, which may be followed by a fraction part and/or an
654 > exponent part. Leading zeros are not allowed. (...) Numeric values that
655 > cannot be represented in the grammar below (such as Infinity and NaN)
656 > are not permitted.
657
658 This description includes both integer and floating-point numbers.
659 However, C++ allows more precise storage if it is known whether the number
660 is a signed integer, an unsigned integer or a floating-point number.
661 Therefore, three different types, @ref number_integer_t, @ref
662 number_unsigned_t and @ref number_float_t are used.
663
664 To store floating-point numbers in C++, a type is defined by the template
665 parameter @a NumberFloatType which chooses the type to use.
666
667 #### Default type
668
669 With the default values for @a NumberFloatType (`double`), the default
670 value for @a number_float_t is:
671
672 @code {.cpp}
673 double
674 @endcode
675
676 #### Default behavior
677
678 - The restrictions about leading zeros is not enforced in C++. Instead,
679 leading zeros in floating-point literals will be ignored. Internally,
680 the value will be stored as decimal number. For instance, the C++
681 floating-point literal `01.2` will be serialized to `1.2`. During
682 deserialization, leading zeros yield an error.
683 - Not-a-number (NaN) values will be serialized to `null`.
684
685 #### Limits
686
687 [RFC 7159](http://rfc7159.net/rfc7159) states:
688 > This specification allows implementations to set limits on the range and
689 > precision of numbers accepted. Since software that implements IEEE
690 > 754-2008 binary64 (double precision) numbers is generally available and
691 > widely used, good interoperability can be achieved by implementations
692 > that expect no more precision or range than these provide, in the sense
693 > that implementations will approximate JSON numbers within the expected
694 > precision.
695
696 This implementation does exactly follow this approach, as it uses double
697 precision floating-point numbers. Note values smaller than
698 `-1.79769313486232e+308` and values greater than `1.79769313486232e+308`
699 will be stored as NaN internally and be serialized to `null`.
700
701 #### Storage
702
703 Floating-point number values are stored directly inside a @ref basic_json
704 type.
705
706 @sa @ref number_integer_t -- type for number values (integer)
707
708 @sa @ref number_unsigned_t -- type for number values (unsigned integer)
709
710 @since version 1.0.0
711 */
712 using number_float_t = NumberFloatType;
713
714 /// @}
715
716
717 ///////////////////////////
718 // JSON type enumeration //
719 ///////////////////////////
720
721 /*!
722 @brief the JSON type enumeration
723
724 This enumeration collects the different JSON types. It is internally used
725 to distinguish the stored values, and the functions @ref is_null(), @ref
726 is_object(), @ref is_array(), @ref is_string(), @ref is_boolean(), @ref
727 is_number() (with @ref is_number_integer(), @ref is_number_unsigned(), and
728 @ref is_number_float()), @ref is_discarded(), @ref is_primitive(), and
729 @ref is_structured() rely on it.
730
731 @note There are three enumeration entries (number_integer,
732 number_unsigned, and number_float), because the library distinguishes
733 these three types for numbers: @ref number_unsigned_t is used for unsigned
734 integers, @ref number_integer_t is used for signed integers, and @ref
735 number_float_t is used for floating-point numbers or to approximate
736 integers which do not fit in the limits of their respective type.
737
738 @sa @ref basic_json(const value_t value_type) -- create a JSON value with
739 the default value for a given type
740
741 @since version 1.0.0
742 */
743 enum class value_t : uint8_t
744 {
745 null, ///< null value
746 object, ///< object (unordered set of name/value pairs)
747 array, ///< array (ordered collection of values)
748 string, ///< string value
749 boolean, ///< boolean value
750 number_integer, ///< number value (signed integer)
751 number_unsigned, ///< number value (unsigned integer)
752 number_float, ///< number value (floating-point)
753 discarded ///< discarded by the the parser callback function
754 };
755
756
757 private:
758
759 /// helper for exception-safe object creation
760 template<typename T, typename... Args>
761 static T* create(Args&& ... args)
762 {
763 AllocatorType<T> alloc;
764 auto deleter = [&](T * object)
765 {
766 alloc.deallocate(object, 1);
767 };
768 std::unique_ptr<T, decltype(deleter)> object(alloc.allocate(1), deleter);
769 alloc.construct(object.get(), std::forward<Args>(args)...);
770 assert(object.get() != nullptr);
771 return object.release();
772 }
773
774 ////////////////////////
775 // JSON value storage //
776 ////////////////////////
777
778 /*!
779 @brief a JSON value
780
781 The actual storage for a JSON value of the @ref basic_json class. This
782 union combines the different storage types for the JSON value types
783 defined in @ref value_t.
784
785 JSON type | value_t type | used type
786 --------- | --------------- | ------------------------
787 object | object | pointer to @ref object_t
788 array | array | pointer to @ref array_t
789 string | string | pointer to @ref string_t
790 boolean | boolean | @ref boolean_t
791 number | number_integer | @ref number_integer_t
792 number | number_unsigned | @ref number_unsigned_t
793 number | number_float | @ref number_float_t
794 null | null | *no value is stored*
795
796 @note Variable-length types (objects, arrays, and strings) are stored as
797 pointers. The size of the union should not exceed 64 bits if the default
798 value types are used.
799
800 @since version 1.0.0
801 */
802 union json_value
803 {
804 /// object (stored with pointer to save storage)
805 object_t* object;
806 /// array (stored with pointer to save storage)
807 array_t* array;
808 /// string (stored with pointer to save storage)
809 string_t* string;
810 /// boolean
811 boolean_t boolean;
812 /// number (integer)
813 number_integer_t number_integer;
814 /// number (unsigned integer)
815 number_unsigned_t number_unsigned;
816 /// number (floating-point)
817 number_float_t number_float;
818
819 /// default constructor (for null values)
820 json_value() = default;
821 /// constructor for booleans
822 json_value(boolean_t v) noexcept : boolean(v) {}
823 /// constructor for numbers (integer)
824 json_value(number_integer_t v) noexcept : number_integer(v) {}
825 /// constructor for numbers (unsigned)
826 json_value(number_unsigned_t v) noexcept : number_unsigned(v) {}
827 /// constructor for numbers (floating-point)
828 json_value(number_float_t v) noexcept : number_float(v) {}
829 /// constructor for empty values of a given type
830 json_value(value_t t)
831 {
832 switch (t)
833 {
834 case value_t::object:
835 {
836 object = create<object_t>();
837 break;
838 }
839
840 case value_t::array:
841 {
842 array = create<array_t>();
843 break;
844 }
845
846 case value_t::string:
847 {
848 string = create<string_t>("");
849 break;
850 }
851
852 case value_t::boolean:
853 {
854 boolean = boolean_t(false);
855 break;
856 }
857
858 case value_t::number_integer:
859 {
860 number_integer = number_integer_t(0);
861 break;
862 }
863
864 case value_t::number_unsigned:
865 {
866 number_unsigned = number_unsigned_t(0);
867 break;
868 }
869
870 case value_t::number_float:
871 {
872 number_float = number_float_t(0.0);
873 break;
874 }
875
876 default:
877 {
878 break;
879 }
880 }
881 }
882
883 /// constructor for strings
884 json_value(const string_t& value)
885 {
886 string = create<string_t>(value);
887 }
888
889 /// constructor for objects
890 json_value(const object_t& value)
891 {
892 object = create<object_t>(value);
893 }
894
895 /// constructor for arrays
896 json_value(const array_t& value)
897 {
898 array = create<array_t>(value);
899 }
900 };
901
902 /*!
903 @brief checks the class invariants
904
905 This function asserts the class invariants. It needs to be called at the
906 end of every constructor to make sure that created objects respect the
907 invariant. Furthermore, it has to be called each time the type of a JSON
908 value is changed, because the invariant expresses a relationship between
909 @a m_type and @a m_value.
910 */
911 void assert_invariant() const
912 {
913 assert(m_type != value_t::object or m_value.object != nullptr);
914 assert(m_type != value_t::array or m_value.array != nullptr);
915 assert(m_type != value_t::string or m_value.string != nullptr);
916 }
917
918 public:
919 //////////////////////////
920 // JSON parser callback //
921 //////////////////////////
922
923 /*!
924 @brief JSON callback events
925
926 This enumeration lists the parser events that can trigger calling a
927 callback function of type @ref parser_callback_t during parsing.
928
929 @image html callback_events.png "Example when certain parse events are triggered"
930
931 @since version 1.0.0
932 */
933 enum class parse_event_t : uint8_t
934 {
935 /// the parser read `{` and started to process a JSON object
936 object_start,
937 /// the parser read `}` and finished processing a JSON object
938 object_end,
939 /// the parser read `[` and started to process a JSON array
940 array_start,
941 /// the parser read `]` and finished processing a JSON array
942 array_end,
943 /// the parser read a key of a value in an object
944 key,
945 /// the parser finished reading a JSON value
946 value
947 };
948
949 /*!
950 @brief per-element parser callback type
951
952 With a parser callback function, the result of parsing a JSON text can be
953 influenced. When passed to @ref parse(std::istream&, const
954 parser_callback_t) or @ref parse(const CharT, const parser_callback_t),
955 it is called on certain events (passed as @ref parse_event_t via parameter
956 @a event) with a set recursion depth @a depth and context JSON value
957 @a parsed. The return value of the callback function is a boolean
958 indicating whether the element that emitted the callback shall be kept or
959 not.
960
961 We distinguish six scenarios (determined by the event type) in which the
962 callback function can be called. The following table describes the values
963 of the parameters @a depth, @a event, and @a parsed.
964
965 parameter @a event | description | parameter @a depth | parameter @a parsed
966 ------------------ | ----------- | ------------------ | -------------------
967 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
968 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
969 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
970 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
971 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
972 parse_event_t::value | the parser finished reading a JSON value | depth of the value | the parsed JSON value
973
974 @image html callback_events.png "Example when certain parse events are triggered"
975
976 Discarding a value (i.e., returning `false`) has different effects
977 depending on the context in which function was called:
978
979 - Discarded values in structured types are skipped. That is, the parser
980 will behave as if the discarded value was never read.
981 - In case a value outside a structured type is skipped, it is replaced
982 with `null`. This case happens if the top-level element is skipped.
983
984 @param[in] depth the depth of the recursion during parsing
985
986 @param[in] event an event of type parse_event_t indicating the context in
987 the callback function has been called
988
989 @param[in,out] parsed the current intermediate parse result; note that
990 writing to this value has no effect for parse_event_t::key events
991
992 @return Whether the JSON value which called the function during parsing
993 should be kept (`true`) or not (`false`). In the latter case, it is either
994 skipped completely or replaced by an empty discarded object.
995
996 @sa @ref parse(std::istream&, parser_callback_t) or
997 @ref parse(const CharT, const parser_callback_t) for examples
998
999 @since version 1.0.0
1000 */
1001 using parser_callback_t = std::function<bool(int depth,
1002 parse_event_t event,
1003 basic_json& parsed)>;
1004
1005
1006 //////////////////
1007 // constructors //
1008 //////////////////
1009
1010 /// @name constructors and destructors
1011 /// Constructors of class @ref basic_json, copy/move constructor, copy
1012 /// assignment, static functions creating objects, and the destructor.
1013 /// @{
1014
1015 /*!
1016 @brief create an empty value with a given type
1017
1018 Create an empty JSON value with a given type. The value will be default
1019 initialized with an empty value which depends on the type:
1020
1021 Value type | initial value
1022 ----------- | -------------
1023 null | `null`
1024 boolean | `false`
1025 string | `""`
1026 number | `0`
1027 object | `{}`
1028 array | `[]`
1029
1030 @param[in] value_type the type of the value to create
1031
1032 @complexity Constant.
1033
1034 @throw std::bad_alloc if allocation for object, array, or string value
1035 fails
1036
1037 @liveexample{The following code shows the constructor for different @ref
1038 value_t values,basic_json__value_t}
1039
1040 @sa @ref basic_json(std::nullptr_t) -- create a `null` value
1041 @sa @ref basic_json(boolean_t value) -- create a boolean value
1042 @sa @ref basic_json(const string_t&) -- create a string value
1043 @sa @ref basic_json(const object_t&) -- create a object value
1044 @sa @ref basic_json(const array_t&) -- create a array value
1045 @sa @ref basic_json(const number_float_t) -- create a number
1046 (floating-point) value
1047 @sa @ref basic_json(const number_integer_t) -- create a number (integer)
1048 value
1049 @sa @ref basic_json(const number_unsigned_t) -- create a number (unsigned)
1050 value
1051
1052 @since version 1.0.0
1053 */
1054 basic_json(const value_t value_type)
1055 : m_type(value_type), m_value(value_type)
1056 {
1057 assert_invariant();
1058 }
1059
1060 /*!
1061 @brief create a null object
1062
1063 Create a `null` JSON value. It either takes a null pointer as parameter
1064 (explicitly creating `null`) or no parameter (implicitly creating `null`).
1065 The passed null pointer itself is not read -- it is only used to choose
1066 the right constructor.
1067
1068 @complexity Constant.
1069
1070 @exceptionsafety No-throw guarantee: this constructor never throws
1071 exceptions.
1072
1073 @liveexample{The following code shows the constructor with and without a
1074 null pointer parameter.,basic_json__nullptr_t}
1075
1076 @since version 1.0.0
1077 */
1078 basic_json(std::nullptr_t = nullptr) noexcept
1079 : basic_json(value_t::null)
1080 {
1081 assert_invariant();
1082 }
1083
1084 /*!
1085 @brief create an object (explicit)
1086
1087 Create an object JSON value with a given content.
1088
1089 @param[in] val a value for the object
1090
1091 @complexity Linear in the size of the passed @a val.
1092
1093 @throw std::bad_alloc if allocation for object value fails
1094
1095 @liveexample{The following code shows the constructor with an @ref
1096 object_t parameter.,basic_json__object_t}
1097
1098 @sa @ref basic_json(const CompatibleObjectType&) -- create an object value
1099 from a compatible STL container
1100
1101 @since version 1.0.0
1102 */
1103 basic_json(const object_t& val)
1104 : m_type(value_t::object), m_value(val)
1105 {
1106 assert_invariant();
1107 }
1108
1109 /*!
1110 @brief create an object (implicit)
1111
1112 Create an object JSON value with a given content. This constructor allows
1113 any type @a CompatibleObjectType that can be used to construct values of
1114 type @ref object_t.
1115
1116 @tparam CompatibleObjectType An object type whose `key_type` and
1117 `value_type` is compatible to @ref object_t. Examples include `std::map`,
1118 `std::unordered_map`, `std::multimap`, and `std::unordered_multimap` with
1119 a `key_type` of `std::string`, and a `value_type` from which a @ref
1120 basic_json value can be constructed.
1121
1122 @param[in] val a value for the object
1123
1124 @complexity Linear in the size of the passed @a val.
1125
1126 @throw std::bad_alloc if allocation for object value fails
1127
1128 @liveexample{The following code shows the constructor with several
1129 compatible object type parameters.,basic_json__CompatibleObjectType}
1130
1131 @sa @ref basic_json(const object_t&) -- create an object value
1132
1133 @since version 1.0.0
1134 */
1135 template<class CompatibleObjectType, typename std::enable_if<
1136 std::is_constructible<typename object_t::key_type, typename CompatibleObjectType::key_type>::value and
1137 std::is_constructible<basic_json, typename CompatibleObjectType::mapped_type>::value, int>::type = 0>
1138 basic_json(const CompatibleObjectType& val)
1139 : m_type(value_t::object)
1140 {
1141 using std::begin;
1142 using std::end;
1143 m_value.object = create<object_t>(begin(val), end(val));
1144 assert_invariant();
1145 }
1146
1147 /*!
1148 @brief create an array (explicit)
1149
1150 Create an array JSON value with a given content.
1151
1152 @param[in] val a value for the array
1153
1154 @complexity Linear in the size of the passed @a val.
1155
1156 @throw std::bad_alloc if allocation for array value fails
1157
1158 @liveexample{The following code shows the constructor with an @ref array_t
1159 parameter.,basic_json__array_t}
1160
1161 @sa @ref basic_json(const CompatibleArrayType&) -- create an array value
1162 from a compatible STL containers
1163
1164 @since version 1.0.0
1165 */
1166 basic_json(const array_t& val)
1167 : m_type(value_t::array), m_value(val)
1168 {
1169 assert_invariant();
1170 }
1171
1172 /*!
1173 @brief create an array (implicit)
1174
1175 Create an array JSON value with a given content. This constructor allows
1176 any type @a CompatibleArrayType that can be used to construct values of
1177 type @ref array_t.
1178
1179 @tparam CompatibleArrayType An object type whose `value_type` is
1180 compatible to @ref array_t. Examples include `std::vector`, `std::deque`,
1181 `std::list`, `std::forward_list`, `std::array`, `std::set`,
1182 `std::unordered_set`, `std::multiset`, and `unordered_multiset` with a
1183 `value_type` from which a @ref basic_json value can be constructed.
1184
1185 @param[in] val a value for the array
1186
1187 @complexity Linear in the size of the passed @a val.
1188
1189 @throw std::bad_alloc if allocation for array value fails
1190
1191 @liveexample{The following code shows the constructor with several
1192 compatible array type parameters.,basic_json__CompatibleArrayType}
1193
1194 @sa @ref basic_json(const array_t&) -- create an array value
1195
1196 @since version 1.0.0
1197 */
1198 template<class CompatibleArrayType, typename std::enable_if<
1199 not std::is_same<CompatibleArrayType, typename basic_json_t::iterator>::value and
1200 not std::is_same<CompatibleArrayType, typename basic_json_t::const_iterator>::value and
1201 not std::is_same<CompatibleArrayType, typename basic_json_t::reverse_iterator>::value and
1202 not std::is_same<CompatibleArrayType, typename basic_json_t::const_reverse_iterator>::value and
1203 not std::is_same<CompatibleArrayType, typename array_t::iterator>::value and
1204 not std::is_same<CompatibleArrayType, typename array_t::const_iterator>::value and
1205 std::is_constructible<basic_json, typename CompatibleArrayType::value_type>::value, int>::type = 0>
1206 basic_json(const CompatibleArrayType& val)
1207 : m_type(value_t::array)
1208 {
1209 using std::begin;
1210 using std::end;
1211 m_value.array = create<array_t>(begin(val), end(val));
1212 assert_invariant();
1213 }
1214
1215 /*!
1216 @brief create a string (explicit)
1217
1218 Create an string JSON value with a given content.
1219
1220 @param[in] val a value for the string
1221
1222 @complexity Linear in the size of the passed @a val.
1223
1224 @throw std::bad_alloc if allocation for string value fails
1225
1226 @liveexample{The following code shows the constructor with an @ref
1227 string_t parameter.,basic_json__string_t}
1228
1229 @sa @ref basic_json(const typename string_t::value_type*) -- create a
1230 string value from a character pointer
1231 @sa @ref basic_json(const CompatibleStringType&) -- create a string value
1232 from a compatible string container
1233
1234 @since version 1.0.0
1235 */
1236 basic_json(const string_t& val)
1237 : m_type(value_t::string), m_value(val)
1238 {
1239 assert_invariant();
1240 }
1241
1242 /*!
1243 @brief create a string (explicit)
1244
1245 Create a string JSON value with a given content.
1246
1247 @param[in] val a literal value for the string
1248
1249 @complexity Linear in the size of the passed @a val.
1250
1251 @throw std::bad_alloc if allocation for string value fails
1252
1253 @liveexample{The following code shows the constructor with string literal
1254 parameter.,basic_json__string_t_value_type}
1255
1256 @sa @ref basic_json(const string_t&) -- create a string value
1257 @sa @ref basic_json(const CompatibleStringType&) -- create a string value
1258 from a compatible string container
1259
1260 @since version 1.0.0
1261 */
1262 basic_json(const typename string_t::value_type* val)
1263 : basic_json(string_t(val))
1264 {
1265 assert_invariant();
1266 }
1267
1268 /*!
1269 @brief create a string (implicit)
1270
1271 Create a string JSON value with a given content.
1272
1273 @param[in] val a value for the string
1274
1275 @tparam CompatibleStringType an string type which is compatible to @ref
1276 string_t, for instance `std::string`.
1277
1278 @complexity Linear in the size of the passed @a val.
1279
1280 @throw std::bad_alloc if allocation for string value fails
1281
1282 @liveexample{The following code shows the construction of a string value
1283 from a compatible type.,basic_json__CompatibleStringType}
1284
1285 @sa @ref basic_json(const string_t&) -- create a string value
1286 @sa @ref basic_json(const typename string_t::value_type*) -- create a
1287 string value from a character pointer
1288
1289 @since version 1.0.0
1290 */
1291 template<class CompatibleStringType, typename std::enable_if<
1292 std::is_constructible<string_t, CompatibleStringType>::value, int>::type = 0>
1293 basic_json(const CompatibleStringType& val)
1294 : basic_json(string_t(val))
1295 {
1296 assert_invariant();
1297 }
1298
1299 /*!
1300 @brief create a boolean (explicit)
1301
1302 Creates a JSON boolean type from a given value.
1303
1304 @param[in] val a boolean value to store
1305
1306 @complexity Constant.
1307
1308 @liveexample{The example below demonstrates boolean
1309 values.,basic_json__boolean_t}
1310
1311 @since version 1.0.0
1312 */
1313 basic_json(boolean_t val) noexcept
1314 : m_type(value_t::boolean), m_value(val)
1315 {
1316 assert_invariant();
1317 }
1318
1319 /*!
1320 @brief create an integer number (explicit)
1321
1322 Create an integer number JSON value with a given content.
1323
1324 @tparam T A helper type to remove this function via SFINAE in case @ref
1325 number_integer_t is the same as `int`. In this case, this constructor
1326 would have the same signature as @ref basic_json(const int value). Note
1327 the helper type @a T is not visible in this constructor's interface.
1328
1329 @param[in] val an integer to create a JSON number from
1330
1331 @complexity Constant.
1332
1333 @liveexample{The example below shows the construction of an integer
1334 number value.,basic_json__number_integer_t}
1335
1336 @sa @ref basic_json(const int) -- create a number value (integer)
1337 @sa @ref basic_json(const CompatibleNumberIntegerType) -- create a number
1338 value (integer) from a compatible number type
1339
1340 @since version 1.0.0
1341 */
1342 template<typename T, typename std::enable_if<
1343 not (std::is_same<T, int>::value) and
1344 std::is_same<T, number_integer_t>::value, int>::type = 0>
1345 basic_json(const number_integer_t val) noexcept
1346 : m_type(value_t::number_integer), m_value(val)
1347 {
1348 assert_invariant();
1349 }
1350
1351 /*!
1352 @brief create an integer number from an enum type (explicit)
1353
1354 Create an integer number JSON value with a given content.
1355
1356 @param[in] val an integer to create a JSON number from
1357
1358 @note This constructor allows to pass enums directly to a constructor. As
1359 C++ has no way of specifying the type of an anonymous enum explicitly, we
1360 can only rely on the fact that such values implicitly convert to int. As
1361 int may already be the same type of number_integer_t, we may need to
1362 switch off the constructor @ref basic_json(const number_integer_t).
1363
1364 @complexity Constant.
1365
1366 @liveexample{The example below shows the construction of an integer
1367 number value from an anonymous enum.,basic_json__const_int}
1368
1369 @sa @ref basic_json(const number_integer_t) -- create a number value
1370 (integer)
1371 @sa @ref basic_json(const CompatibleNumberIntegerType) -- create a number
1372 value (integer) from a compatible number type
1373
1374 @since version 1.0.0
1375 */
1376 basic_json(const int val) noexcept
1377 : m_type(value_t::number_integer),
1378 m_value(static_cast<number_integer_t>(val))
1379 {
1380 assert_invariant();
1381 }
1382
1383 /*!
1384 @brief create an integer number (implicit)
1385
1386 Create an integer number JSON value with a given content. This constructor
1387 allows any type @a CompatibleNumberIntegerType that can be used to
1388 construct values of type @ref number_integer_t.
1389
1390 @tparam CompatibleNumberIntegerType An integer type which is compatible to
1391 @ref number_integer_t. Examples include the types `int`, `int32_t`,
1392 `long`, and `short`.
1393
1394 @param[in] val an integer to create a JSON number from
1395
1396 @complexity Constant.
1397
1398 @liveexample{The example below shows the construction of several integer
1399 number values from compatible
1400 types.,basic_json__CompatibleIntegerNumberType}
1401
1402 @sa @ref basic_json(const number_integer_t) -- create a number value
1403 (integer)
1404 @sa @ref basic_json(const int) -- create a number value (integer)
1405
1406 @since version 1.0.0
1407 */
1408 template<typename CompatibleNumberIntegerType, typename std::enable_if<
1409 std::is_constructible<number_integer_t, CompatibleNumberIntegerType>::value and
1410 std::numeric_limits<CompatibleNumberIntegerType>::is_integer and
1411 std::numeric_limits<CompatibleNumberIntegerType>::is_signed,
1412 CompatibleNumberIntegerType>::type = 0>
1413 basic_json(const CompatibleNumberIntegerType val) noexcept
1414 : m_type(value_t::number_integer),
1415 m_value(static_cast<number_integer_t>(val))
1416 {
1417 assert_invariant();
1418 }
1419
1420 /*!
1421 @brief create an unsigned integer number (explicit)
1422
1423 Create an unsigned integer number JSON value with a given content.
1424
1425 @tparam T helper type to compare number_unsigned_t and unsigned int (not
1426 visible in) the interface.
1427
1428 @param[in] val an integer to create a JSON number from
1429
1430 @complexity Constant.
1431
1432 @sa @ref basic_json(const CompatibleNumberUnsignedType) -- create a number
1433 value (unsigned integer) from a compatible number type
1434
1435 @since version 2.0.0
1436 */
1437 template<typename T, typename std::enable_if<
1438 not (std::is_same<T, int>::value) and
1439 std::is_same<T, number_unsigned_t>::value, int>::type = 0>
1440 basic_json(const number_unsigned_t val) noexcept
1441 : m_type(value_t::number_unsigned), m_value(val)
1442 {
1443 assert_invariant();
1444 }
1445
1446 /*!
1447 @brief create an unsigned number (implicit)
1448
1449 Create an unsigned number JSON value with a given content. This
1450 constructor allows any type @a CompatibleNumberUnsignedType that can be
1451 used to construct values of type @ref number_unsigned_t.
1452
1453 @tparam CompatibleNumberUnsignedType An integer type which is compatible
1454 to @ref number_unsigned_t. Examples may include the types `unsigned int`,
1455 `uint32_t`, or `unsigned short`.
1456
1457 @param[in] val an unsigned integer to create a JSON number from
1458
1459 @complexity Constant.
1460
1461 @sa @ref basic_json(const number_unsigned_t) -- create a number value
1462 (unsigned)
1463
1464 @since version 2.0.0
1465 */
1466 template<typename CompatibleNumberUnsignedType, typename std::enable_if <
1467 std::is_constructible<number_unsigned_t, CompatibleNumberUnsignedType>::value and
1468 std::numeric_limits<CompatibleNumberUnsignedType>::is_integer and
1469 not std::numeric_limits<CompatibleNumberUnsignedType>::is_signed,
1470 CompatibleNumberUnsignedType>::type = 0>
1471 basic_json(const CompatibleNumberUnsignedType val) noexcept
1472 : m_type(value_t::number_unsigned),
1473 m_value(static_cast<number_unsigned_t>(val))
1474 {
1475 assert_invariant();
1476 }
1477
1478 /*!
1479 @brief create a floating-point number (explicit)
1480
1481 Create a floating-point number JSON value with a given content.
1482
1483 @param[in] val a floating-point value to create a JSON number from
1484
1485 @note [RFC 7159](http://www.rfc-editor.org/rfc/rfc7159.txt), section 6
1486 disallows NaN values:
1487 > Numeric values that cannot be represented in the grammar below (such as
1488 > Infinity and NaN) are not permitted.
1489 In case the parameter @a val is not a number, a JSON null value is created
1490 instead.
1491
1492 @complexity Constant.
1493
1494 @liveexample{The following example creates several floating-point
1495 values.,basic_json__number_float_t}
1496
1497 @sa @ref basic_json(const CompatibleNumberFloatType) -- create a number
1498 value (floating-point) from a compatible number type
1499
1500 @since version 1.0.0
1501 */
1502 basic_json(const number_float_t val) noexcept
1503 : m_type(value_t::number_float), m_value(val)
1504 {
1505 // replace infinity and NAN by null
1506 if (not std::isfinite(val))
1507 {
1508 m_type = value_t::null;
1509 m_value = json_value();
1510 }
1511
1512 assert_invariant();
1513 }
1514
1515 /*!
1516 @brief create an floating-point number (implicit)
1517
1518 Create an floating-point number JSON value with a given content. This
1519 constructor allows any type @a CompatibleNumberFloatType that can be used
1520 to construct values of type @ref number_float_t.
1521
1522 @tparam CompatibleNumberFloatType A floating-point type which is
1523 compatible to @ref number_float_t. Examples may include the types `float`
1524 or `double`.
1525
1526 @param[in] val a floating-point to create a JSON number from
1527
1528 @note [RFC 7159](http://www.rfc-editor.org/rfc/rfc7159.txt), section 6
1529 disallows NaN values:
1530 > Numeric values that cannot be represented in the grammar below (such as
1531 > Infinity and NaN) are not permitted.
1532 In case the parameter @a val is not a number, a JSON null value is
1533 created instead.
1534
1535 @complexity Constant.
1536
1537 @liveexample{The example below shows the construction of several
1538 floating-point number values from compatible
1539 types.,basic_json__CompatibleNumberFloatType}
1540
1541 @sa @ref basic_json(const number_float_t) -- create a number value
1542 (floating-point)
1543
1544 @since version 1.0.0
1545 */
1546 template<typename CompatibleNumberFloatType, typename = typename std::enable_if<
1547 std::is_constructible<number_float_t, CompatibleNumberFloatType>::value and
1548 std::is_floating_point<CompatibleNumberFloatType>::value>::type>
1549 basic_json(const CompatibleNumberFloatType val) noexcept
1550 : basic_json(number_float_t(val))
1551 {
1552 assert_invariant();
1553 }
1554
1555 /*!
1556 @brief create a container (array or object) from an initializer list
1557
1558 Creates a JSON value of type array or object from the passed initializer
1559 list @a init. In case @a type_deduction is `true` (default), the type of
1560 the JSON value to be created is deducted from the initializer list @a init
1561 according to the following rules:
1562
1563 1. If the list is empty, an empty JSON object value `{}` is created.
1564 2. If the list consists of pairs whose first element is a string, a JSON
1565 object value is created where the first elements of the pairs are
1566 treated as keys and the second elements are as values.
1567 3. In all other cases, an array is created.
1568
1569 The rules aim to create the best fit between a C++ initializer list and
1570 JSON values. The rationale is as follows:
1571
1572 1. The empty initializer list is written as `{}` which is exactly an empty
1573 JSON object.
1574 2. C++ has now way of describing mapped types other than to list a list of
1575 pairs. As JSON requires that keys must be of type string, rule 2 is the
1576 weakest constraint one can pose on initializer lists to interpret them
1577 as an object.
1578 3. In all other cases, the initializer list could not be interpreted as
1579 JSON object type, so interpreting it as JSON array type is safe.
1580
1581 With the rules described above, the following JSON values cannot be
1582 expressed by an initializer list:
1583
1584 - the empty array (`[]`): use @ref array(std::initializer_list<basic_json>)
1585 with an empty initializer list in this case
1586 - arrays whose elements satisfy rule 2: use @ref
1587 array(std::initializer_list<basic_json>) with the same initializer list
1588 in this case
1589
1590 @note When used without parentheses around an empty initializer list, @ref
1591 basic_json() is called instead of this function, yielding the JSON null
1592 value.
1593
1594 @param[in] init initializer list with JSON values
1595
1596 @param[in] type_deduction internal parameter; when set to `true`, the type
1597 of the JSON value is deducted from the initializer list @a init; when set
1598 to `false`, the type provided via @a manual_type is forced. This mode is
1599 used by the functions @ref array(std::initializer_list<basic_json>) and
1600 @ref object(std::initializer_list<basic_json>).
1601
1602 @param[in] manual_type internal parameter; when @a type_deduction is set
1603 to `false`, the created JSON value will use the provided type (only @ref
1604 value_t::array and @ref value_t::object are valid); when @a type_deduction
1605 is set to `true`, this parameter has no effect
1606
1607 @throw std::domain_error if @a type_deduction is `false`, @a manual_type
1608 is `value_t::object`, but @a init contains an element which is not a pair
1609 whose first element is a string; example: `"cannot create object from
1610 initializer list"`
1611
1612 @complexity Linear in the size of the initializer list @a init.
1613
1614 @liveexample{The example below shows how JSON values are created from
1615 initializer lists.,basic_json__list_init_t}
1616
1617 @sa @ref array(std::initializer_list<basic_json>) -- create a JSON array
1618 value from an initializer list
1619 @sa @ref object(std::initializer_list<basic_json>) -- create a JSON object
1620 value from an initializer list
1621
1622 @since version 1.0.0
1623 */
1624 basic_json(std::initializer_list<basic_json> init,
1625 bool type_deduction = true,
1626 value_t manual_type = value_t::array)
1627 {
1628 // check if each element is an array with two elements whose first
1629 // element is a string
1630 bool is_an_object = std::all_of(init.begin(), init.end(),
1631 [](const basic_json & element)
1632 {
1633 return element.is_array() and element.size() == 2 and element[0].is_string();
1634 });
1635
1636 // adjust type if type deduction is not wanted
1637 if (not type_deduction)
1638 {
1639 // if array is wanted, do not create an object though possible
1640 if (manual_type == value_t::array)
1641 {
1642 is_an_object = false;
1643 }
1644
1645 // if object is wanted but impossible, throw an exception
1646 if (manual_type == value_t::object and not is_an_object)
1647 {
1648 throw std::domain_error("cannot create object from initializer list");
1649 }
1650 }
1651
1652 if (is_an_object)
1653 {
1654 // the initializer list is a list of pairs -> create object
1655 m_type = value_t::object;
1656 m_value = value_t::object;
1657
1658 std::for_each(init.begin(), init.end(), [this](const basic_json & element)
1659 {
1660 m_value.object->emplace(*(element[0].m_value.string), element[1]);
1661 });
1662 }
1663 else
1664 {
1665 // the initializer list describes an array -> create array
1666 m_type = value_t::array;
1667 m_value.array = create<array_t>(init);
1668 }
1669
1670 assert_invariant();
1671 }
1672
1673 /*!
1674 @brief explicitly create an array from an initializer list
1675
1676 Creates a JSON array value from a given initializer list. That is, given a
1677 list of values `a, b, c`, creates the JSON value `[a, b, c]`. If the
1678 initializer list is empty, the empty array `[]` is created.
1679
1680 @note This function is only needed to express two edge cases that cannot
1681 be realized with the initializer list constructor (@ref
1682 basic_json(std::initializer_list<basic_json>, bool, value_t)). These cases
1683 are:
1684 1. creating an array whose elements are all pairs whose first element is a
1685 string -- in this case, the initializer list constructor would create an
1686 object, taking the first elements as keys
1687 2. creating an empty array -- passing the empty initializer list to the
1688 initializer list constructor yields an empty object
1689
1690 @param[in] init initializer list with JSON values to create an array from
1691 (optional)
1692
1693 @return JSON array value
1694
1695 @complexity Linear in the size of @a init.
1696
1697 @liveexample{The following code shows an example for the `array`
1698 function.,array}
1699
1700 @sa @ref basic_json(std::initializer_list<basic_json>, bool, value_t) --
1701 create a JSON value from an initializer list
1702 @sa @ref object(std::initializer_list<basic_json>) -- create a JSON object
1703 value from an initializer list
1704
1705 @since version 1.0.0
1706 */
1707 static basic_json array(std::initializer_list<basic_json> init =
1708 std::initializer_list<basic_json>())
1709 {
1710 return basic_json(init, false, value_t::array);
1711 }
1712
1713 /*!
1714 @brief explicitly create an object from an initializer list
1715
1716 Creates a JSON object value from a given initializer list. The initializer
1717 lists elements must be pairs, and their first elements must be strings. If
1718 the initializer list is empty, the empty object `{}` is created.
1719
1720 @note This function is only added for symmetry reasons. In contrast to the
1721 related function @ref array(std::initializer_list<basic_json>), there are
1722 no cases which can only be expressed by this function. That is, any
1723 initializer list @a init can also be passed to the initializer list
1724 constructor @ref basic_json(std::initializer_list<basic_json>, bool,
1725 value_t).
1726
1727 @param[in] init initializer list to create an object from (optional)
1728
1729 @return JSON object value
1730
1731 @throw std::domain_error if @a init is not a pair whose first elements are
1732 strings; thrown by
1733 @ref basic_json(std::initializer_list<basic_json>, bool, value_t)
1734
1735 @complexity Linear in the size of @a init.
1736
1737 @liveexample{The following code shows an example for the `object`
1738 function.,object}
1739
1740 @sa @ref basic_json(std::initializer_list<basic_json>, bool, value_t) --
1741 create a JSON value from an initializer list
1742 @sa @ref array(std::initializer_list<basic_json>) -- create a JSON array
1743 value from an initializer list
1744
1745 @since version 1.0.0
1746 */
1747 static basic_json object(std::initializer_list<basic_json> init =
1748 std::initializer_list<basic_json>())
1749 {
1750 return basic_json(init, false, value_t::object);
1751 }
1752
1753 /*!
1754 @brief construct an array with count copies of given value
1755
1756 Constructs a JSON array value by creating @a cnt copies of a passed value.
1757 In case @a cnt is `0`, an empty array is created. As postcondition,
1758 `std::distance(begin(),end()) == cnt` holds.
1759
1760 @param[in] cnt the number of JSON copies of @a val to create
1761 @param[in] val the JSON value to copy
1762
1763 @complexity Linear in @a cnt.
1764
1765 @liveexample{The following code shows examples for the @ref
1766 basic_json(size_type\, const basic_json&)
1767 constructor.,basic_json__size_type_basic_json}
1768
1769 @since version 1.0.0
1770 */
1771 basic_json(size_type cnt, const basic_json& val)
1772 : m_type(value_t::array)
1773 {
1774 m_value.array = create<array_t>(cnt, val);
1775 assert_invariant();
1776 }
1777
1778 /*!
1779 @brief construct a JSON container given an iterator range
1780
1781 Constructs the JSON value with the contents of the range `[first, last)`.
1782 The semantics depends on the different types a JSON value can have:
1783 - In case of primitive types (number, boolean, or string), @a first must
1784 be `begin()` and @a last must be `end()`. In this case, the value is
1785 copied. Otherwise, std::out_of_range is thrown.
1786 - In case of structured types (array, object), the constructor behaves as
1787 similar versions for `std::vector`.
1788 - In case of a null type, std::domain_error is thrown.
1789
1790 @tparam InputIT an input iterator type (@ref iterator or @ref
1791 const_iterator)
1792
1793 @param[in] first begin of the range to copy from (included)
1794 @param[in] last end of the range to copy from (excluded)
1795
1796 @pre Iterators @a first and @a last must be initialized. **This
1797 precondition is enforced with an assertion.**
1798
1799 @throw std::domain_error if iterators are not compatible; that is, do not
1800 belong to the same JSON value; example: `"iterators are not compatible"`
1801 @throw std::out_of_range if iterators are for a primitive type (number,
1802 boolean, or string) where an out of range error can be detected easily;
1803 example: `"iterators out of range"`
1804 @throw std::bad_alloc if allocation for object, array, or string fails
1805 @throw std::domain_error if called with a null value; example: `"cannot
1806 use construct with iterators from null"`
1807
1808 @complexity Linear in distance between @a first and @a last.
1809
1810 @liveexample{The example below shows several ways to create JSON values by
1811 specifying a subrange with iterators.,basic_json__InputIt_InputIt}
1812
1813 @since version 1.0.0
1814 */
1815 template<class InputIT, typename std::enable_if<
1816 std::is_same<InputIT, typename basic_json_t::iterator>::value or
1817 std::is_same<InputIT, typename basic_json_t::const_iterator>::value, int>::type = 0>
1818 basic_json(InputIT first, InputIT last)
1819 {
1820 assert(first.m_object != nullptr);
1821 assert(last.m_object != nullptr);
1822
1823 // make sure iterator fits the current value
1824 if (first.m_object != last.m_object)
1825 {
1826 throw std::domain_error("iterators are not compatible");
1827 }
1828
1829 // copy type from first iterator
1830 m_type = first.m_object->m_type;
1831
1832 // check if iterator range is complete for primitive values
1833 switch (m_type)
1834 {
1835 case value_t::boolean:
1836 case value_t::number_float:
1837 case value_t::number_integer:
1838 case value_t::number_unsigned:
1839 case value_t::string:
1840 {
1841 if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end())
1842 {
1843 throw std::out_of_range("iterators out of range");
1844 }
1845 break;
1846 }
1847
1848 default:
1849 {
1850 break;
1851 }
1852 }
1853
1854 switch (m_type)
1855 {
1856 case value_t::number_integer:
1857 {
1858 m_value.number_integer = first.m_object->m_value.number_integer;
1859 break;
1860 }
1861
1862 case value_t::number_unsigned:
1863 {
1864 m_value.number_unsigned = first.m_object->m_value.number_unsigned;
1865 break;
1866 }
1867
1868 case value_t::number_float:
1869 {
1870 m_value.number_float = first.m_object->m_value.number_float;
1871 break;
1872 }
1873
1874 case value_t::boolean:
1875 {
1876 m_value.boolean = first.m_object->m_value.boolean;
1877 break;
1878 }
1879
1880 case value_t::string:
1881 {
1882 m_value = *first.m_object->m_value.string;
1883 break;
1884 }
1885
1886 case value_t::object:
1887 {
1888 m_value.object = create<object_t>(first.m_it.object_iterator, last.m_it.object_iterator);
1889 break;
1890 }
1891
1892 case value_t::array:
1893 {
1894 m_value.array = create<array_t>(first.m_it.array_iterator, last.m_it.array_iterator);
1895 break;
1896 }
1897
1898 default:
1899 {
1900 throw std::domain_error("cannot use construct with iterators from " + first.m_object->type_name());
1901 }
1902 }
1903
1904 assert_invariant();
1905 }
1906
1907 /*!
1908 @brief construct a JSON value given an input stream
1909
1910 @param[in,out] i stream to read a serialized JSON value from
1911 @param[in] cb a parser callback function of type @ref parser_callback_t
1912 which is used to control the deserialization by filtering unwanted values
1913 (optional)
1914
1915 @complexity Linear in the length of the input. The parser is a predictive
1916 LL(1) parser. The complexity can be higher if the parser callback function
1917 @a cb has a super-linear complexity.
1918
1919 @note A UTF-8 byte order mark is silently ignored.
1920
1921 @deprecated This constructor is deprecated and will be removed in version
1922 3.0.0 to unify the interface of the library. Deserialization will be
1923 done by stream operators or by calling one of the `parse` functions,
1924 e.g. @ref parse(std::istream&, const parser_callback_t). That is, calls
1925 like `json j(i);` for an input stream @a i need to be replaced by
1926 `json j = json::parse(i);`. See the example below.
1927
1928 @liveexample{The example below demonstrates constructing a JSON value from
1929 a `std::stringstream` with and without callback
1930 function.,basic_json__istream}
1931
1932 @since version 2.0.0, deprecated in version 2.0.3, to be removed in
1933 version 3.0.0
1934 */
1935 JSON_DEPRECATED
1936 explicit basic_json(std::istream& i, const parser_callback_t cb = nullptr)
1937 {
1938 *this = parser(i, cb).parse();
1939 assert_invariant();
1940 }
1941
1942 ///////////////////////////////////////
1943 // other constructors and destructor //
1944 ///////////////////////////////////////
1945
1946 /*!
1947 @brief copy constructor
1948
1949 Creates a copy of a given JSON value.
1950
1951 @param[in] other the JSON value to copy
1952
1953 @complexity Linear in the size of @a other.
1954
1955 @requirement This function helps `basic_json` satisfying the
1956 [Container](http://en.cppreference.com/w/cpp/concept/Container)
1957 requirements:
1958 - The complexity is linear.
1959 - As postcondition, it holds: `other == basic_json(other)`.
1960
1961 @throw std::bad_alloc if allocation for object, array, or string fails.
1962
1963 @liveexample{The following code shows an example for the copy
1964 constructor.,basic_json__basic_json}
1965
1966 @since version 1.0.0
1967 */
1968 basic_json(const basic_json& other)
1969 : m_type(other.m_type)
1970 {
1971 // check of passed value is valid
1972 other.assert_invariant();
1973
1974 switch (m_type)
1975 {
1976 case value_t::object:
1977 {
1978 m_value = *other.m_value.object;
1979 break;
1980 }
1981
1982 case value_t::array:
1983 {
1984 m_value = *other.m_value.array;
1985 break;
1986 }
1987
1988 case value_t::string:
1989 {
1990 m_value = *other.m_value.string;
1991 break;
1992 }
1993
1994 case value_t::boolean:
1995 {
1996 m_value = other.m_value.boolean;
1997 break;
1998 }
1999
2000 case value_t::number_integer:
2001 {
2002 m_value = other.m_value.number_integer;
2003 break;
2004 }
2005
2006 case value_t::number_unsigned:
2007 {
2008 m_value = other.m_value.number_unsigned;
2009 break;
2010 }
2011
2012 case value_t::number_float:
2013 {
2014 m_value = other.m_value.number_float;
2015 break;
2016 }
2017
2018 default:
2019 {
2020 break;
2021 }
2022 }
2023
2024 assert_invariant();
2025 }
2026
2027 /*!
2028 @brief move constructor
2029
2030 Move constructor. Constructs a JSON value with the contents of the given
2031 value @a other using move semantics. It "steals" the resources from @a
2032 other and leaves it as JSON null value.
2033
2034 @param[in,out] other value to move to this object
2035
2036 @post @a other is a JSON null value
2037
2038 @complexity Constant.
2039
2040 @liveexample{The code below shows the move constructor explicitly called
2041 via std::move.,basic_json__moveconstructor}
2042
2043 @since version 1.0.0
2044 */
2045 basic_json(basic_json&& other) noexcept
2046 : m_type(std::move(other.m_type)),
2047 m_value(std::move(other.m_value))
2048 {
2049 // check that passed value is valid
2050 other.assert_invariant();
2051
2052 // invalidate payload
2053 other.m_type = value_t::null;
2054 other.m_value = {};
2055
2056 assert_invariant();
2057 }
2058
2059 /*!
2060 @brief copy assignment
2061
2062 Copy assignment operator. Copies a JSON value via the "copy and swap"
2063 strategy: It is expressed in terms of the copy constructor, destructor,
2064 and the swap() member function.
2065
2066 @param[in] other value to copy from
2067
2068 @complexity Linear.
2069
2070 @requirement This function helps `basic_json` satisfying the
2071 [Container](http://en.cppreference.com/w/cpp/concept/Container)
2072 requirements:
2073 - The complexity is linear.
2074
2075 @liveexample{The code below shows and example for the copy assignment. It
2076 creates a copy of value `a` which is then swapped with `b`. Finally\, the
2077 copy of `a` (which is the null value after the swap) is
2078 destroyed.,basic_json__copyassignment}
2079
2080 @since version 1.0.0
2081 */
2082 reference& operator=(basic_json other) noexcept (
2083 std::is_nothrow_move_constructible<value_t>::value and
2084 std::is_nothrow_move_assignable<value_t>::value and
2085 std::is_nothrow_move_constructible<json_value>::value and
2086 std::is_nothrow_move_assignable<json_value>::value
2087 )
2088 {
2089 // check that passed value is valid
2090 other.assert_invariant();
2091
2092 using std::swap;
2093 swap(m_type, other.m_type);
2094 swap(m_value, other.m_value);
2095
2096 assert_invariant();
2097 return *this;
2098 }
2099
2100 /*!
2101 @brief destructor
2102
2103 Destroys the JSON value and frees all allocated memory.
2104
2105 @complexity Linear.
2106
2107 @requirement This function helps `basic_json` satisfying the
2108 [Container](http://en.cppreference.com/w/cpp/concept/Container)
2109 requirements:
2110 - The complexity is linear.
2111 - All stored elements are destroyed and all memory is freed.
2112
2113 @since version 1.0.0
2114 */
2115 ~basic_json()
2116 {
2117 assert_invariant();
2118
2119 switch (m_type)
2120 {
2121 case value_t::object:
2122 {
2123 AllocatorType<object_t> alloc;
2124 alloc.destroy(m_value.object);
2125 alloc.deallocate(m_value.object, 1);
2126 break;
2127 }
2128
2129 case value_t::array:
2130 {
2131 AllocatorType<array_t> alloc;
2132 alloc.destroy(m_value.array);
2133 alloc.deallocate(m_value.array, 1);
2134 break;
2135 }
2136
2137 case value_t::string:
2138 {
2139 AllocatorType<string_t> alloc;
2140 alloc.destroy(m_value.string);
2141 alloc.deallocate(m_value.string, 1);
2142 break;
2143 }
2144
2145 default:
2146 {
2147 // all other types need no specific destructor
2148 break;
2149 }
2150 }
2151 }
2152
2153 /// @}
2154
2155 public:
2156 ///////////////////////
2157 // object inspection //
2158 ///////////////////////
2159
2160 /// @name object inspection
2161 /// Functions to inspect the type of a JSON value.
2162 /// @{
2163
2164 /*!
2165 @brief serialization
2166
2167 Serialization function for JSON values. The function tries to mimic
2168 Python's `json.dumps()` function, and currently supports its @a indent
2169 parameter.
2170
2171 @param[in] indent If indent is nonnegative, then array elements and object
2172 members will be pretty-printed with that indent level. An indent level of
2173 `0` will only insert newlines. `-1` (the default) selects the most compact
2174 representation.
2175
2176 @return string containing the serialization of the JSON value
2177
2178 @complexity Linear.
2179
2180 @liveexample{The following example shows the effect of different @a indent
2181 parameters to the result of the serialization.,dump}
2182
2183 @see https://docs.python.org/2/library/json.html#json.dump
2184
2185 @since version 1.0.0
2186 */
2187 string_t dump(const int indent = -1) const
2188 {
2189 std::stringstream ss;
2190 // fix locale problems
2191 ss.imbue(std::locale::classic());
2192
2193 // 6, 15 or 16 digits of precision allows round-trip IEEE 754
2194 // string->float->string, string->double->string or string->long
2195 // double->string; to be safe, we read this value from
2196 // std::numeric_limits<number_float_t>::digits10
2197 ss.precision(std::numeric_limits<double>::digits10);
2198
2199 if (indent >= 0)
2200 {
2201 dump(ss, true, static_cast<unsigned int>(indent));
2202 }
2203 else
2204 {
2205 dump(ss, false, 0);
2206 }
2207
2208 return ss.str();
2209 }
2210
2211 /*!
2212 @brief return the type of the JSON value (explicit)
2213
2214 Return the type of the JSON value as a value from the @ref value_t
2215 enumeration.
2216
2217 @return the type of the JSON value
2218
2219 @complexity Constant.
2220
2221 @exceptionsafety No-throw guarantee: this member function never throws
2222 exceptions.
2223
2224 @liveexample{The following code exemplifies `type()` for all JSON
2225 types.,type}
2226
2227 @since version 1.0.0
2228 */
2229 constexpr value_t type() const noexcept
2230 {
2231 return m_type;
2232 }
2233
2234 /*!
2235 @brief return whether type is primitive
2236
2237 This function returns true iff the JSON type is primitive (string, number,
2238 boolean, or null).
2239
2240 @return `true` if type is primitive (string, number, boolean, or null),
2241 `false` otherwise.
2242
2243 @complexity Constant.
2244
2245 @exceptionsafety No-throw guarantee: this member function never throws
2246 exceptions.
2247
2248 @liveexample{The following code exemplifies `is_primitive()` for all JSON
2249 types.,is_primitive}
2250
2251 @sa @ref is_structured() -- returns whether JSON value is structured
2252 @sa @ref is_null() -- returns whether JSON value is `null`
2253 @sa @ref is_string() -- returns whether JSON value is a string
2254 @sa @ref is_boolean() -- returns whether JSON value is a boolean
2255 @sa @ref is_number() -- returns whether JSON value is a number
2256
2257 @since version 1.0.0
2258 */
2259 constexpr bool is_primitive() const noexcept
2260 {
2261 return is_null() or is_string() or is_boolean() or is_number();
2262 }
2263
2264 /*!
2265 @brief return whether type is structured
2266
2267 This function returns true iff the JSON type is structured (array or
2268 object).
2269
2270 @return `true` if type is structured (array or object), `false` otherwise.
2271
2272 @complexity Constant.
2273
2274 @exceptionsafety No-throw guarantee: this member function never throws
2275 exceptions.
2276
2277 @liveexample{The following code exemplifies `is_structured()` for all JSON
2278 types.,is_structured}
2279
2280 @sa @ref is_primitive() -- returns whether value is primitive
2281 @sa @ref is_array() -- returns whether value is an array
2282 @sa @ref is_object() -- returns whether value is an object
2283
2284 @since version 1.0.0
2285 */
2286 constexpr bool is_structured() const noexcept
2287 {
2288 return is_array() or is_object();
2289 }
2290
2291 /*!
2292 @brief return whether value is null
2293
2294 This function returns true iff the JSON value is null.
2295
2296 @return `true` if type is null, `false` otherwise.
2297
2298 @complexity Constant.
2299
2300 @exceptionsafety No-throw guarantee: this member function never throws
2301 exceptions.
2302
2303 @liveexample{The following code exemplifies `is_null()` for all JSON
2304 types.,is_null}
2305
2306 @since version 1.0.0
2307 */
2308 constexpr bool is_null() const noexcept
2309 {
2310 return m_type == value_t::null;
2311 }
2312
2313 /*!
2314 @brief return whether value is a boolean
2315
2316 This function returns true iff the JSON value is a boolean.
2317
2318 @return `true` if type is boolean, `false` otherwise.
2319
2320 @complexity Constant.
2321
2322 @exceptionsafety No-throw guarantee: this member function never throws
2323 exceptions.
2324
2325 @liveexample{The following code exemplifies `is_boolean()` for all JSON
2326 types.,is_boolean}
2327
2328 @since version 1.0.0
2329 */
2330 constexpr bool is_boolean() const noexcept
2331 {
2332 return m_type == value_t::boolean;
2333 }
2334
2335 /*!
2336 @brief return whether value is a number
2337
2338 This function returns true iff the JSON value is a number. This includes
2339 both integer and floating-point values.
2340
2341 @return `true` if type is number (regardless whether integer, unsigned
2342 integer or floating-type), `false` otherwise.
2343
2344 @complexity Constant.
2345
2346 @exceptionsafety No-throw guarantee: this member function never throws
2347 exceptions.
2348
2349 @liveexample{The following code exemplifies `is_number()` for all JSON
2350 types.,is_number}
2351
2352 @sa @ref is_number_integer() -- check if value is an integer or unsigned
2353 integer number
2354 @sa @ref is_number_unsigned() -- check if value is an unsigned integer
2355 number
2356 @sa @ref is_number_float() -- check if value is a floating-point number
2357
2358 @since version 1.0.0
2359 */
2360 constexpr bool is_number() const noexcept
2361 {
2362 return is_number_integer() or is_number_float();
2363 }
2364
2365 /*!
2366 @brief return whether value is an integer number
2367
2368 This function returns true iff the JSON value is an integer or unsigned
2369 integer number. This excludes floating-point values.
2370
2371 @return `true` if type is an integer or unsigned integer number, `false`
2372 otherwise.
2373
2374 @complexity Constant.
2375
2376 @exceptionsafety No-throw guarantee: this member function never throws
2377 exceptions.
2378
2379 @liveexample{The following code exemplifies `is_number_integer()` for all
2380 JSON types.,is_number_integer}
2381
2382 @sa @ref is_number() -- check if value is a number
2383 @sa @ref is_number_unsigned() -- check if value is an unsigned integer
2384 number
2385 @sa @ref is_number_float() -- check if value is a floating-point number
2386
2387 @since version 1.0.0
2388 */
2389 constexpr bool is_number_integer() const noexcept
2390 {
2391 return m_type == value_t::number_integer or m_type == value_t::number_unsigned;
2392 }
2393
2394 /*!
2395 @brief return whether value is an unsigned integer number
2396
2397 This function returns true iff the JSON value is an unsigned integer
2398 number. This excludes floating-point and (signed) integer values.
2399
2400 @return `true` if type is an unsigned integer number, `false` otherwise.
2401
2402 @complexity Constant.
2403
2404 @exceptionsafety No-throw guarantee: this member function never throws
2405 exceptions.
2406
2407 @liveexample{The following code exemplifies `is_number_unsigned()` for all
2408 JSON types.,is_number_unsigned}
2409
2410 @sa @ref is_number() -- check if value is a number
2411 @sa @ref is_number_integer() -- check if value is an integer or unsigned
2412 integer number
2413 @sa @ref is_number_float() -- check if value is a floating-point number
2414
2415 @since version 2.0.0
2416 */
2417 constexpr bool is_number_unsigned() const noexcept
2418 {
2419 return m_type == value_t::number_unsigned;
2420 }
2421
2422 /*!
2423 @brief return whether value is a floating-point number
2424
2425 This function returns true iff the JSON value is a floating-point number.
2426 This excludes integer and unsigned integer values.
2427
2428 @return `true` if type is a floating-point number, `false` otherwise.
2429
2430 @complexity Constant.
2431
2432 @exceptionsafety No-throw guarantee: this member function never throws
2433 exceptions.
2434
2435 @liveexample{The following code exemplifies `is_number_float()` for all
2436 JSON types.,is_number_float}
2437
2438 @sa @ref is_number() -- check if value is number
2439 @sa @ref is_number_integer() -- check if value is an integer number
2440 @sa @ref is_number_unsigned() -- check if value is an unsigned integer
2441 number
2442
2443 @since version 1.0.0
2444 */
2445 constexpr bool is_number_float() const noexcept
2446 {
2447 return m_type == value_t::number_float;
2448 }
2449
2450 /*!
2451 @brief return whether value is an object
2452
2453 This function returns true iff the JSON value is an object.
2454
2455 @return `true` if type is object, `false` otherwise.
2456
2457 @complexity Constant.
2458
2459 @exceptionsafety No-throw guarantee: this member function never throws
2460 exceptions.
2461
2462 @liveexample{The following code exemplifies `is_object()` for all JSON
2463 types.,is_object}
2464
2465 @since version 1.0.0
2466 */
2467 constexpr bool is_object() const noexcept
2468 {
2469 return m_type == value_t::object;
2470 }
2471
2472 /*!
2473 @brief return whether value is an array
2474
2475 This function returns true iff the JSON value is an array.
2476
2477 @return `true` if type is array, `false` otherwise.
2478
2479 @complexity Constant.
2480
2481 @exceptionsafety No-throw guarantee: this member function never throws
2482 exceptions.
2483
2484 @liveexample{The following code exemplifies `is_array()` for all JSON
2485 types.,is_array}
2486
2487 @since version 1.0.0
2488 */
2489 constexpr bool is_array() const noexcept
2490 {
2491 return m_type == value_t::array;
2492 }
2493
2494 /*!
2495 @brief return whether value is a string
2496
2497 This function returns true iff the JSON value is a string.
2498
2499 @return `true` if type is string, `false` otherwise.
2500
2501 @complexity Constant.
2502
2503 @exceptionsafety No-throw guarantee: this member function never throws
2504 exceptions.
2505
2506 @liveexample{The following code exemplifies `is_string()` for all JSON
2507 types.,is_string}
2508
2509 @since version 1.0.0
2510 */
2511 constexpr bool is_string() const noexcept
2512 {
2513 return m_type == value_t::string;
2514 }
2515
2516 /*!
2517 @brief return whether value is discarded
2518
2519 This function returns true iff the JSON value was discarded during parsing
2520 with a callback function (see @ref parser_callback_t).
2521
2522 @note This function will always be `false` for JSON values after parsing.
2523 That is, discarded values can only occur during parsing, but will be
2524 removed when inside a structured value or replaced by null in other cases.
2525
2526 @return `true` if type is discarded, `false` otherwise.
2527
2528 @complexity Constant.
2529
2530 @exceptionsafety No-throw guarantee: this member function never throws
2531 exceptions.
2532
2533 @liveexample{The following code exemplifies `is_discarded()` for all JSON
2534 types.,is_discarded}
2535
2536 @since version 1.0.0
2537 */
2538 constexpr bool is_discarded() const noexcept
2539 {
2540 return m_type == value_t::discarded;
2541 }
2542
2543 /*!
2544 @brief return the type of the JSON value (implicit)
2545
2546 Implicitly return the type of the JSON value as a value from the @ref
2547 value_t enumeration.
2548
2549 @return the type of the JSON value
2550
2551 @complexity Constant.
2552
2553 @exceptionsafety No-throw guarantee: this member function never throws
2554 exceptions.
2555
2556 @liveexample{The following code exemplifies the @ref value_t operator for
2557 all JSON types.,operator__value_t}
2558
2559 @since version 1.0.0
2560 */
2561 constexpr operator value_t() const noexcept
2562 {
2563 return m_type;
2564 }
2565
2566 /// @}
2567
2568 private:
2569 //////////////////
2570 // value access //
2571 //////////////////
2572
2573 /// get an object (explicit)
2574 template<class T, typename std::enable_if<
2575 std::is_convertible<typename object_t::key_type, typename T::key_type>::value and
2576 std::is_convertible<basic_json_t, typename T::mapped_type>::value, int>::type = 0>
2577 T get_impl(T*) const
2578 {
2579 if (is_object())
2580 {
2581 return T(m_value.object->begin(), m_value.object->end());
2582 }
2583 else
2584 {
2585 throw std::domain_error("type must be object, but is " + type_name());
2586 }
2587 }
2588
2589 /// get an object (explicit)
2590 object_t get_impl(object_t*) const
2591 {
2592 if (is_object())
2593 {
2594 return *(m_value.object);
2595 }
2596 else
2597 {
2598 throw std::domain_error("type must be object, but is " + type_name());
2599 }
2600 }
2601
2602 /// get an array (explicit)
2603 template<class T, typename std::enable_if<
2604 std::is_convertible<basic_json_t, typename T::value_type>::value and
2605 not std::is_same<basic_json_t, typename T::value_type>::value and
2606 not std::is_arithmetic<T>::value and
2607 not std::is_convertible<std::string, T>::value and
2608 not has_mapped_type<T>::value, int>::type = 0>
2609 T get_impl(T*) const
2610 {
2611 if (is_array())
2612 {
2613 T to_vector;
2614 std::transform(m_value.array->begin(), m_value.array->end(),
2615 std::inserter(to_vector, to_vector.end()), [](basic_json i)
2616 {
2617 return i.get<typename T::value_type>();
2618 });
2619 return to_vector;
2620 }
2621 else
2622 {
2623 throw std::domain_error("type must be array, but is " + type_name());
2624 }
2625 }
2626
2627 /// get an array (explicit)
2628 template<class T, typename std::enable_if<
2629 std::is_convertible<basic_json_t, T>::value and
2630 not std::is_same<basic_json_t, T>::value, int>::type = 0>
2631 std::vector<T> get_impl(std::vector<T>*) const
2632 {
2633 if (is_array())
2634 {
2635 std::vector<T> to_vector;
2636 to_vector.reserve(m_value.array->size());
2637 std::transform(m_value.array->begin(), m_value.array->end(),
2638 std::inserter(to_vector, to_vector.end()), [](basic_json i)
2639 {
2640 return i.get<T>();
2641 });
2642 return to_vector;
2643 }
2644 else
2645 {
2646 throw std::domain_error("type must be array, but is " + type_name());
2647 }
2648 }
2649
2650 /// get an array (explicit)
2651 template<class T, typename std::enable_if<
2652 std::is_same<basic_json, typename T::value_type>::value and
2653 not has_mapped_type<T>::value, int>::type = 0>
2654 T get_impl(T*) const
2655 {
2656 if (is_array())
2657 {
2658 return T(m_value.array->begin(), m_value.array->end());
2659 }
2660 else
2661 {
2662 throw std::domain_error("type must be array, but is " + type_name());
2663 }
2664 }
2665
2666 /// get an array (explicit)
2667 array_t get_impl(array_t*) const
2668 {
2669 if (is_array())
2670 {
2671 return *(m_value.array);
2672 }
2673 else
2674 {
2675 throw std::domain_error("type must be array, but is " + type_name());
2676 }
2677 }
2678
2679 /// get a string (explicit)
2680 template<typename T, typename std::enable_if<
2681 std::is_convertible<string_t, T>::value, int>::type = 0>
2682 T get_impl(T*) const
2683 {
2684 if (is_string())
2685 {
2686 return *m_value.string;
2687 }
2688 else
2689 {
2690 throw std::domain_error("type must be string, but is " + type_name());
2691 }
2692 }
2693
2694 /// get a number (explicit)
2695 template<typename T, typename std::enable_if<
2696 std::is_arithmetic<T>::value, int>::type = 0>
2697 T get_impl(T*) const
2698 {
2699 switch (m_type)
2700 {
2701 case value_t::number_integer:
2702 {
2703 return static_cast<T>(m_value.number_integer);
2704 }
2705
2706 case value_t::number_unsigned:
2707 {
2708 return static_cast<T>(m_value.number_unsigned);
2709 }
2710
2711 case value_t::number_float:
2712 {
2713 return static_cast<T>(m_value.number_float);
2714 }
2715
2716 default:
2717 {
2718 throw std::domain_error("type must be number, but is " + type_name());
2719 }
2720 }
2721 }
2722
2723 /// get a boolean (explicit)
2724 constexpr boolean_t get_impl(boolean_t*) const
2725 {
2726 return is_boolean()
2727 ? m_value.boolean
2728 : throw std::domain_error("type must be boolean, but is " + type_name());
2729 }
2730
2731 /// get a pointer to the value (object)
2732 object_t* get_impl_ptr(object_t*) noexcept
2733 {
2734 return is_object() ? m_value.object : nullptr;
2735 }
2736
2737 /// get a pointer to the value (object)
2738 constexpr const object_t* get_impl_ptr(const object_t*) const noexcept
2739 {
2740 return is_object() ? m_value.object : nullptr;
2741 }
2742
2743 /// get a pointer to the value (array)
2744 array_t* get_impl_ptr(array_t*) noexcept
2745 {
2746 return is_array() ? m_value.array : nullptr;
2747 }
2748
2749 /// get a pointer to the value (array)
2750 constexpr const array_t* get_impl_ptr(const array_t*) const noexcept
2751 {
2752 return is_array() ? m_value.array : nullptr;
2753 }
2754
2755 /// get a pointer to the value (string)
2756 string_t* get_impl_ptr(string_t*) noexcept
2757 {
2758 return is_string() ? m_value.string : nullptr;
2759 }
2760
2761 /// get a pointer to the value (string)
2762 constexpr const string_t* get_impl_ptr(const string_t*) const noexcept
2763 {
2764 return is_string() ? m_value.string : nullptr;
2765 }
2766
2767 /// get a pointer to the value (boolean)
2768 boolean_t* get_impl_ptr(boolean_t*) noexcept
2769 {
2770 return is_boolean() ? &m_value.boolean : nullptr;
2771 }
2772
2773 /// get a pointer to the value (boolean)
2774 constexpr const boolean_t* get_impl_ptr(const boolean_t*) const noexcept
2775 {
2776 return is_boolean() ? &m_value.boolean : nullptr;
2777 }
2778
2779 /// get a pointer to the value (integer number)
2780 number_integer_t* get_impl_ptr(number_integer_t*) noexcept
2781 {
2782 return is_number_integer() ? &m_value.number_integer : nullptr;
2783 }
2784
2785 /// get a pointer to the value (integer number)
2786 constexpr const number_integer_t* get_impl_ptr(const number_integer_t*) const noexcept
2787 {
2788 return is_number_integer() ? &m_value.number_integer : nullptr;
2789 }
2790
2791 /// get a pointer to the value (unsigned number)
2792 number_unsigned_t* get_impl_ptr(number_unsigned_t*) noexcept
2793 {
2794 return is_number_unsigned() ? &m_value.number_unsigned : nullptr;
2795 }
2796
2797 /// get a pointer to the value (unsigned number)
2798 constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t*) const noexcept
2799 {
2800 return is_number_unsigned() ? &m_value.number_unsigned : nullptr;
2801 }
2802
2803 /// get a pointer to the value (floating-point number)
2804 number_float_t* get_impl_ptr(number_float_t*) noexcept
2805 {
2806 return is_number_float() ? &m_value.number_float : nullptr;
2807 }
2808
2809 /// get a pointer to the value (floating-point number)
2810 constexpr const number_float_t* get_impl_ptr(const number_float_t*) const noexcept
2811 {
2812 return is_number_float() ? &m_value.number_float : nullptr;
2813 }
2814
2815 /*!
2816 @brief helper function to implement get_ref()
2817
2818 This funcion helps to implement get_ref() without code duplication for
2819 const and non-const overloads
2820
2821 @tparam ThisType will be deduced as `basic_json` or `const basic_json`
2822
2823 @throw std::domain_error if ReferenceType does not match underlying value
2824 type of the current JSON
2825 */
2826 template<typename ReferenceType, typename ThisType>
2827 static ReferenceType get_ref_impl(ThisType& obj)
2828 {
2829 // helper type
2830 using PointerType = typename std::add_pointer<ReferenceType>::type;
2831
2832 // delegate the call to get_ptr<>()
2833 auto ptr = obj.template get_ptr<PointerType>();
2834
2835 if (ptr != nullptr)
2836 {
2837 return *ptr;
2838 }
2839 else
2840 {
2841 throw std::domain_error("incompatible ReferenceType for get_ref, actual type is " +
2842 obj.type_name());
2843 }
2844 }
2845
2846 public:
2847
2848 /// @name value access
2849 /// Direct access to the stored value of a JSON value.
2850 /// @{
2851
2852 /*!
2853 @brief get a value (explicit)
2854
2855 Explicit type conversion between the JSON value and a compatible value.
2856
2857 @tparam ValueType non-pointer type compatible to the JSON value, for
2858 instance `int` for JSON integer numbers, `bool` for JSON booleans, or
2859 `std::vector` types for JSON arrays
2860
2861 @return copy of the JSON value, converted to type @a ValueType
2862
2863 @throw std::domain_error in case passed type @a ValueType is incompatible
2864 to JSON; example: `"type must be object, but is null"`
2865
2866 @complexity Linear in the size of the JSON value.
2867
2868 @liveexample{The example below shows several conversions from JSON values
2869 to other types. There a few things to note: (1) Floating-point numbers can
2870 be converted to integers\, (2) A JSON array can be converted to a standard
2871 `std::vector<short>`\, (3) A JSON object can be converted to C++
2872 associative containers such as `std::unordered_map<std::string\,
2873 json>`.,get__ValueType_const}
2874
2875 @internal
2876 The idea of using a casted null pointer to choose the correct
2877 implementation is from <http://stackoverflow.com/a/8315197/266378>.
2878 @endinternal
2879
2880 @sa @ref operator ValueType() const for implicit conversion
2881 @sa @ref get() for pointer-member access
2882
2883 @since version 1.0.0
2884 */
2885 template<typename ValueType, typename std::enable_if<
2886 not std::is_pointer<ValueType>::value, int>::type = 0>
2887 ValueType get() const
2888 {
2889 return get_impl(static_cast<ValueType*>(nullptr));
2890 }
2891
2892 /*!
2893 @brief get a pointer value (explicit)
2894
2895 Explicit pointer access to the internally stored JSON value. No copies are
2896 made.
2897
2898 @warning The pointer becomes invalid if the underlying JSON object
2899 changes.
2900
2901 @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref
2902 object_t, @ref string_t, @ref boolean_t, @ref number_integer_t,
2903 @ref number_unsigned_t, or @ref number_float_t.
2904
2905 @return pointer to the internally stored JSON value if the requested
2906 pointer type @a PointerType fits to the JSON value; `nullptr` otherwise
2907
2908 @complexity Constant.
2909
2910 @liveexample{The example below shows how pointers to internal values of a
2911 JSON value can be requested. Note that no type conversions are made and a
2912 `nullptr` is returned if the value and the requested pointer type does not
2913 match.,get__PointerType}
2914
2915 @sa @ref get_ptr() for explicit pointer-member access
2916
2917 @since version 1.0.0
2918 */
2919 template<typename PointerType, typename std::enable_if<
2920 std::is_pointer<PointerType>::value, int>::type = 0>
2921 PointerType get() noexcept
2922 {
2923 // delegate the call to get_ptr
2924 return get_ptr<PointerType>();
2925 }
2926
2927 /*!
2928 @brief get a pointer value (explicit)
2929 @copydoc get()
2930 */
2931 template<typename PointerType, typename std::enable_if<
2932 std::is_pointer<PointerType>::value, int>::type = 0>
2933 constexpr const PointerType get() const noexcept
2934 {
2935 // delegate the call to get_ptr
2936 return get_ptr<PointerType>();
2937 }
2938
2939 /*!
2940 @brief get a pointer value (implicit)
2941
2942 Implicit pointer access to the internally stored JSON value. No copies are
2943 made.
2944
2945 @warning Writing data to the pointee of the result yields an undefined
2946 state.
2947
2948 @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref
2949 object_t, @ref string_t, @ref boolean_t, @ref number_integer_t,
2950 @ref number_unsigned_t, or @ref number_float_t. Enforced by a static
2951 assertion.
2952
2953 @return pointer to the internally stored JSON value if the requested
2954 pointer type @a PointerType fits to the JSON value; `nullptr` otherwise
2955
2956 @complexity Constant.
2957
2958 @liveexample{The example below shows how pointers to internal values of a
2959 JSON value can be requested. Note that no type conversions are made and a
2960 `nullptr` is returned if the value and the requested pointer type does not
2961 match.,get_ptr}
2962
2963 @since version 1.0.0
2964 */
2965 template<typename PointerType, typename std::enable_if<
2966 std::is_pointer<PointerType>::value, int>::type = 0>
2967 PointerType get_ptr() noexcept
2968 {
2969 // get the type of the PointerType (remove pointer and const)
2970 using pointee_t = typename std::remove_const<typename
2971 std::remove_pointer<typename
2972 std::remove_const<PointerType>::type>::type>::type;
2973 // make sure the type matches the allowed types
2974 static_assert(
2975 std::is_same<object_t, pointee_t>::value
2976 or std::is_same<array_t, pointee_t>::value
2977 or std::is_same<string_t, pointee_t>::value
2978 or std::is_same<boolean_t, pointee_t>::value
2979 or std::is_same<number_integer_t, pointee_t>::value
2980 or std::is_same<number_unsigned_t, pointee_t>::value
2981 or std::is_same<number_float_t, pointee_t>::value
2982 , "incompatible pointer type");
2983
2984 // delegate the call to get_impl_ptr<>()
2985 return get_impl_ptr(static_cast<PointerType>(nullptr));
2986 }
2987
2988 /*!
2989 @brief get a pointer value (implicit)
2990 @copydoc get_ptr()
2991 */
2992 template<typename PointerType, typename std::enable_if<
2993 std::is_pointer<PointerType>::value and
2994 std::is_const<typename std::remove_pointer<PointerType>::type>::value, int>::type = 0>
2995 constexpr const PointerType get_ptr() const noexcept
2996 {
2997 // get the type of the PointerType (remove pointer and const)
2998 using pointee_t = typename std::remove_const<typename
2999 std::remove_pointer<typename
3000 std::remove_const<PointerType>::type>::type>::type;
3001 // make sure the type matches the allowed types
3002 static_assert(
3003 std::is_same<object_t, pointee_t>::value
3004 or std::is_same<array_t, pointee_t>::value
3005 or std::is_same<string_t, pointee_t>::value
3006 or std::is_same<boolean_t, pointee_t>::value
3007 or std::is_same<number_integer_t, pointee_t>::value
3008 or std::is_same<number_unsigned_t, pointee_t>::value
3009 or std::is_same<number_float_t, pointee_t>::value
3010 , "incompatible pointer type");
3011
3012 // delegate the call to get_impl_ptr<>() const
3013 return get_impl_ptr(static_cast<const PointerType>(nullptr));
3014 }
3015
3016 /*!
3017 @brief get a reference value (implicit)
3018
3019 Implict reference access to the internally stored JSON value. No copies
3020 are made.
3021
3022 @warning Writing data to the referee of the result yields an undefined
3023 state.
3024
3025 @tparam ReferenceType reference type; must be a reference to @ref array_t,
3026 @ref object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or
3027 @ref number_float_t. Enforced by static assertion.
3028
3029 @return reference to the internally stored JSON value if the requested
3030 reference type @a ReferenceType fits to the JSON value; throws
3031 std::domain_error otherwise
3032
3033 @throw std::domain_error in case passed type @a ReferenceType is
3034 incompatible with the stored JSON value
3035
3036 @complexity Constant.
3037
3038 @liveexample{The example shows several calls to `get_ref()`.,get_ref}
3039
3040 @since version 1.1.0
3041 */
3042 template<typename ReferenceType, typename std::enable_if<
3043 std::is_reference<ReferenceType>::value, int>::type = 0>
3044 ReferenceType get_ref()
3045 {
3046 // delegate call to get_ref_impl
3047 return get_ref_impl<ReferenceType>(*this);
3048 }
3049
3050 /*!
3051 @brief get a reference value (implicit)
3052 @copydoc get_ref()
3053 */
3054 template<typename ReferenceType, typename std::enable_if<
3055 std::is_reference<ReferenceType>::value and
3056 std::is_const<typename std::remove_reference<ReferenceType>::type>::value, int>::type = 0>
3057 ReferenceType get_ref() const
3058 {
3059 // delegate call to get_ref_impl
3060 return get_ref_impl<ReferenceType>(*this);
3061 }
3062
3063 /*!
3064 @brief get a value (implicit)
3065
3066 Implicit type conversion between the JSON value and a compatible value.
3067 The call is realized by calling @ref get() const.
3068
3069 @tparam ValueType non-pointer type compatible to the JSON value, for
3070 instance `int` for JSON integer numbers, `bool` for JSON booleans, or
3071 `std::vector` types for JSON arrays. The character type of @ref string_t
3072 as well as an initializer list of this type is excluded to avoid
3073 ambiguities as these types implicitly convert to `std::string`.
3074
3075 @return copy of the JSON value, converted to type @a ValueType
3076
3077 @throw std::domain_error in case passed type @a ValueType is incompatible
3078 to JSON, thrown by @ref get() const
3079
3080 @complexity Linear in the size of the JSON value.
3081
3082 @liveexample{The example below shows several conversions from JSON values
3083 to other types. There a few things to note: (1) Floating-point numbers can
3084 be converted to integers\, (2) A JSON array can be converted to a standard
3085 `std::vector<short>`\, (3) A JSON object can be converted to C++
3086 associative containers such as `std::unordered_map<std::string\,
3087 json>`.,operator__ValueType}
3088
3089 @since version 1.0.0
3090 */
3091 template < typename ValueType, typename std::enable_if <
3092 not std::is_pointer<ValueType>::value and
3093 not std::is_same<ValueType, typename string_t::value_type>::value
3094#ifndef _MSC_VER // Fix for issue #167 operator<< abiguity under VS2015
3095 and not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value
3096#endif
3097 , int >::type = 0 >
3098 operator ValueType() const
3099 {
3100 // delegate the call to get<>() const
3101 return get<ValueType>();
3102 }
3103
3104 /// @}
3105
3106
3107 ////////////////////
3108 // element access //
3109 ////////////////////
3110
3111 /// @name element access
3112 /// Access to the JSON value.
3113 /// @{
3114
3115 /*!
3116 @brief access specified array element with bounds checking
3117
3118 Returns a reference to the element at specified location @a idx, with
3119 bounds checking.
3120
3121 @param[in] idx index of the element to access
3122
3123 @return reference to the element at index @a idx
3124
3125 @throw std::domain_error if the JSON value is not an array; example:
3126 `"cannot use at() with string"`
3127 @throw std::out_of_range if the index @a idx is out of range of the array;
3128 that is, `idx >= size()`; example: `"array index 7 is out of range"`
3129
3130 @complexity Constant.
3131
3132 @liveexample{The example below shows how array elements can be read and
3133 written using `at()`.,at__size_type}
3134
3135 @since version 1.0.0
3136 */
3137 reference at(size_type idx)
3138 {
3139 // at only works for arrays
3140 if (is_array())
3141 {
3142 try
3143 {
3144 return m_value.array->at(idx);
3145 }
3146 catch (std::out_of_range&)
3147 {
3148 // create better exception explanation
3149 throw std::out_of_range("array index " + std::to_string(idx) + " is out of range");
3150 }
3151 }
3152 else
3153 {
3154 throw std::domain_error("cannot use at() with " + type_name());
3155 }
3156 }
3157
3158 /*!
3159 @brief access specified array element with bounds checking
3160
3161 Returns a const reference to the element at specified location @a idx,
3162 with bounds checking.
3163
3164 @param[in] idx index of the element to access
3165
3166 @return const reference to the element at index @a idx
3167
3168 @throw std::domain_error if the JSON value is not an array; example:
3169 `"cannot use at() with string"`
3170 @throw std::out_of_range if the index @a idx is out of range of the array;
3171 that is, `idx >= size()`; example: `"array index 7 is out of range"`
3172
3173 @complexity Constant.
3174
3175 @liveexample{The example below shows how array elements can be read using
3176 `at()`.,at__size_type_const}
3177
3178 @since version 1.0.0
3179 */
3180 const_reference at(size_type idx) const
3181 {
3182 // at only works for arrays
3183 if (is_array())
3184 {
3185 try
3186 {
3187 return m_value.array->at(idx);
3188 }
3189 catch (std::out_of_range&)
3190 {
3191 // create better exception explanation
3192 throw std::out_of_range("array index " + std::to_string(idx) + " is out of range");
3193 }
3194 }
3195 else
3196 {
3197 throw std::domain_error("cannot use at() with " + type_name());
3198 }
3199 }
3200
3201 /*!
3202 @brief access specified object element with bounds checking
3203
3204 Returns a reference to the element at with specified key @a key, with
3205 bounds checking.
3206
3207 @param[in] key key of the element to access
3208
3209 @return reference to the element at key @a key
3210
3211 @throw std::domain_error if the JSON value is not an object; example:
3212 `"cannot use at() with boolean"`
3213 @throw std::out_of_range if the key @a key is is not stored in the object;
3214 that is, `find(key) == end()`; example: `"key "the fast" not found"`
3215
3216 @complexity Logarithmic in the size of the container.
3217
3218 @liveexample{The example below shows how object elements can be read and
3219 written using `at()`.,at__object_t_key_type}
3220
3221 @sa @ref operator[](const typename object_t::key_type&) for unchecked
3222 access by reference
3223 @sa @ref value() for access by value with a default value
3224
3225 @since version 1.0.0
3226 */
3227 reference at(const typename object_t::key_type& key)
3228 {
3229 // at only works for objects
3230 if (is_object())
3231 {
3232 try
3233 {
3234 return m_value.object->at(key);
3235 }
3236 catch (std::out_of_range&)
3237 {
3238 // create better exception explanation
3239 throw std::out_of_range("key '" + key + "' not found");
3240 }
3241 }
3242 else
3243 {
3244 throw std::domain_error("cannot use at() with " + type_name());
3245 }
3246 }
3247
3248 /*!
3249 @brief access specified object element with bounds checking
3250
3251 Returns a const reference to the element at with specified key @a key,
3252 with bounds checking.
3253
3254 @param[in] key key of the element to access
3255
3256 @return const reference to the element at key @a key
3257
3258 @throw std::domain_error if the JSON value is not an object; example:
3259 `"cannot use at() with boolean"`
3260 @throw std::out_of_range if the key @a key is is not stored in the object;
3261 that is, `find(key) == end()`; example: `"key "the fast" not found"`
3262
3263 @complexity Logarithmic in the size of the container.
3264
3265 @liveexample{The example below shows how object elements can be read using
3266 `at()`.,at__object_t_key_type_const}
3267
3268 @sa @ref operator[](const typename object_t::key_type&) for unchecked
3269 access by reference
3270 @sa @ref value() for access by value with a default value
3271
3272 @since version 1.0.0
3273 */
3274 const_reference at(const typename object_t::key_type& key) const
3275 {
3276 // at only works for objects
3277 if (is_object())
3278 {
3279 try
3280 {
3281 return m_value.object->at(key);
3282 }
3283 catch (std::out_of_range&)
3284 {
3285 // create better exception explanation
3286 throw std::out_of_range("key '" + key + "' not found");
3287 }
3288 }
3289 else
3290 {
3291 throw std::domain_error("cannot use at() with " + type_name());
3292 }
3293 }
3294
3295 /*!
3296 @brief access specified array element
3297
3298 Returns a reference to the element at specified location @a idx.
3299
3300 @note If @a idx is beyond the range of the array (i.e., `idx >= size()`),
3301 then the array is silently filled up with `null` values to make `idx` a
3302 valid reference to the last stored element.
3303
3304 @param[in] idx index of the element to access
3305
3306 @return reference to the element at index @a idx
3307
3308 @throw std::domain_error if JSON is not an array or null; example:
3309 `"cannot use operator[] with string"`
3310
3311 @complexity Constant if @a idx is in the range of the array. Otherwise
3312 linear in `idx - size()`.
3313
3314 @liveexample{The example below shows how array elements can be read and
3315 written using `[]` operator. Note the addition of `null`
3316 values.,operatorarray__size_type}
3317
3318 @since version 1.0.0
3319 */
3320 reference operator[](size_type idx)
3321 {
3322 // implicitly convert null value to an empty array
3323 if (is_null())
3324 {
3325 m_type = value_t::array;
3326 m_value.array = create<array_t>();
3327 assert_invariant();
3328 }
3329
3330 // operator[] only works for arrays
3331 if (is_array())
3332 {
3333 // fill up array with null values if given idx is outside range
3334 if (idx >= m_value.array->size())
3335 {
3336 m_value.array->insert(m_value.array->end(),
3337 idx - m_value.array->size() + 1,
3338 basic_json());
3339 }
3340
3341 return m_value.array->operator[](idx);
3342 }
3343 else
3344 {
3345 throw std::domain_error("cannot use operator[] with " + type_name());
3346 }
3347 }
3348
3349 /*!
3350 @brief access specified array element
3351
3352 Returns a const reference to the element at specified location @a idx.
3353
3354 @param[in] idx index of the element to access
3355
3356 @return const reference to the element at index @a idx
3357
3358 @throw std::domain_error if JSON is not an array; example: `"cannot use
3359 operator[] with null"`
3360
3361 @complexity Constant.
3362
3363 @liveexample{The example below shows how array elements can be read using
3364 the `[]` operator.,operatorarray__size_type_const}
3365
3366 @since version 1.0.0
3367 */
3368 const_reference operator[](size_type idx) const
3369 {
3370 // const operator[] only works for arrays
3371 if (is_array())
3372 {
3373 return m_value.array->operator[](idx);
3374 }
3375 else
3376 {
3377 throw std::domain_error("cannot use operator[] with " + type_name());
3378 }
3379 }
3380
3381 /*!
3382 @brief access specified object element
3383
3384 Returns a reference to the element at with specified key @a key.
3385
3386 @note If @a key is not found in the object, then it is silently added to
3387 the object and filled with a `null` value to make `key` a valid reference.
3388 In case the value was `null` before, it is converted to an object.
3389
3390 @param[in] key key of the element to access
3391
3392 @return reference to the element at key @a key
3393
3394 @throw std::domain_error if JSON is not an object or null; example:
3395 `"cannot use operator[] with string"`
3396
3397 @complexity Logarithmic in the size of the container.
3398
3399 @liveexample{The example below shows how object elements can be read and
3400 written using the `[]` operator.,operatorarray__key_type}
3401
3402 @sa @ref at(const typename object_t::key_type&) for access by reference
3403 with range checking
3404 @sa @ref value() for access by value with a default value
3405
3406 @since version 1.0.0
3407 */
3408 reference operator[](const typename object_t::key_type& key)
3409 {
3410 // implicitly convert null value to an empty object
3411 if (is_null())
3412 {
3413 m_type = value_t::object;
3414 m_value.object = create<object_t>();
3415 assert_invariant();
3416 }
3417
3418 // operator[] only works for objects
3419 if (is_object())
3420 {
3421 return m_value.object->operator[](key);
3422 }
3423 else
3424 {
3425 throw std::domain_error("cannot use operator[] with " + type_name());
3426 }
3427 }
3428
3429 /*!
3430 @brief read-only access specified object element
3431
3432 Returns a const reference to the element at with specified key @a key. No
3433 bounds checking is performed.
3434
3435 @warning If the element with key @a key does not exist, the behavior is
3436 undefined.
3437
3438 @param[in] key key of the element to access
3439
3440 @return const reference to the element at key @a key
3441
3442 @pre The element with key @a key must exist. **This precondition is
3443 enforced with an assertion.**
3444
3445 @throw std::domain_error if JSON is not an object; example: `"cannot use
3446 operator[] with null"`
3447
3448 @complexity Logarithmic in the size of the container.
3449
3450 @liveexample{The example below shows how object elements can be read using
3451 the `[]` operator.,operatorarray__key_type_const}
3452
3453 @sa @ref at(const typename object_t::key_type&) for access by reference
3454 with range checking
3455 @sa @ref value() for access by value with a default value
3456
3457 @since version 1.0.0
3458 */
3459 const_reference operator[](const typename object_t::key_type& key) const
3460 {
3461 // const operator[] only works for objects
3462 if (is_object())
3463 {
3464 assert(m_value.object->find(key) != m_value.object->end());
3465 return m_value.object->find(key)->second;
3466 }
3467 else
3468 {
3469 throw std::domain_error("cannot use operator[] with " + type_name());
3470 }
3471 }
3472
3473 /*!
3474 @brief access specified object element
3475
3476 Returns a reference to the element at with specified key @a key.
3477
3478 @note If @a key is not found in the object, then it is silently added to
3479 the object and filled with a `null` value to make `key` a valid reference.
3480 In case the value was `null` before, it is converted to an object.
3481
3482 @param[in] key key of the element to access
3483
3484 @return reference to the element at key @a key
3485
3486 @throw std::domain_error if JSON is not an object or null; example:
3487 `"cannot use operator[] with string"`
3488
3489 @complexity Logarithmic in the size of the container.
3490
3491 @liveexample{The example below shows how object elements can be read and
3492 written using the `[]` operator.,operatorarray__key_type}
3493
3494 @sa @ref at(const typename object_t::key_type&) for access by reference
3495 with range checking
3496 @sa @ref value() for access by value with a default value
3497
3498 @since version 1.0.0
3499 */
3500 template<typename T, std::size_t n>
3501 reference operator[](T * (&key)[n])
3502 {
3503 return operator[](static_cast<const T>(key));
3504 }
3505
3506 /*!
3507 @brief read-only access specified object element
3508
3509 Returns a const reference to the element at with specified key @a key. No
3510 bounds checking is performed.
3511
3512 @warning If the element with key @a key does not exist, the behavior is
3513 undefined.
3514
3515 @note This function is required for compatibility reasons with Clang.
3516
3517 @param[in] key key of the element to access
3518
3519 @return const reference to the element at key @a key
3520
3521 @throw std::domain_error if JSON is not an object; example: `"cannot use
3522 operator[] with null"`
3523
3524 @complexity Logarithmic in the size of the container.
3525
3526 @liveexample{The example below shows how object elements can be read using
3527 the `[]` operator.,operatorarray__key_type_const}
3528
3529 @sa @ref at(const typename object_t::key_type&) for access by reference
3530 with range checking
3531 @sa @ref value() for access by value with a default value
3532
3533 @since version 1.0.0
3534 */
3535 template<typename T, std::size_t n>
3536 const_reference operator[](T * (&key)[n]) const
3537 {
3538 return operator[](static_cast<const T>(key));
3539 }
3540
3541 /*!
3542 @brief access specified object element
3543
3544 Returns a reference to the element at with specified key @a key.
3545
3546 @note If @a key is not found in the object, then it is silently added to
3547 the object and filled with a `null` value to make `key` a valid reference.
3548 In case the value was `null` before, it is converted to an object.
3549
3550 @param[in] key key of the element to access
3551
3552 @return reference to the element at key @a key
3553
3554 @throw std::domain_error if JSON is not an object or null; example:
3555 `"cannot use operator[] with string"`
3556
3557 @complexity Logarithmic in the size of the container.
3558
3559 @liveexample{The example below shows how object elements can be read and
3560 written using the `[]` operator.,operatorarray__key_type}
3561
3562 @sa @ref at(const typename object_t::key_type&) for access by reference
3563 with range checking
3564 @sa @ref value() for access by value with a default value
3565
3566 @since version 1.1.0
3567 */
3568 template<typename T>
3569 reference operator[](T* key)
3570 {
3571 // implicitly convert null to object
3572 if (is_null())
3573 {
3574 m_type = value_t::object;
3575 m_value = value_t::object;
3576 assert_invariant();
3577 }
3578
3579 // at only works for objects
3580 if (is_object())
3581 {
3582 return m_value.object->operator[](key);
3583 }
3584 else
3585 {
3586 throw std::domain_error("cannot use operator[] with " + type_name());
3587 }
3588 }
3589
3590 /*!
3591 @brief read-only access specified object element
3592
3593 Returns a const reference to the element at with specified key @a key. No
3594 bounds checking is performed.
3595
3596 @warning If the element with key @a key does not exist, the behavior is
3597 undefined.
3598
3599 @param[in] key key of the element to access
3600
3601 @return const reference to the element at key @a key
3602
3603 @pre The element with key @a key must exist. **This precondition is
3604 enforced with an assertion.**
3605
3606 @throw std::domain_error if JSON is not an object; example: `"cannot use
3607 operator[] with null"`
3608
3609 @complexity Logarithmic in the size of the container.
3610
3611 @liveexample{The example below shows how object elements can be read using
3612 the `[]` operator.,operatorarray__key_type_const}
3613
3614 @sa @ref at(const typename object_t::key_type&) for access by reference
3615 with range checking
3616 @sa @ref value() for access by value with a default value
3617
3618 @since version 1.1.0
3619 */
3620 template<typename T>
3621 const_reference operator[](T* key) const
3622 {
3623 // at only works for objects
3624 if (is_object())
3625 {
3626 assert(m_value.object->find(key) != m_value.object->end());
3627 return m_value.object->find(key)->second;
3628 }
3629 else
3630 {
3631 throw std::domain_error("cannot use operator[] with " + type_name());
3632 }
3633 }
3634
3635 /*!
3636 @brief access specified object element with default value
3637
3638 Returns either a copy of an object's element at the specified key @a key
3639 or a given default value if no element with key @a key exists.
3640
3641 The function is basically equivalent to executing
3642 @code {.cpp}
3643 try {
3644 return at(key);
3645 } catch(std::out_of_range) {
3646 return default_value;
3647 }
3648 @endcode
3649
3650 @note Unlike @ref at(const typename object_t::key_type&), this function
3651 does not throw if the given key @a key was not found.
3652
3653 @note Unlike @ref operator[](const typename object_t::key_type& key), this
3654 function does not implicitly add an element to the position defined by @a
3655 key. This function is furthermore also applicable to const objects.
3656
3657 @param[in] key key of the element to access
3658 @param[in] default_value the value to return if @a key is not found
3659
3660 @tparam ValueType type compatible to JSON values, for instance `int` for
3661 JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for
3662 JSON arrays. Note the type of the expected value at @a key and the default
3663 value @a default_value must be compatible.
3664
3665 @return copy of the element at key @a key or @a default_value if @a key
3666 is not found
3667
3668 @throw std::domain_error if JSON is not an object; example: `"cannot use
3669 value() with null"`
3670
3671 @complexity Logarithmic in the size of the container.
3672
3673 @liveexample{The example below shows how object elements can be queried
3674 with a default value.,basic_json__value}
3675
3676 @sa @ref at(const typename object_t::key_type&) for access by reference
3677 with range checking
3678 @sa @ref operator[](const typename object_t::key_type&) for unchecked
3679 access by reference
3680
3681 @since version 1.0.0
3682 */
3683 template<class ValueType, typename std::enable_if<
3684 std::is_convertible<basic_json_t, ValueType>::value, int>::type = 0>
3685 ValueType value(const typename object_t::key_type& key, ValueType default_value) const
3686 {
3687 // at only works for objects
3688 if (is_object())
3689 {
3690 // if key is found, return value and given default value otherwise
3691 const auto it = find(key);
3692 if (it != end())
3693 {
3694 return *it;
3695 }
3696 else
3697 {
3698 return default_value;
3699 }
3700 }
3701 else
3702 {
3703 throw std::domain_error("cannot use value() with " + type_name());
3704 }
3705 }
3706
3707 /*!
3708 @brief overload for a default value of type const char*
3709 @copydoc basic_json::value(const typename object_t::key_type&, ValueType) const
3710 */
3711 string_t value(const typename object_t::key_type& key, const char* default_value) const
3712 {
3713 return value(key, string_t(default_value));
3714 }
3715
3716 /*!
3717 @brief access specified object element via JSON Pointer with default value
3718
3719 Returns either a copy of an object's element at the specified key @a key
3720 or a given default value if no element with key @a key exists.
3721
3722 The function is basically equivalent to executing
3723 @code {.cpp}
3724 try {
3725 return at(ptr);
3726 } catch(std::out_of_range) {
3727 return default_value;
3728 }
3729 @endcode
3730
3731 @note Unlike @ref at(const json_pointer&), this function does not throw
3732 if the given key @a key was not found.
3733
3734 @param[in] ptr a JSON pointer to the element to access
3735 @param[in] default_value the value to return if @a ptr found no value
3736
3737 @tparam ValueType type compatible to JSON values, for instance `int` for
3738 JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for
3739 JSON arrays. Note the type of the expected value at @a key and the default
3740 value @a default_value must be compatible.
3741
3742 @return copy of the element at key @a key or @a default_value if @a key
3743 is not found
3744
3745 @throw std::domain_error if JSON is not an object; example: `"cannot use
3746 value() with null"`
3747
3748 @complexity Logarithmic in the size of the container.
3749
3750 @liveexample{The example below shows how object elements can be queried
3751 with a default value.,basic_json__value_ptr}
3752
3753 @sa @ref operator[](const json_pointer&) for unchecked access by reference
3754
3755 @since version 2.0.2
3756 */
3757 template<class ValueType, typename std::enable_if<
3758 std::is_convertible<basic_json_t, ValueType>::value, int>::type = 0>
3759 ValueType value(const json_pointer& ptr, ValueType default_value) const
3760 {
3761 // at only works for objects
3762 if (is_object())
3763 {
3764 // if pointer resolves a value, return it or use default value
3765 try
3766 {
3767 return ptr.get_checked(this);
3768 }
3769 catch (std::out_of_range&)
3770 {
3771 return default_value;
3772 }
3773 }
3774 else
3775 {
3776 throw std::domain_error("cannot use value() with " + type_name());
3777 }
3778 }
3779
3780 /*!
3781 @brief overload for a default value of type const char*
3782 @copydoc basic_json::value(const json_pointer&, ValueType) const
3783 */
3784 string_t value(const json_pointer& ptr, const char* default_value) const
3785 {
3786 return value(ptr, string_t(default_value));
3787 }
3788
3789 /*!
3790 @brief access the first element
3791
3792 Returns a reference to the first element in the container. For a JSON
3793 container `c`, the expression `c.front()` is equivalent to `*c.begin()`.
3794
3795 @return In case of a structured type (array or object), a reference to the
3796 first element is returned. In cast of number, string, or boolean values, a
3797 reference to the value is returned.
3798
3799 @complexity Constant.
3800
3801 @pre The JSON value must not be `null` (would throw `std::out_of_range`)
3802 or an empty array or object (undefined behavior, **guarded by
3803 assertions**).
3804 @post The JSON value remains unchanged.
3805
3806 @throw std::out_of_range when called on `null` value
3807
3808 @liveexample{The following code shows an example for `front()`.,front}
3809
3810 @sa @ref back() -- access the last element
3811
3812 @since version 1.0.0
3813 */
3814 reference front()
3815 {
3816 return *begin();
3817 }
3818
3819 /*!
3820 @copydoc basic_json::front()
3821 */
3822 const_reference front() const
3823 {
3824 return *cbegin();
3825 }
3826
3827 /*!
3828 @brief access the last element
3829
3830 Returns a reference to the last element in the container. For a JSON
3831 container `c`, the expression `c.back()` is equivalent to
3832 @code {.cpp}
3833 auto tmp = c.end();
3834 --tmp;
3835 return *tmp;
3836 @endcode
3837
3838 @return In case of a structured type (array or object), a reference to the
3839 last element is returned. In cast of number, string, or boolean values, a
3840 reference to the value is returned.
3841
3842 @complexity Constant.
3843
3844 @pre The JSON value must not be `null` (would throw `std::out_of_range`)
3845 or an empty array or object (undefined behavior, **guarded by
3846 assertions**).
3847 @post The JSON value remains unchanged.
3848
3849 @throw std::out_of_range when called on `null` value.
3850
3851 @liveexample{The following code shows an example for `back()`.,back}
3852
3853 @sa @ref front() -- access the first element
3854
3855 @since version 1.0.0
3856 */
3857 reference back()
3858 {
3859 auto tmp = end();
3860 --tmp;
3861 return *tmp;
3862 }
3863
3864 /*!
3865 @copydoc basic_json::back()
3866 */
3867 const_reference back() const
3868 {
3869 auto tmp = cend();
3870 --tmp;
3871 return *tmp;
3872 }
3873
3874 /*!
3875 @brief remove element given an iterator
3876
3877 Removes the element specified by iterator @a pos. The iterator @a pos must
3878 be valid and dereferenceable. Thus the `end()` iterator (which is valid,
3879 but is not dereferenceable) cannot be used as a value for @a pos.
3880
3881 If called on a primitive type other than `null`, the resulting JSON value
3882 will be `null`.
3883
3884 @param[in] pos iterator to the element to remove
3885 @return Iterator following the last removed element. If the iterator @a
3886 pos refers to the last element, the `end()` iterator is returned.
3887
3888 @tparam IteratorType an @ref iterator or @ref const_iterator
3889
3890 @post Invalidates iterators and references at or after the point of the
3891 erase, including the `end()` iterator.
3892
3893 @throw std::domain_error if called on a `null` value; example: `"cannot
3894 use erase() with null"`
3895 @throw std::domain_error if called on an iterator which does not belong to
3896 the current JSON value; example: `"iterator does not fit current value"`
3897 @throw std::out_of_range if called on a primitive type with invalid
3898 iterator (i.e., any iterator which is not `begin()`); example: `"iterator
3899 out of range"`
3900
3901 @complexity The complexity depends on the type:
3902 - objects: amortized constant
3903 - arrays: linear in distance between pos and the end of the container
3904 - strings: linear in the length of the string
3905 - other types: constant
3906
3907 @liveexample{The example shows the result of `erase()` for different JSON
3908 types.,erase__IteratorType}
3909
3910 @sa @ref erase(IteratorType, IteratorType) -- removes the elements in
3911 the given range
3912 @sa @ref erase(const typename object_t::key_type&) -- removes the element
3913 from an object at the given key
3914 @sa @ref erase(const size_type) -- removes the element from an array at
3915 the given index
3916
3917 @since version 1.0.0
3918 */
3919 template<class IteratorType, typename std::enable_if<
3920 std::is_same<IteratorType, typename basic_json_t::iterator>::value or
3921 std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int>::type
3922 = 0>
3923 IteratorType erase(IteratorType pos)
3924 {
3925 // make sure iterator fits the current value
3926 if (this != pos.m_object)
3927 {
3928 throw std::domain_error("iterator does not fit current value");
3929 }
3930
3931 IteratorType result = end();
3932
3933 switch (m_type)
3934 {
3935 case value_t::boolean:
3936 case value_t::number_float:
3937 case value_t::number_integer:
3938 case value_t::number_unsigned:
3939 case value_t::string:
3940 {
3941 if (not pos.m_it.primitive_iterator.is_begin())
3942 {
3943 throw std::out_of_range("iterator out of range");
3944 }
3945
3946 if (is_string())
3947 {
3948 AllocatorType<string_t> alloc;
3949 alloc.destroy(m_value.string);
3950 alloc.deallocate(m_value.string, 1);
3951 m_value.string = nullptr;
3952 }
3953
3954 m_type = value_t::null;
3955 assert_invariant();
3956 break;
3957 }
3958
3959 case value_t::object:
3960 {
3961 result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator);
3962 break;
3963 }
3964
3965 case value_t::array:
3966 {
3967 result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator);
3968 break;
3969 }
3970
3971 default:
3972 {
3973 throw std::domain_error("cannot use erase() with " + type_name());
3974 }
3975 }
3976
3977 return result;
3978 }
3979
3980 /*!
3981 @brief remove elements given an iterator range
3982
3983 Removes the element specified by the range `[first; last)`. The iterator
3984 @a first does not need to be dereferenceable if `first == last`: erasing
3985 an empty range is a no-op.
3986
3987 If called on a primitive type other than `null`, the resulting JSON value
3988 will be `null`.
3989
3990 @param[in] first iterator to the beginning of the range to remove
3991 @param[in] last iterator past the end of the range to remove
3992 @return Iterator following the last removed element. If the iterator @a
3993 second refers to the last element, the `end()` iterator is returned.
3994
3995 @tparam IteratorType an @ref iterator or @ref const_iterator
3996
3997 @post Invalidates iterators and references at or after the point of the
3998 erase, including the `end()` iterator.
3999
4000 @throw std::domain_error if called on a `null` value; example: `"cannot
4001 use erase() with null"`
4002 @throw std::domain_error if called on iterators which does not belong to
4003 the current JSON value; example: `"iterators do not fit current value"`
4004 @throw std::out_of_range if called on a primitive type with invalid
4005 iterators (i.e., if `first != begin()` and `last != end()`); example:
4006 `"iterators out of range"`
4007
4008 @complexity The complexity depends on the type:
4009 - objects: `log(size()) + std::distance(first, last)`
4010 - arrays: linear in the distance between @a first and @a last, plus linear
4011 in the distance between @a last and end of the container
4012 - strings: linear in the length of the string
4013 - other types: constant
4014
4015 @liveexample{The example shows the result of `erase()` for different JSON
4016 types.,erase__IteratorType_IteratorType}
4017
4018 @sa @ref erase(IteratorType) -- removes the element at a given position
4019 @sa @ref erase(const typename object_t::key_type&) -- removes the element
4020 from an object at the given key
4021 @sa @ref erase(const size_type) -- removes the element from an array at
4022 the given index
4023
4024 @since version 1.0.0
4025 */
4026 template<class IteratorType, typename std::enable_if<
4027 std::is_same<IteratorType, typename basic_json_t::iterator>::value or
4028 std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int>::type
4029 = 0>
4030 IteratorType erase(IteratorType first, IteratorType last)
4031 {
4032 // make sure iterator fits the current value
4033 if (this != first.m_object or this != last.m_object)
4034 {
4035 throw std::domain_error("iterators do not fit current value");
4036 }
4037
4038 IteratorType result = end();
4039
4040 switch (m_type)
4041 {
4042 case value_t::boolean:
4043 case value_t::number_float:
4044 case value_t::number_integer:
4045 case value_t::number_unsigned:
4046 case value_t::string:
4047 {
4048 if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end())
4049 {
4050 throw std::out_of_range("iterators out of range");
4051 }
4052
4053 if (is_string())
4054 {
4055 AllocatorType<string_t> alloc;
4056 alloc.destroy(m_value.string);
4057 alloc.deallocate(m_value.string, 1);
4058 m_value.string = nullptr;
4059 }
4060
4061 m_type = value_t::null;
4062 assert_invariant();
4063 break;
4064 }
4065
4066 case value_t::object:
4067 {
4068 result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator,
4069 last.m_it.object_iterator);
4070 break;
4071 }
4072
4073 case value_t::array:
4074 {
4075 result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator,
4076 last.m_it.array_iterator);
4077 break;
4078 }
4079
4080 default:
4081 {
4082 throw std::domain_error("cannot use erase() with " + type_name());
4083 }
4084 }
4085
4086 return result;
4087 }
4088
4089 /*!
4090 @brief remove element from a JSON object given a key
4091
4092 Removes elements from a JSON object with the key value @a key.
4093
4094 @param[in] key value of the elements to remove
4095
4096 @return Number of elements removed. If @a ObjectType is the default
4097 `std::map` type, the return value will always be `0` (@a key was not
4098 found) or `1` (@a key was found).
4099
4100 @post References and iterators to the erased elements are invalidated.
4101 Other references and iterators are not affected.
4102
4103 @throw std::domain_error when called on a type other than JSON object;
4104 example: `"cannot use erase() with null"`
4105
4106 @complexity `log(size()) + count(key)`
4107
4108 @liveexample{The example shows the effect of `erase()`.,erase__key_type}
4109
4110 @sa @ref erase(IteratorType) -- removes the element at a given position
4111 @sa @ref erase(IteratorType, IteratorType) -- removes the elements in
4112 the given range
4113 @sa @ref erase(const size_type) -- removes the element from an array at
4114 the given index
4115
4116 @since version 1.0.0
4117 */
4118 size_type erase(const typename object_t::key_type& key)
4119 {
4120 // this erase only works for objects
4121 if (is_object())
4122 {
4123 return m_value.object->erase(key);
4124 }
4125 else
4126 {
4127 throw std::domain_error("cannot use erase() with " + type_name());
4128 }
4129 }
4130
4131 /*!
4132 @brief remove element from a JSON array given an index
4133
4134 Removes element from a JSON array at the index @a idx.
4135
4136 @param[in] idx index of the element to remove
4137
4138 @throw std::domain_error when called on a type other than JSON array;
4139 example: `"cannot use erase() with null"`
4140 @throw std::out_of_range when `idx >= size()`; example: `"array index 17
4141 is out of range"`
4142
4143 @complexity Linear in distance between @a idx and the end of the container.
4144
4145 @liveexample{The example shows the effect of `erase()`.,erase__size_type}
4146
4147 @sa @ref erase(IteratorType) -- removes the element at a given position
4148 @sa @ref erase(IteratorType, IteratorType) -- removes the elements in
4149 the given range
4150 @sa @ref erase(const typename object_t::key_type&) -- removes the element
4151 from an object at the given key
4152
4153 @since version 1.0.0
4154 */
4155 void erase(const size_type idx)
4156 {
4157 // this erase only works for arrays
4158 if (is_array())
4159 {
4160 if (idx >= size())
4161 {
4162 throw std::out_of_range("array index " + std::to_string(idx) + " is out of range");
4163 }
4164
4165 m_value.array->erase(m_value.array->begin() + static_cast<difference_type>(idx));
4166 }
4167 else
4168 {
4169 throw std::domain_error("cannot use erase() with " + type_name());
4170 }
4171 }
4172
4173 /// @}
4174
4175
4176 ////////////
4177 // lookup //
4178 ////////////
4179
4180 /// @name lookup
4181 /// @{
4182
4183 /*!
4184 @brief find an element in a JSON object
4185
4186 Finds an element in a JSON object with key equivalent to @a key. If the
4187 element is not found or the JSON value is not an object, end() is
4188 returned.
4189
4190 @param[in] key key value of the element to search for
4191
4192 @return Iterator to an element with key equivalent to @a key. If no such
4193 element is found, past-the-end (see end()) iterator is returned.
4194
4195 @complexity Logarithmic in the size of the JSON object.
4196
4197 @liveexample{The example shows how `find()` is used.,find__key_type}
4198
4199 @since version 1.0.0
4200 */
4201 iterator find(typename object_t::key_type key)
4202 {
4203 auto result = end();
4204
4205 if (is_object())
4206 {
4207 result.m_it.object_iterator = m_value.object->find(key);
4208 }
4209
4210 return result;
4211 }
4212
4213 /*!
4214 @brief find an element in a JSON object
4215 @copydoc find(typename object_t::key_type)
4216 */
4217 const_iterator find(typename object_t::key_type key) const
4218 {
4219 auto result = cend();
4220
4221 if (is_object())
4222 {
4223 result.m_it.object_iterator = m_value.object->find(key);
4224 }
4225
4226 return result;
4227 }
4228
4229 /*!
4230 @brief returns the number of occurrences of a key in a JSON object
4231
4232 Returns the number of elements with key @a key. If ObjectType is the
4233 default `std::map` type, the return value will always be `0` (@a key was
4234 not found) or `1` (@a key was found).
4235
4236 @param[in] key key value of the element to count
4237
4238 @return Number of elements with key @a key. If the JSON value is not an
4239 object, the return value will be `0`.
4240
4241 @complexity Logarithmic in the size of the JSON object.
4242
4243 @liveexample{The example shows how `count()` is used.,count}
4244
4245 @since version 1.0.0
4246 */
4247 size_type count(typename object_t::key_type key) const
4248 {
4249 // return 0 for all nonobject types
4250 return is_object() ? m_value.object->count(key) : 0;
4251 }
4252
4253 /// @}
4254
4255
4256 ///////////////
4257 // iterators //
4258 ///////////////
4259
4260 /// @name iterators
4261 /// @{
4262
4263 /*!
4264 @brief returns an iterator to the first element
4265
4266 Returns an iterator to the first element.
4267
4268 @image html range-begin-end.svg "Illustration from cppreference.com"
4269
4270 @return iterator to the first element
4271
4272 @complexity Constant.
4273
4274 @requirement This function helps `basic_json` satisfying the
4275 [Container](http://en.cppreference.com/w/cpp/concept/Container)
4276 requirements:
4277 - The complexity is constant.
4278
4279 @liveexample{The following code shows an example for `begin()`.,begin}
4280
4281 @sa @ref cbegin() -- returns a const iterator to the beginning
4282 @sa @ref end() -- returns an iterator to the end
4283 @sa @ref cend() -- returns a const iterator to the end
4284
4285 @since version 1.0.0
4286 */
4287 iterator begin() noexcept
4288 {
4289 iterator result(this);
4290 result.set_begin();
4291 return result;
4292 }
4293
4294 /*!
4295 @copydoc basic_json::cbegin()
4296 */
4297 const_iterator begin() const noexcept
4298 {
4299 return cbegin();
4300 }
4301
4302 /*!
4303 @brief returns a const iterator to the first element
4304
4305 Returns a const iterator to the first element.
4306
4307 @image html range-begin-end.svg "Illustration from cppreference.com"
4308
4309 @return const iterator to the first element
4310
4311 @complexity Constant.
4312
4313 @requirement This function helps `basic_json` satisfying the
4314 [Container](http://en.cppreference.com/w/cpp/concept/Container)
4315 requirements:
4316 - The complexity is constant.
4317 - Has the semantics of `const_cast<const basic_json&>(*this).begin()`.
4318
4319 @liveexample{The following code shows an example for `cbegin()`.,cbegin}
4320
4321 @sa @ref begin() -- returns an iterator to the beginning
4322 @sa @ref end() -- returns an iterator to the end
4323 @sa @ref cend() -- returns a const iterator to the end
4324
4325 @since version 1.0.0
4326 */
4327 const_iterator cbegin() const noexcept
4328 {
4329 const_iterator result(this);
4330 result.set_begin();
4331 return result;
4332 }
4333
4334 /*!
4335 @brief returns an iterator to one past the last element
4336
4337 Returns an iterator to one past the last element.
4338
4339 @image html range-begin-end.svg "Illustration from cppreference.com"
4340
4341 @return iterator one past the last element
4342
4343 @complexity Constant.
4344
4345 @requirement This function helps `basic_json` satisfying the
4346 [Container](http://en.cppreference.com/w/cpp/concept/Container)
4347 requirements:
4348 - The complexity is constant.
4349
4350 @liveexample{The following code shows an example for `end()`.,end}
4351
4352 @sa @ref cend() -- returns a const iterator to the end
4353 @sa @ref begin() -- returns an iterator to the beginning
4354 @sa @ref cbegin() -- returns a const iterator to the beginning
4355
4356 @since version 1.0.0
4357 */
4358 iterator end() noexcept
4359 {
4360 iterator result(this);
4361 result.set_end();
4362 return result;
4363 }
4364
4365 /*!
4366 @copydoc basic_json::cend()
4367 */
4368 const_iterator end() const noexcept
4369 {
4370 return cend();
4371 }
4372
4373 /*!
4374 @brief returns a const iterator to one past the last element
4375
4376 Returns a const iterator to one past the last element.
4377
4378 @image html range-begin-end.svg "Illustration from cppreference.com"
4379
4380 @return const iterator one past the last element
4381
4382 @complexity Constant.
4383
4384 @requirement This function helps `basic_json` satisfying the
4385 [Container](http://en.cppreference.com/w/cpp/concept/Container)
4386 requirements:
4387 - The complexity is constant.
4388 - Has the semantics of `const_cast<const basic_json&>(*this).end()`.
4389
4390 @liveexample{The following code shows an example for `cend()`.,cend}
4391
4392 @sa @ref end() -- returns an iterator to the end
4393 @sa @ref begin() -- returns an iterator to the beginning
4394 @sa @ref cbegin() -- returns a const iterator to the beginning
4395
4396 @since version 1.0.0
4397 */
4398 const_iterator cend() const noexcept
4399 {
4400 const_iterator result(this);
4401 result.set_end();
4402 return result;
4403 }
4404
4405 /*!
4406 @brief returns an iterator to the reverse-beginning
4407
4408 Returns an iterator to the reverse-beginning; that is, the last element.
4409
4410 @image html range-rbegin-rend.svg "Illustration from cppreference.com"
4411
4412 @complexity Constant.
4413
4414 @requirement This function helps `basic_json` satisfying the
4415 [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer)
4416 requirements:
4417 - The complexity is constant.
4418 - Has the semantics of `reverse_iterator(end())`.
4419
4420 @liveexample{The following code shows an example for `rbegin()`.,rbegin}
4421
4422 @sa @ref crbegin() -- returns a const reverse iterator to the beginning
4423 @sa @ref rend() -- returns a reverse iterator to the end
4424 @sa @ref crend() -- returns a const reverse iterator to the end
4425
4426 @since version 1.0.0
4427 */
4428 reverse_iterator rbegin() noexcept
4429 {
4430 return reverse_iterator(end());
4431 }
4432
4433 /*!
4434 @copydoc basic_json::crbegin()
4435 */
4436 const_reverse_iterator rbegin() const noexcept
4437 {
4438 return crbegin();
4439 }
4440
4441 /*!
4442 @brief returns an iterator to the reverse-end
4443
4444 Returns an iterator to the reverse-end; that is, one before the first
4445 element.
4446
4447 @image html range-rbegin-rend.svg "Illustration from cppreference.com"
4448
4449 @complexity Constant.
4450
4451 @requirement This function helps `basic_json` satisfying the
4452 [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer)
4453 requirements:
4454 - The complexity is constant.
4455 - Has the semantics of `reverse_iterator(begin())`.
4456
4457 @liveexample{The following code shows an example for `rend()`.,rend}
4458
4459 @sa @ref crend() -- returns a const reverse iterator to the end
4460 @sa @ref rbegin() -- returns a reverse iterator to the beginning
4461 @sa @ref crbegin() -- returns a const reverse iterator to the beginning
4462
4463 @since version 1.0.0
4464 */
4465 reverse_iterator rend() noexcept
4466 {
4467 return reverse_iterator(begin());
4468 }
4469
4470 /*!
4471 @copydoc basic_json::crend()
4472 */
4473 const_reverse_iterator rend() const noexcept
4474 {
4475 return crend();
4476 }
4477
4478 /*!
4479 @brief returns a const reverse iterator to the last element
4480
4481 Returns a const iterator to the reverse-beginning; that is, the last
4482 element.
4483
4484 @image html range-rbegin-rend.svg "Illustration from cppreference.com"
4485
4486 @complexity Constant.
4487
4488 @requirement This function helps `basic_json` satisfying the
4489 [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer)
4490 requirements:
4491 - The complexity is constant.
4492 - Has the semantics of `const_cast<const basic_json&>(*this).rbegin()`.
4493
4494 @liveexample{The following code shows an example for `crbegin()`.,crbegin}
4495
4496 @sa @ref rbegin() -- returns a reverse iterator to the beginning
4497 @sa @ref rend() -- returns a reverse iterator to the end
4498 @sa @ref crend() -- returns a const reverse iterator to the end
4499
4500 @since version 1.0.0
4501 */
4502 const_reverse_iterator crbegin() const noexcept
4503 {
4504 return const_reverse_iterator(cend());
4505 }
4506
4507 /*!
4508 @brief returns a const reverse iterator to one before the first
4509
4510 Returns a const reverse iterator to the reverse-end; that is, one before
4511 the first element.
4512
4513 @image html range-rbegin-rend.svg "Illustration from cppreference.com"
4514
4515 @complexity Constant.
4516
4517 @requirement This function helps `basic_json` satisfying the
4518 [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer)
4519 requirements:
4520 - The complexity is constant.
4521 - Has the semantics of `const_cast<const basic_json&>(*this).rend()`.
4522
4523 @liveexample{The following code shows an example for `crend()`.,crend}
4524
4525 @sa @ref rend() -- returns a reverse iterator to the end
4526 @sa @ref rbegin() -- returns a reverse iterator to the beginning
4527 @sa @ref crbegin() -- returns a const reverse iterator to the beginning
4528
4529 @since version 1.0.0
4530 */
4531 const_reverse_iterator crend() const noexcept
4532 {
4533 return const_reverse_iterator(cbegin());
4534 }
4535
4536 private:
4537 // forward declaration
4538 template<typename IteratorType> class iteration_proxy;
4539
4540 public:
4541 /*!
4542 @brief wrapper to access iterator member functions in range-based for
4543
4544 This function allows to access @ref iterator::key() and @ref
4545 iterator::value() during range-based for loops. In these loops, a
4546 reference to the JSON values is returned, so there is no access to the
4547 underlying iterator.
4548
4549 @note The name of this function is not yet final and may change in the
4550 future.
4551 */
4552 static iteration_proxy<iterator> iterator_wrapper(reference cont)
4553 {
4554 return iteration_proxy<iterator>(cont);
4555 }
4556
4557 /*!
4558 @copydoc iterator_wrapper(reference)
4559 */
4560 static iteration_proxy<const_iterator> iterator_wrapper(const_reference cont)
4561 {
4562 return iteration_proxy<const_iterator>(cont);
4563 }
4564
4565 /// @}
4566
4567
4568 //////////////
4569 // capacity //
4570 //////////////
4571
4572 /// @name capacity
4573 /// @{
4574
4575 /*!
4576 @brief checks whether the container is empty
4577
4578 Checks if a JSON value has no elements.
4579
4580 @return The return value depends on the different types and is
4581 defined as follows:
4582 Value type | return value
4583 ----------- | -------------
4584 null | `true`
4585 boolean | `false`
4586 string | `false`
4587 number | `false`
4588 object | result of function `object_t::empty()`
4589 array | result of function `array_t::empty()`
4590
4591 @note This function does not return whether a string stored as JSON value
4592 is empty - it returns whether the JSON container itself is empty which is
4593 false in the case of a string.
4594
4595 @complexity Constant, as long as @ref array_t and @ref object_t satisfy
4596 the Container concept; that is, their `empty()` functions have constant
4597 complexity.
4598
4599 @requirement This function helps `basic_json` satisfying the
4600 [Container](http://en.cppreference.com/w/cpp/concept/Container)
4601 requirements:
4602 - The complexity is constant.
4603 - Has the semantics of `begin() == end()`.
4604
4605 @liveexample{The following code uses `empty()` to check if a JSON
4606 object contains any elements.,empty}
4607
4608 @sa @ref size() -- returns the number of elements
4609
4610 @since version 1.0.0
4611 */
4612 bool empty() const noexcept
4613 {
4614 switch (m_type)
4615 {
4616 case value_t::null:
4617 {
4618 // null values are empty
4619 return true;
4620 }
4621
4622 case value_t::array:
4623 {
4624 // delegate call to array_t::empty()
4625 return m_value.array->empty();
4626 }
4627
4628 case value_t::object:
4629 {
4630 // delegate call to object_t::empty()
4631 return m_value.object->empty();
4632 }
4633
4634 default:
4635 {
4636 // all other types are nonempty
4637 return false;
4638 }
4639 }
4640 }
4641
4642 /*!
4643 @brief returns the number of elements
4644
4645 Returns the number of elements in a JSON value.
4646
4647 @return The return value depends on the different types and is
4648 defined as follows:
4649 Value type | return value
4650 ----------- | -------------
4651 null | `0`
4652 boolean | `1`
4653 string | `1`
4654 number | `1`
4655 object | result of function object_t::size()
4656 array | result of function array_t::size()
4657
4658 @note This function does not return the length of a string stored as JSON
4659 value - it returns the number of elements in the JSON value which is 1 in
4660 the case of a string.
4661
4662 @complexity Constant, as long as @ref array_t and @ref object_t satisfy
4663 the Container concept; that is, their size() functions have constant
4664 complexity.
4665
4666 @requirement This function helps `basic_json` satisfying the
4667 [Container](http://en.cppreference.com/w/cpp/concept/Container)
4668 requirements:
4669 - The complexity is constant.
4670 - Has the semantics of `std::distance(begin(), end())`.
4671
4672 @liveexample{The following code calls `size()` on the different value
4673 types.,size}
4674
4675 @sa @ref empty() -- checks whether the container is empty
4676 @sa @ref max_size() -- returns the maximal number of elements
4677
4678 @since version 1.0.0
4679 */
4680 size_type size() const noexcept
4681 {
4682 switch (m_type)
4683 {
4684 case value_t::null:
4685 {
4686 // null values are empty
4687 return 0;
4688 }
4689
4690 case value_t::array:
4691 {
4692 // delegate call to array_t::size()
4693 return m_value.array->size();
4694 }
4695
4696 case value_t::object:
4697 {
4698 // delegate call to object_t::size()
4699 return m_value.object->size();
4700 }
4701
4702 default:
4703 {
4704 // all other types have size 1
4705 return 1;
4706 }
4707 }
4708 }
4709
4710 /*!
4711 @brief returns the maximum possible number of elements
4712
4713 Returns the maximum number of elements a JSON value is able to hold due to
4714 system or library implementation limitations, i.e. `std::distance(begin(),
4715 end())` for the JSON value.
4716
4717 @return The return value depends on the different types and is
4718 defined as follows:
4719 Value type | return value
4720 ----------- | -------------
4721 null | `0` (same as `size()`)
4722 boolean | `1` (same as `size()`)
4723 string | `1` (same as `size()`)
4724 number | `1` (same as `size()`)
4725 object | result of function `object_t::max_size()`
4726 array | result of function `array_t::max_size()`
4727
4728 @complexity Constant, as long as @ref array_t and @ref object_t satisfy
4729 the Container concept; that is, their `max_size()` functions have constant
4730 complexity.
4731
4732 @requirement This function helps `basic_json` satisfying the
4733 [Container](http://en.cppreference.com/w/cpp/concept/Container)
4734 requirements:
4735 - The complexity is constant.
4736 - Has the semantics of returning `b.size()` where `b` is the largest
4737 possible JSON value.
4738
4739 @liveexample{The following code calls `max_size()` on the different value
4740 types. Note the output is implementation specific.,max_size}
4741
4742 @sa @ref size() -- returns the number of elements
4743
4744 @since version 1.0.0
4745 */
4746 size_type max_size() const noexcept
4747 {
4748 switch (m_type)
4749 {
4750 case value_t::array:
4751 {
4752 // delegate call to array_t::max_size()
4753 return m_value.array->max_size();
4754 }
4755
4756 case value_t::object:
4757 {
4758 // delegate call to object_t::max_size()
4759 return m_value.object->max_size();
4760 }
4761
4762 default:
4763 {
4764 // all other types have max_size() == size()
4765 return size();
4766 }
4767 }
4768 }
4769
4770 /// @}
4771
4772
4773 ///////////////
4774 // modifiers //
4775 ///////////////
4776
4777 /// @name modifiers
4778 /// @{
4779
4780 /*!
4781 @brief clears the contents
4782
4783 Clears the content of a JSON value and resets it to the default value as
4784 if @ref basic_json(value_t) would have been called:
4785
4786 Value type | initial value
4787 ----------- | -------------
4788 null | `null`
4789 boolean | `false`
4790 string | `""`
4791 number | `0`
4792 object | `{}`
4793 array | `[]`
4794
4795 @note Floating-point numbers are set to `0.0` which will be serialized to
4796 `0`. The vale type remains @ref number_float_t.
4797
4798 @complexity Linear in the size of the JSON value.
4799
4800 @liveexample{The example below shows the effect of `clear()` to different
4801 JSON types.,clear}
4802
4803 @since version 1.0.0
4804 */
4805 void clear() noexcept
4806 {
4807 switch (m_type)
4808 {
4809 case value_t::number_integer:
4810 {
4811 m_value.number_integer = 0;
4812 break;
4813 }
4814
4815 case value_t::number_unsigned:
4816 {
4817 m_value.number_unsigned = 0;
4818 break;
4819 }
4820
4821 case value_t::number_float:
4822 {
4823 m_value.number_float = 0.0;
4824 break;
4825 }
4826
4827 case value_t::boolean:
4828 {
4829 m_value.boolean = false;
4830 break;
4831 }
4832
4833 case value_t::string:
4834 {
4835 m_value.string->clear();
4836 break;
4837 }
4838
4839 case value_t::array:
4840 {
4841 m_value.array->clear();
4842 break;
4843 }
4844
4845 case value_t::object:
4846 {
4847 m_value.object->clear();
4848 break;
4849 }
4850
4851 default:
4852 {
4853 break;
4854 }
4855 }
4856 }
4857
4858 /*!
4859 @brief add an object to an array
4860
4861 Appends the given element @a val to the end of the JSON value. If the
4862 function is called on a JSON null value, an empty array is created before
4863 appending @a val.
4864
4865 @param[in] val the value to add to the JSON array
4866
4867 @throw std::domain_error when called on a type other than JSON array or
4868 null; example: `"cannot use push_back() with number"`
4869
4870 @complexity Amortized constant.
4871
4872 @liveexample{The example shows how `push_back()` and `+=` can be used to
4873 add elements to a JSON array. Note how the `null` value was silently
4874 converted to a JSON array.,push_back}
4875
4876 @since version 1.0.0
4877 */
4878 void push_back(basic_json&& val)
4879 {
4880 // push_back only works for null objects or arrays
4881 if (not(is_null() or is_array()))
4882 {
4883 throw std::domain_error("cannot use push_back() with " + type_name());
4884 }
4885
4886 // transform null object into an array
4887 if (is_null())
4888 {
4889 m_type = value_t::array;
4890 m_value = value_t::array;
4891 assert_invariant();
4892 }
4893
4894 // add element to array (move semantics)
4895 m_value.array->push_back(std::move(val));
4896 // invalidate object
4897 val.m_type = value_t::null;
4898 }
4899
4900 /*!
4901 @brief add an object to an array
4902 @copydoc push_back(basic_json&&)
4903 */
4904 reference operator+=(basic_json&& val)
4905 {
4906 push_back(std::move(val));
4907 return *this;
4908 }
4909
4910 /*!
4911 @brief add an object to an array
4912 @copydoc push_back(basic_json&&)
4913 */
4914 void push_back(const basic_json& val)
4915 {
4916 // push_back only works for null objects or arrays
4917 if (not(is_null() or is_array()))
4918 {
4919 throw std::domain_error("cannot use push_back() with " + type_name());
4920 }
4921
4922 // transform null object into an array
4923 if (is_null())
4924 {
4925 m_type = value_t::array;
4926 m_value = value_t::array;
4927 assert_invariant();
4928 }
4929
4930 // add element to array
4931 m_value.array->push_back(val);
4932 }
4933
4934 /*!
4935 @brief add an object to an array
4936 @copydoc push_back(basic_json&&)
4937 */
4938 reference operator+=(const basic_json& val)
4939 {
4940 push_back(val);
4941 return *this;
4942 }
4943
4944 /*!
4945 @brief add an object to an object
4946
4947 Inserts the given element @a val to the JSON object. If the function is
4948 called on a JSON null value, an empty object is created before inserting
4949 @a val.
4950
4951 @param[in] val the value to add to the JSON object
4952
4953 @throw std::domain_error when called on a type other than JSON object or
4954 null; example: `"cannot use push_back() with number"`
4955
4956 @complexity Logarithmic in the size of the container, O(log(`size()`)).
4957
4958 @liveexample{The example shows how `push_back()` and `+=` can be used to
4959 add elements to a JSON object. Note how the `null` value was silently
4960 converted to a JSON object.,push_back__object_t__value}
4961
4962 @since version 1.0.0
4963 */
4964 void push_back(const typename object_t::value_type& val)
4965 {
4966 // push_back only works for null objects or objects
4967 if (not(is_null() or is_object()))
4968 {
4969 throw std::domain_error("cannot use push_back() with " + type_name());
4970 }
4971
4972 // transform null object into an object
4973 if (is_null())
4974 {
4975 m_type = value_t::object;
4976 m_value = value_t::object;
4977 assert_invariant();
4978 }
4979
4980 // add element to array
4981 m_value.object->insert(val);
4982 }
4983
4984 /*!
4985 @brief add an object to an object
4986 @copydoc push_back(const typename object_t::value_type&)
4987 */
4988 reference operator+=(const typename object_t::value_type& val)
4989 {
4990 push_back(val);
4991 return *this;
4992 }
4993
4994 /*!
4995 @brief add an object to an object
4996
4997 This function allows to use `push_back` with an initializer list. In case
4998
4999 1. the current value is an object,
5000 2. the initializer list @a init contains only two elements, and
5001 3. the first element of @a init is a string,
5002
5003 @a init is converted into an object element and added using
5004 @ref push_back(const typename object_t::value_type&). Otherwise, @a init
5005 is converted to a JSON value and added using @ref push_back(basic_json&&).
5006
5007 @param init an initializer list
5008
5009 @complexity Linear in the size of the initializer list @a init.
5010
5011 @note This function is required to resolve an ambiguous overload error,
5012 because pairs like `{"key", "value"}` can be both interpreted as
5013 `object_t::value_type` or `std::initializer_list<basic_json>`, see
5014 https://github.com/nlohmann/json/issues/235 for more information.
5015
5016 @liveexample{The example shows how initializer lists are treated as
5017 objects when possible.,push_back__initializer_list}
5018 */
5019 void push_back(std::initializer_list<basic_json> init)
5020 {
5021 if (is_object() and init.size() == 2 and init.begin()->is_string())
5022 {
5023 const string_t key = *init.begin();
5024 push_back(typename object_t::value_type(key, *(init.begin() + 1)));
5025 }
5026 else
5027 {
5028 push_back(basic_json(init));
5029 }
5030 }
5031
5032 /*!
5033 @brief add an object to an object
5034 @copydoc push_back(std::initializer_list<basic_json>)
5035 */
5036 reference operator+=(std::initializer_list<basic_json> init)
5037 {
5038 push_back(init);
5039 return *this;
5040 }
5041
5042 /*!
5043 @brief add an object to an array
5044
5045 Creates a JSON value from the passed parameters @a args to the end of the
5046 JSON value. If the function is called on a JSON null value, an empty array
5047 is created before appending the value created from @a args.
5048
5049 @param[in] args arguments to forward to a constructor of @ref basic_json
5050 @tparam Args compatible types to create a @ref basic_json object
5051
5052 @throw std::domain_error when called on a type other than JSON array or
5053 null; example: `"cannot use emplace_back() with number"`
5054
5055 @complexity Amortized constant.
5056
5057 @liveexample{The example shows how `push_back()` can be used to add
5058 elements to a JSON array. Note how the `null` value was silently converted
5059 to a JSON array.,emplace_back}
5060
5061 @since version 2.0.8
5062 */
5063 template<class... Args>
5064 void emplace_back(Args&& ... args)
5065 {
5066 // emplace_back only works for null objects or arrays
5067 if (not(is_null() or is_array()))
5068 {
5069 throw std::domain_error("cannot use emplace_back() with " + type_name());
5070 }
5071
5072 // transform null object into an array
5073 if (is_null())
5074 {
5075 m_type = value_t::array;
5076 m_value = value_t::array;
5077 assert_invariant();
5078 }
5079
5080 // add element to array (perfect forwarding)
5081 m_value.array->emplace_back(std::forward<Args>(args)...);
5082 }
5083
5084 /*!
5085 @brief add an object to an object if key does not exist
5086
5087 Inserts a new element into a JSON object constructed in-place with the given
5088 @a args if there is no element with the key in the container. If the
5089 function is called on a JSON null value, an empty object is created before
5090 appending the value created from @a args.
5091
5092 @param[in] args arguments to forward to a constructor of @ref basic_json
5093 @tparam Args compatible types to create a @ref basic_json object
5094
5095 @return a pair consisting of an iterator to the inserted element, or the
5096 already-existing element if no insertion happened, and a bool
5097 denoting whether the insertion took place.
5098
5099 @throw std::domain_error when called on a type other than JSON object or
5100 null; example: `"cannot use emplace() with number"`
5101
5102 @complexity Logarithmic in the size of the container, O(log(`size()`)).
5103
5104 @liveexample{The example shows how `emplace()` can be used to add elements
5105 to a JSON object. Note how the `null` value was silently converted to a
5106 JSON object. Further note how no value is added if there was already one
5107 value stored with the same key.,emplace}
5108
5109 @since version 2.0.8
5110 */
5111 template<class... Args>
5112 std::pair<iterator, bool> emplace(Args&& ... args)
5113 {
5114 // emplace only works for null objects or arrays
5115 if (not(is_null() or is_object()))
5116 {
5117 throw std::domain_error("cannot use emplace() with " + type_name());
5118 }
5119
5120 // transform null object into an object
5121 if (is_null())
5122 {
5123 m_type = value_t::object;
5124 m_value = value_t::object;
5125 assert_invariant();
5126 }
5127
5128 // add element to array (perfect forwarding)
5129 auto res = m_value.object->emplace(std::forward<Args>(args)...);
5130 // create result iterator and set iterator to the result of emplace
5131 auto it = begin();
5132 it.m_it.object_iterator = res.first;
5133
5134 // return pair of iterator and boolean
5135 return {it, res.second};
5136 }
5137
5138 /*!
5139 @brief inserts element
5140
5141 Inserts element @a val before iterator @a pos.
5142
5143 @param[in] pos iterator before which the content will be inserted; may be
5144 the end() iterator
5145 @param[in] val element to insert
5146 @return iterator pointing to the inserted @a val.
5147
5148 @throw std::domain_error if called on JSON values other than arrays;
5149 example: `"cannot use insert() with string"`
5150 @throw std::domain_error if @a pos is not an iterator of *this; example:
5151 `"iterator does not fit current value"`
5152
5153 @complexity Constant plus linear in the distance between pos and end of the
5154 container.
5155
5156 @liveexample{The example shows how `insert()` is used.,insert}
5157
5158 @since version 1.0.0
5159 */
5160 iterator insert(const_iterator pos, const basic_json& val)
5161 {
5162 // insert only works for arrays
5163 if (is_array())
5164 {
5165 // check if iterator pos fits to this JSON value
5166 if (pos.m_object != this)
5167 {
5168 throw std::domain_error("iterator does not fit current value");
5169 }
5170
5171 // insert to array and return iterator
5172 iterator result(this);
5173 result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val);
5174 return result;
5175 }
5176 else
5177 {
5178 throw std::domain_error("cannot use insert() with " + type_name());
5179 }
5180 }
5181
5182 /*!
5183 @brief inserts element
5184 @copydoc insert(const_iterator, const basic_json&)
5185 */
5186 iterator insert(const_iterator pos, basic_json&& val)
5187 {
5188 return insert(pos, val);
5189 }
5190
5191 /*!
5192 @brief inserts elements
5193
5194 Inserts @a cnt copies of @a val before iterator @a pos.
5195
5196 @param[in] pos iterator before which the content will be inserted; may be
5197 the end() iterator
5198 @param[in] cnt number of copies of @a val to insert
5199 @param[in] val element to insert
5200 @return iterator pointing to the first element inserted, or @a pos if
5201 `cnt==0`
5202
5203 @throw std::domain_error if called on JSON values other than arrays;
5204 example: `"cannot use insert() with string"`
5205 @throw std::domain_error if @a pos is not an iterator of *this; example:
5206 `"iterator does not fit current value"`
5207
5208 @complexity Linear in @a cnt plus linear in the distance between @a pos
5209 and end of the container.
5210
5211 @liveexample{The example shows how `insert()` is used.,insert__count}
5212
5213 @since version 1.0.0
5214 */
5215 iterator insert(const_iterator pos, size_type cnt, const basic_json& val)
5216 {
5217 // insert only works for arrays
5218 if (is_array())
5219 {
5220 // check if iterator pos fits to this JSON value
5221 if (pos.m_object != this)
5222 {
5223 throw std::domain_error("iterator does not fit current value");
5224 }
5225
5226 // insert to array and return iterator
5227 iterator result(this);
5228 result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val);
5229 return result;
5230 }
5231 else
5232 {
5233 throw std::domain_error("cannot use insert() with " + type_name());
5234 }
5235 }
5236
5237 /*!
5238 @brief inserts elements
5239
5240 Inserts elements from range `[first, last)` before iterator @a pos.
5241
5242 @param[in] pos iterator before which the content will be inserted; may be
5243 the end() iterator
5244 @param[in] first begin of the range of elements to insert
5245 @param[in] last end of the range of elements to insert
5246
5247 @throw std::domain_error if called on JSON values other than arrays;
5248 example: `"cannot use insert() with string"`
5249 @throw std::domain_error if @a pos is not an iterator of *this; example:
5250 `"iterator does not fit current value"`
5251 @throw std::domain_error if @a first and @a last do not belong to the same
5252 JSON value; example: `"iterators do not fit"`
5253 @throw std::domain_error if @a first or @a last are iterators into
5254 container for which insert is called; example: `"passed iterators may not
5255 belong to container"`
5256
5257 @return iterator pointing to the first element inserted, or @a pos if
5258 `first==last`
5259
5260 @complexity Linear in `std::distance(first, last)` plus linear in the
5261 distance between @a pos and end of the container.
5262
5263 @liveexample{The example shows how `insert()` is used.,insert__range}
5264
5265 @since version 1.0.0
5266 */
5267 iterator insert(const_iterator pos, const_iterator first, const_iterator last)
5268 {
5269 // insert only works for arrays
5270 if (not is_array())
5271 {
5272 throw std::domain_error("cannot use insert() with " + type_name());
5273 }
5274
5275 // check if iterator pos fits to this JSON value
5276 if (pos.m_object != this)
5277 {
5278 throw std::domain_error("iterator does not fit current value");
5279 }
5280
5281 // check if range iterators belong to the same JSON object
5282 if (first.m_object != last.m_object)
5283 {
5284 throw std::domain_error("iterators do not fit");
5285 }
5286
5287 if (first.m_object == this or last.m_object == this)
5288 {
5289 throw std::domain_error("passed iterators may not belong to container");
5290 }
5291
5292 // insert to array and return iterator
5293 iterator result(this);
5294 result.m_it.array_iterator = m_value.array->insert(
5295 pos.m_it.array_iterator,
5296 first.m_it.array_iterator,
5297 last.m_it.array_iterator);
5298 return result;
5299 }
5300
5301 /*!
5302 @brief inserts elements
5303
5304 Inserts elements from initializer list @a ilist before iterator @a pos.
5305
5306 @param[in] pos iterator before which the content will be inserted; may be
5307 the end() iterator
5308 @param[in] ilist initializer list to insert the values from
5309
5310 @throw std::domain_error if called on JSON values other than arrays;
5311 example: `"cannot use insert() with string"`
5312 @throw std::domain_error if @a pos is not an iterator of *this; example:
5313 `"iterator does not fit current value"`
5314
5315 @return iterator pointing to the first element inserted, or @a pos if
5316 `ilist` is empty
5317
5318 @complexity Linear in `ilist.size()` plus linear in the distance between
5319 @a pos and end of the container.
5320
5321 @liveexample{The example shows how `insert()` is used.,insert__ilist}
5322
5323 @since version 1.0.0
5324 */
5325 iterator insert(const_iterator pos, std::initializer_list<basic_json> ilist)
5326 {
5327 // insert only works for arrays
5328 if (not is_array())
5329 {
5330 throw std::domain_error("cannot use insert() with " + type_name());
5331 }
5332
5333 // check if iterator pos fits to this JSON value
5334 if (pos.m_object != this)
5335 {
5336 throw std::domain_error("iterator does not fit current value");
5337 }
5338
5339 // insert to array and return iterator
5340 iterator result(this);
5341 result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist);
5342 return result;
5343 }
5344
5345 /*!
5346 @brief exchanges the values
5347
5348 Exchanges the contents of the JSON value with those of @a other. Does not
5349 invoke any move, copy, or swap operations on individual elements. All
5350 iterators and references remain valid. The past-the-end iterator is
5351 invalidated.
5352
5353 @param[in,out] other JSON value to exchange the contents with
5354
5355 @complexity Constant.
5356
5357 @liveexample{The example below shows how JSON values can be swapped with
5358 `swap()`.,swap__reference}
5359
5360 @since version 1.0.0
5361 */
5362 void swap(reference other) noexcept (
5363 std::is_nothrow_move_constructible<value_t>::value and
5364 std::is_nothrow_move_assignable<value_t>::value and
5365 std::is_nothrow_move_constructible<json_value>::value and
5366 std::is_nothrow_move_assignable<json_value>::value
5367 )
5368 {
5369 std::swap(m_type, other.m_type);
5370 std::swap(m_value, other.m_value);
5371 assert_invariant();
5372 }
5373
5374 /*!
5375 @brief exchanges the values
5376
5377 Exchanges the contents of a JSON array with those of @a other. Does not
5378 invoke any move, copy, or swap operations on individual elements. All
5379 iterators and references remain valid. The past-the-end iterator is
5380 invalidated.
5381
5382 @param[in,out] other array to exchange the contents with
5383
5384 @throw std::domain_error when JSON value is not an array; example: `"cannot
5385 use swap() with string"`
5386
5387 @complexity Constant.
5388
5389 @liveexample{The example below shows how arrays can be swapped with
5390 `swap()`.,swap__array_t}
5391
5392 @since version 1.0.0
5393 */
5394 void swap(array_t& other)
5395 {
5396 // swap only works for arrays
5397 if (is_array())
5398 {
5399 std::swap(*(m_value.array), other);
5400 }
5401 else
5402 {
5403 throw std::domain_error("cannot use swap() with " + type_name());
5404 }
5405 }
5406
5407 /*!
5408 @brief exchanges the values
5409
5410 Exchanges the contents of a JSON object with those of @a other. Does not
5411 invoke any move, copy, or swap operations on individual elements. All
5412 iterators and references remain valid. The past-the-end iterator is
5413 invalidated.
5414
5415 @param[in,out] other object to exchange the contents with
5416
5417 @throw std::domain_error when JSON value is not an object; example:
5418 `"cannot use swap() with string"`
5419
5420 @complexity Constant.
5421
5422 @liveexample{The example below shows how objects can be swapped with
5423 `swap()`.,swap__object_t}
5424
5425 @since version 1.0.0
5426 */
5427 void swap(object_t& other)
5428 {
5429 // swap only works for objects
5430 if (is_object())
5431 {
5432 std::swap(*(m_value.object), other);
5433 }
5434 else
5435 {
5436 throw std::domain_error("cannot use swap() with " + type_name());
5437 }
5438 }
5439
5440 /*!
5441 @brief exchanges the values
5442
5443 Exchanges the contents of a JSON string with those of @a other. Does not
5444 invoke any move, copy, or swap operations on individual elements. All
5445 iterators and references remain valid. The past-the-end iterator is
5446 invalidated.
5447
5448 @param[in,out] other string to exchange the contents with
5449
5450 @throw std::domain_error when JSON value is not a string; example: `"cannot
5451 use swap() with boolean"`
5452
5453 @complexity Constant.
5454
5455 @liveexample{The example below shows how strings can be swapped with
5456 `swap()`.,swap__string_t}
5457
5458 @since version 1.0.0
5459 */
5460 void swap(string_t& other)
5461 {
5462 // swap only works for strings
5463 if (is_string())
5464 {
5465 std::swap(*(m_value.string), other);
5466 }
5467 else
5468 {
5469 throw std::domain_error("cannot use swap() with " + type_name());
5470 }
5471 }
5472
5473 /// @}
5474
5475
5476 //////////////////////////////////////////
5477 // lexicographical comparison operators //
5478 //////////////////////////////////////////
5479
5480 /// @name lexicographical comparison operators
5481 /// @{
5482
5483 private:
5484 /*!
5485 @brief comparison operator for JSON types
5486
5487 Returns an ordering that is similar to Python:
5488 - order: null < boolean < number < object < array < string
5489 - furthermore, each type is not smaller than itself
5490
5491 @since version 1.0.0
5492 */
5493 friend bool operator<(const value_t lhs, const value_t rhs) noexcept
5494 {
5495 static constexpr std::array<uint8_t, 8> order = {{
5496 0, // null
5497 3, // object
5498 4, // array
5499 5, // string
5500 1, // boolean
5501 2, // integer
5502 2, // unsigned
5503 2, // float
5504 }
5505 };
5506
5507 // discarded values are not comparable
5508 if (lhs == value_t::discarded or rhs == value_t::discarded)
5509 {
5510 return false;
5511 }
5512
5513 return order[static_cast<std::size_t>(lhs)] < order[static_cast<std::size_t>(rhs)];
5514 }
5515
5516 public:
5517 /*!
5518 @brief comparison: equal
5519
5520 Compares two JSON values for equality according to the following rules:
5521 - Two JSON values are equal if (1) they are from the same type and (2)
5522 their stored values are the same.
5523 - Integer and floating-point numbers are automatically converted before
5524 comparison. Floating-point numbers are compared indirectly: two
5525 floating-point numbers `f1` and `f2` are considered equal if neither
5526 `f1 > f2` nor `f2 > f1` holds.
5527 - Two JSON null values are equal.
5528
5529 @param[in] lhs first JSON value to consider
5530 @param[in] rhs second JSON value to consider
5531 @return whether the values @a lhs and @a rhs are equal
5532
5533 @complexity Linear.
5534
5535 @liveexample{The example demonstrates comparing several JSON
5536 types.,operator__equal}
5537
5538 @since version 1.0.0
5539 */
5540 friend bool operator==(const_reference lhs, const_reference rhs) noexcept
5541 {
5542 const auto lhs_type = lhs.type();
5543 const auto rhs_type = rhs.type();
5544
5545 if (lhs_type == rhs_type)
5546 {
5547 switch (lhs_type)
5548 {
5549 case value_t::array:
5550 {
5551 return *lhs.m_value.array == *rhs.m_value.array;
5552 }
5553 case value_t::object:
5554 {
5555 return *lhs.m_value.object == *rhs.m_value.object;
5556 }
5557 case value_t::null:
5558 {
5559 return true;
5560 }
5561 case value_t::string:
5562 {
5563 return *lhs.m_value.string == *rhs.m_value.string;
5564 }
5565 case value_t::boolean:
5566 {
5567 return lhs.m_value.boolean == rhs.m_value.boolean;
5568 }
5569 case value_t::number_integer:
5570 {
5571 return lhs.m_value.number_integer == rhs.m_value.number_integer;
5572 }
5573 case value_t::number_unsigned:
5574 {
5575 return lhs.m_value.number_unsigned == rhs.m_value.number_unsigned;
5576 }
5577 case value_t::number_float:
5578 {
5579 return lhs.m_value.number_float == rhs.m_value.number_float;
5580 }
5581 default:
5582 {
5583 return false;
5584 }
5585 }
5586 }
5587 else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float)
5588 {
5589 return static_cast<number_float_t>(lhs.m_value.number_integer) == rhs.m_value.number_float;
5590 }
5591 else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer)
5592 {
5593 return lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_integer);
5594 }
5595 else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float)
5596 {
5597 return static_cast<number_float_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_float;
5598 }
5599 else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned)
5600 {
5601 return lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_unsigned);
5602 }
5603 else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer)
5604 {
5605 return static_cast<number_integer_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_integer;
5606 }
5607 else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned)
5608 {
5609 return lhs.m_value.number_integer == static_cast<number_integer_t>(rhs.m_value.number_unsigned);
5610 }
5611
5612 return false;
5613 }
5614
5615 /*!
5616 @brief comparison: equal
5617
5618 The functions compares the given JSON value against a null pointer. As the
5619 null pointer can be used to initialize a JSON value to null, a comparison
5620 of JSON value @a v with a null pointer should be equivalent to call
5621 `v.is_null()`.
5622
5623 @param[in] v JSON value to consider
5624 @return whether @a v is null
5625
5626 @complexity Constant.
5627
5628 @liveexample{The example compares several JSON types to the null pointer.
5629 ,operator__equal__nullptr_t}
5630
5631 @since version 1.0.0
5632 */
5633 friend bool operator==(const_reference v, std::nullptr_t) noexcept
5634 {
5635 return v.is_null();
5636 }
5637
5638 /*!
5639 @brief comparison: equal
5640 @copydoc operator==(const_reference, std::nullptr_t)
5641 */
5642 friend bool operator==(std::nullptr_t, const_reference v) noexcept
5643 {
5644 return v.is_null();
5645 }
5646
5647 /*!
5648 @brief comparison: not equal
5649
5650 Compares two JSON values for inequality by calculating `not (lhs == rhs)`.
5651
5652 @param[in] lhs first JSON value to consider
5653 @param[in] rhs second JSON value to consider
5654 @return whether the values @a lhs and @a rhs are not equal
5655
5656 @complexity Linear.
5657
5658 @liveexample{The example demonstrates comparing several JSON
5659 types.,operator__notequal}
5660
5661 @since version 1.0.0
5662 */
5663 friend bool operator!=(const_reference lhs, const_reference rhs) noexcept
5664 {
5665 return not (lhs == rhs);
5666 }
5667
5668 /*!
5669 @brief comparison: not equal
5670
5671 The functions compares the given JSON value against a null pointer. As the
5672 null pointer can be used to initialize a JSON value to null, a comparison
5673 of JSON value @a v with a null pointer should be equivalent to call
5674 `not v.is_null()`.
5675
5676 @param[in] v JSON value to consider
5677 @return whether @a v is not null
5678
5679 @complexity Constant.
5680
5681 @liveexample{The example compares several JSON types to the null pointer.
5682 ,operator__notequal__nullptr_t}
5683
5684 @since version 1.0.0
5685 */
5686 friend bool operator!=(const_reference v, std::nullptr_t) noexcept
5687 {
5688 return not v.is_null();
5689 }
5690
5691 /*!
5692 @brief comparison: not equal
5693 @copydoc operator!=(const_reference, std::nullptr_t)
5694 */
5695 friend bool operator!=(std::nullptr_t, const_reference v) noexcept
5696 {
5697 return not v.is_null();
5698 }
5699
5700 /*!
5701 @brief comparison: less than
5702
5703 Compares whether one JSON value @a lhs is less than another JSON value @a
5704 rhs according to the following rules:
5705 - If @a lhs and @a rhs have the same type, the values are compared using
5706 the default `<` operator.
5707 - Integer and floating-point numbers are automatically converted before
5708 comparison
5709 - In case @a lhs and @a rhs have different types, the values are ignored
5710 and the order of the types is considered, see
5711 @ref operator<(const value_t, const value_t).
5712
5713 @param[in] lhs first JSON value to consider
5714 @param[in] rhs second JSON value to consider
5715 @return whether @a lhs is less than @a rhs
5716
5717 @complexity Linear.
5718
5719 @liveexample{The example demonstrates comparing several JSON
5720 types.,operator__less}
5721
5722 @since version 1.0.0
5723 */
5724 friend bool operator<(const_reference lhs, const_reference rhs) noexcept
5725 {
5726 const auto lhs_type = lhs.type();
5727 const auto rhs_type = rhs.type();
5728
5729 if (lhs_type == rhs_type)
5730 {
5731 switch (lhs_type)
5732 {
5733 case value_t::array:
5734 {
5735 return *lhs.m_value.array < *rhs.m_value.array;
5736 }
5737 case value_t::object:
5738 {
5739 return *lhs.m_value.object < *rhs.m_value.object;
5740 }
5741 case value_t::null:
5742 {
5743 return false;
5744 }
5745 case value_t::string:
5746 {
5747 return *lhs.m_value.string < *rhs.m_value.string;
5748 }
5749 case value_t::boolean:
5750 {
5751 return lhs.m_value.boolean < rhs.m_value.boolean;
5752 }
5753 case value_t::number_integer:
5754 {
5755 return lhs.m_value.number_integer < rhs.m_value.number_integer;
5756 }
5757 case value_t::number_unsigned:
5758 {
5759 return lhs.m_value.number_unsigned < rhs.m_value.number_unsigned;
5760 }
5761 case value_t::number_float:
5762 {
5763 return lhs.m_value.number_float < rhs.m_value.number_float;
5764 }
5765 default:
5766 {
5767 return false;
5768 }
5769 }
5770 }
5771 else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float)
5772 {
5773 return static_cast<number_float_t>(lhs.m_value.number_integer) < rhs.m_value.number_float;
5774 }
5775 else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer)
5776 {
5777 return lhs.m_value.number_float < static_cast<number_float_t>(rhs.m_value.number_integer);
5778 }
5779 else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float)
5780 {
5781 return static_cast<number_float_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_float;
5782 }
5783 else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned)
5784 {
5785 return lhs.m_value.number_float < static_cast<number_float_t>(rhs.m_value.number_unsigned);
5786 }
5787 else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned)
5788 {
5789 return lhs.m_value.number_integer < static_cast<number_integer_t>(rhs.m_value.number_unsigned);
5790 }
5791 else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer)
5792 {
5793 return static_cast<number_integer_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_integer;
5794 }
5795
5796 // We only reach this line if we cannot compare values. In that case,
5797 // we compare types. Note we have to call the operator explicitly,
5798 // because MSVC has problems otherwise.
5799 return operator<(lhs_type, rhs_type);
5800 }
5801
5802 /*!
5803 @brief comparison: less than or equal
5804
5805 Compares whether one JSON value @a lhs is less than or equal to another
5806 JSON value by calculating `not (rhs < lhs)`.
5807
5808 @param[in] lhs first JSON value to consider
5809 @param[in] rhs second JSON value to consider
5810 @return whether @a lhs is less than or equal to @a rhs
5811
5812 @complexity Linear.
5813
5814 @liveexample{The example demonstrates comparing several JSON
5815 types.,operator__greater}
5816
5817 @since version 1.0.0
5818 */
5819 friend bool operator<=(const_reference lhs, const_reference rhs) noexcept
5820 {
5821 return not (rhs < lhs);
5822 }
5823
5824 /*!
5825 @brief comparison: greater than
5826
5827 Compares whether one JSON value @a lhs is greater than another
5828 JSON value by calculating `not (lhs <= rhs)`.
5829
5830 @param[in] lhs first JSON value to consider
5831 @param[in] rhs second JSON value to consider
5832 @return whether @a lhs is greater than to @a rhs
5833
5834 @complexity Linear.
5835
5836 @liveexample{The example demonstrates comparing several JSON
5837 types.,operator__lessequal}
5838
5839 @since version 1.0.0
5840 */
5841 friend bool operator>(const_reference lhs, const_reference rhs) noexcept
5842 {
5843 return not (lhs <= rhs);
5844 }
5845
5846 /*!
5847 @brief comparison: greater than or equal
5848
5849 Compares whether one JSON value @a lhs is greater than or equal to another
5850 JSON value by calculating `not (lhs < rhs)`.
5851
5852 @param[in] lhs first JSON value to consider
5853 @param[in] rhs second JSON value to consider
5854 @return whether @a lhs is greater than or equal to @a rhs
5855
5856 @complexity Linear.
5857
5858 @liveexample{The example demonstrates comparing several JSON
5859 types.,operator__greaterequal}
5860
5861 @since version 1.0.0
5862 */
5863 friend bool operator>=(const_reference lhs, const_reference rhs) noexcept
5864 {
5865 return not (lhs < rhs);
5866 }
5867
5868 /// @}
5869
5870
5871 ///////////////////
5872 // serialization //
5873 ///////////////////
5874
5875 /// @name serialization
5876 /// @{
5877
5878 /*!
5879 @brief serialize to stream
5880
5881 Serialize the given JSON value @a j to the output stream @a o. The JSON
5882 value will be serialized using the @ref dump member function. The
5883 indentation of the output can be controlled with the member variable
5884 `width` of the output stream @a o. For instance, using the manipulator
5885 `std::setw(4)` on @a o sets the indentation level to `4` and the
5886 serialization result is the same as calling `dump(4)`.
5887
5888 @note During serializaion, the locale and the precision of the output
5889 stream @a o are changed. The original values are restored when the
5890 function returns.
5891
5892 @param[in,out] o stream to serialize to
5893 @param[in] j JSON value to serialize
5894
5895 @return the stream @a o
5896
5897 @complexity Linear.
5898
5899 @liveexample{The example below shows the serialization with different
5900 parameters to `width` to adjust the indentation level.,operator_serialize}
5901
5902 @since version 1.0.0
5903 */
5904 friend std::ostream& operator<<(std::ostream& o, const basic_json& j)
5905 {
5906 // read width member and use it as indentation parameter if nonzero
5907 const bool pretty_print = (o.width() > 0);
5908 const auto indentation = (pretty_print ? o.width() : 0);
5909
5910 // reset width to 0 for subsequent calls to this stream
5911 o.width(0);
5912
5913 // fix locale problems
5914 const auto old_locale = o.imbue(std::locale::classic());
5915 // set precision
5916
5917 // 6, 15 or 16 digits of precision allows round-trip IEEE 754
5918 // string->float->string, string->double->string or string->long
5919 // double->string; to be safe, we read this value from
5920 // std::numeric_limits<number_float_t>::digits10
5921 const auto old_precision = o.precision(std::numeric_limits<double>::digits10);
5922
5923 // do the actual serialization
5924 j.dump(o, pretty_print, static_cast<unsigned int>(indentation));
5925
5926 // reset locale and precision
5927 o.imbue(old_locale);
5928 o.precision(old_precision);
5929 return o;
5930 }
5931
5932 /*!
5933 @brief serialize to stream
5934 @copydoc operator<<(std::ostream&, const basic_json&)
5935 */
5936 friend std::ostream& operator>>(const basic_json& j, std::ostream& o)
5937 {
5938 return o << j;
5939 }
5940
5941 /// @}
5942
5943
5944 /////////////////////
5945 // deserialization //
5946 /////////////////////
5947
5948 /// @name deserialization
5949 /// @{
5950
5951 /*!
5952 @brief deserialize from an array
5953
5954 This function reads from an array of 1-byte values.
5955
5956 @pre Each element of the container has a size of 1 byte. Violating this
5957 precondition yields undefined behavior. **This precondition is enforced
5958 with a static assertion.**
5959
5960 @param[in] array array to read from
5961 @param[in] cb a parser callback function of type @ref parser_callback_t
5962 which is used to control the deserialization by filtering unwanted values
5963 (optional)
5964
5965 @return result of the deserialization
5966
5967 @complexity Linear in the length of the input. The parser is a predictive
5968 LL(1) parser. The complexity can be higher if the parser callback function
5969 @a cb has a super-linear complexity.
5970
5971 @note A UTF-8 byte order mark is silently ignored.
5972
5973 @liveexample{The example below demonstrates the `parse()` function reading
5974 from an array.,parse__array__parser_callback_t}
5975
5976 @since version 2.0.3
5977 */
5978 template<class T, std::size_t N>
5979 static basic_json parse(T (&array)[N],
5980 const parser_callback_t cb = nullptr)
5981 {
5982 // delegate the call to the iterator-range parse overload
5983 return parse(std::begin(array), std::end(array), cb);
5984 }
5985
5986 /*!
5987 @brief deserialize from string literal
5988
5989 @tparam CharT character/literal type with size of 1 byte
5990 @param[in] s string literal to read a serialized JSON value from
5991 @param[in] cb a parser callback function of type @ref parser_callback_t
5992 which is used to control the deserialization by filtering unwanted values
5993 (optional)
5994
5995 @return result of the deserialization
5996
5997 @complexity Linear in the length of the input. The parser is a predictive
5998 LL(1) parser. The complexity can be higher if the parser callback function
5999 @a cb has a super-linear complexity.
6000
6001 @note A UTF-8 byte order mark is silently ignored.
6002 @note String containers like `std::string` or @ref string_t can be parsed
6003 with @ref parse(const ContiguousContainer&, const parser_callback_t)
6004
6005 @liveexample{The example below demonstrates the `parse()` function with
6006 and without callback function.,parse__string__parser_callback_t}
6007
6008 @sa @ref parse(std::istream&, const parser_callback_t) for a version that
6009 reads from an input stream
6010
6011 @since version 1.0.0 (originally for @ref string_t)
6012 */
6013 template<typename CharT, typename std::enable_if<
6014 std::is_pointer<CharT>::value and
6015 std::is_integral<typename std::remove_pointer<CharT>::type>::value and
6016 sizeof(typename std::remove_pointer<CharT>::type) == 1, int>::type = 0>
6017 static basic_json parse(const CharT s,
6018 const parser_callback_t cb = nullptr)
6019 {
6020 return parser(reinterpret_cast<const char*>(s), cb).parse();
6021 }
6022
6023 /*!
6024 @brief deserialize from stream
6025
6026 @param[in,out] i stream to read a serialized JSON value from
6027 @param[in] cb a parser callback function of type @ref parser_callback_t
6028 which is used to control the deserialization by filtering unwanted values
6029 (optional)
6030
6031 @return result of the deserialization
6032
6033 @complexity Linear in the length of the input. The parser is a predictive
6034 LL(1) parser. The complexity can be higher if the parser callback function
6035 @a cb has a super-linear complexity.
6036
6037 @note A UTF-8 byte order mark is silently ignored.
6038
6039 @liveexample{The example below demonstrates the `parse()` function with
6040 and without callback function.,parse__istream__parser_callback_t}
6041
6042 @sa @ref parse(const CharT, const parser_callback_t) for a version
6043 that reads from a string
6044
6045 @since version 1.0.0
6046 */
6047 static basic_json parse(std::istream& i,
6048 const parser_callback_t cb = nullptr)
6049 {
6050 return parser(i, cb).parse();
6051 }
6052
6053 /*!
6054 @copydoc parse(std::istream&, const parser_callback_t)
6055 */
6056 static basic_json parse(std::istream&& i,
6057 const parser_callback_t cb = nullptr)
6058 {
6059 return parser(i, cb).parse();
6060 }
6061
6062 /*!
6063 @brief deserialize from an iterator range with contiguous storage
6064
6065 This function reads from an iterator range of a container with contiguous
6066 storage of 1-byte values. Compatible container types include
6067 `std::vector`, `std::string`, `std::array`, `std::valarray`, and
6068 `std::initializer_list`. Furthermore, C-style arrays can be used with
6069 `std::begin()`/`std::end()`. User-defined containers can be used as long
6070 as they implement random-access iterators and a contiguous storage.
6071
6072 @pre The iterator range is contiguous. Violating this precondition yields
6073 undefined behavior. **This precondition is enforced with an assertion.**
6074 @pre Each element in the range has a size of 1 byte. Violating this
6075 precondition yields undefined behavior. **This precondition is enforced
6076 with a static assertion.**
6077
6078 @warning There is no way to enforce all preconditions at compile-time. If
6079 the function is called with noncompliant iterators and with
6080 assertions switched off, the behavior is undefined and will most
6081 likely yield segmentation violation.
6082
6083 @tparam IteratorType iterator of container with contiguous storage
6084 @param[in] first begin of the range to parse (included)
6085 @param[in] last end of the range to parse (excluded)
6086 @param[in] cb a parser callback function of type @ref parser_callback_t
6087 which is used to control the deserialization by filtering unwanted values
6088 (optional)
6089
6090 @return result of the deserialization
6091
6092 @complexity Linear in the length of the input. The parser is a predictive
6093 LL(1) parser. The complexity can be higher if the parser callback function
6094 @a cb has a super-linear complexity.
6095
6096 @note A UTF-8 byte order mark is silently ignored.
6097
6098 @liveexample{The example below demonstrates the `parse()` function reading
6099 from an iterator range.,parse__iteratortype__parser_callback_t}
6100
6101 @since version 2.0.3
6102 */
6103 template<class IteratorType, typename std::enable_if<
6104 std::is_base_of<
6105 std::random_access_iterator_tag,
6106 typename std::iterator_traits<IteratorType>::iterator_category>::value, int>::type = 0>
6107 static basic_json parse(IteratorType first, IteratorType last,
6108 const parser_callback_t cb = nullptr)
6109 {
6110 // assertion to check that the iterator range is indeed contiguous,
6111 // see http://stackoverflow.com/a/35008842/266378 for more discussion
6112 assert(std::accumulate(first, last, std::make_pair<bool, int>(true, 0),
6113 [&first](std::pair<bool, int> res, decltype(*first) val)
6114 {
6115 res.first &= (val == *(std::next(std::addressof(*first), res.second++)));
6116 return res;
6117 }).first);
6118
6119 // assertion to check that each element is 1 byte long
6120 static_assert(sizeof(typename std::iterator_traits<IteratorType>::value_type) == 1,
6121 "each element in the iterator range must have the size of 1 byte");
6122
6123 // if iterator range is empty, create a parser with an empty string
6124 // to generate "unexpected EOF" error message
6125 if (std::distance(first, last) <= 0)
6126 {
6127 return parser("").parse();
6128 }
6129
6130 return parser(first, last, cb).parse();
6131 }
6132
6133 /*!
6134 @brief deserialize from a container with contiguous storage
6135
6136 This function reads from a container with contiguous storage of 1-byte
6137 values. Compatible container types include `std::vector`, `std::string`,
6138 `std::array`, and `std::initializer_list`. User-defined containers can be
6139 used as long as they implement random-access iterators and a contiguous
6140 storage.
6141
6142 @pre The container storage is contiguous. Violating this precondition
6143 yields undefined behavior. **This precondition is enforced with an
6144 assertion.**
6145 @pre Each element of the container has a size of 1 byte. Violating this
6146 precondition yields undefined behavior. **This precondition is enforced
6147 with a static assertion.**
6148
6149 @warning There is no way to enforce all preconditions at compile-time. If
6150 the function is called with a noncompliant container and with
6151 assertions switched off, the behavior is undefined and will most
6152 likely yield segmentation violation.
6153
6154 @tparam ContiguousContainer container type with contiguous storage
6155 @param[in] c container to read from
6156 @param[in] cb a parser callback function of type @ref parser_callback_t
6157 which is used to control the deserialization by filtering unwanted values
6158 (optional)
6159
6160 @return result of the deserialization
6161
6162 @complexity Linear in the length of the input. The parser is a predictive
6163 LL(1) parser. The complexity can be higher if the parser callback function
6164 @a cb has a super-linear complexity.
6165
6166 @note A UTF-8 byte order mark is silently ignored.
6167
6168 @liveexample{The example below demonstrates the `parse()` function reading
6169 from a contiguous container.,parse__contiguouscontainer__parser_callback_t}
6170
6171 @since version 2.0.3
6172 */
6173 template<class ContiguousContainer, typename std::enable_if<
6174 not std::is_pointer<ContiguousContainer>::value and
6175 std::is_base_of<
6176 std::random_access_iterator_tag,
6177 typename std::iterator_traits<decltype(std::begin(std::declval<ContiguousContainer const>()))>::iterator_category>::value
6178 , int>::type = 0>
6179 static basic_json parse(const ContiguousContainer& c,
6180 const parser_callback_t cb = nullptr)
6181 {
6182 // delegate the call to the iterator-range parse overload
6183 return parse(std::begin(c), std::end(c), cb);
6184 }
6185
6186 /*!
6187 @brief deserialize from stream
6188
6189 Deserializes an input stream to a JSON value.
6190
6191 @param[in,out] i input stream to read a serialized JSON value from
6192 @param[in,out] j JSON value to write the deserialized input to
6193
6194 @throw std::invalid_argument in case of parse errors
6195
6196 @complexity Linear in the length of the input. The parser is a predictive
6197 LL(1) parser.
6198
6199 @note A UTF-8 byte order mark is silently ignored.
6200
6201 @liveexample{The example below shows how a JSON value is constructed by
6202 reading a serialization from a stream.,operator_deserialize}
6203
6204 @sa parse(std::istream&, const parser_callback_t) for a variant with a
6205 parser callback function to filter values while parsing
6206
6207 @since version 1.0.0
6208 */
6209 friend std::istream& operator<<(basic_json& j, std::istream& i)
6210 {
6211 j = parser(i).parse();
6212 return i;
6213 }
6214
6215 /*!
6216 @brief deserialize from stream
6217 @copydoc operator<<(basic_json&, std::istream&)
6218 */
6219 friend std::istream& operator>>(std::istream& i, basic_json& j)
6220 {
6221 j = parser(i).parse();
6222 return i;
6223 }
6224
6225 /// @}
6226
6227 //////////////////////////////////////////
6228 // binary serialization/deserialization //
6229 //////////////////////////////////////////
6230
6231 /// @name binary serialization/deserialization support
6232 /// @{
6233
6234 private:
6235 template<typename T>
6236 static void add_to_vector(std::vector<uint8_t>& vec, size_t bytes, const T number)
6237 {
6238 assert(bytes == 1 or bytes == 2 or bytes == 4 or bytes == 8);
6239
6240 switch (bytes)
6241 {
6242 case 8:
6243 {
6244 vec.push_back(static_cast<uint8_t>((number >> 070) & 0xff));
6245 vec.push_back(static_cast<uint8_t>((number >> 060) & 0xff));
6246 vec.push_back(static_cast<uint8_t>((number >> 050) & 0xff));
6247 vec.push_back(static_cast<uint8_t>((number >> 040) & 0xff));
6248 // intentional fall-through
6249 }
6250
6251 case 4:
6252 {
6253 vec.push_back(static_cast<uint8_t>((number >> 030) & 0xff));
6254 vec.push_back(static_cast<uint8_t>((number >> 020) & 0xff));
6255 // intentional fall-through
6256 }
6257
6258 case 2:
6259 {
6260 vec.push_back(static_cast<uint8_t>((number >> 010) & 0xff));
6261 // intentional fall-through
6262 }
6263
6264 case 1:
6265 {
6266 vec.push_back(static_cast<uint8_t>(number & 0xff));
6267 break;
6268 }
6269 }
6270 }
6271
6272 /*!
6273 @brief take sufficient bytes from a vector to fill an integer variable
6274
6275 In the context of binary serialization formats, we need to read several
6276 bytes from a byte vector and combine them to multi-byte integral data
6277 types.
6278
6279 @param[in] vec byte vector to read from
6280 @param[in] current_index the position in the vector after which to read
6281
6282 @return the next sizeof(T) bytes from @a vec, in reverse order as T
6283
6284 @tparam T the integral return type
6285
6286 @throw std::out_of_range if there are less than sizeof(T)+1 bytes in the
6287 vector @a vec to read
6288
6289 In the for loop, the bytes from the vector are copied in reverse order into
6290 the return value. In the figures below, let sizeof(T)=4 and `i` be the loop
6291 variable.
6292
6293 Precondition:
6294
6295 vec: | | | a | b | c | d | T: | | | | |
6296 ^ ^ ^ ^
6297 current_index i ptr sizeof(T)
6298
6299 Postcondition:
6300
6301 vec: | | | a | b | c | d | T: | d | c | b | a |
6302 ^ ^ ^
6303 | i ptr
6304 current_index
6305
6306 @sa Code adapted from <http://stackoverflow.com/a/41031865/266378>.
6307 */
6308 template<typename T>
6309 static T get_from_vector(const std::vector<uint8_t>& vec, const size_t current_index)
6310 {
6311 if (current_index + sizeof(T) + 1 > vec.size())
6312 {
6313 throw std::out_of_range("cannot read " + std::to_string(sizeof(T)) + " bytes from vector");
6314 }
6315
6316 T result;
6317 uint8_t* ptr = reinterpret_cast<uint8_t*>(&result);
6318 for (size_t i = 0; i < sizeof(T); ++i)
6319 {
6320 *ptr++ = vec[current_index + sizeof(T) - i];
6321 }
6322 return result;
6323 }
6324
6325 /*!
6326 @brief create a MessagePack serialization of a given JSON value
6327
6328 This is a straightforward implementation of the MessagePack specification.
6329
6330 @param[in] j JSON value to serialize
6331 @param[in,out] v byte vector to write the serialization to
6332
6333 @sa https://github.com/msgpack/msgpack/blob/master/spec.md
6334 */
6335 static void to_msgpack_internal(const basic_json& j, std::vector<uint8_t>& v)
6336 {
6337 switch (j.type())
6338 {
6339 case value_t::null:
6340 {
6341 // nil
6342 v.push_back(0xc0);
6343 break;
6344 }
6345
6346 case value_t::boolean:
6347 {
6348 // true and false
6349 v.push_back(j.m_value.boolean ? 0xc3 : 0xc2);
6350 break;
6351 }
6352
6353 case value_t::number_integer:
6354 {
6355 if (j.m_value.number_integer >= 0)
6356 {
6357 // MessagePack does not differentiate between positive
6358 // signed integers and unsigned integers. Therefore, we used
6359 // the code from the value_t::number_unsigned case here.
6360 if (j.m_value.number_unsigned < 128)
6361 {
6362 // positive fixnum
6363 add_to_vector(v, 1, j.m_value.number_unsigned);
6364 }
6365 else if (j.m_value.number_unsigned <= UINT8_MAX)
6366 {
6367 // uint 8
6368 v.push_back(0xcc);
6369 add_to_vector(v, 1, j.m_value.number_unsigned);
6370 }
6371 else if (j.m_value.number_unsigned <= UINT16_MAX)
6372 {
6373 // uint 16
6374 v.push_back(0xcd);
6375 add_to_vector(v, 2, j.m_value.number_unsigned);
6376 }
6377 else if (j.m_value.number_unsigned <= UINT32_MAX)
6378 {
6379 // uint 32
6380 v.push_back(0xce);
6381 add_to_vector(v, 4, j.m_value.number_unsigned);
6382 }
6383 else if (j.m_value.number_unsigned <= UINT64_MAX)
6384 {
6385 // uint 64
6386 v.push_back(0xcf);
6387 add_to_vector(v, 8, j.m_value.number_unsigned);
6388 }
6389 }
6390 else
6391 {
6392 if (j.m_value.number_integer >= -32)
6393 {
6394 // negative fixnum
6395 add_to_vector(v, 1, j.m_value.number_integer);
6396 }
6397 else if (j.m_value.number_integer >= INT8_MIN and j.m_value.number_integer <= INT8_MAX)
6398 {
6399 // int 8
6400 v.push_back(0xd0);
6401 add_to_vector(v, 1, j.m_value.number_integer);
6402 }
6403 else if (j.m_value.number_integer >= INT16_MIN and j.m_value.number_integer <= INT16_MAX)
6404 {
6405 // int 16
6406 v.push_back(0xd1);
6407 add_to_vector(v, 2, j.m_value.number_integer);
6408 }
6409 else if (j.m_value.number_integer >= INT32_MIN and j.m_value.number_integer <= INT32_MAX)
6410 {
6411 // int 32
6412 v.push_back(0xd2);
6413 add_to_vector(v, 4, j.m_value.number_integer);
6414 }
6415 else if (j.m_value.number_integer >= INT64_MIN and j.m_value.number_integer <= INT64_MAX)
6416 {
6417 // int 64
6418 v.push_back(0xd3);
6419 add_to_vector(v, 8, j.m_value.number_integer);
6420 }
6421 }
6422 break;
6423 }
6424
6425 case value_t::number_unsigned:
6426 {
6427 if (j.m_value.number_unsigned < 128)
6428 {
6429 // positive fixnum
6430 add_to_vector(v, 1, j.m_value.number_unsigned);
6431 }
6432 else if (j.m_value.number_unsigned <= UINT8_MAX)
6433 {
6434 // uint 8
6435 v.push_back(0xcc);
6436 add_to_vector(v, 1, j.m_value.number_unsigned);
6437 }
6438 else if (j.m_value.number_unsigned <= UINT16_MAX)
6439 {
6440 // uint 16
6441 v.push_back(0xcd);
6442 add_to_vector(v, 2, j.m_value.number_unsigned);
6443 }
6444 else if (j.m_value.number_unsigned <= UINT32_MAX)
6445 {
6446 // uint 32
6447 v.push_back(0xce);
6448 add_to_vector(v, 4, j.m_value.number_unsigned);
6449 }
6450 else if (j.m_value.number_unsigned <= UINT64_MAX)
6451 {
6452 // uint 64
6453 v.push_back(0xcf);
6454 add_to_vector(v, 8, j.m_value.number_unsigned);
6455 }
6456 break;
6457 }
6458
6459 case value_t::number_float:
6460 {
6461 // float 64
6462 v.push_back(0xcb);
6463 const uint8_t* helper = reinterpret_cast<const uint8_t*>(&(j.m_value.number_float));
6464 for (size_t i = 0; i < 8; ++i)
6465 {
6466 v.push_back(helper[7 - i]);
6467 }
6468 break;
6469 }
6470
6471 case value_t::string:
6472 {
6473 const auto N = j.m_value.string->size();
6474 if (N <= 31)
6475 {
6476 // fixstr
6477 v.push_back(static_cast<uint8_t>(0xa0 | N));
6478 }
6479 else if (N <= 255)
6480 {
6481 // str 8
6482 v.push_back(0xd9);
6483 add_to_vector(v, 1, N);
6484 }
6485 else if (N <= 65535)
6486 {
6487 // str 16
6488 v.push_back(0xda);
6489 add_to_vector(v, 2, N);
6490 }
6491 else if (N <= 4294967295)
6492 {
6493 // str 32
6494 v.push_back(0xdb);
6495 add_to_vector(v, 4, N);
6496 }
6497
6498 // append string
6499 std::copy(j.m_value.string->begin(), j.m_value.string->end(),
6500 std::back_inserter(v));
6501 break;
6502 }
6503
6504 case value_t::array:
6505 {
6506 const auto N = j.m_value.array->size();
6507 if (N <= 15)
6508 {
6509 // fixarray
6510 v.push_back(static_cast<uint8_t>(0x90 | N));
6511 }
6512 else if (N <= 0xffff)
6513 {
6514 // array 16
6515 v.push_back(0xdc);
6516 add_to_vector(v, 2, N);
6517 }
6518 else if (N <= 0xffffffff)
6519 {
6520 // array 32
6521 v.push_back(0xdd);
6522 add_to_vector(v, 4, N);
6523 }
6524
6525 // append each element
6526 for (const auto& el : *j.m_value.array)
6527 {
6528 to_msgpack_internal(el, v);
6529 }
6530 break;
6531 }
6532
6533 case value_t::object:
6534 {
6535 const auto N = j.m_value.object->size();
6536 if (N <= 15)
6537 {
6538 // fixmap
6539 v.push_back(static_cast<uint8_t>(0x80 | (N & 0xf)));
6540 }
6541 else if (N <= 65535)
6542 {
6543 // map 16
6544 v.push_back(0xde);
6545 add_to_vector(v, 2, N);
6546 }
6547 else if (N <= 4294967295)
6548 {
6549 // map 32
6550 v.push_back(0xdf);
6551 add_to_vector(v, 4, N);
6552 }
6553
6554 // append each element
6555 for (const auto& el : *j.m_value.object)
6556 {
6557 to_msgpack_internal(el.first, v);
6558 to_msgpack_internal(el.second, v);
6559 }
6560 break;
6561 }
6562
6563 default:
6564 {
6565 break;
6566 }
6567 }
6568 }
6569
6570 /*!
6571 @brief create a CBOR serialization of a given JSON value
6572
6573 This is a straightforward implementation of the CBOR specification.
6574
6575 @param[in] j JSON value to serialize
6576 @param[in,out] v byte vector to write the serialization to
6577
6578 @sa https://tools.ietf.org/html/rfc7049
6579 */
6580 static void to_cbor_internal(const basic_json& j, std::vector<uint8_t>& v)
6581 {
6582 switch (j.type())
6583 {
6584 case value_t::null:
6585 {
6586 v.push_back(0xf6);
6587 break;
6588 }
6589
6590 case value_t::boolean:
6591 {
6592 v.push_back(j.m_value.boolean ? 0xf5 : 0xf4);
6593 break;
6594 }
6595
6596 case value_t::number_integer:
6597 {
6598 if (j.m_value.number_integer >= 0)
6599 {
6600 // CBOR does not differentiate between positive signed
6601 // integers and unsigned integers. Therefore, we used the
6602 // code from the value_t::number_unsigned case here.
6603 if (j.m_value.number_integer <= 0x17)
6604 {
6605 add_to_vector(v, 1, j.m_value.number_integer);
6606 }
6607 else if (j.m_value.number_integer <= UINT8_MAX)
6608 {
6609 v.push_back(0x18);
6610 // one-byte uint8_t
6611 add_to_vector(v, 1, j.m_value.number_integer);
6612 }
6613 else if (j.m_value.number_integer <= UINT16_MAX)
6614 {
6615 v.push_back(0x19);
6616 // two-byte uint16_t
6617 add_to_vector(v, 2, j.m_value.number_integer);
6618 }
6619 else if (j.m_value.number_integer <= UINT32_MAX)
6620 {
6621 v.push_back(0x1a);
6622 // four-byte uint32_t
6623 add_to_vector(v, 4, j.m_value.number_integer);
6624 }
6625 else
6626 {
6627 v.push_back(0x1b);
6628 // eight-byte uint64_t
6629 add_to_vector(v, 8, j.m_value.number_integer);
6630 }
6631 }
6632 else
6633 {
6634 // The conversions below encode the sign in the first byte,
6635 // and the value is converted to a positive number.
6636 const auto positive_number = -1 - j.m_value.number_integer;
6637 if (j.m_value.number_integer >= -24)
6638 {
6639 v.push_back(static_cast<uint8_t>(0x20 + positive_number));
6640 }
6641 else if (positive_number <= UINT8_MAX)
6642 {
6643 // int 8
6644 v.push_back(0x38);
6645 add_to_vector(v, 1, positive_number);
6646 }
6647 else if (positive_number <= UINT16_MAX)
6648 {
6649 // int 16
6650 v.push_back(0x39);
6651 add_to_vector(v, 2, positive_number);
6652 }
6653 else if (positive_number <= UINT32_MAX)
6654 {
6655 // int 32
6656 v.push_back(0x3a);
6657 add_to_vector(v, 4, positive_number);
6658 }
6659 else
6660 {
6661 // int 64
6662 v.push_back(0x3b);
6663 add_to_vector(v, 8, positive_number);
6664 }
6665 }
6666 break;
6667 }
6668
6669 case value_t::number_unsigned:
6670 {
6671 if (j.m_value.number_unsigned <= 0x17)
6672 {
6673 v.push_back(static_cast<uint8_t>(j.m_value.number_unsigned));
6674 }
6675 else if (j.m_value.number_unsigned <= 0xff)
6676 {
6677 v.push_back(0x18);
6678 // one-byte uint8_t
6679 add_to_vector(v, 1, j.m_value.number_unsigned);
6680 }
6681 else if (j.m_value.number_unsigned <= 0xffff)
6682 {
6683 v.push_back(0x19);
6684 // two-byte uint16_t
6685 add_to_vector(v, 2, j.m_value.number_unsigned);
6686 }
6687 else if (j.m_value.number_unsigned <= 0xffffffff)
6688 {
6689 v.push_back(0x1a);
6690 // four-byte uint32_t
6691 add_to_vector(v, 4, j.m_value.number_unsigned);
6692 }
6693 else if (j.m_value.number_unsigned <= 0xffffffffffffffff)
6694 {
6695 v.push_back(0x1b);
6696 // eight-byte uint64_t
6697 add_to_vector(v, 8, j.m_value.number_unsigned);
6698 }
6699 break;
6700 }
6701
6702 case value_t::number_float:
6703 {
6704 // Double-Precision Float
6705 v.push_back(0xfb);
6706 const uint8_t* helper = reinterpret_cast<const uint8_t*>(&(j.m_value.number_float));
6707 for (size_t i = 0; i < 8; ++i)
6708 {
6709 v.push_back(helper[7 - i]);
6710 }
6711 break;
6712 }
6713
6714 case value_t::string:
6715 {
6716 const auto N = j.m_value.string->size();
6717 if (N <= 0x17)
6718 {
6719 v.push_back(0x60 + N); // 1 byte for string + size
6720 }
6721 else if (N <= 0xff)
6722 {
6723 v.push_back(0x78); // one-byte uint8_t for N
6724 add_to_vector(v, 1, N);
6725 }
6726 else if (N <= 0xffff)
6727 {
6728 v.push_back(0x79); // two-byte uint16_t for N
6729 add_to_vector(v, 2, N);
6730 }
6731 else if (N <= 0xffffffff)
6732 {
6733 v.push_back(0x7a); // four-byte uint32_t for N
6734 add_to_vector(v, 4, N);
6735 }
6736 // LCOV_EXCL_START
6737 else if (N <= 0xffffffffffffffff)
6738 {
6739 v.push_back(0x7b); // eight-byte uint64_t for N
6740 add_to_vector(v, 8, N);
6741 }
6742 // LCOV_EXCL_STOP
6743
6744 // append string
6745 std::copy(j.m_value.string->begin(), j.m_value.string->end(),
6746 std::back_inserter(v));
6747 break;
6748 }
6749
6750 case value_t::array:
6751 {
6752 const auto N = j.m_value.array->size();
6753 if (N <= 0x17)
6754 {
6755 v.push_back(0x80 + N); // 1 byte for array + size
6756 }
6757 else if (N <= 0xff)
6758 {
6759 v.push_back(0x98); // one-byte uint8_t for N
6760 add_to_vector(v, 1, N);
6761 }
6762 else if (N <= 0xffff)
6763 {
6764 v.push_back(0x99); // two-byte uint16_t for N
6765 add_to_vector(v, 2, N);
6766 }
6767 else if (N <= 0xffffffff)
6768 {
6769 v.push_back(0x9a); // four-byte uint32_t for N
6770 add_to_vector(v, 4, N);
6771 }
6772 // LCOV_EXCL_START
6773 else if (N <= 0xffffffffffffffff)
6774 {
6775 v.push_back(0x9b); // eight-byte uint64_t for N
6776 add_to_vector(v, 8, N);
6777 }
6778 // LCOV_EXCL_STOP
6779
6780 // append each element
6781 for (const auto& el : *j.m_value.array)
6782 {
6783 to_cbor_internal(el, v);
6784 }
6785 break;
6786 }
6787
6788 case value_t::object:
6789 {
6790 const auto N = j.m_value.object->size();
6791 if (N <= 0x17)
6792 {
6793 v.push_back(0xa0 + N); // 1 byte for object + size
6794 }
6795 else if (N <= 0xff)
6796 {
6797 v.push_back(0xb8);
6798 add_to_vector(v, 1, N); // one-byte uint8_t for N
6799 }
6800 else if (N <= 0xffff)
6801 {
6802 v.push_back(0xb9);
6803 add_to_vector(v, 2, N); // two-byte uint16_t for N
6804 }
6805 else if (N <= 0xffffffff)
6806 {
6807 v.push_back(0xba);
6808 add_to_vector(v, 4, N); // four-byte uint32_t for N
6809 }
6810 // LCOV_EXCL_START
6811 else if (N <= 0xffffffffffffffff)
6812 {
6813 v.push_back(0xbb);
6814 add_to_vector(v, 8, N); // eight-byte uint64_t for N
6815 }
6816 // LCOV_EXCL_STOP
6817
6818 // append each element
6819 for (const auto& el : *j.m_value.object)
6820 {
6821 to_cbor_internal(el.first, v);
6822 to_cbor_internal(el.second, v);
6823 }
6824 break;
6825 }
6826
6827 default:
6828 {
6829 break;
6830 }
6831 }
6832 }
6833
6834 /*!
6835 @brief create a JSON value from a given MessagePack vector
6836
6837 @param[in] v MessagePack serialization
6838 @param[in] idx byte index to start reading from @a v
6839
6840 @return deserialized JSON value
6841
6842 @throw std::invalid_argument if unsupported features from MessagePack were
6843 used in the given vector @a v or if the input is not valid MessagePack
6844 @throw std::out_of_range if the given vector ends prematurely
6845
6846 @sa https://github.com/msgpack/msgpack/blob/master/spec.md
6847 */
6848 static basic_json from_msgpack_internal(const std::vector<uint8_t>& v, size_t& idx)
6849 {
6850 // store and increment index
6851 const size_t current_idx = idx++;
6852
6853 if (v[current_idx] <= 0xbf)
6854 {
6855 if (v[current_idx] <= 0x7f) // positive fixint
6856 {
6857 return v[current_idx];
6858 }
6859 else if (v[current_idx] <= 0x8f) // fixmap
6860 {
6861 basic_json result = value_t::object;
6862 const size_t len = v[current_idx] & 0x0f;
6863 for (size_t i = 0; i < len; ++i)
6864 {
6865 std::string key = from_msgpack_internal(v, idx);
6866 result[key] = from_msgpack_internal(v, idx);
6867 }
6868 return result;
6869 }
6870 else if (v[current_idx] <= 0x9f) // fixarray
6871 {
6872 basic_json result = value_t::array;
6873 const size_t len = v[current_idx] & 0x0f;
6874 for (size_t i = 0; i < len; ++i)
6875 {
6876 result.push_back(from_msgpack_internal(v, idx));
6877 }
6878 return result;
6879 }
6880 else // fixstr
6881 {
6882 const size_t len = v[current_idx] & 0x1f;
6883 const size_t offset = current_idx + 1;
6884 idx += len; // skip content bytes
6885 return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
6886 }
6887 }
6888 else if (v[current_idx] >= 0xe0) // negative fixint
6889 {
6890 return static_cast<int8_t>(v[current_idx]);
6891 }
6892 else
6893 {
6894 switch (v[current_idx])
6895 {
6896 case 0xc0: // nil
6897 {
6898 return value_t::null;
6899 }
6900
6901 case 0xc2: // false
6902 {
6903 return false;
6904 }
6905
6906 case 0xc3: // true
6907 {
6908 return true;
6909 }
6910
6911 case 0xca: // float 32
6912 {
6913 // copy bytes in reverse order into the double variable
6914 float res;
6915 for (size_t byte = 0; byte < sizeof(float); ++byte)
6916 {
6917 reinterpret_cast<uint8_t*>(&res)[sizeof(float) - byte - 1] = v[current_idx + 1 + byte];
6918 }
6919 idx += sizeof(float); // skip content bytes
6920 return res;
6921 }
6922
6923 case 0xcb: // float 64
6924 {
6925 // copy bytes in reverse order into the double variable
6926 double res;
6927 for (size_t byte = 0; byte < sizeof(double); ++byte)
6928 {
6929 reinterpret_cast<uint8_t*>(&res)[sizeof(double) - byte - 1] = v[current_idx + 1 + byte];
6930 }
6931 idx += sizeof(double); // skip content bytes
6932 return res;
6933 }
6934
6935 case 0xcc: // uint 8
6936 {
6937 idx += 1; // skip content byte
6938 return get_from_vector<uint8_t>(v, current_idx);
6939 }
6940
6941 case 0xcd: // uint 16
6942 {
6943 idx += 2; // skip 2 content bytes
6944 return get_from_vector<uint16_t>(v, current_idx);
6945 }
6946
6947 case 0xce: // uint 32
6948 {
6949 idx += 4; // skip 4 content bytes
6950 return get_from_vector<uint32_t>(v, current_idx);
6951 }
6952
6953 case 0xcf: // uint 64
6954 {
6955 idx += 8; // skip 8 content bytes
6956 return get_from_vector<uint64_t>(v, current_idx);
6957 }
6958
6959 case 0xd0: // int 8
6960 {
6961 idx += 1; // skip content byte
6962 return get_from_vector<int8_t>(v, current_idx);
6963 }
6964
6965 case 0xd1: // int 16
6966 {
6967 idx += 2; // skip 2 content bytes
6968 return get_from_vector<int16_t>(v, current_idx);
6969 }
6970
6971 case 0xd2: // int 32
6972 {
6973 idx += 4; // skip 4 content bytes
6974 return get_from_vector<int32_t>(v, current_idx);
6975 }
6976
6977 case 0xd3: // int 64
6978 {
6979 idx += 8; // skip 8 content bytes
6980 return get_from_vector<int64_t>(v, current_idx);
6981 }
6982
6983 case 0xd9: // str 8
6984 {
6985 const auto len = static_cast<size_t>(get_from_vector<uint8_t>(v, current_idx));
6986 const size_t offset = current_idx + 2;
6987 idx += len + 1; // skip size byte + content bytes
6988 return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
6989 }
6990
6991 case 0xda: // str 16
6992 {
6993 const auto len = static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx));
6994 const size_t offset = current_idx + 3;
6995 idx += len + 2; // skip 2 size bytes + content bytes
6996 return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
6997 }
6998
6999 case 0xdb: // str 32
7000 {
7001 const auto len = static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx));
7002 const size_t offset = current_idx + 5;
7003 idx += len + 4; // skip 4 size bytes + content bytes
7004 return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
7005 }
7006
7007 case 0xdc: // array 16
7008 {
7009 basic_json result = value_t::array;
7010 const auto len = static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx));
7011 idx += 2; // skip 2 size bytes
7012 for (size_t i = 0; i < len; ++i)
7013 {
7014 result.push_back(from_msgpack_internal(v, idx));
7015 }
7016 return result;
7017 }
7018
7019 case 0xdd: // array 32
7020 {
7021 basic_json result = value_t::array;
7022 const auto len = static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx));
7023 idx += 4; // skip 4 size bytes
7024 for (size_t i = 0; i < len; ++i)
7025 {
7026 result.push_back(from_msgpack_internal(v, idx));
7027 }
7028 return result;
7029 }
7030
7031 case 0xde: // map 16
7032 {
7033 basic_json result = value_t::object;
7034 const auto len = static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx));
7035 idx += 2; // skip 2 size bytes
7036 for (size_t i = 0; i < len; ++i)
7037 {
7038 std::string key = from_msgpack_internal(v, idx);
7039 result[key] = from_msgpack_internal(v, idx);
7040 }
7041 return result;
7042 }
7043
7044 case 0xdf: // map 32
7045 {
7046 basic_json result = value_t::object;
7047 const auto len = static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx));
7048 idx += 4; // skip 4 size bytes
7049 for (size_t i = 0; i < len; ++i)
7050 {
7051 std::string key = from_msgpack_internal(v, idx);
7052 result[key] = from_msgpack_internal(v, idx);
7053 }
7054 return result;
7055 }
7056
7057 default:
7058 {
7059 throw std::invalid_argument("error parsing a msgpack @ " + std::to_string(current_idx) + ": " + std::to_string(static_cast<int>(v[current_idx])));
7060 }
7061 }
7062 }
7063 }
7064
7065 /*!
7066 @brief create a JSON value from a given CBOR vector
7067
7068 @param[in] v CBOR serialization
7069 @param[in] idx byte index to start reading from @a v
7070
7071 @return deserialized JSON value
7072
7073 @throw std::invalid_argument if unsupported features from CBOR were used in
7074 the given vector @a v or if the input is not valid CBOR
7075 @throw std::out_of_range if the given vector ends prematurely
7076
7077 @sa https://tools.ietf.org/html/rfc7049
7078 */
7079 static basic_json from_cbor_internal(const std::vector<uint8_t>& v, size_t& idx)
7080 {
7081 // store and increment index
7082 const size_t current_idx = idx++;
7083
7084 switch (v[current_idx])
7085 {
7086 // Integer 0x00..0x17 (0..23)
7087 case 0x00:
7088 case 0x01:
7089 case 0x02:
7090 case 0x03:
7091 case 0x04:
7092 case 0x05:
7093 case 0x06:
7094 case 0x07:
7095 case 0x08:
7096 case 0x09:
7097 case 0x0a:
7098 case 0x0b:
7099 case 0x0c:
7100 case 0x0d:
7101 case 0x0e:
7102 case 0x0f:
7103 case 0x10:
7104 case 0x11:
7105 case 0x12:
7106 case 0x13:
7107 case 0x14:
7108 case 0x15:
7109 case 0x16:
7110 case 0x17:
7111 {
7112 return v[current_idx];
7113 }
7114
7115 case 0x18: // Unsigned integer (one-byte uint8_t follows)
7116 {
7117 idx += 1; // skip content byte
7118 return get_from_vector<uint8_t>(v, current_idx);
7119 }
7120
7121 case 0x19: // Unsigned integer (two-byte uint16_t follows)
7122 {
7123 idx += 2; // skip 2 content bytes
7124 return get_from_vector<uint16_t>(v, current_idx);
7125 }
7126
7127 case 0x1a: // Unsigned integer (four-byte uint32_t follows)
7128 {
7129 idx += 4; // skip 4 content bytes
7130 return get_from_vector<uint32_t>(v, current_idx);
7131 }
7132
7133 case 0x1b: // Unsigned integer (eight-byte uint64_t follows)
7134 {
7135 idx += 8; // skip 8 content bytes
7136 return get_from_vector<uint64_t>(v, current_idx);
7137 }
7138
7139 // Negative integer -1-0x00..-1-0x17 (-1..-24)
7140 case 0x20:
7141 case 0x21:
7142 case 0x22:
7143 case 0x23:
7144 case 0x24:
7145 case 0x25:
7146 case 0x26:
7147 case 0x27:
7148 case 0x28:
7149 case 0x29:
7150 case 0x2a:
7151 case 0x2b:
7152 case 0x2c:
7153 case 0x2d:
7154 case 0x2e:
7155 case 0x2f:
7156 case 0x30:
7157 case 0x31:
7158 case 0x32:
7159 case 0x33:
7160 case 0x34:
7161 case 0x35:
7162 case 0x36:
7163 case 0x37:
7164 {
7165 return static_cast<int8_t>(0x20 - 1 - v[current_idx]);
7166 }
7167
7168 case 0x38: // Negative integer (one-byte uint8_t follows)
7169 {
7170 idx += 1; // skip content byte
7171 // must be uint8_t !
7172 return static_cast<number_integer_t>(-1) - get_from_vector<uint8_t>(v, current_idx);
7173 }
7174
7175 case 0x39: // Negative integer -1-n (two-byte uint16_t follows)
7176 {
7177 idx += 2; // skip 2 content bytes
7178 return static_cast<number_integer_t>(-1) - get_from_vector<uint16_t>(v, current_idx);
7179 }
7180
7181 case 0x3a: // Negative integer -1-n (four-byte uint32_t follows)
7182 {
7183 idx += 4; // skip 4 content bytes
7184 return static_cast<number_integer_t>(-1) - get_from_vector<uint32_t>(v, current_idx);
7185 }
7186
7187 case 0x3b: // Negative integer -1-n (eight-byte uint64_t follows)
7188 {
7189 idx += 8; // skip 8 content bytes
7190 return static_cast<number_integer_t>(-1) - static_cast<number_integer_t>(get_from_vector<uint64_t>(v, current_idx));
7191 }
7192
7193 // UTF-8 string (0x00..0x17 bytes follow)
7194 case 0x60:
7195 case 0x61:
7196 case 0x62:
7197 case 0x63:
7198 case 0x64:
7199 case 0x65:
7200 case 0x66:
7201 case 0x67:
7202 case 0x68:
7203 case 0x69:
7204 case 0x6a:
7205 case 0x6b:
7206 case 0x6c:
7207 case 0x6d:
7208 case 0x6e:
7209 case 0x6f:
7210 case 0x70:
7211 case 0x71:
7212 case 0x72:
7213 case 0x73:
7214 case 0x74:
7215 case 0x75:
7216 case 0x76:
7217 case 0x77:
7218 {
7219 const auto len = static_cast<size_t>(v[current_idx] - 0x60);
7220 const size_t offset = current_idx + 1;
7221 idx += len; // skip content bytes
7222 return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
7223 }
7224
7225 case 0x78: // UTF-8 string (one-byte uint8_t for n follows)
7226 {
7227 const auto len = static_cast<size_t>(get_from_vector<uint8_t>(v, current_idx));
7228 const size_t offset = current_idx + 2;
7229 idx += len + 1; // skip size byte + content bytes
7230 return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
7231 }
7232
7233 case 0x79: // UTF-8 string (two-byte uint16_t for n follow)
7234 {
7235 const auto len = static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx));
7236 const size_t offset = current_idx + 3;
7237 idx += len + 2; // skip 2 size bytes + content bytes
7238 return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
7239 }
7240
7241 case 0x7a: // UTF-8 string (four-byte uint32_t for n follow)
7242 {
7243 const auto len = static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx));
7244 const size_t offset = current_idx + 5;
7245 idx += len + 4; // skip 4 size bytes + content bytes
7246 return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
7247 }
7248
7249 case 0x7b: // UTF-8 string (eight-byte uint64_t for n follow)
7250 {
7251 const auto len = static_cast<size_t>(get_from_vector<uint64_t>(v, current_idx));
7252 const size_t offset = current_idx + 9;
7253 idx += len + 8; // skip 8 size bytes + content bytes
7254 return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
7255 }
7256
7257 case 0x7f: // UTF-8 string (indefinite length)
7258 {
7259 std::string result;
7260 while (v[idx] != 0xff)
7261 {
7262 string_t s = from_cbor_internal(v, idx);
7263 result += s;
7264 }
7265 // skip break byte (0xFF)
7266 idx += 1;
7267 return result;
7268 }
7269
7270 // array (0x00..0x17 data items follow)
7271 case 0x80:
7272 case 0x81:
7273 case 0x82:
7274 case 0x83:
7275 case 0x84:
7276 case 0x85:
7277 case 0x86:
7278 case 0x87:
7279 case 0x88:
7280 case 0x89:
7281 case 0x8a:
7282 case 0x8b:
7283 case 0x8c:
7284 case 0x8d:
7285 case 0x8e:
7286 case 0x8f:
7287 case 0x90:
7288 case 0x91:
7289 case 0x92:
7290 case 0x93:
7291 case 0x94:
7292 case 0x95:
7293 case 0x96:
7294 case 0x97:
7295 {
7296 basic_json result = value_t::array;
7297 const auto len = static_cast<size_t>(v[current_idx] - 0x80);
7298 for (size_t i = 0; i < len; ++i)
7299 {
7300 result.push_back(from_cbor_internal(v, idx));
7301 }
7302 return result;
7303 }
7304
7305 case 0x98: // array (one-byte uint8_t for n follows)
7306 {
7307 basic_json result = value_t::array;
7308 const auto len = static_cast<size_t>(get_from_vector<uint8_t>(v, current_idx));
7309 idx += 1; // skip 1 size byte
7310 for (size_t i = 0; i < len; ++i)
7311 {
7312 result.push_back(from_cbor_internal(v, idx));
7313 }
7314 return result;
7315 }
7316
7317 case 0x99: // array (two-byte uint16_t for n follow)
7318 {
7319 basic_json result = value_t::array;
7320 const auto len = static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx));
7321 idx += 2; // skip 4 size bytes
7322 for (size_t i = 0; i < len; ++i)
7323 {
7324 result.push_back(from_cbor_internal(v, idx));
7325 }
7326 return result;
7327 }
7328
7329 case 0x9a: // array (four-byte uint32_t for n follow)
7330 {
7331 basic_json result = value_t::array;
7332 const auto len = static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx));
7333 idx += 4; // skip 4 size bytes
7334 for (size_t i = 0; i < len; ++i)
7335 {
7336 result.push_back(from_cbor_internal(v, idx));
7337 }
7338 return result;
7339 }
7340
7341 case 0x9b: // array (eight-byte uint64_t for n follow)
7342 {
7343 basic_json result = value_t::array;
7344 const auto len = static_cast<size_t>(get_from_vector<uint64_t>(v, current_idx));
7345 idx += 8; // skip 8 size bytes
7346 for (size_t i = 0; i < len; ++i)
7347 {
7348 result.push_back(from_cbor_internal(v, idx));
7349 }
7350 return result;
7351 }
7352
7353 case 0x9f: // array (indefinite length)
7354 {
7355 basic_json result = value_t::array;
7356 while (v[idx] != 0xff)
7357 {
7358 result.push_back(from_cbor_internal(v, idx));
7359 }
7360 // skip break byte (0xFF)
7361 idx += 1;
7362 return result;
7363 }
7364
7365 // map (0x00..0x17 pairs of data items follow)
7366 case 0xa0:
7367 case 0xa1:
7368 case 0xa2:
7369 case 0xa3:
7370 case 0xa4:
7371 case 0xa5:
7372 case 0xa6:
7373 case 0xa7:
7374 case 0xa8:
7375 case 0xa9:
7376 case 0xaa:
7377 case 0xab:
7378 case 0xac:
7379 case 0xad:
7380 case 0xae:
7381 case 0xaf:
7382 case 0xb0:
7383 case 0xb1:
7384 case 0xb2:
7385 case 0xb3:
7386 case 0xb4:
7387 case 0xb5:
7388 case 0xb6:
7389 case 0xb7:
7390 {
7391 basic_json result = value_t::object;
7392 const auto len = static_cast<size_t>(v[current_idx] - 0xa0);
7393 for (size_t i = 0; i < len; ++i)
7394 {
7395 std::string key = from_cbor_internal(v, idx);
7396 result[key] = from_cbor_internal(v, idx);
7397 }
7398 return result;
7399 }
7400
7401 case 0xb8: // map (one-byte uint8_t for n follows)
7402 {
7403 basic_json result = value_t::object;
7404 const auto len = static_cast<size_t>(get_from_vector<uint8_t>(v, current_idx));
7405 idx += 1; // skip 1 size byte
7406 for (size_t i = 0; i < len; ++i)
7407 {
7408 std::string key = from_cbor_internal(v, idx);
7409 result[key] = from_cbor_internal(v, idx);
7410 }
7411 return result;
7412 }
7413
7414 case 0xb9: // map (two-byte uint16_t for n follow)
7415 {
7416 basic_json result = value_t::object;
7417 const auto len = static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx));
7418 idx += 2; // skip 2 size bytes
7419 for (size_t i = 0; i < len; ++i)
7420 {
7421 std::string key = from_cbor_internal(v, idx);
7422 result[key] = from_cbor_internal(v, idx);
7423 }
7424 return result;
7425 }
7426
7427 case 0xba: // map (four-byte uint32_t for n follow)
7428 {
7429 basic_json result = value_t::object;
7430 const auto len = static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx));
7431 idx += 4; // skip 4 size bytes
7432 for (size_t i = 0; i < len; ++i)
7433 {
7434 std::string key = from_cbor_internal(v, idx);
7435 result[key] = from_cbor_internal(v, idx);
7436 }
7437 return result;
7438 }
7439
7440 case 0xbb: // map (eight-byte uint64_t for n follow)
7441 {
7442 basic_json result = value_t::object;
7443 const auto len = static_cast<size_t>(get_from_vector<uint64_t>(v, current_idx));
7444 idx += 8; // skip 8 size bytes
7445 for (size_t i = 0; i < len; ++i)
7446 {
7447 std::string key = from_cbor_internal(v, idx);
7448 result[key] = from_cbor_internal(v, idx);
7449 }
7450 return result;
7451 }
7452
7453 case 0xbf: // map (indefinite length)
7454 {
7455 basic_json result = value_t::object;
7456 while (v[idx] != 0xff)
7457 {
7458 std::string key = from_cbor_internal(v, idx);
7459 result[key] = from_cbor_internal(v, idx);
7460 }
7461 // skip break byte (0xFF)
7462 idx += 1;
7463 return result;
7464 }
7465
7466 case 0xf4: // false
7467 {
7468 return false;
7469 }
7470
7471 case 0xf5: // true
7472 {
7473 return true;
7474 }
7475
7476 case 0xf6: // null
7477 {
7478 return value_t::null;
7479 }
7480
7481 case 0xf9: // Half-Precision Float (two-byte IEEE 754)
7482 {
7483 idx += 2; // skip two content bytes
7484
7485 // code from RFC 7049, Appendix D, Figure 3:
7486 // As half-precision floating-point numbers were only added to
7487 // IEEE 754 in 2008, today's programming platforms often still
7488 // only have limited support for them. It is very easy to
7489 // include at least decoding support for them even without such
7490 // support. An example of a small decoder for half-precision
7491 // floating-point numbers in the C language is shown in Fig. 3.
7492 const int half = (v[current_idx + 1] << 8) + v[current_idx + 2];
7493 const int exp = (half >> 10) & 0x1f;
7494 const int mant = half & 0x3ff;
7495 double val;
7496 if (exp == 0)
7497 {
7498 val = std::ldexp(mant, -24);
7499 }
7500 else if (exp != 31)
7501 {
7502 val = std::ldexp(mant + 1024, exp - 25);
7503 }
7504 else
7505 {
7506 val = mant == 0 ? INFINITY : NAN;
7507 }
7508 return half & 0x8000 ? -val : val;
7509 }
7510
7511 case 0xfa: // Single-Precision Float (four-byte IEEE 754)
7512 {
7513 // copy bytes in reverse order into the float variable
7514 float res;
7515 for (size_t byte = 0; byte < sizeof(float); ++byte)
7516 {
7517 reinterpret_cast<uint8_t*>(&res)[sizeof(float) - byte - 1] = v[current_idx + 1 + byte];
7518 }
7519 idx += sizeof(float); // skip content bytes
7520 return res;
7521 }
7522
7523 case 0xfb: // Double-Precision Float (eight-byte IEEE 754)
7524 {
7525 // copy bytes in reverse order into the double variable
7526 double res;
7527 for (size_t byte = 0; byte < sizeof(double); ++byte)
7528 {
7529 reinterpret_cast<uint8_t*>(&res)[sizeof(double) - byte - 1] = v[current_idx + 1 + byte];
7530 }
7531 idx += sizeof(double); // skip content bytes
7532 return res;
7533 }
7534
7535 default: // anything else (0xFF is handled inside the other types)
7536 {
7537 throw std::invalid_argument("error parsing a CBOR @ " + std::to_string(current_idx) + ": " + std::to_string(static_cast<int>(v[current_idx])));
7538 }
7539 }
7540 }
7541
7542 public:
7543 /*!
7544 @brief create a MessagePack serialization of a given JSON value
7545
7546 Serializes a given JSON value @a j to a byte vector using the MessagePack
7547 serialization format. MessagePack is a binary serialization format which
7548 aims to be more compact than JSON itself, yet more efficient to parse.
7549
7550 @param[in] j JSON value to serialize
7551 @return MessagePack serialization as byte vector
7552
7553 @complexity Linear in the size of the JSON value @a j.
7554
7555 @liveexample{The example shows the serialization of a JSON value to a byte
7556 vector in MessagePack format.,to_msgpack}
7557
7558 @sa http://msgpack.org
7559 @sa @ref from_msgpack(const std::vector<uint8_t>&) for the analogous
7560 deserialization
7561 @sa @ref to_cbor(const basic_json& for the related CBOR format
7562 */
7563 static std::vector<uint8_t> to_msgpack(const basic_json& j)
7564 {
7565 std::vector<uint8_t> result;
7566 to_msgpack_internal(j, result);
7567 return result;
7568 }
7569
7570 /*!
7571 @brief create a JSON value from a byte vector in MessagePack format
7572
7573 Deserializes a given byte vector @a v to a JSON value using the MessagePack
7574 serialization format.
7575
7576 @param[in] v a byte vector in MessagePack format
7577 @return deserialized JSON value
7578
7579 @throw std::invalid_argument if unsupported features from MessagePack were
7580 used in the given vector @a v or if the input is not valid MessagePack
7581 @throw std::out_of_range if the given vector ends prematurely
7582
7583 @complexity Linear in the size of the byte vector @a v.
7584
7585 @liveexample{The example shows the deserialization of a byte vector in
7586 MessagePack format to a JSON value.,from_msgpack}
7587
7588 @sa http://msgpack.org
7589 @sa @ref to_msgpack(const basic_json&) for the analogous serialization
7590 @sa @ref from_cbor(const std::vector<uint8_t>&) for the related CBOR format
7591 */
7592 static basic_json from_msgpack(const std::vector<uint8_t>& v)
7593 {
7594 size_t i = 0;
7595 return from_msgpack_internal(v, i);
7596 }
7597
7598 /*!
7599 @brief create a MessagePack serialization of a given JSON value
7600
7601 Serializes a given JSON value @a j to a byte vector using the CBOR (Concise
7602 Binary Object Representation) serialization format. CBOR is a binary
7603 serialization format which aims to be more compact than JSON itself, yet
7604 more efficient to parse.
7605
7606 @param[in] j JSON value to serialize
7607 @return MessagePack serialization as byte vector
7608
7609 @complexity Linear in the size of the JSON value @a j.
7610
7611 @liveexample{The example shows the serialization of a JSON value to a byte
7612 vector in CBOR format.,to_cbor}
7613
7614 @sa http://cbor.io
7615 @sa @ref from_cbor(const std::vector<uint8_t>&) for the analogous
7616 deserialization
7617 @sa @ref to_msgpack(const basic_json& for the related MessagePack format
7618 */
7619 static std::vector<uint8_t> to_cbor(const basic_json& j)
7620 {
7621 std::vector<uint8_t> result;
7622 to_cbor_internal(j, result);
7623 return result;
7624 }
7625
7626 /*!
7627 @brief create a JSON value from a byte vector in CBOR format
7628
7629 Deserializes a given byte vector @a v to a JSON value using the CBOR
7630 (Concise Binary Object Representation) serialization format.
7631
7632 @param[in] v a byte vector in CBOR format
7633 @return deserialized JSON value
7634
7635 @throw std::invalid_argument if unsupported features from CBOR were used in
7636 the given vector @a v or if the input is not valid MessagePack
7637 @throw std::out_of_range if the given vector ends prematurely
7638
7639 @complexity Linear in the size of the byte vector @a v.
7640
7641 @liveexample{The example shows the deserialization of a byte vector in CBOR
7642 format to a JSON value.,from_cbor}
7643
7644 @sa http://cbor.io
7645 @sa @ref to_cbor(const basic_json&) for the analogous serialization
7646 @sa @ref from_msgpack(const std::vector<uint8_t>&) for the related
7647 MessagePack format
7648 */
7649 static basic_json from_cbor(const std::vector<uint8_t>& v)
7650 {
7651 size_t i = 0;
7652 return from_cbor_internal(v, i);
7653 }
7654
7655 /// @}
7656
7657 private:
7658 ///////////////////////////
7659 // convenience functions //
7660 ///////////////////////////
7661
7662 /*!
7663 @brief return the type as string
7664
7665 Returns the type name as string to be used in error messages - usually to
7666 indicate that a function was called on a wrong JSON type.
7667
7668 @return basically a string representation of a the @a m_type member
7669
7670 @complexity Constant.
7671
7672 @since version 1.0.0
7673 */
7674 std::string type_name() const
7675 {
7676 switch (m_type)
7677 {
7678 case value_t::null:
7679 return "null";
7680 case value_t::object:
7681 return "object";
7682 case value_t::array:
7683 return "array";
7684 case value_t::string:
7685 return "string";
7686 case value_t::boolean:
7687 return "boolean";
7688 case value_t::discarded:
7689 return "discarded";
7690 default:
7691 return "number";
7692 }
7693 }
7694
7695 /*!
7696 @brief calculates the extra space to escape a JSON string
7697
7698 @param[in] s the string to escape
7699 @return the number of characters required to escape string @a s
7700
7701 @complexity Linear in the length of string @a s.
7702 */
7703 static std::size_t extra_space(const string_t& s) noexcept
7704 {
7705 return std::accumulate(s.begin(), s.end(), size_t{},
7706 [](size_t res, typename string_t::value_type c)
7707 {
7708 switch (c)
7709 {
7710 case '"':
7711 case '\\':
7712 case '\b':
7713 case '\f':
7714 case '\n':
7715 case '\r':
7716 case '\t':
7717 {
7718 // from c (1 byte) to \x (2 bytes)
7719 return res + 1;
7720 }
7721
7722 default:
7723 {
7724 if (c >= 0x00 and c <= 0x1f)
7725 {
7726 // from c (1 byte) to \uxxxx (6 bytes)
7727 return res + 5;
7728 }
7729 else
7730 {
7731 return res;
7732 }
7733 }
7734 }
7735 });
7736 }
7737
7738 /*!
7739 @brief escape a string
7740
7741 Escape a string by replacing certain special characters by a sequence of
7742 an escape character (backslash) and another character and other control
7743 characters by a sequence of "\u" followed by a four-digit hex
7744 representation.
7745
7746 @param[in] s the string to escape
7747 @return the escaped string
7748
7749 @complexity Linear in the length of string @a s.
7750 */
7751 static string_t escape_string(const string_t& s)
7752 {
7753 const auto space = extra_space(s);
7754 if (space == 0)
7755 {
7756 return s;
7757 }
7758
7759 // create a result string of necessary size
7760 string_t result(s.size() + space, '\\');
7761 std::size_t pos = 0;
7762
7763 for (const auto& c : s)
7764 {
7765 switch (c)
7766 {
7767 // quotation mark (0x22)
7768 case '"':
7769 {
7770 result[pos + 1] = '"';
7771 pos += 2;
7772 break;
7773 }
7774
7775 // reverse solidus (0x5c)
7776 case '\\':
7777 {
7778 // nothing to change
7779 pos += 2;
7780 break;
7781 }
7782
7783 // backspace (0x08)
7784 case '\b':
7785 {
7786 result[pos + 1] = 'b';
7787 pos += 2;
7788 break;
7789 }
7790
7791 // formfeed (0x0c)
7792 case '\f':
7793 {
7794 result[pos + 1] = 'f';
7795 pos += 2;
7796 break;
7797 }
7798
7799 // newline (0x0a)
7800 case '\n':
7801 {
7802 result[pos + 1] = 'n';
7803 pos += 2;
7804 break;
7805 }
7806
7807 // carriage return (0x0d)
7808 case '\r':
7809 {
7810 result[pos + 1] = 'r';
7811 pos += 2;
7812 break;
7813 }
7814
7815 // horizontal tab (0x09)
7816 case '\t':
7817 {
7818 result[pos + 1] = 't';
7819 pos += 2;
7820 break;
7821 }
7822
7823 default:
7824 {
7825 if (c >= 0x00 and c <= 0x1f)
7826 {
7827 // convert a number 0..15 to its hex representation
7828 // (0..f)
7829 static const char hexify[16] =
7830 {
7831 '0', '1', '2', '3', '4', '5', '6', '7',
7832 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
7833 };
7834
7835 // print character c as \uxxxx
7836 for (const char m :
7837 { 'u', '0', '0', hexify[c >> 4], hexify[c & 0x0f]
7838 })
7839 {
7840 result[++pos] = m;
7841 }
7842
7843 ++pos;
7844 }
7845 else
7846 {
7847 // all other characters are added as-is
7848 result[pos++] = c;
7849 }
7850 break;
7851 }
7852 }
7853 }
7854
7855 return result;
7856 }
7857
7858 /*!
7859 @brief internal implementation of the serialization function
7860
7861 This function is called by the public member function dump and organizes
7862 the serialization internally. The indentation level is propagated as
7863 additional parameter. In case of arrays and objects, the function is
7864 called recursively. Note that
7865
7866 - strings and object keys are escaped using `escape_string()`
7867 - integer numbers are converted implicitly via `operator<<`
7868 - floating-point numbers are converted to a string using `"%g"` format
7869
7870 @param[out] o stream to write to
7871 @param[in] pretty_print whether the output shall be pretty-printed
7872 @param[in] indent_step the indent level
7873 @param[in] current_indent the current indent level (only used internally)
7874 */
7875 void dump(std::ostream& o,
7876 const bool pretty_print,
7877 const unsigned int indent_step,
7878 const unsigned int current_indent = 0) const
7879 {
7880 // variable to hold indentation for recursive calls
7881 unsigned int new_indent = current_indent;
7882
7883 switch (m_type)
7884 {
7885 case value_t::object:
7886 {
7887 if (m_value.object->empty())
7888 {
7889 o << "{}";
7890 return;
7891 }
7892
7893 o << "{";
7894
7895 // increase indentation
7896 if (pretty_print)
7897 {
7898 new_indent += indent_step;
7899 o << "\n";
7900 }
7901
7902 for (auto i = m_value.object->cbegin(); i != m_value.object->cend(); ++i)
7903 {
7904 if (i != m_value.object->cbegin())
7905 {
7906 o << (pretty_print ? ",\n" : ",");
7907 }
7908 o << string_t(new_indent, ' ') << "\""
7909 << escape_string(i->first) << "\":"
7910 << (pretty_print ? " " : "");
7911 i->second.dump(o, pretty_print, indent_step, new_indent);
7912 }
7913
7914 // decrease indentation
7915 if (pretty_print)
7916 {
7917 new_indent -= indent_step;
7918 o << "\n";
7919 }
7920
7921 o << string_t(new_indent, ' ') + "}";
7922 return;
7923 }
7924
7925 case value_t::array:
7926 {
7927 if (m_value.array->empty())
7928 {
7929 o << "[]";
7930 return;
7931 }
7932
7933 o << "[";
7934
7935 // increase indentation
7936 if (pretty_print)
7937 {
7938 new_indent += indent_step;
7939 o << "\n";
7940 }
7941
7942 for (auto i = m_value.array->cbegin(); i != m_value.array->cend(); ++i)
7943 {
7944 if (i != m_value.array->cbegin())
7945 {
7946 o << (pretty_print ? ",\n" : ",");
7947 }
7948 o << string_t(new_indent, ' ');
7949 i->dump(o, pretty_print, indent_step, new_indent);
7950 }
7951
7952 // decrease indentation
7953 if (pretty_print)
7954 {
7955 new_indent -= indent_step;
7956 o << "\n";
7957 }
7958
7959 o << string_t(new_indent, ' ') << "]";
7960 return;
7961 }
7962
7963 case value_t::string:
7964 {
7965 o << string_t("\"") << escape_string(*m_value.string) << "\"";
7966 return;
7967 }
7968
7969 case value_t::boolean:
7970 {
7971 o << (m_value.boolean ? "true" : "false");
7972 return;
7973 }
7974
7975 case value_t::number_integer:
7976 {
7977 o << m_value.number_integer;
7978 return;
7979 }
7980
7981 case value_t::number_unsigned:
7982 {
7983 o << m_value.number_unsigned;
7984 return;
7985 }
7986
7987 case value_t::number_float:
7988 {
7989 if (m_value.number_float == 0)
7990 {
7991 // special case for zero to get "0.0"/"-0.0"
7992 o << (std::signbit(m_value.number_float) ? "-0.0" : "0.0");
7993 }
7994 else
7995 {
7996 o << m_value.number_float;
7997 }
7998 return;
7999 }
8000
8001 case value_t::discarded:
8002 {
8003 o << "<discarded>";
8004 return;
8005 }
8006
8007 case value_t::null:
8008 {
8009 o << "null";
8010 return;
8011 }
8012 }
8013 }
8014
8015 private:
8016 //////////////////////
8017 // member variables //
8018 //////////////////////
8019
8020 /// the type of the current element
8021 value_t m_type = value_t::null;
8022
8023 /// the value of the current element
8024 json_value m_value = {};
8025
8026
8027 private:
8028 ///////////////
8029 // iterators //
8030 ///////////////
8031
8032 /*!
8033 @brief an iterator for primitive JSON types
8034
8035 This class models an iterator for primitive JSON types (boolean, number,
8036 string). It's only purpose is to allow the iterator/const_iterator classes
8037 to "iterate" over primitive values. Internally, the iterator is modeled by
8038 a `difference_type` variable. Value begin_value (`0`) models the begin,
8039 end_value (`1`) models past the end.
8040 */
8041 class primitive_iterator_t
8042 {
8043 public:
8044 /// set iterator to a defined beginning
8045 void set_begin() noexcept
8046 {
8047 m_it = begin_value;
8048 }
8049
8050 /// set iterator to a defined past the end
8051 void set_end() noexcept
8052 {
8053 m_it = end_value;
8054 }
8055
8056 /// return whether the iterator can be dereferenced
8057 constexpr bool is_begin() const noexcept
8058 {
8059 return (m_it == begin_value);
8060 }
8061
8062 /// return whether the iterator is at end
8063 constexpr bool is_end() const noexcept
8064 {
8065 return (m_it == end_value);
8066 }
8067
8068 /// return reference to the value to change and compare
8069 operator difference_type& () noexcept
8070 {
8071 return m_it;
8072 }
8073
8074 /// return value to compare
8075 constexpr operator difference_type () const noexcept
8076 {
8077 return m_it;
8078 }
8079
8080 private:
8081 static constexpr difference_type begin_value = 0;
8082 static constexpr difference_type end_value = begin_value + 1;
8083
8084 /// iterator as signed integer type
8085 difference_type m_it = std::numeric_limits<std::ptrdiff_t>::denorm_min();
8086 };
8087
8088 /*!
8089 @brief an iterator value
8090
8091 @note This structure could easily be a union, but MSVC currently does not
8092 allow unions members with complex constructors, see
8093 https://github.com/nlohmann/json/pull/105.
8094 */
8095 struct internal_iterator
8096 {
8097 /// iterator for JSON objects
8098 typename object_t::iterator object_iterator;
8099 /// iterator for JSON arrays
8100 typename array_t::iterator array_iterator;
8101 /// generic iterator for all other types
8102 primitive_iterator_t primitive_iterator;
8103
8104 /// create an uninitialized internal_iterator
8105 internal_iterator() noexcept
8106 : object_iterator(), array_iterator(), primitive_iterator()
8107 {}
8108 };
8109
8110 /// proxy class for the iterator_wrapper functions
8111 template<typename IteratorType>
8112 class iteration_proxy
8113 {
8114 private:
8115 /// helper class for iteration
8116 class iteration_proxy_internal
8117 {
8118 private:
8119 /// the iterator
8120 IteratorType anchor;
8121 /// an index for arrays (used to create key names)
8122 size_t array_index = 0;
8123
8124 public:
8125 explicit iteration_proxy_internal(IteratorType it) noexcept
8126 : anchor(it)
8127 {}
8128
8129 /// dereference operator (needed for range-based for)
8130 iteration_proxy_internal& operator*()
8131 {
8132 return *this;
8133 }
8134
8135 /// increment operator (needed for range-based for)
8136 iteration_proxy_internal& operator++()
8137 {
8138 ++anchor;
8139 ++array_index;
8140
8141 return *this;
8142 }
8143
8144 /// inequality operator (needed for range-based for)
8145 bool operator!= (const iteration_proxy_internal& o) const
8146 {
8147 return anchor != o.anchor;
8148 }
8149
8150 /// return key of the iterator
8151 typename basic_json::string_t key() const
8152 {
8153 assert(anchor.m_object != nullptr);
8154
8155 switch (anchor.m_object->type())
8156 {
8157 // use integer array index as key
8158 case value_t::array:
8159 {
8160 return std::to_string(array_index);
8161 }
8162
8163 // use key from the object
8164 case value_t::object:
8165 {
8166 return anchor.key();
8167 }
8168
8169 // use an empty key for all primitive types
8170 default:
8171 {
8172 return "";
8173 }
8174 }
8175 }
8176
8177 /// return value of the iterator
8178 typename IteratorType::reference value() const
8179 {
8180 return anchor.value();
8181 }
8182 };
8183
8184 /// the container to iterate
8185 typename IteratorType::reference container;
8186
8187 public:
8188 /// construct iteration proxy from a container
8189 explicit iteration_proxy(typename IteratorType::reference cont)
8190 : container(cont)
8191 {}
8192
8193 /// return iterator begin (needed for range-based for)
8194 iteration_proxy_internal begin() noexcept
8195 {
8196 return iteration_proxy_internal(container.begin());
8197 }
8198
8199 /// return iterator end (needed for range-based for)
8200 iteration_proxy_internal end() noexcept
8201 {
8202 return iteration_proxy_internal(container.end());
8203 }
8204 };
8205
8206 public:
8207 /*!
8208 @brief a template for a random access iterator for the @ref basic_json class
8209
8210 This class implements a both iterators (iterator and const_iterator) for the
8211 @ref basic_json class.
8212
8213 @note An iterator is called *initialized* when a pointer to a JSON value
8214 has been set (e.g., by a constructor or a copy assignment). If the
8215 iterator is default-constructed, it is *uninitialized* and most
8216 methods are undefined. **The library uses assertions to detect calls
8217 on uninitialized iterators.**
8218
8219 @requirement The class satisfies the following concept requirements:
8220 - [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator):
8221 The iterator that can be moved to point (forward and backward) to any
8222 element in constant time.
8223
8224 @since version 1.0.0, simplified in version 2.0.9
8225 */
8226 template<typename U>
8227 class iter_impl : public std::iterator<std::random_access_iterator_tag, U>
8228 {
8229 /// allow basic_json to access private members
8230 friend class basic_json;
8231
8232 // make sure U is basic_json or const basic_json
8233 static_assert(std::is_same<U, basic_json>::value
8234 or std::is_same<U, const basic_json>::value,
8235 "iter_impl only accepts (const) basic_json");
8236
8237 public:
8238 /// the type of the values when the iterator is dereferenced
8239 using value_type = typename basic_json::value_type;
8240 /// a type to represent differences between iterators
8241 using difference_type = typename basic_json::difference_type;
8242 /// defines a pointer to the type iterated over (value_type)
8243 using pointer = typename std::conditional<std::is_const<U>::value,
8244 typename basic_json::const_pointer,
8245 typename basic_json::pointer>::type;
8246 /// defines a reference to the type iterated over (value_type)
8247 using reference = typename std::conditional<std::is_const<U>::value,
8248 typename basic_json::const_reference,
8249 typename basic_json::reference>::type;
8250 /// the category of the iterator
8251 using iterator_category = std::bidirectional_iterator_tag;
8252
8253 /// default constructor
8254 iter_impl() = default;
8255
8256 /*!
8257 @brief constructor for a given JSON instance
8258 @param[in] object pointer to a JSON object for this iterator
8259 @pre object != nullptr
8260 @post The iterator is initialized; i.e. `m_object != nullptr`.
8261 */
8262 explicit iter_impl(pointer object) noexcept
8263 : m_object(object)
8264 {
8265 assert(m_object != nullptr);
8266
8267 switch (m_object->m_type)
8268 {
8269 case basic_json::value_t::object:
8270 {
8271 m_it.object_iterator = typename object_t::iterator();
8272 break;
8273 }
8274
8275 case basic_json::value_t::array:
8276 {
8277 m_it.array_iterator = typename array_t::iterator();
8278 break;
8279 }
8280
8281 default:
8282 {
8283 m_it.primitive_iterator = primitive_iterator_t();
8284 break;
8285 }
8286 }
8287 }
8288
8289 /*
8290 Use operator `const_iterator` instead of `const_iterator(const iterator&
8291 other) noexcept` to avoid two class definitions for @ref iterator and
8292 @ref const_iterator.
8293
8294 This function is only called if this class is an @ref iterator. If this
8295 class is a @ref const_iterator this function is not called.
8296 */
8297 operator const_iterator() const
8298 {
8299 const_iterator ret;
8300
8301 if (m_object)
8302 {
8303 ret.m_object = m_object;
8304 ret.m_it = m_it;
8305 }
8306
8307 return ret;
8308 }
8309
8310 /*!
8311 @brief copy constructor
8312 @param[in] other iterator to copy from
8313 @note It is not checked whether @a other is initialized.
8314 */
8315 iter_impl(const iter_impl& other) noexcept
8316 : m_object(other.m_object), m_it(other.m_it)
8317 {}
8318
8319 /*!
8320 @brief copy assignment
8321 @param[in,out] other iterator to copy from
8322 @note It is not checked whether @a other is initialized.
8323 */
8324 iter_impl& operator=(iter_impl other) noexcept(
8325 std::is_nothrow_move_constructible<pointer>::value and
8326 std::is_nothrow_move_assignable<pointer>::value and
8327 std::is_nothrow_move_constructible<internal_iterator>::value and
8328 std::is_nothrow_move_assignable<internal_iterator>::value
8329 )
8330 {
8331 std::swap(m_object, other.m_object);
8332 std::swap(m_it, other.m_it);
8333 return *this;
8334 }
8335
8336 private:
8337 /*!
8338 @brief set the iterator to the first value
8339 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8340 */
8341 void set_begin() noexcept
8342 {
8343 assert(m_object != nullptr);
8344
8345 switch (m_object->m_type)
8346 {
8347 case basic_json::value_t::object:
8348 {
8349 m_it.object_iterator = m_object->m_value.object->begin();
8350 break;
8351 }
8352
8353 case basic_json::value_t::array:
8354 {
8355 m_it.array_iterator = m_object->m_value.array->begin();
8356 break;
8357 }
8358
8359 case basic_json::value_t::null:
8360 {
8361 // set to end so begin()==end() is true: null is empty
8362 m_it.primitive_iterator.set_end();
8363 break;
8364 }
8365
8366 default:
8367 {
8368 m_it.primitive_iterator.set_begin();
8369 break;
8370 }
8371 }
8372 }
8373
8374 /*!
8375 @brief set the iterator past the last value
8376 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8377 */
8378 void set_end() noexcept
8379 {
8380 assert(m_object != nullptr);
8381
8382 switch (m_object->m_type)
8383 {
8384 case basic_json::value_t::object:
8385 {
8386 m_it.object_iterator = m_object->m_value.object->end();
8387 break;
8388 }
8389
8390 case basic_json::value_t::array:
8391 {
8392 m_it.array_iterator = m_object->m_value.array->end();
8393 break;
8394 }
8395
8396 default:
8397 {
8398 m_it.primitive_iterator.set_end();
8399 break;
8400 }
8401 }
8402 }
8403
8404 public:
8405 /*!
8406 @brief return a reference to the value pointed to by the iterator
8407 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8408 */
8409 reference operator*() const
8410 {
8411 assert(m_object != nullptr);
8412
8413 switch (m_object->m_type)
8414 {
8415 case basic_json::value_t::object:
8416 {
8417 assert(m_it.object_iterator != m_object->m_value.object->end());
8418 return m_it.object_iterator->second;
8419 }
8420
8421 case basic_json::value_t::array:
8422 {
8423 assert(m_it.array_iterator != m_object->m_value.array->end());
8424 return *m_it.array_iterator;
8425 }
8426
8427 case basic_json::value_t::null:
8428 {
8429 throw std::out_of_range("cannot get value");
8430 }
8431
8432 default:
8433 {
8434 if (m_it.primitive_iterator.is_begin())
8435 {
8436 return *m_object;
8437 }
8438 else
8439 {
8440 throw std::out_of_range("cannot get value");
8441 }
8442 }
8443 }
8444 }
8445
8446 /*!
8447 @brief dereference the iterator
8448 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8449 */
8450 pointer operator->() const
8451 {
8452 assert(m_object != nullptr);
8453
8454 switch (m_object->m_type)
8455 {
8456 case basic_json::value_t::object:
8457 {
8458 assert(m_it.object_iterator != m_object->m_value.object->end());
8459 return &(m_it.object_iterator->second);
8460 }
8461
8462 case basic_json::value_t::array:
8463 {
8464 assert(m_it.array_iterator != m_object->m_value.array->end());
8465 return &*m_it.array_iterator;
8466 }
8467
8468 default:
8469 {
8470 if (m_it.primitive_iterator.is_begin())
8471 {
8472 return m_object;
8473 }
8474 else
8475 {
8476 throw std::out_of_range("cannot get value");
8477 }
8478 }
8479 }
8480 }
8481
8482 /*!
8483 @brief post-increment (it++)
8484 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8485 */
8486 iter_impl operator++(int)
8487 {
8488 auto result = *this;
8489 ++(*this);
8490 return result;
8491 }
8492
8493 /*!
8494 @brief pre-increment (++it)
8495 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8496 */
8497 iter_impl& operator++()
8498 {
8499 assert(m_object != nullptr);
8500
8501 switch (m_object->m_type)
8502 {
8503 case basic_json::value_t::object:
8504 {
8505 std::advance(m_it.object_iterator, 1);
8506 break;
8507 }
8508
8509 case basic_json::value_t::array:
8510 {
8511 std::advance(m_it.array_iterator, 1);
8512 break;
8513 }
8514
8515 default:
8516 {
8517 ++m_it.primitive_iterator;
8518 break;
8519 }
8520 }
8521
8522 return *this;
8523 }
8524
8525 /*!
8526 @brief post-decrement (it--)
8527 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8528 */
8529 iter_impl operator--(int)
8530 {
8531 auto result = *this;
8532 --(*this);
8533 return result;
8534 }
8535
8536 /*!
8537 @brief pre-decrement (--it)
8538 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8539 */
8540 iter_impl& operator--()
8541 {
8542 assert(m_object != nullptr);
8543
8544 switch (m_object->m_type)
8545 {
8546 case basic_json::value_t::object:
8547 {
8548 std::advance(m_it.object_iterator, -1);
8549 break;
8550 }
8551
8552 case basic_json::value_t::array:
8553 {
8554 std::advance(m_it.array_iterator, -1);
8555 break;
8556 }
8557
8558 default:
8559 {
8560 --m_it.primitive_iterator;
8561 break;
8562 }
8563 }
8564
8565 return *this;
8566 }
8567
8568 /*!
8569 @brief comparison: equal
8570 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8571 */
8572 bool operator==(const iter_impl& other) const
8573 {
8574 // if objects are not the same, the comparison is undefined
8575 if (m_object != other.m_object)
8576 {
8577 throw std::domain_error("cannot compare iterators of different containers");
8578 }
8579
8580 assert(m_object != nullptr);
8581
8582 switch (m_object->m_type)
8583 {
8584 case basic_json::value_t::object:
8585 {
8586 return (m_it.object_iterator == other.m_it.object_iterator);
8587 }
8588
8589 case basic_json::value_t::array:
8590 {
8591 return (m_it.array_iterator == other.m_it.array_iterator);
8592 }
8593
8594 default:
8595 {
8596 return (m_it.primitive_iterator == other.m_it.primitive_iterator);
8597 }
8598 }
8599 }
8600
8601 /*!
8602 @brief comparison: not equal
8603 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8604 */
8605 bool operator!=(const iter_impl& other) const
8606 {
8607 return not operator==(other);
8608 }
8609
8610 /*!
8611 @brief comparison: smaller
8612 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8613 */
8614 bool operator<(const iter_impl& other) const
8615 {
8616 // if objects are not the same, the comparison is undefined
8617 if (m_object != other.m_object)
8618 {
8619 throw std::domain_error("cannot compare iterators of different containers");
8620 }
8621
8622 assert(m_object != nullptr);
8623
8624 switch (m_object->m_type)
8625 {
8626 case basic_json::value_t::object:
8627 {
8628 throw std::domain_error("cannot compare order of object iterators");
8629 }
8630
8631 case basic_json::value_t::array:
8632 {
8633 return (m_it.array_iterator < other.m_it.array_iterator);
8634 }
8635
8636 default:
8637 {
8638 return (m_it.primitive_iterator < other.m_it.primitive_iterator);
8639 }
8640 }
8641 }
8642
8643 /*!
8644 @brief comparison: less than or equal
8645 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8646 */
8647 bool operator<=(const iter_impl& other) const
8648 {
8649 return not other.operator < (*this);
8650 }
8651
8652 /*!
8653 @brief comparison: greater than
8654 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8655 */
8656 bool operator>(const iter_impl& other) const
8657 {
8658 return not operator<=(other);
8659 }
8660
8661 /*!
8662 @brief comparison: greater than or equal
8663 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8664 */
8665 bool operator>=(const iter_impl& other) const
8666 {
8667 return not operator<(other);
8668 }
8669
8670 /*!
8671 @brief add to iterator
8672 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8673 */
8674 iter_impl& operator+=(difference_type i)
8675 {
8676 assert(m_object != nullptr);
8677
8678 switch (m_object->m_type)
8679 {
8680 case basic_json::value_t::object:
8681 {
8682 throw std::domain_error("cannot use offsets with object iterators");
8683 }
8684
8685 case basic_json::value_t::array:
8686 {
8687 std::advance(m_it.array_iterator, i);
8688 break;
8689 }
8690
8691 default:
8692 {
8693 m_it.primitive_iterator += i;
8694 break;
8695 }
8696 }
8697
8698 return *this;
8699 }
8700
8701 /*!
8702 @brief subtract from iterator
8703 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8704 */
8705 iter_impl& operator-=(difference_type i)
8706 {
8707 return operator+=(-i);
8708 }
8709
8710 /*!
8711 @brief add to iterator
8712 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8713 */
8714 iter_impl operator+(difference_type i)
8715 {
8716 auto result = *this;
8717 result += i;
8718 return result;
8719 }
8720
8721 /*!
8722 @brief subtract from iterator
8723 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8724 */
8725 iter_impl operator-(difference_type i)
8726 {
8727 auto result = *this;
8728 result -= i;
8729 return result;
8730 }
8731
8732 /*!
8733 @brief return difference
8734 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8735 */
8736 difference_type operator-(const iter_impl& other) const
8737 {
8738 assert(m_object != nullptr);
8739
8740 switch (m_object->m_type)
8741 {
8742 case basic_json::value_t::object:
8743 {
8744 throw std::domain_error("cannot use offsets with object iterators");
8745 }
8746
8747 case basic_json::value_t::array:
8748 {
8749 return m_it.array_iterator - other.m_it.array_iterator;
8750 }
8751
8752 default:
8753 {
8754 return m_it.primitive_iterator - other.m_it.primitive_iterator;
8755 }
8756 }
8757 }
8758
8759 /*!
8760 @brief access to successor
8761 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8762 */
8763 reference operator[](difference_type n) const
8764 {
8765 assert(m_object != nullptr);
8766
8767 switch (m_object->m_type)
8768 {
8769 case basic_json::value_t::object:
8770 {
8771 throw std::domain_error("cannot use operator[] for object iterators");
8772 }
8773
8774 case basic_json::value_t::array:
8775 {
8776 return *std::next(m_it.array_iterator, n);
8777 }
8778
8779 case basic_json::value_t::null:
8780 {
8781 throw std::out_of_range("cannot get value");
8782 }
8783
8784 default:
8785 {
8786 if (m_it.primitive_iterator == -n)
8787 {
8788 return *m_object;
8789 }
8790 else
8791 {
8792 throw std::out_of_range("cannot get value");
8793 }
8794 }
8795 }
8796 }
8797
8798 /*!
8799 @brief return the key of an object iterator
8800 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8801 */
8802 typename object_t::key_type key() const
8803 {
8804 assert(m_object != nullptr);
8805
8806 if (m_object->is_object())
8807 {
8808 return m_it.object_iterator->first;
8809 }
8810 else
8811 {
8812 throw std::domain_error("cannot use key() for non-object iterators");
8813 }
8814 }
8815
8816 /*!
8817 @brief return the value of an iterator
8818 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8819 */
8820 reference value() const
8821 {
8822 return operator*();
8823 }
8824
8825 private:
8826 /// associated JSON instance
8827 pointer m_object = nullptr;
8828 /// the actual iterator of the associated instance
8829 internal_iterator m_it = internal_iterator();
8830 };
8831
8832 /*!
8833 @brief a template for a reverse iterator class
8834
8835 @tparam Base the base iterator type to reverse. Valid types are @ref
8836 iterator (to create @ref reverse_iterator) and @ref const_iterator (to
8837 create @ref const_reverse_iterator).
8838
8839 @requirement The class satisfies the following concept requirements:
8840 - [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator):
8841 The iterator that can be moved to point (forward and backward) to any
8842 element in constant time.
8843 - [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator):
8844 It is possible to write to the pointed-to element (only if @a Base is
8845 @ref iterator).
8846
8847 @since version 1.0.0
8848 */
8849 template<typename Base>
8850 class json_reverse_iterator : public std::reverse_iterator<Base>
8851 {
8852 public:
8853 /// shortcut to the reverse iterator adaptor
8854 using base_iterator = std::reverse_iterator<Base>;
8855 /// the reference type for the pointed-to element
8856 using reference = typename Base::reference;
8857
8858 /// create reverse iterator from iterator
8859 json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept
8860 : base_iterator(it)
8861 {}
8862
8863 /// create reverse iterator from base class
8864 json_reverse_iterator(const base_iterator& it) noexcept
8865 : base_iterator(it)
8866 {}
8867
8868 /// post-increment (it++)
8869 json_reverse_iterator operator++(int)
8870 {
8871 return base_iterator::operator++(1);
8872 }
8873
8874 /// pre-increment (++it)
8875 json_reverse_iterator& operator++()
8876 {
8877 base_iterator::operator++();
8878 return *this;
8879 }
8880
8881 /// post-decrement (it--)
8882 json_reverse_iterator operator--(int)
8883 {
8884 return base_iterator::operator--(1);
8885 }
8886
8887 /// pre-decrement (--it)
8888 json_reverse_iterator& operator--()
8889 {
8890 base_iterator::operator--();
8891 return *this;
8892 }
8893
8894 /// add to iterator
8895 json_reverse_iterator& operator+=(difference_type i)
8896 {
8897 base_iterator::operator+=(i);
8898 return *this;
8899 }
8900
8901 /// add to iterator
8902 json_reverse_iterator operator+(difference_type i) const
8903 {
8904 auto result = *this;
8905 result += i;
8906 return result;
8907 }
8908
8909 /// subtract from iterator
8910 json_reverse_iterator operator-(difference_type i) const
8911 {
8912 auto result = *this;
8913 result -= i;
8914 return result;
8915 }
8916
8917 /// return difference
8918 difference_type operator-(const json_reverse_iterator& other) const
8919 {
8920 return this->base() - other.base();
8921 }
8922
8923 /// access to successor
8924 reference operator[](difference_type n) const
8925 {
8926 return *(this->operator+(n));
8927 }
8928
8929 /// return the key of an object iterator
8930 typename object_t::key_type key() const
8931 {
8932 auto it = --this->base();
8933 return it.key();
8934 }
8935
8936 /// return the value of an iterator
8937 reference value() const
8938 {
8939 auto it = --this->base();
8940 return it.operator * ();
8941 }
8942 };
8943
8944
8945 private:
8946 //////////////////////
8947 // lexer and parser //
8948 //////////////////////
8949
8950 /*!
8951 @brief lexical analysis
8952
8953 This class organizes the lexical analysis during JSON deserialization. The
8954 core of it is a scanner generated by [re2c](http://re2c.org) that
8955 processes a buffer and recognizes tokens according to RFC 7159.
8956 */
8957 class lexer
8958 {
8959 public:
8960 /// token types for the parser
8961 enum class token_type
8962 {
8963 uninitialized, ///< indicating the scanner is uninitialized
8964 literal_true, ///< the `true` literal
8965 literal_false, ///< the `false` literal
8966 literal_null, ///< the `null` literal
8967 value_string, ///< a string -- use get_string() for actual value
8968 value_number, ///< a number -- use get_number() for actual value
8969 begin_array, ///< the character for array begin `[`
8970 begin_object, ///< the character for object begin `{`
8971 end_array, ///< the character for array end `]`
8972 end_object, ///< the character for object end `}`
8973 name_separator, ///< the name separator `:`
8974 value_separator, ///< the value separator `,`
8975 parse_error, ///< indicating a parse error
8976 end_of_input ///< indicating the end of the input buffer
8977 };
8978
8979 /// the char type to use in the lexer
8980 using lexer_char_t = unsigned char;
8981
8982 /// a lexer from a buffer with given length
8983 lexer(const lexer_char_t* buff, const size_t len) noexcept
8984 : m_content(buff)
8985 {
8986 assert(m_content != nullptr);
8987 m_start = m_cursor = m_content;
8988 m_limit = m_content + len;
8989 }
8990
8991 /// a lexer from an input stream
8992 explicit lexer(std::istream& s)
8993 : m_stream(&s), m_line_buffer()
8994 {
8995 // immediately abort if stream is erroneous
8996 if (s.fail())
8997 {
8998 throw std::invalid_argument("stream error: " + std::string(strerror(errno)));
8999 }
9000
9001 // fill buffer
9002 fill_line_buffer();
9003
9004 // skip UTF-8 byte-order mark
9005 if (m_line_buffer.size() >= 3 and m_line_buffer.substr(0, 3) == "\xEF\xBB\xBF")
9006 {
9007 m_line_buffer[0] = ' ';
9008 m_line_buffer[1] = ' ';
9009 m_line_buffer[2] = ' ';
9010 }
9011 }
9012
9013 // switch off unwanted functions (due to pointer members)
9014 lexer() = delete;
9015 lexer(const lexer&) = delete;
9016 lexer operator=(const lexer&) = delete;
9017
9018 /*!
9019 @brief create a string from one or two Unicode code points
9020
9021 There are two cases: (1) @a codepoint1 is in the Basic Multilingual
9022 Plane (U+0000 through U+FFFF) and @a codepoint2 is 0, or (2)
9023 @a codepoint1 and @a codepoint2 are a UTF-16 surrogate pair to
9024 represent a code point above U+FFFF.
9025
9026 @param[in] codepoint1 the code point (can be high surrogate)
9027 @param[in] codepoint2 the code point (can be low surrogate or 0)
9028
9029 @return string representation of the code point; the length of the
9030 result string is between 1 and 4 characters.
9031
9032 @throw std::out_of_range if code point is > 0x10ffff; example: `"code
9033 points above 0x10FFFF are invalid"`
9034 @throw std::invalid_argument if the low surrogate is invalid; example:
9035 `""missing or wrong low surrogate""`
9036
9037 @complexity Constant.
9038
9039 @see <http://en.wikipedia.org/wiki/UTF-8#Sample_code>
9040 */
9041 static string_t to_unicode(const std::size_t codepoint1,
9042 const std::size_t codepoint2 = 0)
9043 {
9044 // calculate the code point from the given code points
9045 std::size_t codepoint = codepoint1;
9046
9047 // check if codepoint1 is a high surrogate
9048 if (codepoint1 >= 0xD800 and codepoint1 <= 0xDBFF)
9049 {
9050 // check if codepoint2 is a low surrogate
9051 if (codepoint2 >= 0xDC00 and codepoint2 <= 0xDFFF)
9052 {
9053 codepoint =
9054 // high surrogate occupies the most significant 22 bits
9055 (codepoint1 << 10)
9056 // low surrogate occupies the least significant 15 bits
9057 + codepoint2
9058 // there is still the 0xD800, 0xDC00 and 0x10000 noise
9059 // in the result so we have to subtract with:
9060 // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00
9061 - 0x35FDC00;
9062 }
9063 else
9064 {
9065 throw std::invalid_argument("missing or wrong low surrogate");
9066 }
9067 }
9068
9069 string_t result;
9070
9071 if (codepoint < 0x80)
9072 {
9073 // 1-byte characters: 0xxxxxxx (ASCII)
9074 result.append(1, static_cast<typename string_t::value_type>(codepoint));
9075 }
9076 else if (codepoint <= 0x7ff)
9077 {
9078 // 2-byte characters: 110xxxxx 10xxxxxx
9079 result.append(1, static_cast<typename string_t::value_type>(0xC0 | ((codepoint >> 6) & 0x1F)));
9080 result.append(1, static_cast<typename string_t::value_type>(0x80 | (codepoint & 0x3F)));
9081 }
9082 else if (codepoint <= 0xffff)
9083 {
9084 // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx
9085 result.append(1, static_cast<typename string_t::value_type>(0xE0 | ((codepoint >> 12) & 0x0F)));
9086 result.append(1, static_cast<typename string_t::value_type>(0x80 | ((codepoint >> 6) & 0x3F)));
9087 result.append(1, static_cast<typename string_t::value_type>(0x80 | (codepoint & 0x3F)));
9088 }
9089 else if (codepoint <= 0x10ffff)
9090 {
9091 // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
9092 result.append(1, static_cast<typename string_t::value_type>(0xF0 | ((codepoint >> 18) & 0x07)));
9093 result.append(1, static_cast<typename string_t::value_type>(0x80 | ((codepoint >> 12) & 0x3F)));
9094 result.append(1, static_cast<typename string_t::value_type>(0x80 | ((codepoint >> 6) & 0x3F)));
9095 result.append(1, static_cast<typename string_t::value_type>(0x80 | (codepoint & 0x3F)));
9096 }
9097 else
9098 {
9099 throw std::out_of_range("code points above 0x10FFFF are invalid");
9100 }
9101
9102 return result;
9103 }
9104
9105 /// return name of values of type token_type (only used for errors)
9106 static std::string token_type_name(const token_type t)
9107 {
9108 switch (t)
9109 {
9110 case token_type::uninitialized:
9111 return "<uninitialized>";
9112 case token_type::literal_true:
9113 return "true literal";
9114 case token_type::literal_false:
9115 return "false literal";
9116 case token_type::literal_null:
9117 return "null literal";
9118 case token_type::value_string:
9119 return "string literal";
9120 case token_type::value_number:
9121 return "number literal";
9122 case token_type::begin_array:
9123 return "'['";
9124 case token_type::begin_object:
9125 return "'{'";
9126 case token_type::end_array:
9127 return "']'";
9128 case token_type::end_object:
9129 return "'}'";
9130 case token_type::name_separator:
9131 return "':'";
9132 case token_type::value_separator:
9133 return "','";
9134 case token_type::parse_error:
9135 return "<parse error>";
9136 case token_type::end_of_input:
9137 return "end of input";
9138 default:
9139 {
9140 // catch non-enum values
9141 return "unknown token"; // LCOV_EXCL_LINE
9142 }
9143 }
9144 }
9145
9146 /*!
9147 This function implements a scanner for JSON. It is specified using
9148 regular expressions that try to follow RFC 7159 as close as possible.
9149 These regular expressions are then translated into a minimized
9150 deterministic finite automaton (DFA) by the tool
9151 [re2c](http://re2c.org). As a result, the translated code for this
9152 function consists of a large block of code with `goto` jumps.
9153
9154 @return the class of the next token read from the buffer
9155
9156 @complexity Linear in the length of the input.\n
9157
9158 Proposition: The loop below will always terminate for finite input.\n
9159
9160 Proof (by contradiction): Assume a finite input. To loop forever, the
9161 loop must never hit code with a `break` statement. The only code
9162 snippets without a `break` statement are the continue statements for
9163 whitespace and byte-order-marks. To loop forever, the input must be an
9164 infinite sequence of whitespace or byte-order-marks. This contradicts
9165 the assumption of finite input, q.e.d.
9166 */
9167 token_type scan()
9168 {
9169 while (true)
9170 {
9171 // pointer for backtracking information
9172 m_marker = nullptr;
9173
9174 // remember the begin of the token
9175 m_start = m_cursor;
9176 assert(m_start != nullptr);
9177
9178
9179 {
9180 lexer_char_t yych;
9181 unsigned int yyaccept = 0;
9182 static const unsigned char yybm[] =
9183 {
9184 0, 0, 0, 0, 0, 0, 0, 0,
9185 0, 32, 32, 0, 0, 32, 0, 0,
9186 0, 0, 0, 0, 0, 0, 0, 0,
9187 0, 0, 0, 0, 0, 0, 0, 0,
9188 160, 128, 0, 128, 128, 128, 128, 128,
9189 128, 128, 128, 128, 128, 128, 128, 128,
9190 192, 192, 192, 192, 192, 192, 192, 192,
9191 192, 192, 128, 128, 128, 128, 128, 128,
9192 128, 128, 128, 128, 128, 128, 128, 128,
9193 128, 128, 128, 128, 128, 128, 128, 128,
9194 128, 128, 128, 128, 128, 128, 128, 128,
9195 128, 128, 128, 128, 0, 128, 128, 128,
9196 128, 128, 128, 128, 128, 128, 128, 128,
9197 128, 128, 128, 128, 128, 128, 128, 128,
9198 128, 128, 128, 128, 128, 128, 128, 128,
9199 128, 128, 128, 128, 128, 128, 128, 128,
9200 0, 0, 0, 0, 0, 0, 0, 0,
9201 0, 0, 0, 0, 0, 0, 0, 0,
9202 0, 0, 0, 0, 0, 0, 0, 0,
9203 0, 0, 0, 0, 0, 0, 0, 0,
9204 0, 0, 0, 0, 0, 0, 0, 0,
9205 0, 0, 0, 0, 0, 0, 0, 0,
9206 0, 0, 0, 0, 0, 0, 0, 0,
9207 0, 0, 0, 0, 0, 0, 0, 0,
9208 0, 0, 0, 0, 0, 0, 0, 0,
9209 0, 0, 0, 0, 0, 0, 0, 0,
9210 0, 0, 0, 0, 0, 0, 0, 0,
9211 0, 0, 0, 0, 0, 0, 0, 0,
9212 0, 0, 0, 0, 0, 0, 0, 0,
9213 0, 0, 0, 0, 0, 0, 0, 0,
9214 0, 0, 0, 0, 0, 0, 0, 0,
9215 0, 0, 0, 0, 0, 0, 0, 0,
9216 };
9217 if ((m_limit - m_cursor) < 5)
9218 {
9219 fill_line_buffer(5); // LCOV_EXCL_LINE
9220 }
9221 yych = *m_cursor;
9222 if (yybm[0 + yych] & 32)
9223 {
9224 goto basic_json_parser_6;
9225 }
9226 if (yych <= '[')
9227 {
9228 if (yych <= '-')
9229 {
9230 if (yych <= '"')
9231 {
9232 if (yych <= 0x00)
9233 {
9234 goto basic_json_parser_2;
9235 }
9236 if (yych <= '!')
9237 {
9238 goto basic_json_parser_4;
9239 }
9240 goto basic_json_parser_9;
9241 }
9242 else
9243 {
9244 if (yych <= '+')
9245 {
9246 goto basic_json_parser_4;
9247 }
9248 if (yych <= ',')
9249 {
9250 goto basic_json_parser_10;
9251 }
9252 goto basic_json_parser_12;
9253 }
9254 }
9255 else
9256 {
9257 if (yych <= '9')
9258 {
9259 if (yych <= '/')
9260 {
9261 goto basic_json_parser_4;
9262 }
9263 if (yych <= '0')
9264 {
9265 goto basic_json_parser_13;
9266 }
9267 goto basic_json_parser_15;
9268 }
9269 else
9270 {
9271 if (yych <= ':')
9272 {
9273 goto basic_json_parser_17;
9274 }
9275 if (yych <= 'Z')
9276 {
9277 goto basic_json_parser_4;
9278 }
9279 goto basic_json_parser_19;
9280 }
9281 }
9282 }
9283 else
9284 {
9285 if (yych <= 'n')
9286 {
9287 if (yych <= 'e')
9288 {
9289 if (yych == ']')
9290 {
9291 goto basic_json_parser_21;
9292 }
9293 goto basic_json_parser_4;
9294 }
9295 else
9296 {
9297 if (yych <= 'f')
9298 {
9299 goto basic_json_parser_23;
9300 }
9301 if (yych <= 'm')
9302 {
9303 goto basic_json_parser_4;
9304 }
9305 goto basic_json_parser_24;
9306 }
9307 }
9308 else
9309 {
9310 if (yych <= 'z')
9311 {
9312 if (yych == 't')
9313 {
9314 goto basic_json_parser_25;
9315 }
9316 goto basic_json_parser_4;
9317 }
9318 else
9319 {
9320 if (yych <= '{')
9321 {
9322 goto basic_json_parser_26;
9323 }
9324 if (yych == '}')
9325 {
9326 goto basic_json_parser_28;
9327 }
9328 goto basic_json_parser_4;
9329 }
9330 }
9331 }
9332basic_json_parser_2:
9333 ++m_cursor;
9334 {
9335 last_token_type = token_type::end_of_input;
9336 break;
9337 }
9338basic_json_parser_4:
9339 ++m_cursor;
9340basic_json_parser_5:
9341 {
9342 last_token_type = token_type::parse_error;
9343 break;
9344 }
9345basic_json_parser_6:
9346 ++m_cursor;
9347 if (m_limit <= m_cursor)
9348 {
9349 fill_line_buffer(1); // LCOV_EXCL_LINE
9350 }
9351 yych = *m_cursor;
9352 if (yybm[0 + yych] & 32)
9353 {
9354 goto basic_json_parser_6;
9355 }
9356 {
9357 continue;
9358 }
9359basic_json_parser_9:
9360 yyaccept = 0;
9361 yych = *(m_marker = ++m_cursor);
9362 if (yych <= 0x1F)
9363 {
9364 goto basic_json_parser_5;
9365 }
9366 if (yych <= 0x7F)
9367 {
9368 goto basic_json_parser_31;
9369 }
9370 if (yych <= 0xC1)
9371 {
9372 goto basic_json_parser_5;
9373 }
9374 if (yych <= 0xF4)
9375 {
9376 goto basic_json_parser_31;
9377 }
9378 goto basic_json_parser_5;
9379basic_json_parser_10:
9380 ++m_cursor;
9381 {
9382 last_token_type = token_type::value_separator;
9383 break;
9384 }
9385basic_json_parser_12:
9386 yych = *++m_cursor;
9387 if (yych <= '/')
9388 {
9389 goto basic_json_parser_5;
9390 }
9391 if (yych <= '0')
9392 {
9393 goto basic_json_parser_13;
9394 }
9395 if (yych <= '9')
9396 {
9397 goto basic_json_parser_15;
9398 }
9399 goto basic_json_parser_5;
9400basic_json_parser_13:
9401 yyaccept = 1;
9402 yych = *(m_marker = ++m_cursor);
9403 if (yych <= 'D')
9404 {
9405 if (yych == '.')
9406 {
9407 goto basic_json_parser_43;
9408 }
9409 }
9410 else
9411 {
9412 if (yych <= 'E')
9413 {
9414 goto basic_json_parser_44;
9415 }
9416 if (yych == 'e')
9417 {
9418 goto basic_json_parser_44;
9419 }
9420 }
9421basic_json_parser_14:
9422 {
9423 last_token_type = token_type::value_number;
9424 break;
9425 }
9426basic_json_parser_15:
9427 yyaccept = 1;
9428 m_marker = ++m_cursor;
9429 if ((m_limit - m_cursor) < 3)
9430 {
9431 fill_line_buffer(3); // LCOV_EXCL_LINE
9432 }
9433 yych = *m_cursor;
9434 if (yybm[0 + yych] & 64)
9435 {
9436 goto basic_json_parser_15;
9437 }
9438 if (yych <= 'D')
9439 {
9440 if (yych == '.')
9441 {
9442 goto basic_json_parser_43;
9443 }
9444 goto basic_json_parser_14;
9445 }
9446 else
9447 {
9448 if (yych <= 'E')
9449 {
9450 goto basic_json_parser_44;
9451 }
9452 if (yych == 'e')
9453 {
9454 goto basic_json_parser_44;
9455 }
9456 goto basic_json_parser_14;
9457 }
9458basic_json_parser_17:
9459 ++m_cursor;
9460 {
9461 last_token_type = token_type::name_separator;
9462 break;
9463 }
9464basic_json_parser_19:
9465 ++m_cursor;
9466 {
9467 last_token_type = token_type::begin_array;
9468 break;
9469 }
9470basic_json_parser_21:
9471 ++m_cursor;
9472 {
9473 last_token_type = token_type::end_array;
9474 break;
9475 }
9476basic_json_parser_23:
9477 yyaccept = 0;
9478 yych = *(m_marker = ++m_cursor);
9479 if (yych == 'a')
9480 {
9481 goto basic_json_parser_45;
9482 }
9483 goto basic_json_parser_5;
9484basic_json_parser_24:
9485 yyaccept = 0;
9486 yych = *(m_marker = ++m_cursor);
9487 if (yych == 'u')
9488 {
9489 goto basic_json_parser_46;
9490 }
9491 goto basic_json_parser_5;
9492basic_json_parser_25:
9493 yyaccept = 0;
9494 yych = *(m_marker = ++m_cursor);
9495 if (yych == 'r')
9496 {
9497 goto basic_json_parser_47;
9498 }
9499 goto basic_json_parser_5;
9500basic_json_parser_26:
9501 ++m_cursor;
9502 {
9503 last_token_type = token_type::begin_object;
9504 break;
9505 }
9506basic_json_parser_28:
9507 ++m_cursor;
9508 {
9509 last_token_type = token_type::end_object;
9510 break;
9511 }
9512basic_json_parser_30:
9513 ++m_cursor;
9514 if (m_limit <= m_cursor)
9515 {
9516 fill_line_buffer(1); // LCOV_EXCL_LINE
9517 }
9518 yych = *m_cursor;
9519basic_json_parser_31:
9520 if (yybm[0 + yych] & 128)
9521 {
9522 goto basic_json_parser_30;
9523 }
9524 if (yych <= 0xE0)
9525 {
9526 if (yych <= '\\')
9527 {
9528 if (yych <= 0x1F)
9529 {
9530 goto basic_json_parser_32;
9531 }
9532 if (yych <= '"')
9533 {
9534 goto basic_json_parser_33;
9535 }
9536 goto basic_json_parser_35;
9537 }
9538 else
9539 {
9540 if (yych <= 0xC1)
9541 {
9542 goto basic_json_parser_32;
9543 }
9544 if (yych <= 0xDF)
9545 {
9546 goto basic_json_parser_36;
9547 }
9548 goto basic_json_parser_37;
9549 }
9550 }
9551 else
9552 {
9553 if (yych <= 0xEF)
9554 {
9555 if (yych == 0xED)
9556 {
9557 goto basic_json_parser_39;
9558 }
9559 goto basic_json_parser_38;
9560 }
9561 else
9562 {
9563 if (yych <= 0xF0)
9564 {
9565 goto basic_json_parser_40;
9566 }
9567 if (yych <= 0xF3)
9568 {
9569 goto basic_json_parser_41;
9570 }
9571 if (yych <= 0xF4)
9572 {
9573 goto basic_json_parser_42;
9574 }
9575 }
9576 }
9577basic_json_parser_32:
9578 m_cursor = m_marker;
9579 if (yyaccept == 0)
9580 {
9581 goto basic_json_parser_5;
9582 }
9583 else
9584 {
9585 goto basic_json_parser_14;
9586 }
9587basic_json_parser_33:
9588 ++m_cursor;
9589 {
9590 last_token_type = token_type::value_string;
9591 break;
9592 }
9593basic_json_parser_35:
9594 ++m_cursor;
9595 if (m_limit <= m_cursor)
9596 {
9597 fill_line_buffer(1); // LCOV_EXCL_LINE
9598 }
9599 yych = *m_cursor;
9600 if (yych <= 'e')
9601 {
9602 if (yych <= '/')
9603 {
9604 if (yych == '"')
9605 {
9606 goto basic_json_parser_30;
9607 }
9608 if (yych <= '.')
9609 {
9610 goto basic_json_parser_32;
9611 }
9612 goto basic_json_parser_30;
9613 }
9614 else
9615 {
9616 if (yych <= '\\')
9617 {
9618 if (yych <= '[')
9619 {
9620 goto basic_json_parser_32;
9621 }
9622 goto basic_json_parser_30;
9623 }
9624 else
9625 {
9626 if (yych == 'b')
9627 {
9628 goto basic_json_parser_30;
9629 }
9630 goto basic_json_parser_32;
9631 }
9632 }
9633 }
9634 else
9635 {
9636 if (yych <= 'q')
9637 {
9638 if (yych <= 'f')
9639 {
9640 goto basic_json_parser_30;
9641 }
9642 if (yych == 'n')
9643 {
9644 goto basic_json_parser_30;
9645 }
9646 goto basic_json_parser_32;
9647 }
9648 else
9649 {
9650 if (yych <= 's')
9651 {
9652 if (yych <= 'r')
9653 {
9654 goto basic_json_parser_30;
9655 }
9656 goto basic_json_parser_32;
9657 }
9658 else
9659 {
9660 if (yych <= 't')
9661 {
9662 goto basic_json_parser_30;
9663 }
9664 if (yych <= 'u')
9665 {
9666 goto basic_json_parser_48;
9667 }
9668 goto basic_json_parser_32;
9669 }
9670 }
9671 }
9672basic_json_parser_36:
9673 ++m_cursor;
9674 if (m_limit <= m_cursor)
9675 {
9676 fill_line_buffer(1); // LCOV_EXCL_LINE
9677 }
9678 yych = *m_cursor;
9679 if (yych <= 0x7F)
9680 {
9681 goto basic_json_parser_32;
9682 }
9683 if (yych <= 0xBF)
9684 {
9685 goto basic_json_parser_30;
9686 }
9687 goto basic_json_parser_32;
9688basic_json_parser_37:
9689 ++m_cursor;
9690 if (m_limit <= m_cursor)
9691 {
9692 fill_line_buffer(1); // LCOV_EXCL_LINE
9693 }
9694 yych = *m_cursor;
9695 if (yych <= 0x9F)
9696 {
9697 goto basic_json_parser_32;
9698 }
9699 if (yych <= 0xBF)
9700 {
9701 goto basic_json_parser_36;
9702 }
9703 goto basic_json_parser_32;
9704basic_json_parser_38:
9705 ++m_cursor;
9706 if (m_limit <= m_cursor)
9707 {
9708 fill_line_buffer(1); // LCOV_EXCL_LINE
9709 }
9710 yych = *m_cursor;
9711 if (yych <= 0x7F)
9712 {
9713 goto basic_json_parser_32;
9714 }
9715 if (yych <= 0xBF)
9716 {
9717 goto basic_json_parser_36;
9718 }
9719 goto basic_json_parser_32;
9720basic_json_parser_39:
9721 ++m_cursor;
9722 if (m_limit <= m_cursor)
9723 {
9724 fill_line_buffer(1); // LCOV_EXCL_LINE
9725 }
9726 yych = *m_cursor;
9727 if (yych <= 0x7F)
9728 {
9729 goto basic_json_parser_32;
9730 }
9731 if (yych <= 0x9F)
9732 {
9733 goto basic_json_parser_36;
9734 }
9735 goto basic_json_parser_32;
9736basic_json_parser_40:
9737 ++m_cursor;
9738 if (m_limit <= m_cursor)
9739 {
9740 fill_line_buffer(1); // LCOV_EXCL_LINE
9741 }
9742 yych = *m_cursor;
9743 if (yych <= 0x8F)
9744 {
9745 goto basic_json_parser_32;
9746 }
9747 if (yych <= 0xBF)
9748 {
9749 goto basic_json_parser_38;
9750 }
9751 goto basic_json_parser_32;
9752basic_json_parser_41:
9753 ++m_cursor;
9754 if (m_limit <= m_cursor)
9755 {
9756 fill_line_buffer(1); // LCOV_EXCL_LINE
9757 }
9758 yych = *m_cursor;
9759 if (yych <= 0x7F)
9760 {
9761 goto basic_json_parser_32;
9762 }
9763 if (yych <= 0xBF)
9764 {
9765 goto basic_json_parser_38;
9766 }
9767 goto basic_json_parser_32;
9768basic_json_parser_42:
9769 ++m_cursor;
9770 if (m_limit <= m_cursor)
9771 {
9772 fill_line_buffer(1); // LCOV_EXCL_LINE
9773 }
9774 yych = *m_cursor;
9775 if (yych <= 0x7F)
9776 {
9777 goto basic_json_parser_32;
9778 }
9779 if (yych <= 0x8F)
9780 {
9781 goto basic_json_parser_38;
9782 }
9783 goto basic_json_parser_32;
9784basic_json_parser_43:
9785 yych = *++m_cursor;
9786 if (yych <= '/')
9787 {
9788 goto basic_json_parser_32;
9789 }
9790 if (yych <= '9')
9791 {
9792 goto basic_json_parser_49;
9793 }
9794 goto basic_json_parser_32;
9795basic_json_parser_44:
9796 yych = *++m_cursor;
9797 if (yych <= ',')
9798 {
9799 if (yych == '+')
9800 {
9801 goto basic_json_parser_51;
9802 }
9803 goto basic_json_parser_32;
9804 }
9805 else
9806 {
9807 if (yych <= '-')
9808 {
9809 goto basic_json_parser_51;
9810 }
9811 if (yych <= '/')
9812 {
9813 goto basic_json_parser_32;
9814 }
9815 if (yych <= '9')
9816 {
9817 goto basic_json_parser_52;
9818 }
9819 goto basic_json_parser_32;
9820 }
9821basic_json_parser_45:
9822 yych = *++m_cursor;
9823 if (yych == 'l')
9824 {
9825 goto basic_json_parser_54;
9826 }
9827 goto basic_json_parser_32;
9828basic_json_parser_46:
9829 yych = *++m_cursor;
9830 if (yych == 'l')
9831 {
9832 goto basic_json_parser_55;
9833 }
9834 goto basic_json_parser_32;
9835basic_json_parser_47:
9836 yych = *++m_cursor;
9837 if (yych == 'u')
9838 {
9839 goto basic_json_parser_56;
9840 }
9841 goto basic_json_parser_32;
9842basic_json_parser_48:
9843 ++m_cursor;
9844 if (m_limit <= m_cursor)
9845 {
9846 fill_line_buffer(1); // LCOV_EXCL_LINE
9847 }
9848 yych = *m_cursor;
9849 if (yych <= '@')
9850 {
9851 if (yych <= '/')
9852 {
9853 goto basic_json_parser_32;
9854 }
9855 if (yych <= '9')
9856 {
9857 goto basic_json_parser_57;
9858 }
9859 goto basic_json_parser_32;
9860 }
9861 else
9862 {
9863 if (yych <= 'F')
9864 {
9865 goto basic_json_parser_57;
9866 }
9867 if (yych <= '`')
9868 {
9869 goto basic_json_parser_32;
9870 }
9871 if (yych <= 'f')
9872 {
9873 goto basic_json_parser_57;
9874 }
9875 goto basic_json_parser_32;
9876 }
9877basic_json_parser_49:
9878 yyaccept = 1;
9879 m_marker = ++m_cursor;
9880 if ((m_limit - m_cursor) < 3)
9881 {
9882 fill_line_buffer(3); // LCOV_EXCL_LINE
9883 }
9884 yych = *m_cursor;
9885 if (yych <= 'D')
9886 {
9887 if (yych <= '/')
9888 {
9889 goto basic_json_parser_14;
9890 }
9891 if (yych <= '9')
9892 {
9893 goto basic_json_parser_49;
9894 }
9895 goto basic_json_parser_14;
9896 }
9897 else
9898 {
9899 if (yych <= 'E')
9900 {
9901 goto basic_json_parser_44;
9902 }
9903 if (yych == 'e')
9904 {
9905 goto basic_json_parser_44;
9906 }
9907 goto basic_json_parser_14;
9908 }
9909basic_json_parser_51:
9910 yych = *++m_cursor;
9911 if (yych <= '/')
9912 {
9913 goto basic_json_parser_32;
9914 }
9915 if (yych >= ':')
9916 {
9917 goto basic_json_parser_32;
9918 }
9919basic_json_parser_52:
9920 ++m_cursor;
9921 if (m_limit <= m_cursor)
9922 {
9923 fill_line_buffer(1); // LCOV_EXCL_LINE
9924 }
9925 yych = *m_cursor;
9926 if (yych <= '/')
9927 {
9928 goto basic_json_parser_14;
9929 }
9930 if (yych <= '9')
9931 {
9932 goto basic_json_parser_52;
9933 }
9934 goto basic_json_parser_14;
9935basic_json_parser_54:
9936 yych = *++m_cursor;
9937 if (yych == 's')
9938 {
9939 goto basic_json_parser_58;
9940 }
9941 goto basic_json_parser_32;
9942basic_json_parser_55:
9943 yych = *++m_cursor;
9944 if (yych == 'l')
9945 {
9946 goto basic_json_parser_59;
9947 }
9948 goto basic_json_parser_32;
9949basic_json_parser_56:
9950 yych = *++m_cursor;
9951 if (yych == 'e')
9952 {
9953 goto basic_json_parser_61;
9954 }
9955 goto basic_json_parser_32;
9956basic_json_parser_57:
9957 ++m_cursor;
9958 if (m_limit <= m_cursor)
9959 {
9960 fill_line_buffer(1); // LCOV_EXCL_LINE
9961 }
9962 yych = *m_cursor;
9963 if (yych <= '@')
9964 {
9965 if (yych <= '/')
9966 {
9967 goto basic_json_parser_32;
9968 }
9969 if (yych <= '9')
9970 {
9971 goto basic_json_parser_63;
9972 }
9973 goto basic_json_parser_32;
9974 }
9975 else
9976 {
9977 if (yych <= 'F')
9978 {
9979 goto basic_json_parser_63;
9980 }
9981 if (yych <= '`')
9982 {
9983 goto basic_json_parser_32;
9984 }
9985 if (yych <= 'f')
9986 {
9987 goto basic_json_parser_63;
9988 }
9989 goto basic_json_parser_32;
9990 }
9991basic_json_parser_58:
9992 yych = *++m_cursor;
9993 if (yych == 'e')
9994 {
9995 goto basic_json_parser_64;
9996 }
9997 goto basic_json_parser_32;
9998basic_json_parser_59:
9999 ++m_cursor;
10000 {
10001 last_token_type = token_type::literal_null;
10002 break;
10003 }
10004basic_json_parser_61:
10005 ++m_cursor;
10006 {
10007 last_token_type = token_type::literal_true;
10008 break;
10009 }
10010basic_json_parser_63:
10011 ++m_cursor;
10012 if (m_limit <= m_cursor)
10013 {
10014 fill_line_buffer(1); // LCOV_EXCL_LINE
10015 }
10016 yych = *m_cursor;
10017 if (yych <= '@')
10018 {
10019 if (yych <= '/')
10020 {
10021 goto basic_json_parser_32;
10022 }
10023 if (yych <= '9')
10024 {
10025 goto basic_json_parser_66;
10026 }
10027 goto basic_json_parser_32;
10028 }
10029 else
10030 {
10031 if (yych <= 'F')
10032 {
10033 goto basic_json_parser_66;
10034 }
10035 if (yych <= '`')
10036 {
10037 goto basic_json_parser_32;
10038 }
10039 if (yych <= 'f')
10040 {
10041 goto basic_json_parser_66;
10042 }
10043 goto basic_json_parser_32;
10044 }
10045basic_json_parser_64:
10046 ++m_cursor;
10047 {
10048 last_token_type = token_type::literal_false;
10049 break;
10050 }
10051basic_json_parser_66:
10052 ++m_cursor;
10053 if (m_limit <= m_cursor)
10054 {
10055 fill_line_buffer(1); // LCOV_EXCL_LINE
10056 }
10057 yych = *m_cursor;
10058 if (yych <= '@')
10059 {
10060 if (yych <= '/')
10061 {
10062 goto basic_json_parser_32;
10063 }
10064 if (yych <= '9')
10065 {
10066 goto basic_json_parser_30;
10067 }
10068 goto basic_json_parser_32;
10069 }
10070 else
10071 {
10072 if (yych <= 'F')
10073 {
10074 goto basic_json_parser_30;
10075 }
10076 if (yych <= '`')
10077 {
10078 goto basic_json_parser_32;
10079 }
10080 if (yych <= 'f')
10081 {
10082 goto basic_json_parser_30;
10083 }
10084 goto basic_json_parser_32;
10085 }
10086 }
10087
10088 }
10089
10090 return last_token_type;
10091 }
10092
10093 /*!
10094 @brief append data from the stream to the line buffer
10095
10096 This function is called by the scan() function when the end of the
10097 buffer (`m_limit`) is reached and the `m_cursor` pointer cannot be
10098 incremented without leaving the limits of the line buffer. Note re2c
10099 decides when to call this function.
10100
10101 If the lexer reads from contiguous storage, there is no trailing null
10102 byte. Therefore, this function must make sure to add these padding
10103 null bytes.
10104
10105 If the lexer reads from an input stream, this function reads the next
10106 line of the input.
10107
10108 @pre
10109 p p p p p p u u u u u x . . . . . .
10110 ^ ^ ^ ^
10111 m_content m_start | m_limit
10112 m_cursor
10113
10114 @post
10115 u u u u u x x x x x x x . . . . . .
10116 ^ ^ ^
10117 | m_cursor m_limit
10118 m_start
10119 m_content
10120 */
10121 void fill_line_buffer(size_t n = 0)
10122 {
10123 // if line buffer is used, m_content points to its data
10124 assert(m_line_buffer.empty()
10125 or m_content == reinterpret_cast<const lexer_char_t*>(m_line_buffer.data()));
10126
10127 // if line buffer is used, m_limit is set past the end of its data
10128 assert(m_line_buffer.empty()
10129 or m_limit == m_content + m_line_buffer.size());
10130
10131 // pointer relationships
10132 assert(m_content <= m_start);
10133 assert(m_start <= m_cursor);
10134 assert(m_cursor <= m_limit);
10135 assert(m_marker == nullptr or m_marker <= m_limit);
10136
10137 // number of processed characters (p)
10138 const size_t num_processed_chars = static_cast<size_t>(m_start - m_content);
10139 // offset for m_marker wrt. to m_start
10140 const auto offset_marker = (m_marker == nullptr) ? 0 : m_marker - m_start;
10141 // number of unprocessed characters (u)
10142 const auto offset_cursor = m_cursor - m_start;
10143
10144 // no stream is used or end of file is reached
10145 if (m_stream == nullptr or m_stream->eof())
10146 {
10147 // m_start may or may not be pointing into m_line_buffer at
10148 // this point. We trust the standand library to do the right
10149 // thing. See http://stackoverflow.com/q/28142011/266378
10150 m_line_buffer.assign(m_start, m_limit);
10151
10152 // append n characters to make sure that there is sufficient
10153 // space between m_cursor and m_limit
10154 m_line_buffer.append(1, '\x00');
10155 if (n > 0)
10156 {
10157 m_line_buffer.append(n - 1, '\x01');
10158 }
10159 }
10160 else
10161 {
10162 // delete processed characters from line buffer
10163 m_line_buffer.erase(0, num_processed_chars);
10164 // read next line from input stream
10165 m_line_buffer_tmp.clear();
10166 std::getline(*m_stream, m_line_buffer_tmp, '\n');
10167
10168 // add line with newline symbol to the line buffer
10169 m_line_buffer += m_line_buffer_tmp;
10170 m_line_buffer.push_back('\n');
10171 }
10172
10173 // set pointers
10174 m_content = reinterpret_cast<const lexer_char_t*>(m_line_buffer.data());
10175 assert(m_content != nullptr);
10176 m_start = m_content;
10177 m_marker = m_start + offset_marker;
10178 m_cursor = m_start + offset_cursor;
10179 m_limit = m_start + m_line_buffer.size();
10180 }
10181
10182 /// return string representation of last read token
10183 string_t get_token_string() const
10184 {
10185 assert(m_start != nullptr);
10186 return string_t(reinterpret_cast<typename string_t::const_pointer>(m_start),
10187 static_cast<size_t>(m_cursor - m_start));
10188 }
10189
10190 /*!
10191 @brief return string value for string tokens
10192
10193 The function iterates the characters between the opening and closing
10194 quotes of the string value. The complete string is the range
10195 [m_start,m_cursor). Consequently, we iterate from m_start+1 to
10196 m_cursor-1.
10197
10198 We differentiate two cases:
10199
10200 1. Escaped characters. In this case, a new character is constructed
10201 according to the nature of the escape. Some escapes create new
10202 characters (e.g., `"\\n"` is replaced by `"\n"`), some are copied
10203 as is (e.g., `"\\\\"`). Furthermore, Unicode escapes of the shape
10204 `"\\uxxxx"` need special care. In this case, to_unicode takes care
10205 of the construction of the values.
10206 2. Unescaped characters are copied as is.
10207
10208 @pre `m_cursor - m_start >= 2`, meaning the length of the last token
10209 is at least 2 bytes which is trivially true for any string (which
10210 consists of at least two quotes).
10211
10212 " c1 c2 c3 ... "
10213 ^ ^
10214 m_start m_cursor
10215
10216 @complexity Linear in the length of the string.\n
10217
10218 Lemma: The loop body will always terminate.\n
10219
10220 Proof (by contradiction): Assume the loop body does not terminate. As
10221 the loop body does not contain another loop, one of the called
10222 functions must never return. The called functions are `std::strtoul`
10223 and to_unicode. Neither function can loop forever, so the loop body
10224 will never loop forever which contradicts the assumption that the loop
10225 body does not terminate, q.e.d.\n
10226
10227 Lemma: The loop condition for the for loop is eventually false.\n
10228
10229 Proof (by contradiction): Assume the loop does not terminate. Due to
10230 the above lemma, this can only be due to a tautological loop
10231 condition; that is, the loop condition i < m_cursor - 1 must always be
10232 true. Let x be the change of i for any loop iteration. Then
10233 m_start + 1 + x < m_cursor - 1 must hold to loop indefinitely. This
10234 can be rephrased to m_cursor - m_start - 2 > x. With the
10235 precondition, we x <= 0, meaning that the loop condition holds
10236 indefinitly if i is always decreased. However, observe that the value
10237 of i is strictly increasing with each iteration, as it is incremented
10238 by 1 in the iteration expression and never decremented inside the loop
10239 body. Hence, the loop condition will eventually be false which
10240 contradicts the assumption that the loop condition is a tautology,
10241 q.e.d.
10242
10243 @return string value of current token without opening and closing
10244 quotes
10245 @throw std::out_of_range if to_unicode fails
10246 */
10247 string_t get_string() const
10248 {
10249 assert(m_cursor - m_start >= 2);
10250
10251 string_t result;
10252 result.reserve(static_cast<size_t>(m_cursor - m_start - 2));
10253
10254 // iterate the result between the quotes
10255 for (const lexer_char_t* i = m_start + 1; i < m_cursor - 1; ++i)
10256 {
10257 // find next escape character
10258 auto e = std::find(i, m_cursor - 1, '\\');
10259 if (e != i)
10260 {
10261 // see https://github.com/nlohmann/json/issues/365#issuecomment-262874705
10262 for (auto k = i; k < e; k++)
10263 {
10264 result.push_back(static_cast<typename string_t::value_type>(*k));
10265 }
10266 i = e - 1; // -1 because of ++i
10267 }
10268 else
10269 {
10270 // processing escaped character
10271 // read next character
10272 ++i;
10273
10274 switch (*i)
10275 {
10276 // the default escapes
10277 case 't':
10278 {
10279 result += "\t";
10280 break;
10281 }
10282 case 'b':
10283 {
10284 result += "\b";
10285 break;
10286 }
10287 case 'f':
10288 {
10289 result += "\f";
10290 break;
10291 }
10292 case 'n':
10293 {
10294 result += "\n";
10295 break;
10296 }
10297 case 'r':
10298 {
10299 result += "\r";
10300 break;
10301 }
10302 case '\\':
10303 {
10304 result += "\\";
10305 break;
10306 }
10307 case '/':
10308 {
10309 result += "/";
10310 break;
10311 }
10312 case '"':
10313 {
10314 result += "\"";
10315 break;
10316 }
10317
10318 // unicode
10319 case 'u':
10320 {
10321 // get code xxxx from uxxxx
10322 auto codepoint = std::strtoul(std::string(reinterpret_cast<typename string_t::const_pointer>(i + 1),
10323 4).c_str(), nullptr, 16);
10324
10325 // check if codepoint is a high surrogate
10326 if (codepoint >= 0xD800 and codepoint <= 0xDBFF)
10327 {
10328 // make sure there is a subsequent unicode
10329 if ((i + 6 >= m_limit) or * (i + 5) != '\\' or * (i + 6) != 'u')
10330 {
10331 throw std::invalid_argument("missing low surrogate");
10332 }
10333
10334 // get code yyyy from uxxxx\uyyyy
10335 auto codepoint2 = std::strtoul(std::string(reinterpret_cast<typename string_t::const_pointer>
10336 (i + 7), 4).c_str(), nullptr, 16);
10337 result += to_unicode(codepoint, codepoint2);
10338 // skip the next 10 characters (xxxx\uyyyy)
10339 i += 10;
10340 }
10341 else if (codepoint >= 0xDC00 and codepoint <= 0xDFFF)
10342 {
10343 // we found a lone low surrogate
10344 throw std::invalid_argument("missing high surrogate");
10345 }
10346 else
10347 {
10348 // add unicode character(s)
10349 result += to_unicode(codepoint);
10350 // skip the next four characters (xxxx)
10351 i += 4;
10352 }
10353 break;
10354 }
10355 }
10356 }
10357 }
10358
10359 return result;
10360 }
10361
10362 /*!
10363 @brief parse floating point number
10364
10365 This function (and its overloads) serves to select the most approprate
10366 standard floating point number parsing function based on the type
10367 supplied via the first parameter. Set this to @a
10368 static_cast<number_float_t*>(nullptr).
10369
10370 @param[in,out] endptr recieves a pointer to the first character after
10371 the number
10372
10373 @return the floating point number
10374 */
10375 long double str_to_float_t(long double* /* type */, char** endptr) const
10376 {
10377 return std::strtold(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
10378 }
10379
10380 /*!
10381 @brief parse floating point number
10382
10383 This function (and its overloads) serves to select the most approprate
10384 standard floating point number parsing function based on the type
10385 supplied via the first parameter. Set this to @a
10386 static_cast<number_float_t*>(nullptr).
10387
10388 @param[in,out] endptr recieves a pointer to the first character after
10389 the number
10390
10391 @return the floating point number
10392 */
10393 double str_to_float_t(double* /* type */, char** endptr) const
10394 {
10395 return std::strtod(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
10396 }
10397
10398 /*!
10399 @brief parse floating point number
10400
10401 This function (and its overloads) serves to select the most approprate
10402 standard floating point number parsing function based on the type
10403 supplied via the first parameter. Set this to @a
10404 static_cast<number_float_t*>(nullptr).
10405
10406 @param[in,out] endptr recieves a pointer to the first character after
10407 the number
10408
10409 @return the floating point number
10410 */
10411 float str_to_float_t(float* /* type */, char** endptr) const
10412 {
10413 return std::strtof(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
10414 }
10415
10416 /*!
10417 @brief return number value for number tokens
10418
10419 This function translates the last token into the most appropriate
10420 number type (either integer, unsigned integer or floating point),
10421 which is passed back to the caller via the result parameter.
10422
10423 This function parses the integer component up to the radix point or
10424 exponent while collecting information about the 'floating point
10425 representation', which it stores in the result parameter. If there is
10426 no radix point or exponent, and the number can fit into a @ref
10427 number_integer_t or @ref number_unsigned_t then it sets the result
10428 parameter accordingly.
10429
10430 If the number is a floating point number the number is then parsed
10431 using @a std:strtod (or @a std:strtof or @a std::strtold).
10432
10433 @param[out] result @ref basic_json object to receive the number, or
10434 NAN if the conversion read past the current token. The latter case
10435 needs to be treated by the caller function.
10436 */
10437 void get_number(basic_json& result) const
10438 {
10439 assert(m_start != nullptr);
10440
10441 const lexer::lexer_char_t* curptr = m_start;
10442
10443 // accumulate the integer conversion result (unsigned for now)
10444 number_unsigned_t value = 0;
10445
10446 // maximum absolute value of the relevant integer type
10447 number_unsigned_t max;
10448
10449 // temporarily store the type to avoid unecessary bitfield access
10450 value_t type;
10451
10452 // look for sign
10453 if (*curptr == '-')
10454 {
10455 type = value_t::number_integer;
10456 max = static_cast<uint64_t>((std::numeric_limits<number_integer_t>::max)()) + 1;
10457 curptr++;
10458 }
10459 else
10460 {
10461 type = value_t::number_unsigned;
10462 max = static_cast<uint64_t>((std::numeric_limits<number_unsigned_t>::max)());
10463 }
10464
10465 // count the significant figures
10466 for (; curptr < m_cursor; curptr++)
10467 {
10468 // quickly skip tests if a digit
10469 if (*curptr < '0' || *curptr > '9')
10470 {
10471 if (*curptr == '.')
10472 {
10473 // don't count '.' but change to float
10474 type = value_t::number_float;
10475 continue;
10476 }
10477 // assume exponent (if not then will fail parse): change to
10478 // float, stop counting and record exponent details
10479 type = value_t::number_float;
10480 break;
10481 }
10482
10483 // skip if definitely not an integer
10484 if (type != value_t::number_float)
10485 {
10486 auto digit = static_cast<number_unsigned_t>(*curptr - '0');
10487
10488 // overflow if value * 10 + digit > max, move terms around
10489 // to avoid overflow in intermediate values
10490 if (value > (max - digit) / 10)
10491 {
10492 // overflow
10493 type = value_t::number_float;
10494 }
10495 else
10496 {
10497 // no overflow
10498 value = value * 10 + digit;
10499 }
10500 }
10501 }
10502
10503 // save the value (if not a float)
10504 if (type == value_t::number_unsigned)
10505 {
10506 result.m_value.number_unsigned = value;
10507 }
10508 else if (type == value_t::number_integer)
10509 {
10510 // invariant: if we parsed a '-', the absolute value is between
10511 // 0 (we allow -0) and max == -INT64_MIN
10512 assert(value >= 0);
10513 assert(value <= max);
10514
10515 if (value == max)
10516 {
10517 // we cannot simply negate value (== max == -INT64_MIN),
10518 // see https://github.com/nlohmann/json/issues/389
10519 result.m_value.number_integer = static_cast<number_integer_t>(INT64_MIN);
10520 }
10521 else
10522 {
10523 // all other values can be negated safely
10524 result.m_value.number_integer = -static_cast<number_integer_t>(value);
10525 }
10526 }
10527 else
10528 {
10529 // parse with strtod
10530 result.m_value.number_float = str_to_float_t(static_cast<number_float_t*>(nullptr), NULL);
10531
10532 // replace infinity and NAN by null
10533 if (not std::isfinite(result.m_value.number_float))
10534 {
10535 type = value_t::null;
10536 result.m_value = basic_json::json_value();
10537 }
10538 }
10539
10540 // save the type
10541 result.m_type = type;
10542 }
10543
10544 private:
10545 /// optional input stream
10546 std::istream* m_stream = nullptr;
10547 /// line buffer buffer for m_stream
10548 string_t m_line_buffer {};
10549 /// used for filling m_line_buffer
10550 string_t m_line_buffer_tmp {};
10551 /// the buffer pointer
10552 const lexer_char_t* m_content = nullptr;
10553 /// pointer to the beginning of the current symbol
10554 const lexer_char_t* m_start = nullptr;
10555 /// pointer for backtracking information
10556 const lexer_char_t* m_marker = nullptr;
10557 /// pointer to the current symbol
10558 const lexer_char_t* m_cursor = nullptr;
10559 /// pointer to the end of the buffer
10560 const lexer_char_t* m_limit = nullptr;
10561 /// the last token type
10562 token_type last_token_type = token_type::end_of_input;
10563 };
10564
10565 /*!
10566 @brief syntax analysis
10567
10568 This class implements a recursive decent parser.
10569 */
10570 class parser
10571 {
10572 public:
10573 /// a parser reading from a string literal
10574 parser(const char* buff, const parser_callback_t cb = nullptr)
10575 : callback(cb),
10576 m_lexer(reinterpret_cast<const typename lexer::lexer_char_t*>(buff), std::strlen(buff))
10577 {}
10578
10579 /// a parser reading from an input stream
10580 parser(std::istream& is, const parser_callback_t cb = nullptr)
10581 : callback(cb), m_lexer(is)
10582 {}
10583
10584 /// a parser reading from an iterator range with contiguous storage
10585 template<class IteratorType, typename std::enable_if<
10586 std::is_same<typename std::iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value
10587 , int>::type
10588 = 0>
10589 parser(IteratorType first, IteratorType last, const parser_callback_t cb = nullptr)
10590 : callback(cb),
10591 m_lexer(reinterpret_cast<const typename lexer::lexer_char_t*>(&(*first)),
10592 static_cast<size_t>(std::distance(first, last)))
10593 {}
10594
10595 /// public parser interface
10596 basic_json parse()
10597 {
10598 // read first token
10599 get_token();
10600
10601 basic_json result = parse_internal(true);
10602 result.assert_invariant();
10603
10604 expect(lexer::token_type::end_of_input);
10605
10606 // return parser result and replace it with null in case the
10607 // top-level value was discarded by the callback function
10608 return result.is_discarded() ? basic_json() : std::move(result);
10609 }
10610
10611 private:
10612 /// the actual parser
10613 basic_json parse_internal(bool keep)
10614 {
10615 auto result = basic_json(value_t::discarded);
10616
10617 switch (last_token)
10618 {
10619 case lexer::token_type::begin_object:
10620 {
10621 if (keep and (not callback
10622 or ((keep = callback(depth++, parse_event_t::object_start, result)) != 0)))
10623 {
10624 // explicitly set result to object to cope with {}
10625 result.m_type = value_t::object;
10626 result.m_value = value_t::object;
10627 }
10628
10629 // read next token
10630 get_token();
10631
10632 // closing } -> we are done
10633 if (last_token == lexer::token_type::end_object)
10634 {
10635 get_token();
10636 if (keep and callback and not callback(--depth, parse_event_t::object_end, result))
10637 {
10638 result = basic_json(value_t::discarded);
10639 }
10640 return result;
10641 }
10642
10643 // no comma is expected here
10644 unexpect(lexer::token_type::value_separator);
10645
10646 // otherwise: parse key-value pairs
10647 do
10648 {
10649 // ugly, but could be fixed with loop reorganization
10650 if (last_token == lexer::token_type::value_separator)
10651 {
10652 get_token();
10653 }
10654
10655 // store key
10656 expect(lexer::token_type::value_string);
10657 const auto key = m_lexer.get_string();
10658
10659 bool keep_tag = false;
10660 if (keep)
10661 {
10662 if (callback)
10663 {
10664 basic_json k(key);
10665 keep_tag = callback(depth, parse_event_t::key, k);
10666 }
10667 else
10668 {
10669 keep_tag = true;
10670 }
10671 }
10672
10673 // parse separator (:)
10674 get_token();
10675 expect(lexer::token_type::name_separator);
10676
10677 // parse and add value
10678 get_token();
10679 auto value = parse_internal(keep);
10680 if (keep and keep_tag and not value.is_discarded())
10681 {
10682 result[key] = std::move(value);
10683 }
10684 }
10685 while (last_token == lexer::token_type::value_separator);
10686
10687 // closing }
10688 expect(lexer::token_type::end_object);
10689 get_token();
10690 if (keep and callback and not callback(--depth, parse_event_t::object_end, result))
10691 {
10692 result = basic_json(value_t::discarded);
10693 }
10694
10695 return result;
10696 }
10697
10698 case lexer::token_type::begin_array:
10699 {
10700 if (keep and (not callback
10701 or ((keep = callback(depth++, parse_event_t::array_start, result)) != 0)))
10702 {
10703 // explicitly set result to object to cope with []
10704 result.m_type = value_t::array;
10705 result.m_value = value_t::array;
10706 }
10707
10708 // read next token
10709 get_token();
10710
10711 // closing ] -> we are done
10712 if (last_token == lexer::token_type::end_array)
10713 {
10714 get_token();
10715 if (callback and not callback(--depth, parse_event_t::array_end, result))
10716 {
10717 result = basic_json(value_t::discarded);
10718 }
10719 return result;
10720 }
10721
10722 // no comma is expected here
10723 unexpect(lexer::token_type::value_separator);
10724
10725 // otherwise: parse values
10726 do
10727 {
10728 // ugly, but could be fixed with loop reorganization
10729 if (last_token == lexer::token_type::value_separator)
10730 {
10731 get_token();
10732 }
10733
10734 // parse value
10735 auto value = parse_internal(keep);
10736 if (keep and not value.is_discarded())
10737 {
10738 result.push_back(std::move(value));
10739 }
10740 }
10741 while (last_token == lexer::token_type::value_separator);
10742
10743 // closing ]
10744 expect(lexer::token_type::end_array);
10745 get_token();
10746 if (keep and callback and not callback(--depth, parse_event_t::array_end, result))
10747 {
10748 result = basic_json(value_t::discarded);
10749 }
10750
10751 return result;
10752 }
10753
10754 case lexer::token_type::literal_null:
10755 {
10756 get_token();
10757 result.m_type = value_t::null;
10758 break;
10759 }
10760
10761 case lexer::token_type::value_string:
10762 {
10763 const auto s = m_lexer.get_string();
10764 get_token();
10765 result = basic_json(s);
10766 break;
10767 }
10768
10769 case lexer::token_type::literal_true:
10770 {
10771 get_token();
10772 result.m_type = value_t::boolean;
10773 result.m_value = true;
10774 break;
10775 }
10776
10777 case lexer::token_type::literal_false:
10778 {
10779 get_token();
10780 result.m_type = value_t::boolean;
10781 result.m_value = false;
10782 break;
10783 }
10784
10785 case lexer::token_type::value_number:
10786 {
10787 m_lexer.get_number(result);
10788 get_token();
10789 break;
10790 }
10791
10792 default:
10793 {
10794 // the last token was unexpected
10795 unexpect(last_token);
10796 }
10797 }
10798
10799 if (keep and callback and not callback(depth, parse_event_t::value, result))
10800 {
10801 result = basic_json(value_t::discarded);
10802 }
10803 return result;
10804 }
10805
10806 /// get next token from lexer
10807 typename lexer::token_type get_token()
10808 {
10809 last_token = m_lexer.scan();
10810 return last_token;
10811 }
10812
10813 void expect(typename lexer::token_type t) const
10814 {
10815 if (t != last_token)
10816 {
10817 std::string error_msg = "parse error - unexpected ";
10818 error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token_string() +
10819 "'") :
10820 lexer::token_type_name(last_token));
10821 error_msg += "; expected " + lexer::token_type_name(t);
10822 throw std::invalid_argument(error_msg);
10823 }
10824 }
10825
10826 void unexpect(typename lexer::token_type t) const
10827 {
10828 if (t == last_token)
10829 {
10830 std::string error_msg = "parse error - unexpected ";
10831 error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token_string() +
10832 "'") :
10833 lexer::token_type_name(last_token));
10834 throw std::invalid_argument(error_msg);
10835 }
10836 }
10837
10838 private:
10839 /// current level of recursion
10840 int depth = 0;
10841 /// callback function
10842 const parser_callback_t callback = nullptr;
10843 /// the type of the last read token
10844 typename lexer::token_type last_token = lexer::token_type::uninitialized;
10845 /// the lexer
10846 lexer m_lexer;
10847 };
10848
10849 public:
10850 /*!
10851 @brief JSON Pointer
10852
10853 A JSON pointer defines a string syntax for identifying a specific value
10854 within a JSON document. It can be used with functions `at` and
10855 `operator[]`. Furthermore, JSON pointers are the base for JSON patches.
10856
10857 @sa [RFC 6901](https://tools.ietf.org/html/rfc6901)
10858
10859 @since version 2.0.0
10860 */
10861 class json_pointer
10862 {
10863 /// allow basic_json to access private members
10864 friend class basic_json;
10865
10866 public:
10867 /*!
10868 @brief create JSON pointer
10869
10870 Create a JSON pointer according to the syntax described in
10871 [Section 3 of RFC6901](https://tools.ietf.org/html/rfc6901#section-3).
10872
10873 @param[in] s string representing the JSON pointer; if omitted, the
10874 empty string is assumed which references the whole JSON
10875 value
10876
10877 @throw std::domain_error if reference token is nonempty and does not
10878 begin with a slash (`/`); example: `"JSON pointer must be empty or
10879 begin with /"`
10880 @throw std::domain_error if a tilde (`~`) is not followed by `0`
10881 (representing `~`) or `1` (representing `/`); example: `"escape error:
10882 ~ must be followed with 0 or 1"`
10883
10884 @liveexample{The example shows the construction several valid JSON
10885 pointers as well as the exceptional behavior.,json_pointer}
10886
10887 @since version 2.0.0
10888 */
10889 explicit json_pointer(const std::string& s = "")
10890 : reference_tokens(split(s))
10891 {}
10892
10893 /*!
10894 @brief return a string representation of the JSON pointer
10895
10896 @invariant For each JSON pointer `ptr`, it holds:
10897 @code {.cpp}
10898 ptr == json_pointer(ptr.to_string());
10899 @endcode
10900
10901 @return a string representation of the JSON pointer
10902
10903 @liveexample{The example shows the result of `to_string`.,
10904 json_pointer__to_string}
10905
10906 @since version 2.0.0
10907 */
10908 std::string to_string() const noexcept
10909 {
10910 return std::accumulate(reference_tokens.begin(),
10911 reference_tokens.end(), std::string{},
10912 [](const std::string & a, const std::string & b)
10913 {
10914 return a + "/" + escape(b);
10915 });
10916 }
10917
10918 /// @copydoc to_string()
10919 operator std::string() const
10920 {
10921 return to_string();
10922 }
10923
10924 private:
10925 /// remove and return last reference pointer
10926 std::string pop_back()
10927 {
10928 if (is_root())
10929 {
10930 throw std::domain_error("JSON pointer has no parent");
10931 }
10932
10933 auto last = reference_tokens.back();
10934 reference_tokens.pop_back();
10935 return last;
10936 }
10937
10938 /// return whether pointer points to the root document
10939 bool is_root() const
10940 {
10941 return reference_tokens.empty();
10942 }
10943
10944 json_pointer top() const
10945 {
10946 if (is_root())
10947 {
10948 throw std::domain_error("JSON pointer has no parent");
10949 }
10950
10951 json_pointer result = *this;
10952 result.reference_tokens = {reference_tokens[0]};
10953 return result;
10954 }
10955
10956 /*!
10957 @brief create and return a reference to the pointed to value
10958
10959 @complexity Linear in the number of reference tokens.
10960 */
10961 reference get_and_create(reference j) const
10962 {
10963 pointer result = &j;
10964
10965 // in case no reference tokens exist, return a reference to the
10966 // JSON value j which will be overwritten by a primitive value
10967 for (const auto& reference_token : reference_tokens)
10968 {
10969 switch (result->m_type)
10970 {
10971 case value_t::null:
10972 {
10973 if (reference_token == "0")
10974 {
10975 // start a new array if reference token is 0
10976 result = &result->operator[](0);
10977 }
10978 else
10979 {
10980 // start a new object otherwise
10981 result = &result->operator[](reference_token);
10982 }
10983 break;
10984 }
10985
10986 case value_t::object:
10987 {
10988 // create an entry in the object
10989 result = &result->operator[](reference_token);
10990 break;
10991 }
10992
10993 case value_t::array:
10994 {
10995 // create an entry in the array
10996 result = &result->operator[](static_cast<size_type>(std::stoi(reference_token)));
10997 break;
10998 }
10999
11000 /*
11001 The following code is only reached if there exists a
11002 reference token _and_ the current value is primitive. In
11003 this case, we have an error situation, because primitive
11004 values may only occur as single value; that is, with an
11005 empty list of reference tokens.
11006 */
11007 default:
11008 {
11009 throw std::domain_error("invalid value to unflatten");
11010 }
11011 }
11012 }
11013
11014 return *result;
11015 }
11016
11017 /*!
11018 @brief return a reference to the pointed to value
11019
11020 @note This version does not throw if a value is not present, but tries
11021 to create nested values instead. For instance, calling this function
11022 with pointer `"/this/that"` on a null value is equivalent to calling
11023 `operator[]("this").operator[]("that")` on that value, effectively
11024 changing the null value to an object.
11025
11026 @param[in] ptr a JSON value
11027
11028 @return reference to the JSON value pointed to by the JSON pointer
11029
11030 @complexity Linear in the length of the JSON pointer.
11031
11032 @throw std::out_of_range if the JSON pointer can not be resolved
11033 @throw std::domain_error if an array index begins with '0'
11034 @throw std::invalid_argument if an array index was not a number
11035 */
11036 reference get_unchecked(pointer ptr) const
11037 {
11038 for (const auto& reference_token : reference_tokens)
11039 {
11040 // convert null values to arrays or objects before continuing
11041 if (ptr->m_type == value_t::null)
11042 {
11043 // check if reference token is a number
11044 const bool nums = std::all_of(reference_token.begin(),
11045 reference_token.end(),
11046 [](const char x)
11047 {
11048 return std::isdigit(x);
11049 });
11050
11051 // change value to array for numbers or "-" or to object
11052 // otherwise
11053 if (nums or reference_token == "-")
11054 {
11055 *ptr = value_t::array;
11056 }
11057 else
11058 {
11059 *ptr = value_t::object;
11060 }
11061 }
11062
11063 switch (ptr->m_type)
11064 {
11065 case value_t::object:
11066 {
11067 // use unchecked object access
11068 ptr = &ptr->operator[](reference_token);
11069 break;
11070 }
11071
11072 case value_t::array:
11073 {
11074 // error condition (cf. RFC 6901, Sect. 4)
11075 if (reference_token.size() > 1 and reference_token[0] == '0')
11076 {
11077 throw std::domain_error("array index must not begin with '0'");
11078 }
11079
11080 if (reference_token == "-")
11081 {
11082 // explicityly treat "-" as index beyond the end
11083 ptr = &ptr->operator[](ptr->m_value.array->size());
11084 }
11085 else
11086 {
11087 // convert array index to number; unchecked access
11088 ptr = &ptr->operator[](static_cast<size_type>(std::stoi(reference_token)));
11089 }
11090 break;
11091 }
11092
11093 default:
11094 {
11095 throw std::out_of_range("unresolved reference token '" + reference_token + "'");
11096 }
11097 }
11098 }
11099
11100 return *ptr;
11101 }
11102
11103 reference get_checked(pointer ptr) const
11104 {
11105 for (const auto& reference_token : reference_tokens)
11106 {
11107 switch (ptr->m_type)
11108 {
11109 case value_t::object:
11110 {
11111 // note: at performs range check
11112 ptr = &ptr->at(reference_token);
11113 break;
11114 }
11115
11116 case value_t::array:
11117 {
11118 if (reference_token == "-")
11119 {
11120 // "-" always fails the range check
11121 throw std::out_of_range("array index '-' (" +
11122 std::to_string(ptr->m_value.array->size()) +
11123 ") is out of range");
11124 }
11125
11126 // error condition (cf. RFC 6901, Sect. 4)
11127 if (reference_token.size() > 1 and reference_token[0] == '0')
11128 {
11129 throw std::domain_error("array index must not begin with '0'");
11130 }
11131
11132 // note: at performs range check
11133 ptr = &ptr->at(static_cast<size_type>(std::stoi(reference_token)));
11134 break;
11135 }
11136
11137 default:
11138 {
11139 throw std::out_of_range("unresolved reference token '" + reference_token + "'");
11140 }
11141 }
11142 }
11143
11144 return *ptr;
11145 }
11146
11147 /*!
11148 @brief return a const reference to the pointed to value
11149
11150 @param[in] ptr a JSON value
11151
11152 @return const reference to the JSON value pointed to by the JSON
11153 pointer
11154 */
11155 const_reference get_unchecked(const_pointer ptr) const
11156 {
11157 for (const auto& reference_token : reference_tokens)
11158 {
11159 switch (ptr->m_type)
11160 {
11161 case value_t::object:
11162 {
11163 // use unchecked object access
11164 ptr = &ptr->operator[](reference_token);
11165 break;
11166 }
11167
11168 case value_t::array:
11169 {
11170 if (reference_token == "-")
11171 {
11172 // "-" cannot be used for const access
11173 throw std::out_of_range("array index '-' (" +
11174 std::to_string(ptr->m_value.array->size()) +
11175 ") is out of range");
11176 }
11177
11178 // error condition (cf. RFC 6901, Sect. 4)
11179 if (reference_token.size() > 1 and reference_token[0] == '0')
11180 {
11181 throw std::domain_error("array index must not begin with '0'");
11182 }
11183
11184 // use unchecked array access
11185 ptr = &ptr->operator[](static_cast<size_type>(std::stoi(reference_token)));
11186 break;
11187 }
11188
11189 default:
11190 {
11191 throw std::out_of_range("unresolved reference token '" + reference_token + "'");
11192 }
11193 }
11194 }
11195
11196 return *ptr;
11197 }
11198
11199 const_reference get_checked(const_pointer ptr) const
11200 {
11201 for (const auto& reference_token : reference_tokens)
11202 {
11203 switch (ptr->m_type)
11204 {
11205 case value_t::object:
11206 {
11207 // note: at performs range check
11208 ptr = &ptr->at(reference_token);
11209 break;
11210 }
11211
11212 case value_t::array:
11213 {
11214 if (reference_token == "-")
11215 {
11216 // "-" always fails the range check
11217 throw std::out_of_range("array index '-' (" +
11218 std::to_string(ptr->m_value.array->size()) +
11219 ") is out of range");
11220 }
11221
11222 // error condition (cf. RFC 6901, Sect. 4)
11223 if (reference_token.size() > 1 and reference_token[0] == '0')
11224 {
11225 throw std::domain_error("array index must not begin with '0'");
11226 }
11227
11228 // note: at performs range check
11229 ptr = &ptr->at(static_cast<size_type>(std::stoi(reference_token)));
11230 break;
11231 }
11232
11233 default:
11234 {
11235 throw std::out_of_range("unresolved reference token '" + reference_token + "'");
11236 }
11237 }
11238 }
11239
11240 return *ptr;
11241 }
11242
11243 /// split the string input to reference tokens
11244 static std::vector<std::string> split(const std::string& reference_string)
11245 {
11246 std::vector<std::string> result;
11247
11248 // special case: empty reference string -> no reference tokens
11249 if (reference_string.empty())
11250 {
11251 return result;
11252 }
11253
11254 // check if nonempty reference string begins with slash
11255 if (reference_string[0] != '/')
11256 {
11257 throw std::domain_error("JSON pointer must be empty or begin with '/'");
11258 }
11259
11260 // extract the reference tokens:
11261 // - slash: position of the last read slash (or end of string)
11262 // - start: position after the previous slash
11263 for (
11264 // search for the first slash after the first character
11265 size_t slash = reference_string.find_first_of("/", 1),
11266 // set the beginning of the first reference token
11267 start = 1;
11268 // we can stop if start == string::npos+1 = 0
11269 start != 0;
11270 // set the beginning of the next reference token
11271 // (will eventually be 0 if slash == std::string::npos)
11272 start = slash + 1,
11273 // find next slash
11274 slash = reference_string.find_first_of("/", start))
11275 {
11276 // use the text between the beginning of the reference token
11277 // (start) and the last slash (slash).
11278 auto reference_token = reference_string.substr(start, slash - start);
11279
11280 // check reference tokens are properly escaped
11281 for (size_t pos = reference_token.find_first_of("~");
11282 pos != std::string::npos;
11283 pos = reference_token.find_first_of("~", pos + 1))
11284 {
11285 assert(reference_token[pos] == '~');
11286
11287 // ~ must be followed by 0 or 1
11288 if (pos == reference_token.size() - 1 or
11289 (reference_token[pos + 1] != '0' and
11290 reference_token[pos + 1] != '1'))
11291 {
11292 throw std::domain_error("escape error: '~' must be followed with '0' or '1'");
11293 }
11294 }
11295
11296 // finally, store the reference token
11297 unescape(reference_token);
11298 result.push_back(reference_token);
11299 }
11300
11301 return result;
11302 }
11303
11304 private:
11305 /*!
11306 @brief replace all occurrences of a substring by another string
11307
11308 @param[in,out] s the string to manipulate; changed so that all
11309 occurrences of @a f are replaced with @a t
11310 @param[in] f the substring to replace with @a t
11311 @param[in] t the string to replace @a f
11312
11313 @pre The search string @a f must not be empty.
11314
11315 @since version 2.0.0
11316 */
11317 static void replace_substring(std::string& s,
11318 const std::string& f,
11319 const std::string& t)
11320 {
11321 assert(not f.empty());
11322
11323 for (
11324 size_t pos = s.find(f); // find first occurrence of f
11325 pos != std::string::npos; // make sure f was found
11326 s.replace(pos, f.size(), t), // replace with t
11327 pos = s.find(f, pos + t.size()) // find next occurrence of f
11328 );
11329 }
11330
11331 /// escape tilde and slash
11332 static std::string escape(std::string s)
11333 {
11334 // escape "~"" to "~0" and "/" to "~1"
11335 replace_substring(s, "~", "~0");
11336 replace_substring(s, "/", "~1");
11337 return s;
11338 }
11339
11340 /// unescape tilde and slash
11341 static void unescape(std::string& s)
11342 {
11343 // first transform any occurrence of the sequence '~1' to '/'
11344 replace_substring(s, "~1", "/");
11345 // then transform any occurrence of the sequence '~0' to '~'
11346 replace_substring(s, "~0", "~");
11347 }
11348
11349 /*!
11350 @param[in] reference_string the reference string to the current value
11351 @param[in] value the value to consider
11352 @param[in,out] result the result object to insert values to
11353
11354 @note Empty objects or arrays are flattened to `null`.
11355 */
11356 static void flatten(const std::string& reference_string,
11357 const basic_json& value,
11358 basic_json& result)
11359 {
11360 switch (value.m_type)
11361 {
11362 case value_t::array:
11363 {
11364 if (value.m_value.array->empty())
11365 {
11366 // flatten empty array as null
11367 result[reference_string] = nullptr;
11368 }
11369 else
11370 {
11371 // iterate array and use index as reference string
11372 for (size_t i = 0; i < value.m_value.array->size(); ++i)
11373 {
11374 flatten(reference_string + "/" + std::to_string(i),
11375 value.m_value.array->operator[](i), result);
11376 }
11377 }
11378 break;
11379 }
11380
11381 case value_t::object:
11382 {
11383 if (value.m_value.object->empty())
11384 {
11385 // flatten empty object as null
11386 result[reference_string] = nullptr;
11387 }
11388 else
11389 {
11390 // iterate object and use keys as reference string
11391 for (const auto& element : *value.m_value.object)
11392 {
11393 flatten(reference_string + "/" + escape(element.first),
11394 element.second, result);
11395 }
11396 }
11397 break;
11398 }
11399
11400 default:
11401 {
11402 // add primitive value with its reference string
11403 result[reference_string] = value;
11404 break;
11405 }
11406 }
11407 }
11408
11409 /*!
11410 @param[in] value flattened JSON
11411
11412 @return unflattened JSON
11413 */
11414 static basic_json unflatten(const basic_json& value)
11415 {
11416 if (not value.is_object())
11417 {
11418 throw std::domain_error("only objects can be unflattened");
11419 }
11420
11421 basic_json result;
11422
11423 // iterate the JSON object values
11424 for (const auto& element : *value.m_value.object)
11425 {
11426 if (not element.second.is_primitive())
11427 {
11428 throw std::domain_error("values in object must be primitive");
11429 }
11430
11431 // assign value to reference pointed to by JSON pointer; Note
11432 // that if the JSON pointer is "" (i.e., points to the whole
11433 // value), function get_and_create returns a reference to
11434 // result itself. An assignment will then create a primitive
11435 // value.
11436 json_pointer(element.first).get_and_create(result) = element.second;
11437 }
11438
11439 return result;
11440 }
11441
11442 private:
11443 /// the reference tokens
11444 std::vector<std::string> reference_tokens {};
11445 };
11446
11447 //////////////////////////
11448 // JSON Pointer support //
11449 //////////////////////////
11450
11451 /// @name JSON Pointer functions
11452 /// @{
11453
11454 /*!
11455 @brief access specified element via JSON Pointer
11456
11457 Uses a JSON pointer to retrieve a reference to the respective JSON value.
11458 No bound checking is performed. Similar to @ref operator[](const typename
11459 object_t::key_type&), `null` values are created in arrays and objects if
11460 necessary.
11461
11462 In particular:
11463 - If the JSON pointer points to an object key that does not exist, it
11464 is created an filled with a `null` value before a reference to it
11465 is returned.
11466 - If the JSON pointer points to an array index that does not exist, it
11467 is created an filled with a `null` value before a reference to it
11468 is returned. All indices between the current maximum and the given
11469 index are also filled with `null`.
11470 - The special value `-` is treated as a synonym for the index past the
11471 end.
11472
11473 @param[in] ptr a JSON pointer
11474
11475 @return reference to the element pointed to by @a ptr
11476
11477 @complexity Constant.
11478
11479 @throw std::out_of_range if the JSON pointer can not be resolved
11480 @throw std::domain_error if an array index begins with '0'
11481 @throw std::invalid_argument if an array index was not a number
11482
11483 @liveexample{The behavior is shown in the example.,operatorjson_pointer}
11484
11485 @since version 2.0.0
11486 */
11487 reference operator[](const json_pointer& ptr)
11488 {
11489 return ptr.get_unchecked(this);
11490 }
11491
11492 /*!
11493 @brief access specified element via JSON Pointer
11494
11495 Uses a JSON pointer to retrieve a reference to the respective JSON value.
11496 No bound checking is performed. The function does not change the JSON
11497 value; no `null` values are created. In particular, the the special value
11498 `-` yields an exception.
11499
11500 @param[in] ptr JSON pointer to the desired element
11501
11502 @return const reference to the element pointed to by @a ptr
11503
11504 @complexity Constant.
11505
11506 @throw std::out_of_range if the JSON pointer can not be resolved
11507 @throw std::domain_error if an array index begins with '0'
11508 @throw std::invalid_argument if an array index was not a number
11509
11510 @liveexample{The behavior is shown in the example.,operatorjson_pointer_const}
11511
11512 @since version 2.0.0
11513 */
11514 const_reference operator[](const json_pointer& ptr) const
11515 {
11516 return ptr.get_unchecked(this);
11517 }
11518
11519 /*!
11520 @brief access specified element via JSON Pointer
11521
11522 Returns a reference to the element at with specified JSON pointer @a ptr,
11523 with bounds checking.
11524
11525 @param[in] ptr JSON pointer to the desired element
11526
11527 @return reference to the element pointed to by @a ptr
11528
11529 @complexity Constant.
11530
11531 @throw std::out_of_range if the JSON pointer can not be resolved
11532 @throw std::domain_error if an array index begins with '0'
11533 @throw std::invalid_argument if an array index was not a number
11534
11535 @liveexample{The behavior is shown in the example.,at_json_pointer}
11536
11537 @since version 2.0.0
11538 */
11539 reference at(const json_pointer& ptr)
11540 {
11541 return ptr.get_checked(this);
11542 }
11543
11544 /*!
11545 @brief access specified element via JSON Pointer
11546
11547 Returns a const reference to the element at with specified JSON pointer @a
11548 ptr, with bounds checking.
11549
11550 @param[in] ptr JSON pointer to the desired element
11551
11552 @return reference to the element pointed to by @a ptr
11553
11554 @complexity Constant.
11555
11556 @throw std::out_of_range if the JSON pointer can not be resolved
11557 @throw std::domain_error if an array index begins with '0'
11558 @throw std::invalid_argument if an array index was not a number
11559
11560 @liveexample{The behavior is shown in the example.,at_json_pointer_const}
11561
11562 @since version 2.0.0
11563 */
11564 const_reference at(const json_pointer& ptr) const
11565 {
11566 return ptr.get_checked(this);
11567 }
11568
11569 /*!
11570 @brief return flattened JSON value
11571
11572 The function creates a JSON object whose keys are JSON pointers (see [RFC
11573 6901](https://tools.ietf.org/html/rfc6901)) and whose values are all
11574 primitive. The original JSON value can be restored using the @ref
11575 unflatten() function.
11576
11577 @return an object that maps JSON pointers to primitve values
11578
11579 @note Empty objects and arrays are flattened to `null` and will not be
11580 reconstructed correctly by the @ref unflatten() function.
11581
11582 @complexity Linear in the size the JSON value.
11583
11584 @liveexample{The following code shows how a JSON object is flattened to an
11585 object whose keys consist of JSON pointers.,flatten}
11586
11587 @sa @ref unflatten() for the reverse function
11588
11589 @since version 2.0.0
11590 */
11591 basic_json flatten() const
11592 {
11593 basic_json result(value_t::object);
11594 json_pointer::flatten("", *this, result);
11595 return result;
11596 }
11597
11598 /*!
11599 @brief unflatten a previously flattened JSON value
11600
11601 The function restores the arbitrary nesting of a JSON value that has been
11602 flattened before using the @ref flatten() function. The JSON value must
11603 meet certain constraints:
11604 1. The value must be an object.
11605 2. The keys must be JSON pointers (see
11606 [RFC 6901](https://tools.ietf.org/html/rfc6901))
11607 3. The mapped values must be primitive JSON types.
11608
11609 @return the original JSON from a flattened version
11610
11611 @note Empty objects and arrays are flattened by @ref flatten() to `null`
11612 values and can not unflattened to their original type. Apart from
11613 this example, for a JSON value `j`, the following is always true:
11614 `j == j.flatten().unflatten()`.
11615
11616 @complexity Linear in the size the JSON value.
11617
11618 @liveexample{The following code shows how a flattened JSON object is
11619 unflattened into the original nested JSON object.,unflatten}
11620
11621 @sa @ref flatten() for the reverse function
11622
11623 @since version 2.0.0
11624 */
11625 basic_json unflatten() const
11626 {
11627 return json_pointer::unflatten(*this);
11628 }
11629
11630 /// @}
11631
11632 //////////////////////////
11633 // JSON Patch functions //
11634 //////////////////////////
11635
11636 /// @name JSON Patch functions
11637 /// @{
11638
11639 /*!
11640 @brief applies a JSON patch
11641
11642 [JSON Patch](http://jsonpatch.com) defines a JSON document structure for
11643 expressing a sequence of operations to apply to a JSON) document. With
11644 this funcion, a JSON Patch is applied to the current JSON value by
11645 executing all operations from the patch.
11646
11647 @param[in] json_patch JSON patch document
11648 @return patched document
11649
11650 @note The application of a patch is atomic: Either all operations succeed
11651 and the patched document is returned or an exception is thrown. In
11652 any case, the original value is not changed: the patch is applied
11653 to a copy of the value.
11654
11655 @throw std::out_of_range if a JSON pointer inside the patch could not
11656 be resolved successfully in the current JSON value; example: `"key baz
11657 not found"`
11658 @throw invalid_argument if the JSON patch is malformed (e.g., mandatory
11659 attributes are missing); example: `"operation add must have member path"`
11660
11661 @complexity Linear in the size of the JSON value and the length of the
11662 JSON patch. As usually only a fraction of the JSON value is affected by
11663 the patch, the complexity can usually be neglected.
11664
11665 @liveexample{The following code shows how a JSON patch is applied to a
11666 value.,patch}
11667
11668 @sa @ref diff -- create a JSON patch by comparing two JSON values
11669
11670 @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902)
11671 @sa [RFC 6901 (JSON Pointer)](https://tools.ietf.org/html/rfc6901)
11672
11673 @since version 2.0.0
11674 */
11675 basic_json patch(const basic_json& json_patch) const
11676 {
11677 // make a working copy to apply the patch to
11678 basic_json result = *this;
11679
11680 // the valid JSON Patch operations
11681 enum class patch_operations {add, remove, replace, move, copy, test, invalid};
11682
11683 const auto get_op = [](const std::string op)
11684 {
11685 if (op == "add")
11686 {
11687 return patch_operations::add;
11688 }
11689 if (op == "remove")
11690 {
11691 return patch_operations::remove;
11692 }
11693 if (op == "replace")
11694 {
11695 return patch_operations::replace;
11696 }
11697 if (op == "move")
11698 {
11699 return patch_operations::move;
11700 }
11701 if (op == "copy")
11702 {
11703 return patch_operations::copy;
11704 }
11705 if (op == "test")
11706 {
11707 return patch_operations::test;
11708 }
11709
11710 return patch_operations::invalid;
11711 };
11712
11713 // wrapper for "add" operation; add value at ptr
11714 const auto operation_add = [&result](json_pointer & ptr, basic_json val)
11715 {
11716 // adding to the root of the target document means replacing it
11717 if (ptr.is_root())
11718 {
11719 result = val;
11720 }
11721 else
11722 {
11723 // make sure the top element of the pointer exists
11724 json_pointer top_pointer = ptr.top();
11725 if (top_pointer != ptr)
11726 {
11727 result.at(top_pointer);
11728 }
11729
11730 // get reference to parent of JSON pointer ptr
11731 const auto last_path = ptr.pop_back();
11732 basic_json& parent = result[ptr];
11733
11734 switch (parent.m_type)
11735 {
11736 case value_t::null:
11737 case value_t::object:
11738 {
11739 // use operator[] to add value
11740 parent[last_path] = val;
11741 break;
11742 }
11743
11744 case value_t::array:
11745 {
11746 if (last_path == "-")
11747 {
11748 // special case: append to back
11749 parent.push_back(val);
11750 }
11751 else
11752 {
11753 const auto idx = std::stoi(last_path);
11754 if (static_cast<size_type>(idx) > parent.size())
11755 {
11756 // avoid undefined behavior
11757 throw std::out_of_range("array index " + std::to_string(idx) + " is out of range");
11758 }
11759 else
11760 {
11761 // default case: insert add offset
11762 parent.insert(parent.begin() + static_cast<difference_type>(idx), val);
11763 }
11764 }
11765 break;
11766 }
11767
11768 default:
11769 {
11770 // if there exists a parent it cannot be primitive
11771 assert(false); // LCOV_EXCL_LINE
11772 }
11773 }
11774 }
11775 };
11776
11777 // wrapper for "remove" operation; remove value at ptr
11778 const auto operation_remove = [&result](json_pointer & ptr)
11779 {
11780 // get reference to parent of JSON pointer ptr
11781 const auto last_path = ptr.pop_back();
11782 basic_json& parent = result.at(ptr);
11783
11784 // remove child
11785 if (parent.is_object())
11786 {
11787 // perform range check
11788 auto it = parent.find(last_path);
11789 if (it != parent.end())
11790 {
11791 parent.erase(it);
11792 }
11793 else
11794 {
11795 throw std::out_of_range("key '" + last_path + "' not found");
11796 }
11797 }
11798 else if (parent.is_array())
11799 {
11800 // note erase performs range check
11801 parent.erase(static_cast<size_type>(std::stoi(last_path)));
11802 }
11803 };
11804
11805 // type check
11806 if (not json_patch.is_array())
11807 {
11808 // a JSON patch must be an array of objects
11809 throw std::invalid_argument("JSON patch must be an array of objects");
11810 }
11811
11812 // iterate and apply th eoperations
11813 for (const auto& val : json_patch)
11814 {
11815 // wrapper to get a value for an operation
11816 const auto get_value = [&val](const std::string & op,
11817 const std::string & member,
11818 bool string_type) -> basic_json&
11819 {
11820 // find value
11821 auto it = val.m_value.object->find(member);
11822
11823 // context-sensitive error message
11824 const auto error_msg = (op == "op") ? "operation" : "operation '" + op + "'";
11825
11826 // check if desired value is present
11827 if (it == val.m_value.object->end())
11828 {
11829 throw std::invalid_argument(error_msg + " must have member '" + member + "'");
11830 }
11831
11832 // check if result is of type string
11833 if (string_type and not it->second.is_string())
11834 {
11835 throw std::invalid_argument(error_msg + " must have string member '" + member + "'");
11836 }
11837
11838 // no error: return value
11839 return it->second;
11840 };
11841
11842 // type check
11843 if (not val.is_object())
11844 {
11845 throw std::invalid_argument("JSON patch must be an array of objects");
11846 }
11847
11848 // collect mandatory members
11849 const std::string op = get_value("op", "op", true);
11850 const std::string path = get_value(op, "path", true);
11851 json_pointer ptr(path);
11852
11853 switch (get_op(op))
11854 {
11855 case patch_operations::add:
11856 {
11857 operation_add(ptr, get_value("add", "value", false));
11858 break;
11859 }
11860
11861 case patch_operations::remove:
11862 {
11863 operation_remove(ptr);
11864 break;
11865 }
11866
11867 case patch_operations::replace:
11868 {
11869 // the "path" location must exist - use at()
11870 result.at(ptr) = get_value("replace", "value", false);
11871 break;
11872 }
11873
11874 case patch_operations::move:
11875 {
11876 const std::string from_path = get_value("move", "from", true);
11877 json_pointer from_ptr(from_path);
11878
11879 // the "from" location must exist - use at()
11880 basic_json v = result.at(from_ptr);
11881
11882 // The move operation is functionally identical to a
11883 // "remove" operation on the "from" location, followed
11884 // immediately by an "add" operation at the target
11885 // location with the value that was just removed.
11886 operation_remove(from_ptr);
11887 operation_add(ptr, v);
11888 break;
11889 }
11890
11891 case patch_operations::copy:
11892 {
11893 const std::string from_path = get_value("copy", "from", true);;
11894 const json_pointer from_ptr(from_path);
11895
11896 // the "from" location must exist - use at()
11897 result[ptr] = result.at(from_ptr);
11898 break;
11899 }
11900
11901 case patch_operations::test:
11902 {
11903 bool success = false;
11904 try
11905 {
11906 // check if "value" matches the one at "path"
11907 // the "path" location must exist - use at()
11908 success = (result.at(ptr) == get_value("test", "value", false));
11909 }
11910 catch (std::out_of_range&)
11911 {
11912 // ignore out of range errors: success remains false
11913 }
11914
11915 // throw an exception if test fails
11916 if (not success)
11917 {
11918 throw std::domain_error("unsuccessful: " + val.dump());
11919 }
11920
11921 break;
11922 }
11923
11924 case patch_operations::invalid:
11925 {
11926 // op must be "add", "remove", "replace", "move", "copy", or
11927 // "test"
11928 throw std::invalid_argument("operation value '" + op + "' is invalid");
11929 }
11930 }
11931 }
11932
11933 return result;
11934 }
11935
11936 /*!
11937 @brief creates a diff as a JSON patch
11938
11939 Creates a [JSON Patch](http://jsonpatch.com) so that value @a source can
11940 be changed into the value @a target by calling @ref patch function.
11941
11942 @invariant For two JSON values @a source and @a target, the following code
11943 yields always `true`:
11944 @code {.cpp}
11945 source.patch(diff(source, target)) == target;
11946 @endcode
11947
11948 @note Currently, only `remove`, `add`, and `replace` operations are
11949 generated.
11950
11951 @param[in] source JSON value to copare from
11952 @param[in] target JSON value to copare against
11953 @param[in] path helper value to create JSON pointers
11954
11955 @return a JSON patch to convert the @a source to @a target
11956
11957 @complexity Linear in the lengths of @a source and @a target.
11958
11959 @liveexample{The following code shows how a JSON patch is created as a
11960 diff for two JSON values.,diff}
11961
11962 @sa @ref patch -- apply a JSON patch
11963
11964 @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902)
11965
11966 @since version 2.0.0
11967 */
11968 static basic_json diff(const basic_json& source,
11969 const basic_json& target,
11970 const std::string& path = "")
11971 {
11972 // the patch
11973 basic_json result(value_t::array);
11974
11975 // if the values are the same, return empty patch
11976 if (source == target)
11977 {
11978 return result;
11979 }
11980
11981 if (source.type() != target.type())
11982 {
11983 // different types: replace value
11984 result.push_back(
11985 {
11986 {"op", "replace"},
11987 {"path", path},
11988 {"value", target}
11989 });
11990 }
11991 else
11992 {
11993 switch (source.type())
11994 {
11995 case value_t::array:
11996 {
11997 // first pass: traverse common elements
11998 size_t i = 0;
11999 while (i < source.size() and i < target.size())
12000 {
12001 // recursive call to compare array values at index i
12002 auto temp_diff = diff(source[i], target[i], path + "/" + std::to_string(i));
12003 result.insert(result.end(), temp_diff.begin(), temp_diff.end());
12004 ++i;
12005 }
12006
12007 // i now reached the end of at least one array
12008 // in a second pass, traverse the remaining elements
12009
12010 // remove my remaining elements
12011 const auto end_index = static_cast<difference_type>(result.size());
12012 while (i < source.size())
12013 {
12014 // add operations in reverse order to avoid invalid
12015 // indices
12016 result.insert(result.begin() + end_index, object(
12017 {
12018 {"op", "remove"},
12019 {"path", path + "/" + std::to_string(i)}
12020 }));
12021 ++i;
12022 }
12023
12024 // add other remaining elements
12025 while (i < target.size())
12026 {
12027 result.push_back(
12028 {
12029 {"op", "add"},
12030 {"path", path + "/" + std::to_string(i)},
12031 {"value", target[i]}
12032 });
12033 ++i;
12034 }
12035
12036 break;
12037 }
12038
12039 case value_t::object:
12040 {
12041 // first pass: traverse this object's elements
12042 for (auto it = source.begin(); it != source.end(); ++it)
12043 {
12044 // escape the key name to be used in a JSON patch
12045 const auto key = json_pointer::escape(it.key());
12046
12047 if (target.find(it.key()) != target.end())
12048 {
12049 // recursive call to compare object values at key it
12050 auto temp_diff = diff(it.value(), target[it.key()], path + "/" + key);
12051 result.insert(result.end(), temp_diff.begin(), temp_diff.end());
12052 }
12053 else
12054 {
12055 // found a key that is not in o -> remove it
12056 result.push_back(object(
12057 {
12058 {"op", "remove"},
12059 {"path", path + "/" + key}
12060 }));
12061 }
12062 }
12063
12064 // second pass: traverse other object's elements
12065 for (auto it = target.begin(); it != target.end(); ++it)
12066 {
12067 if (source.find(it.key()) == source.end())
12068 {
12069 // found a key that is not in this -> add it
12070 const auto key = json_pointer::escape(it.key());
12071 result.push_back(
12072 {
12073 {"op", "add"},
12074 {"path", path + "/" + key},
12075 {"value", it.value()}
12076 });
12077 }
12078 }
12079
12080 break;
12081 }
12082
12083 default:
12084 {
12085 // both primitive type: replace value
12086 result.push_back(
12087 {
12088 {"op", "replace"},
12089 {"path", path},
12090 {"value", target}
12091 });
12092 break;
12093 }
12094 }
12095 }
12096
12097 return result;
12098 }
12099
12100 /// @}
12101};
12102
12103
12104/////////////
12105// presets //
12106/////////////
12107
12108/*!
12109@brief default JSON class
12110
12111This type is the default specialization of the @ref basic_json class which
12112uses the standard template types.
12113
12114@since version 1.0.0
12115*/
12116using json = basic_json<>;
12117}
12118
12119
12120///////////////////////
12121// nonmember support //
12122///////////////////////
12123
12124// specialization of std::swap, and std::hash
12125namespace std
12126{
12127/*!
12128@brief exchanges the values of two JSON objects
12129
12130@since version 1.0.0
12131*/
12132template<>
12133inline void swap(nlohmann::json& j1,
12134 nlohmann::json& j2) noexcept(
12135 is_nothrow_move_constructible<nlohmann::json>::value and
12136 is_nothrow_move_assignable<nlohmann::json>::value
12137 )
12138{
12139 j1.swap(j2);
12140}
12141
12142/// hash value for JSON objects
12143template<>
12144struct hash<nlohmann::json>
12145{
12146 /*!
12147 @brief return a hash value for a JSON object
12148
12149 @since version 1.0.0
12150 */
12151 std::size_t operator()(const nlohmann::json& j) const
12152 {
12153 // a naive hashing via the string representation
12154 const auto& h = hash<nlohmann::json::string_t>();
12155 return h(j.dump());
12156 }
12157};
12158}
12159
12160/*!
12161@brief user-defined string literal for JSON values
12162
12163This operator implements a user-defined string literal for JSON objects. It
12164can be used by adding `"_json"` to a string literal and returns a JSON object
12165if no parse error occurred.
12166
12167@param[in] s a string representation of a JSON object
12168@param[in] n the length of string @a s
12169@return a JSON object
12170
12171@since version 1.0.0
12172*/
12173inline nlohmann::json operator "" _json(const char* s, std::size_t n)
12174{
12175 return nlohmann::json::parse(s, s + n);
12176}
12177
12178/*!
12179@brief user-defined string literal for JSON pointer
12180
12181This operator implements a user-defined string literal for JSON Pointers. It
12182can be used by adding `"_json_pointer"` to a string literal and returns a JSON pointer
12183object if no parse error occurred.
12184
12185@param[in] s a string representation of a JSON Pointer
12186@param[in] n the length of string @a s
12187@return a JSON pointer object
12188
12189@since version 2.0.0
12190*/
12191inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t n)
12192{
12193 return nlohmann::json::json_pointer(std::string(s, n));
12194}
12195
12196// restore GCC/clang diagnostic settings
12197#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
12198 #pragma GCC diagnostic pop
12199#endif
12200
12201#endif