Skip to content

Commit 46f6777

Browse files
authored
change json_decode so that it accepts string_view instead of KPHP string (#1398)
1 parent e39f13b commit 46f6777

7 files changed

Lines changed: 47 additions & 39 deletions

File tree

runtime-common/stdlib/serialization/from-json-processor.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,12 +204,14 @@ ClassName f$JsonEncoder$$from_json_impl(Tag /*tag*/, const string& json_string,
204204
auto& msg = SerializationLibContext::get().last_json_processor_error;
205205
msg = {};
206206

207-
auto [json, success] = json_decode(json_string, FromJsonVisitor<Tag>::get_json_obj_magic_key());
207+
auto opt_json = json_decode({json_string.c_str(), json_string.size()}, {FromJsonVisitor<Tag>::get_json_obj_magic_key()});
208208

209-
if (!success) {
209+
if (!opt_json.has_value()) {
210210
msg.append(json_string.empty() ? "provided empty json string" : "failed to parse json string");
211211
return {};
212212
}
213+
214+
auto json = *std::move(opt_json);
213215
if constexpr (!impl_::IsJsonFlattenClass<typename ClassName::ClassType>::value) {
214216
if (!json.is_array() || json.as_array().is_vector()) {
215217
msg.append("root element of json string must be an object type, got ");

runtime-common/stdlib/serialization/json-functions.cpp

Lines changed: 30 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44

55
#include "runtime-common/stdlib/serialization/json-functions.h"
66

7+
#include <cstddef>
8+
#include <optional>
9+
#include <string_view>
10+
711
#include "common/algorithms/find.h"
812
#include "runtime-common/core/runtime-core.h"
913
#include "runtime-common/stdlib/string/string-functions.h"
@@ -316,17 +320,17 @@ bool JsonEncoder::encode(const mixed& v, string_buffer& sb) noexcept {
316320

317321
namespace {
318322

319-
void json_skip_blanks(const char* s, int& i) noexcept {
323+
void json_skip_blanks(const char* s, size_t& i) noexcept {
320324
while (vk::any_of_equal(s[i], ' ', '\t', '\r', '\n')) {
321325
i++;
322326
}
323327
}
324328

325-
bool do_json_decode(const char* s, int s_len, int& i, mixed& v, const char* json_obj_magic_key) noexcept {
329+
bool do_json_decode(std::string_view s, size_t& i, mixed& v, std::string_view json_obj_magic_key) noexcept {
326330
if (!v.is_null()) {
327331
v.destroy();
328332
}
329-
json_skip_blanks(s, i);
333+
json_skip_blanks(s.data(), i);
330334
switch (s[i]) {
331335
case 'n':
332336
if (s[i + 1] == 'u' && s[i + 2] == 'l' && s[i + 3] == 'l') {
@@ -351,14 +355,14 @@ bool do_json_decode(const char* s, int s_len, int& i, mixed& v, const char* json
351355
case '"': {
352356
int j = i + 1;
353357
int slashes = 0;
354-
while (j < s_len && s[j] != '"') {
358+
while (j < s.size() && s[j] != '"') {
355359
if (s[j] == '\\') {
356360
slashes++;
357361
j++;
358362
}
359363
j++;
360364
}
361-
if (j < s_len) {
365+
if (j < s.size()) {
362366
int len = j - i - 1 - slashes;
363367

364368
string value(len, false);
@@ -469,15 +473,15 @@ bool do_json_decode(const char* s, int s_len, int& i, mixed& v, const char* json
469473
case '[': {
470474
array<mixed> res;
471475
i++;
472-
json_skip_blanks(s, i);
476+
json_skip_blanks(s.data(), i);
473477
if (s[i] != ']') {
474478
do {
475479
mixed value;
476-
if (!do_json_decode(s, s_len, i, value, json_obj_magic_key)) {
480+
if (!do_json_decode(s, i, value, json_obj_magic_key)) {
477481
return false;
478482
}
479483
res.push_back(value);
480-
json_skip_blanks(s, i);
484+
json_skip_blanks(s.data(), i);
481485
} while (s[i++] == ',');
482486

483487
if (s[i - 1] != ']') {
@@ -493,22 +497,22 @@ bool do_json_decode(const char* s, int s_len, int& i, mixed& v, const char* json
493497
case '{': {
494498
array<mixed> res;
495499
i++;
496-
json_skip_blanks(s, i);
500+
json_skip_blanks(s.data(), i);
497501
if (s[i] != '}') {
498502
do {
499503
mixed key;
500-
if (!do_json_decode(s, s_len, i, key, json_obj_magic_key) || !key.is_string()) {
504+
if (!do_json_decode(s, i, key, json_obj_magic_key) || !key.is_string()) {
501505
return false;
502506
}
503-
json_skip_blanks(s, i);
507+
json_skip_blanks(s.data(), i);
504508
if (s[i++] != ':') {
505509
return false;
506510
}
507511

508-
if (!do_json_decode(s, s_len, i, res[key], json_obj_magic_key)) {
512+
if (!do_json_decode(s, i, res[key], json_obj_magic_key)) {
509513
return false;
510514
}
511-
json_skip_blanks(s, i);
515+
json_skip_blanks(s.data(), i);
512516
} while (s[i++] == ',');
513517

514518
if (s[i - 1] != '}') {
@@ -520,8 +524,8 @@ bool do_json_decode(const char* s, int s_len, int& i, mixed& v, const char* json
520524

521525
// it's impossible to distinguish whether empty php array was an json array or json object;
522526
// to overcome it we add dummy key to php array that make array::is_vector() returning false, so we have difference
523-
if (json_obj_magic_key && res.empty()) {
524-
res[string{json_obj_magic_key}] = true;
527+
if (!json_obj_magic_key.empty() && res.empty()) {
528+
res[string{json_obj_magic_key.data(), static_cast<string::size_type>(json_obj_magic_key.size())}] = true;
525529
}
526530

527531
new (&v) mixed(res);
@@ -534,15 +538,15 @@ bool do_json_decode(const char* s, int s_len, int& i, mixed& v, const char* json
534538
}
535539
if (j > i) {
536540
int64_t intval = 0;
537-
if (php_try_to_int(s + i, j - i, &intval)) {
541+
if (php_try_to_int(s.data() + i, j - i, &intval)) {
538542
i = j;
539543
new (&v) mixed(intval);
540544
return true;
541545
}
542546

543547
char* end_ptr;
544-
double floatval = strtod(s + i, &end_ptr);
545-
if (end_ptr == s + j) {
548+
double floatval = strtod(s.data() + i, &end_ptr);
549+
if (end_ptr == s.data() + j) {
546550
i = j;
547551
new (&v) mixed(floatval);
548552
return true;
@@ -557,22 +561,20 @@ bool do_json_decode(const char* s, int s_len, int& i, mixed& v, const char* json
557561

558562
} // namespace
559563

560-
std::pair<mixed, bool> json_decode(const string& v, const char* json_obj_magic_key) noexcept {
561-
mixed result;
562-
int i = 0;
563-
if (do_json_decode(v.c_str(), v.size(), i, result, json_obj_magic_key)) {
564-
json_skip_blanks(v.c_str(), i);
565-
if (i == static_cast<int>(v.size())) {
566-
bool success = true;
567-
return {result, success};
564+
std::optional<mixed> json_decode(std::string_view v, std::string_view json_obj_magic_key) noexcept {
565+
mixed result{};
566+
size_t i{};
567+
if (do_json_decode(v, i, result, json_obj_magic_key)) {
568+
json_skip_blanks(v.data(), i);
569+
if (i == v.size()) {
570+
return result;
568571
}
569572
}
570-
571573
return {};
572574
}
573575

574576
mixed f$json_decode(const string& v, bool assoc) noexcept {
575577
// TODO It was a warning before (in case if assoc is false), but then it was disabled, should we enable it again?
576578
static_cast<void>(assoc);
577-
return json_decode(v).first;
579+
return json_decode({v.c_str(), v.size()}, {}).value_or(mixed{});
578580
}

runtime-common/stdlib/serialization/json-functions.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
#pragma once
66

77
#include <array>
8+
#include <optional>
9+
#include <string_view>
810

911
#include "common/mixin/not_copyable.h"
1012
#include "runtime-common/core/runtime-core.h"
@@ -174,5 +176,6 @@ inline Optional<string> f$vk_json_encode(const T& v) noexcept {
174176
return f$json_encode(v, 0, true);
175177
}
176178

177-
std::pair<mixed, bool> json_decode(const string& v, const char* json_obj_magic_key = nullptr) noexcept;
179+
std::optional<mixed> json_decode(std::string_view v, std::string_view json_obj_magic_key = {}) noexcept;
180+
178181
mixed f$json_decode(const string& v, bool assoc = false) noexcept;

runtime-light/state/component-state.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,8 @@ void ComponentState::parse_ini_arg(std::string_view key_view, std::string_view v
4545
}
4646

4747
void ComponentState::parse_runtime_config_arg(std::string_view value_view) noexcept {
48-
// FIXME: actually no need to allocate string here
49-
if (auto [config, ok]{json_decode(string{value_view.data(), static_cast<string::size_type>(value_view.size())})}; ok) [[likely]] {
50-
runtime_config = std::move(config);
48+
if (auto opt_config{json_decode(value_view)}; opt_config) [[likely]] {
49+
runtime_config = *std::move(opt_config);
5150
} else {
5251
kphp::log::warning("runtime config isn't a valid JSON");
5352
}

runtime-light/stdlib/confdata/confdata-functions.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ mixed extract_confdata_value(const tl::confdataValue& confdata_value) noexcept {
3636
if (confdata_value.is_php_serialized.value) {
3737
return unserialize_raw(confdata_value.value.value.data(), static_cast<string::size_type>(confdata_value.value.value.size()));
3838
} else if (confdata_value.is_json_serialized.value) {
39-
return f$json_decode(string{confdata_value.value.value.data(), static_cast<string::size_type>(confdata_value.value.value.size())});
39+
return json_decode(confdata_value.value.value).value_or(mixed{});
4040
} else {
4141
return string{confdata_value.value.value.data(), static_cast<string::size_type>(confdata_value.value.value.size())};
4242
}

runtime/memcache.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
#include "runtime/memcache.h"
66

7+
#include <cstddef>
8+
79
#include "runtime-common/core/utils/kphp-assert-core.h"
810
#include "runtime-common/stdlib/serialization/json-functions.h"
911
#include "runtime-common/stdlib/serialization/serialize-functions.h"
@@ -163,7 +165,7 @@ mixed mc_get_value(const char* result_str, int32_t result_str_len, int64_t flags
163165
result = unserialize_raw(result_str, result_str_len);
164166
} else if (flags & MEMCACHE_JSON_SERIALIZED) {
165167
flags ^= MEMCACHE_JSON_SERIALIZED;
166-
result = json_decode({result_str, static_cast<string::size_type>(result_str_len)}).first;
168+
result = json_decode({result_str, static_cast<size_t>(result_str_len)}).value_or(mixed{});
167169
} else {
168170
result = string(result_str, result_str_len);
169171
}

server/php-engine.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2187,12 +2187,12 @@ int main_args_handler(int i, const char *long_option) {
21872187
}
21882188
std::stringstream stringstream;
21892189
stringstream << file.rdbuf();
2190-
auto [config, success] = json_decode(string(stringstream.str().c_str()));
2191-
if (!success) {
2190+
auto opt_config = json_decode(stringstream.str());
2191+
if (!opt_config.has_value()) {
21922192
kprintf("--%s option : file is not JSON\n", long_option);
21932193
return -1;
21942194
}
2195-
runtime_config = std::move(config);
2195+
runtime_config = *std::move(opt_config);
21962196
return 0;
21972197
}
21982198
case 2033: {

0 commit comments

Comments
 (0)