44inline const std::vector<std::shared_ptr<millijson::Base> >&
extract_array(
45 const std::unordered_map<std::string, std::shared_ptr<millijson::Base> >&
properties,
46 const std::string&
name,
47 const std::string&
path)
51 throw std::runtime_error(
"expected '" +
name +
"' property for object at '" +
path +
"'");
56 throw std::runtime_error(
"expected an array in '" +
path +
"." +
name +
"'");
62inline const millijson::Array*
has_names(
const std::unordered_map<std::string, std::shared_ptr<millijson::Base> >&
properties,
const std::string&
path) {
69 if (
name_ptr->type() != millijson::ARRAY) {
70 throw std::runtime_error(
"expected an array in '" +
path +
".names'");
72 return static_cast<const millijson::Array*
>(
name_ptr.get());
75template<
class Destination>
79 throw std::runtime_error(
"length of 'names' and 'values' should be the same in '" +
path +
"'");
82 for (
size_t i = 0;
i <
names.size(); ++
i) {
83 if (
names[
i]->type() != millijson::STRING) {
84 throw std::runtime_error(
"expected a string at '" +
path +
".names[" + std::to_string(
i) +
"]'");
90template<
class Function>
92 const std::unordered_map<std::string, std::shared_ptr<millijson::Base> >&
properties,
93 const std::string&
path,
98 throw std::runtime_error(
"expected 'values' property for object at '" +
path +
"'");
104 typename std::invoke_result<Function,std::vector<std::shared_ptr<millijson::Base> >,
bool,
bool>::type
out_ptr;
110 std::vector<std::shared_ptr<millijson::Base> >
temp {
values_ptr };
120template<
class Destination,
class Function>
122 for (
size_t i = 0;
i <
values.size(); ++
i) {
123 if (
values[
i]->type() == millijson::NOTHING) {
124 dest->set_missing(
i);
128 if (
values[
i]->type() != millijson::NUMBER) {
129 throw std::runtime_error(
"expected a number at '" +
path +
".values[" + std::to_string(
i) +
"]'");
132 auto val =
static_cast<const millijson::Number*
>(
values[
i].get())->
value;
133 if (
val != std::floor(
val)) {
134 throw std::runtime_error(
"expected an integer at '" +
path +
".values[" + std::to_string(
i) +
"]'");
137 constexpr double upper = std::numeric_limits<int32_t>::max();
138 constexpr double lower = std::numeric_limits<int32_t>::min();
140 throw std::runtime_error(
"value at '" +
path +
".values[" + std::to_string(
i) +
"]' cannot be represented by a 32-bit signed integer");
144 if (
version.equals(1, 0) &&
val == -2147483648) {
145 dest->set_missing(
i);
154template<
class Destination,
class Function>
156 for (
size_t i = 0;
i <
values.size(); ++
i) {
157 if (
values[
i]->type() == millijson::NOTHING) {
158 dest->set_missing(
i);
162 if (
values[
i]->type() != millijson::STRING) {
163 throw std::runtime_error(
"expected a string at '" +
path +
".values[" + std::to_string(
i) +
"]'");
166 const auto&
str =
static_cast<const millijson::String*
>(
values[
i].get())->
value;
172template<
class Provisioner,
class Externals>
174 if (
contents->type() != millijson::OBJECT) {
175 throw std::runtime_error(
"each R object should be represented by a JSON object at '" +
path +
"'");
178 auto optr =
static_cast<const millijson::Object*
>(
contents);
179 const auto&
map =
optr->values;
181 auto tIt =
map.find(
"type");
183 throw std::runtime_error(
"missing 'type' property for JSON object at '" +
path +
"'");
186 if (
type_ptr->type() != millijson::STRING) {
187 throw std::runtime_error(
"expected a string at '" +
path +
".type'");
189 const auto& type =
static_cast<const millijson::String*
>(
type_ptr.get())->
value;
191 std::shared_ptr<Base>
output;
192 if (type ==
"nothing") {
193 output.reset(Provisioner::new_Nothing());
195 }
else if (type ==
"external") {
196 auto iIt =
map.find(
"index");
198 throw std::runtime_error(
"expected 'index' property for 'external' type at '" +
path +
"'");
201 if (
index_ptr->type() != millijson::NUMBER) {
202 throw std::runtime_error(
"expected a number at '" +
path +
".index'");
204 auto index =
static_cast<const millijson::Number*
>(
index_ptr.get())->
value;
206 if (index != std::floor(index)) {
207 throw std::runtime_error(
"expected an integer at '" +
path +
".index'");
209 throw std::runtime_error(
"external index out of range at '" +
path +
".index'");
211 output.reset(Provisioner::new_External(
ext.get(index)));
213 }
else if (type ==
"integer") {
221 }
else if (type ==
"factor" || (
version.equals(1, 0) && type ==
"ordered")) {
223 if (type ==
"ordered") {
226 auto oIt =
map.find(
"ordered");
228 if (
oIt->second->type() != millijson::BOOLEAN) {
229 throw std::runtime_error(
"expected a boolean at '" +
path +
".ordered'");
231 auto optr =
static_cast<const millijson::Boolean*
>((
oIt->second).
get());
243 throw std::runtime_error(
"factor indices of out of range of levels in '" +
path +
"'");
249 std::unordered_set<std::string>
existing;
250 for (
size_t l = 0;
l <
lvals.size(); ++
l) {
251 if (
lvals[
l]->type() != millijson::STRING) {
252 throw std::runtime_error(
"expected strings at '" +
path +
".levels[" + std::to_string(
l) +
"]'");
255 const auto&
level =
static_cast<const millijson::String*
>(
lvals[
l].get())->
value;
257 throw std::runtime_error(
"detected duplicate string at '" +
path +
".levels[" + std::to_string(
l) +
"]'");
263 }
else if (type ==
"boolean") {
268 for (
size_t i = 0;
i <
vals.size(); ++
i) {
269 if (
vals[
i]->type() == millijson::NOTHING) {
274 if (
vals[
i]->type() != millijson::BOOLEAN) {
275 throw std::runtime_error(
"expected a boolean at '" +
path +
".values[" + std::to_string(
i) +
"]'");
283 }
else if (type ==
"number") {
288 for (
size_t i = 0;
i <
vals.size(); ++
i) {
289 if (
vals[
i]->type() == millijson::NOTHING) {
294 if (
vals[
i]->type() == millijson::NUMBER) {
296 }
else if (
vals[
i]->type() == millijson::STRING) {
297 auto str =
static_cast<const millijson::String*
>(
vals[
i].get())->
value;
299 ptr->set(
i, std::numeric_limits<double>::quiet_NaN());
300 }
else if (
str ==
"Inf") {
301 ptr->set(
i, std::numeric_limits<double>::infinity());
302 }
else if (
str ==
"-Inf") {
303 ptr->set(
i, -std::numeric_limits<double>::infinity());
305 throw std::runtime_error(
"unsupported string '" +
str +
"' at '" +
path +
".values[" + std::to_string(
i) +
"]'");
308 throw std::runtime_error(
"expected a number at '" +
path +
".values[" + std::to_string(
i) +
"]'");
315 }
else if (type ==
"string" || (
version.equals(1, 0) && (type ==
"date" || type ==
"date-time"))) {
318 if (type ==
"date") {
319 format = StringVector::DATE;
320 }
else if (type ==
"date-time") {
321 format = StringVector::DATETIME;
324 auto fIt =
map.find(
"format");
326 if (
fIt->second->type() != millijson::STRING) {
327 throw std::runtime_error(
"expected a string at '" +
path +
".format'");
329 auto fptr =
static_cast<const millijson::String*
>(
fIt->second.get());
330 if (
fptr->value ==
"date") {
331 format = StringVector::DATE;
332 }
else if (
fptr->value ==
"date-time") {
333 format = StringVector::DATETIME;
335 throw std::runtime_error(
"unsupported format '" +
fptr->value +
"' at '" +
path +
".format'");
344 if (
format == StringVector::NONE) {
346 }
else if (
format == StringVector::DATE) {
348 if (!ritsuko::is_date(
x.c_str(),
x.size())) {
349 throw std::runtime_error(
"dates should follow YYYY-MM-DD formatting in '" + path +
".values'");
352 }
else if (
format == StringVector::DATETIME) {
354 if (!ritsuko::is_rfc3339(
x.c_str(),
x.size())) {
355 throw std::runtime_error(
"date-times should follow the Internet Date/Time format in '" + path +
".values'");
363 }
else if (type ==
"list") {
371 for (
size_t i = 0;
i <
vals.size(); ++
i) {
380 throw std::runtime_error(
"unknown object type '" + type +
"' at '" +
path +
".type'");
422template<
class Provisioner,
class Externals>
424 std::shared_ptr<millijson::Base>
contents;
434 if (
contents->type() == millijson::OBJECT) {
435 auto optr =
static_cast<const millijson::Object*
>(
contents.get());
436 const auto&
map =
optr->values;
437 auto vIt =
map.find(
"version");
439 if (
vIt->second->type() != millijson::STRING) {
440 throw std::runtime_error(
"expected a string in 'version'");
442 const auto&
vstr =
static_cast<const millijson::String*
>(
vIt->second.get())->
value;
443 auto vraw = ritsuko::parse_version_string(
vstr.c_str(),
vstr.size(),
true);
453 throw std::runtime_error(
"top-level object should represent an R list");
474template<
class Provisioner>
497template<
class Provisioner,
class Externals>
517template<
class Provisioner>
541template<
class Provisioner,
class Externals>
562template<
class Provisioner>
ParsedList parse_file(const std::string &file, Externals ext, Options options=Options())
Definition parse_json.hpp:498
ParsedList parse(byteme::Reader &reader, Externals ext, Options options=Options())
Definition parse_json.hpp:423
void validate(byteme::Reader &reader, int num_external=0, Options options=Options())
Definition parse_json.hpp:576
void validate_buffer(const unsigned char *buffer, size_t len, int num_external=0, Options options=Options())
Definition parse_json.hpp:605
ParsedList parse_buffer(const unsigned char *buffer, size_t len, Externals ext, Options options=Options())
Definition parse_json.hpp:542