45inline const std::vector<std::shared_ptr<millijson::Base> >&
extract_array(
46 const std::unordered_map<std::string, std::shared_ptr<millijson::Base> >&
properties,
47 const std::string&
name,
48 const std::string&
path)
52 throw std::runtime_error(
"expected '" +
name +
"' property for object at '" +
path +
"'");
57 throw std::runtime_error(
"expected an array in '" +
path +
"." +
name +
"'");
63inline const millijson::Array*
has_names(
const std::unordered_map<std::string, std::shared_ptr<millijson::Base> >&
properties,
const std::string&
path) {
70 if (
name_ptr->type() != millijson::ARRAY) {
71 throw std::runtime_error(
"expected an array in '" +
path +
".names'");
73 return static_cast<const millijson::Array*
>(
name_ptr.get());
76template<
class Destination>
80 throw std::runtime_error(
"length of 'names' and 'values' should be the same in '" +
path +
"'");
83 for (
size_t i = 0;
i <
names.size(); ++
i) {
84 if (
names[
i]->type() != millijson::STRING) {
85 throw std::runtime_error(
"expected a string at '" +
path +
".names[" + std::to_string(
i) +
"]'");
91template<
class Function>
93 const std::unordered_map<std::string, std::shared_ptr<millijson::Base> >&
properties,
94 const std::string&
path,
99 throw std::runtime_error(
"expected 'values' property for object at '" +
path +
"'");
105 typename std::invoke_result<Function,std::vector<std::shared_ptr<millijson::Base> >,
bool,
bool>::type
out_ptr;
111 std::vector<std::shared_ptr<millijson::Base> >
temp {
values_ptr };
121template<
class Destination,
class Function>
123 for (
size_t i = 0;
i <
values.size(); ++
i) {
124 if (
values[
i]->type() == millijson::NOTHING) {
125 dest->set_missing(
i);
129 if (
values[
i]->type() != millijson::NUMBER) {
130 throw std::runtime_error(
"expected a number at '" +
path +
".values[" + std::to_string(
i) +
"]'");
133 auto val =
static_cast<const millijson::Number*
>(
values[
i].get())->
value;
134 if (
val != std::floor(
val)) {
135 throw std::runtime_error(
"expected an integer at '" +
path +
".values[" + std::to_string(
i) +
"]'");
138 constexpr double upper = std::numeric_limits<int32_t>::max();
139 constexpr double lower = std::numeric_limits<int32_t>::min();
141 throw std::runtime_error(
"value at '" +
path +
".values[" + std::to_string(
i) +
"]' cannot be represented by a 32-bit signed integer");
145 if (
version.equals(1, 0) &&
val == -2147483648) {
146 dest->set_missing(
i);
155template<
class Destination,
class Function>
157 for (
size_t i = 0;
i <
values.size(); ++
i) {
158 if (
values[
i]->type() == millijson::NOTHING) {
159 dest->set_missing(
i);
163 if (
values[
i]->type() != millijson::STRING) {
164 throw std::runtime_error(
"expected a string at '" +
path +
".values[" + std::to_string(
i) +
"]'");
167 const auto&
str =
static_cast<const millijson::String*
>(
values[
i].get())->
value;
173template<
class Provisioner,
class Externals>
175 if (
contents->type() != millijson::OBJECT) {
176 throw std::runtime_error(
"each R object should be represented by a JSON object at '" +
path +
"'");
179 auto optr =
static_cast<const millijson::Object*
>(
contents);
180 const auto&
map =
optr->values;
182 auto tIt =
map.find(
"type");
184 throw std::runtime_error(
"missing 'type' property for JSON object at '" +
path +
"'");
187 if (
type_ptr->type() != millijson::STRING) {
188 throw std::runtime_error(
"expected a string at '" +
path +
".type'");
190 const auto& type =
static_cast<const millijson::String*
>(
type_ptr.get())->
value;
192 std::shared_ptr<Base>
output;
193 if (type ==
"nothing") {
194 output.reset(Provisioner::new_Nothing());
196 }
else if (type ==
"external") {
197 auto iIt =
map.find(
"index");
199 throw std::runtime_error(
"expected 'index' property for 'external' type at '" +
path +
"'");
202 if (
index_ptr->type() != millijson::NUMBER) {
203 throw std::runtime_error(
"expected a number at '" +
path +
".index'");
205 auto index =
static_cast<const millijson::Number*
>(
index_ptr.get())->
value;
207 if (index != std::floor(index)) {
208 throw std::runtime_error(
"expected an integer at '" +
path +
".index'");
210 throw std::runtime_error(
"external index out of range at '" +
path +
".index'");
212 output.reset(Provisioner::new_External(
ext.get(index)));
214 }
else if (type ==
"integer") {
222 }
else if (type ==
"factor" || (
version.equals(1, 0) && type ==
"ordered")) {
224 if (type ==
"ordered") {
227 auto oIt =
map.find(
"ordered");
229 if (
oIt->second->type() != millijson::BOOLEAN) {
230 throw std::runtime_error(
"expected a boolean at '" +
path +
".ordered'");
232 auto optr =
static_cast<const millijson::Boolean*
>((
oIt->second).
get());
244 throw std::runtime_error(
"factor indices of out of range of levels in '" +
path +
"'");
250 std::unordered_set<std::string>
existing;
251 for (
size_t l = 0;
l <
lvals.size(); ++
l) {
252 if (
lvals[
l]->type() != millijson::STRING) {
253 throw std::runtime_error(
"expected strings at '" +
path +
".levels[" + std::to_string(
l) +
"]'");
256 const auto&
level =
static_cast<const millijson::String*
>(
lvals[
l].get())->
value;
258 throw std::runtime_error(
"detected duplicate string at '" +
path +
".levels[" + std::to_string(
l) +
"]'");
264 }
else if (type ==
"boolean") {
269 for (
size_t i = 0;
i <
vals.size(); ++
i) {
270 if (
vals[
i]->type() == millijson::NOTHING) {
275 if (
vals[
i]->type() != millijson::BOOLEAN) {
276 throw std::runtime_error(
"expected a boolean at '" +
path +
".values[" + std::to_string(
i) +
"]'");
284 }
else if (type ==
"number") {
289 for (
size_t i = 0;
i <
vals.size(); ++
i) {
290 if (
vals[
i]->type() == millijson::NOTHING) {
295 if (
vals[
i]->type() == millijson::NUMBER) {
297 }
else if (
vals[
i]->type() == millijson::STRING) {
298 auto str =
static_cast<const millijson::String*
>(
vals[
i].get())->
value;
300 ptr->set(
i, std::numeric_limits<double>::quiet_NaN());
301 }
else if (
str ==
"Inf") {
302 ptr->set(
i, std::numeric_limits<double>::infinity());
303 }
else if (
str ==
"-Inf") {
304 ptr->set(
i, -std::numeric_limits<double>::infinity());
306 throw std::runtime_error(
"unsupported string '" +
str +
"' at '" +
path +
".values[" + std::to_string(
i) +
"]'");
309 throw std::runtime_error(
"expected a number at '" +
path +
".values[" + std::to_string(
i) +
"]'");
316 }
else if (type ==
"string" || (
version.equals(1, 0) && (type ==
"date" || type ==
"date-time"))) {
319 if (type ==
"date") {
320 format = StringVector::DATE;
321 }
else if (type ==
"date-time") {
322 format = StringVector::DATETIME;
325 auto fIt =
map.find(
"format");
327 if (
fIt->second->type() != millijson::STRING) {
328 throw std::runtime_error(
"expected a string at '" +
path +
".format'");
330 auto fptr =
static_cast<const millijson::String*
>(
fIt->second.get());
331 if (
fptr->value ==
"date") {
332 format = StringVector::DATE;
333 }
else if (
fptr->value ==
"date-time") {
334 format = StringVector::DATETIME;
336 throw std::runtime_error(
"unsupported format '" +
fptr->value +
"' at '" +
path +
".format'");
345 if (
format == StringVector::NONE) {
347 }
else if (
format == StringVector::DATE) {
349 if (!ritsuko::is_date(
x.c_str(),
x.size())) {
350 throw std::runtime_error(
"dates should follow YYYY-MM-DD formatting in '" + path +
".values'");
353 }
else if (
format == StringVector::DATETIME) {
355 if (!ritsuko::is_rfc3339(
x.c_str(),
x.size())) {
356 throw std::runtime_error(
"date-times should follow the Internet Date/Time format in '" + path +
".values'");
364 }
else if (type ==
"list") {
372 for (
size_t i = 0;
i <
vals.size(); ++
i) {
381 throw std::runtime_error(
"unknown object type '" + type +
"' at '" +
path +
".type'");
423template<
class Provisioner,
class Externals>
425 std::shared_ptr<millijson::Base>
contents;
435 if (
contents->type() == millijson::OBJECT) {
436 auto optr =
static_cast<const millijson::Object*
>(
contents.get());
437 const auto&
map =
optr->values;
438 auto vIt =
map.find(
"version");
440 if (
vIt->second->type() != millijson::STRING) {
441 throw std::runtime_error(
"expected a string in 'version'");
443 const auto&
vstr =
static_cast<const millijson::String*
>(
vIt->second.get())->
value;
444 auto vraw = ritsuko::parse_version_string(
vstr.c_str(),
vstr.size(),
true);
454 throw std::runtime_error(
"top-level object should represent an R list");
475template<
class Provisioner>
498template<
class Provisioner,
class Externals>
518template<
class Provisioner>
542template<
class Provisioner,
class Externals>
563template<
class Provisioner>
ParsedList parse_file(const std::string &file, Externals ext, Options options=Options())
Definition parse_json.hpp:499
ParsedList parse(byteme::Reader &reader, Externals ext, Options options=Options())
Definition parse_json.hpp:424
void validate(byteme::Reader &reader, int num_external=0, Options options=Options())
Definition parse_json.hpp:577
void validate_buffer(const unsigned char *buffer, size_t len, int num_external=0, Options options=Options())
Definition parse_json.hpp:606
ParsedList parse_buffer(const unsigned char *buffer, size_t len, Externals ext, Options options=Options())
Definition parse_json.hpp:543