Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 1 addition & 6 deletions cpp/src/arrow/integration/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,7 @@ install_headers(['json_integration.h'])
exc = executable(
'arrow-json-integration-test',
sources: ['json_integration_test.cc'],
dependencies: [
arrow_test_dep_no_main,
rapidjson_dep,
simdjson_dep,
gflags_dep,
],
dependencies: [arrow_test_dep_no_main, rapidjson_dep, gflags_dep],
)

arrow_c_data_integration_lib = library(
Expand Down
10 changes: 5 additions & 5 deletions cpp/src/arrow/json/from_string.cc
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ class ConcreteConverter : public JSONConverter {
int32_t num_elements = 0;
for (auto element : json_array) {
ARROW_ASSIGN_OR_RAISE(auto value,
internal::GetSimdjsonResult<sj::value>(
internal::ResolveSimdjsonResult<sj::value>(
element, "Could not iterate elements of JSON array: "));
RETURN_NOT_OK(self->AppendValue(value));
num_elements++;
Expand Down Expand Up @@ -287,7 +287,7 @@ Status ProcessJsonArrayElements(
}

ARROW_ASSIGN_OR_RAISE(sj::value element,
internal::GetSimdjsonResult<sj::value>(
internal::ResolveSimdjsonResult<sj::value>(
*it, "Could not iterate elements of JSON array: "));
RETURN_NOT_OK(handler(element));
++it;
Expand Down Expand Up @@ -652,7 +652,7 @@ class MapConverter final : public ConcreteConverter<MapConverter> {
for (auto json_pair_result : array) {
ARROW_ASSIGN_OR_RAISE(
auto json_pair,
internal::GetSimdjsonResult<sj::value>(
internal::ResolveSimdjsonResult<sj::value>(
json_pair_result, "Could not iterate elements of JSON array: "));
ARROW_ASSIGN_OR_RAISE(auto json_pair_array,
internal::GetJsonAs<sj::array>(json_pair));
Expand Down Expand Up @@ -763,7 +763,7 @@ class StructConverter final : public ConcreteConverter<StructConverter> {
size_t i = 0;
for (auto child : array) {
ARROW_ASSIGN_OR_RAISE(auto child_value,
internal::GetSimdjsonResult<sj::value>(
internal::ResolveSimdjsonResult<sj::value>(
child, "Could not iterate elements of JSON array: "));
RETURN_NOT_OK(child_converters_[i]->AppendValue(child_value));
++i;
Expand All @@ -779,7 +779,7 @@ class StructConverter final : public ConcreteConverter<StructConverter> {
std::vector<bool> field_seen(num_fields, false);
for (auto field_result : object) {
ARROW_ASSIGN_OR_RAISE(auto field,
internal::GetSimdjsonResult<sj::field>(
internal::ResolveSimdjsonResult<sj::field>(
field_result, "Error getting field of object: "));
std::string_view key;
if (field.unescaped_key(/*allow_replacement=*/false).get(key) !=
Expand Down
18 changes: 9 additions & 9 deletions cpp/src/arrow/json/json_writer_internal.cc
Original file line number Diff line number Diff line change
Expand Up @@ -108,14 +108,14 @@ Status JsonWriter::WriteValue(sj::value value) {

for (auto field : object) {
ARROW_ASSIGN_OR_RAISE(
auto key, internal::GetSimdjsonResult(field.unescaped_key(),
"Failed to get object key: "));
auto key, internal::ResolveSimdjsonResult(field.unescaped_key(),
"Failed to get object key"));

Key(key);

ARROW_ASSIGN_OR_RAISE(
auto field_value,
internal::GetSimdjsonResult(field.value(), "Failed to get object value: "));
ARROW_ASSIGN_OR_RAISE(auto field_value,
internal::ResolveSimdjsonResult(
field.value(), "Failed to get object value"));

RETURN_NOT_OK(WriteValue(field_value));
}
Expand All @@ -130,7 +130,7 @@ Status JsonWriter::WriteValue(sj::value value) {
for (auto element : array) {
ARROW_ASSIGN_OR_RAISE(
auto element_value,
internal::GetSimdjsonResult(element, "Failed to iterate JSON array: "));
internal::ResolveSimdjsonResult(element, "Failed to iterate JSON array"));

RETURN_NOT_OK(WriteValue(element_value));
}
Expand Down Expand Up @@ -170,9 +170,9 @@ Status JsonWriter::WriteValue(sj::value value) {
},

[&](sj::value value) -> Status {
ARROW_ASSIGN_OR_RAISE(auto raw_json,
internal::GetSimdjsonResult(simdjson::to_json_string(value),
"Failed to get raw JSON: "));
ARROW_ASSIGN_OR_RAISE(auto raw_json, internal::ResolveSimdjsonResult(
simdjson::to_json_string(value),
"Failed to get raw JSON"));
RawValue(raw_json);
return Status::OK();
});
Expand Down
120 changes: 104 additions & 16 deletions cpp/src/arrow/util/simdjson_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,11 @@ constexpr const char* JsonTypeName() {
}

template <typename T>
Result<T> GetSimdjsonResult(simdjson::simdjson_result<T> result, std::string_view error) {
Result<T> ResolveSimdjsonResult(simdjson::simdjson_result<T> result,
Comment thread
Reranko05 marked this conversation as resolved.
std::string_view error) {
T value;
if (auto error_code = std::move(result).get(value); error_code != simdjson::SUCCESS) {
return Status::Invalid(error, simdjson::error_message(error_code));
return Status::Invalid(error, ": ", simdjson::error_message(error_code));
Comment thread
Reranko05 marked this conversation as resolved.
Comment thread
Reranko05 marked this conversation as resolved.
}
return value;
}
Expand All @@ -98,63 +99,65 @@ Status VisitJsonValue(simdjson::ondemand::value value, ObjectFn&& object_fn,
NullFn&& null_fn, Int64Fn&& int64_fn, Uint64Fn&& uint64_fn,
DoubleFn&& double_fn, BigIntegerFn&& big_integer_fn) {
ARROW_ASSIGN_OR_RAISE(
auto type, GetSimdjsonResult(value.type(), "Failed to determine JSON type: "));
auto type, ResolveSimdjsonResult(value.type(), "Failed to determine JSON type"));

switch (type) {
case simdjson::ondemand::json_type::object: {
ARROW_ASSIGN_OR_RAISE(
auto object,
GetSimdjsonResult(value.get_object(), "Failed to get JSON object: "));
ResolveSimdjsonResult(value.get_object(), "Failed to get JSON object"));
return object_fn(object);
}

case simdjson::ondemand::json_type::array: {
ARROW_ASSIGN_OR_RAISE(
auto array, GetSimdjsonResult(value.get_array(), "Failed to get JSON array: "));
auto array,
ResolveSimdjsonResult(value.get_array(), "Failed to get JSON array"));
return array_fn(array);
}

case simdjson::ondemand::json_type::string: {
ARROW_ASSIGN_OR_RAISE(
auto string,
GetSimdjsonResult(value.get_string(), "Failed to get JSON string: "));
ResolveSimdjsonResult(value.get_string(), "Failed to get JSON string"));
return string_fn(string);
}

case simdjson::ondemand::json_type::boolean: {
ARROW_ASSIGN_OR_RAISE(
auto boolean,
GetSimdjsonResult(value.get_bool(), "Failed to get JSON boolean: "));
ResolveSimdjsonResult(value.get_bool(), "Failed to get JSON boolean"));
return bool_fn(boolean);
}

case simdjson::ondemand::json_type::null:
return null_fn();

case simdjson::ondemand::json_type::number: {
ARROW_ASSIGN_OR_RAISE(auto number_type,
GetSimdjsonResult(value.get_number_type(),
"Failed to determine JSON number type: "));
ARROW_ASSIGN_OR_RAISE(
auto number_type,
ResolveSimdjsonResult(value.get_number_type(),
"Failed to determine JSON number type"));

switch (number_type) {
case simdjson::ondemand::number_type::signed_integer: {
ARROW_ASSIGN_OR_RAISE(
auto number,
GetSimdjsonResult(value.get_int64(), "Failed to get signed integer: "));
ResolveSimdjsonResult(value.get_int64(), "Failed to get signed integer"));
return int64_fn(number);
}

case simdjson::ondemand::number_type::unsigned_integer: {
ARROW_ASSIGN_OR_RAISE(
auto number,
GetSimdjsonResult(value.get_uint64(), "Failed to get unsigned integer: "));
ARROW_ASSIGN_OR_RAISE(auto number,
ResolveSimdjsonResult(value.get_uint64(),
"Failed to get unsigned integer"));
return uint64_fn(number);
}

case simdjson::ondemand::number_type::floating_point_number: {
ARROW_ASSIGN_OR_RAISE(
auto number, GetSimdjsonResult(value.get_double(),
"Failed to get floating-point number: "));
auto number, ResolveSimdjsonResult(value.get_double(),
"Failed to get floating-point number"));
return double_fn(number);
}

Expand Down Expand Up @@ -240,5 +243,90 @@ Result<SimdjsonValueType> GetJsonAs(simdjson::ondemand::value& value) {
return typed_value;
}

template <typename T>
Result<T> GetJsonField(simdjson::ondemand::object& object, std::string_view key) {
for (auto field_result : object) {
ARROW_ASSIGN_OR_RAISE(
auto field, ResolveSimdjsonResult(field_result, "Failed to iterate JSON object"));

ARROW_ASSIGN_OR_RAISE(
auto field_key,
ResolveSimdjsonResult(field.unescaped_key(), "Failed to get JSON object key"));

if (field_key == key) {
auto value = field.value();

if constexpr (std::is_same_v<T, simdjson::ondemand::value>) {
return value;
} else {
return GetJsonAs<T>(value);
}
}
}

return Status::KeyError("Missing JSON field: ", key);
}

inline Result<std::string> MinifyJson(std::string_view json) {
std::string minified(json.size(), '\0');
size_t minified_len = 0;

if (auto error =
simdjson::minify(json.data(), json.size(), minified.data(), minified_len);
error != simdjson::SUCCESS) {
return Status::Invalid("Failed to minify JSON: ", simdjson::error_message(error));
}

minified.resize(minified_len);
return minified;
}

inline Status ValidateJsonObject(simdjson::ondemand::object object);

inline Status ValidateJsonArray(simdjson::ondemand::array array);

inline Status ConsumeJsonValue(simdjson::ondemand::value value) {
return VisitJsonValue(
value, ValidateJsonObject, ValidateJsonArray,
[](std::string_view) { return Status::OK(); }, [](bool) { return Status::OK(); },
[]() { return Status::OK(); }, [](int64_t) { return Status::OK(); },
[](uint64_t) { return Status::OK(); }, [](double) { return Status::OK(); },
[](simdjson::ondemand::value) { return Status::OK(); });
}

inline Status ValidateJsonObject(simdjson::ondemand::object object) {
for (auto field_result : object) {
ARROW_ASSIGN_OR_RAISE(
auto field, ResolveSimdjsonResult(field_result, "Failed to iterate JSON object"));

RETURN_NOT_OK(ConsumeJsonValue(field.value()));
}

return Status::OK();
}

inline Status ValidateJsonArray(simdjson::ondemand::array array) {
for (auto element_result : array) {
ARROW_ASSIGN_OR_RAISE(
auto value,
ResolveSimdjsonResult(element_result, "Failed to iterate JSON array"));

RETURN_NOT_OK(ConsumeJsonValue(value));
}

return Status::OK();
}

inline Status ValidateJsonDocument(simdjson::ondemand::parser& parser,
simdjson::padded_string& json) {
ARROW_ASSIGN_OR_RAISE(
auto document, ResolveSimdjsonResult(parser.iterate(json), "Failed to parse JSON"));

ARROW_ASSIGN_OR_RAISE(auto value, ResolveSimdjsonResult(document.get_value(),
"Failed to get JSON value"));

return ConsumeJsonValue(value);
}

} // namespace internal
} // namespace arrow
9 changes: 5 additions & 4 deletions cpp/src/parquet/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -263,9 +263,9 @@ endif()

list(APPEND PARQUET_SHARED_LINK_LIBS arrow_shared)

# Add RapidJSON & simdjson libraries
list(APPEND PARQUET_SHARED_PRIVATE_LINK_LIBS RapidJSON simdjson::simdjson)
list(APPEND PARQUET_STATIC_LINK_LIBS RapidJSON simdjson::simdjson)
# Add simdjson libraries
list(APPEND PARQUET_SHARED_PRIVATE_LINK_LIBS simdjson::simdjson)
list(APPEND PARQUET_STATIC_LINK_LIBS simdjson::simdjson)

# These are libraries that we will link privately with parquet_shared (as they
# do not need to be linked transitively by other linkers)
Expand Down Expand Up @@ -323,7 +323,7 @@ if(ARROW_TESTING)
# "link" our dependencies so that include paths are configured
# correctly
target_link_libraries(parquet_testing PUBLIC ${ARROW_GTEST_GMOCK})
list(APPEND PARQUET_TEST_LINK_LIBS parquet_testing RapidJSON)
list(APPEND PARQUET_TEST_LINK_LIBS parquet_testing simdjson::simdjson)
endif()

if(NOT ARROW_BUILD_SHARED)
Expand Down Expand Up @@ -379,6 +379,7 @@ add_parquet_test(internals-test
bloom_filter_test.cc
geospatial/statistics_test.cc
geospatial/util_internal_test.cc
geospatial/util_json_internal_test.cc
metadata_test.cc
page_index_test.cc
properties_test.cc
Expand Down
Loading
Loading