Skip to content

Commit

Permalink
✨ Change return type of write method
Browse files Browse the repository at this point in the history
  • Loading branch information
yosh-matsuda committed Mar 26, 2023
1 parent 64bd2ad commit ac859b8
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 142 deletions.
42 changes: 22 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,23 +80,23 @@ auto success = *obj["success"].as_bool();
auto list = *obj["array"].as_array();
for (const auto& v : list)
{
// `write` returns JSON string as shared_ptr<std::string_view>
std::cout << *v.write() << std::endl;
// `write` returns JSON read-only string
std::cout << v.write() << std::endl;
}

// The range value type of object class is a key-value pair
auto dict = *obj["currency"].as_object();
for (const auto& [k, v] : dict)
{
std::cout << "{" << k << ": " << *v.write() << "}" << std::endl;
std::cout << "{" << k << ": " << v.write() << "}" << std::endl;
}

// JSON array/object to container conversion
auto numbers = cast<std::vector<int>>(list);
auto currency = cast<std::map<std::string_view, double>>(dict);

// Stringify as shared_ptr<std::string_view>
std::cout << *obj.write() << std::endl;
// Stringify rea-only string
std::cout << obj.write() << std::endl;
// -> {"id":1,"pi":3.141592,"name":"example","array":[0,1,2,3,4],
// "currency":{"USD":129.66,"EUR":140.35,"GBP":158.72},"success":true}
```
Expand Down Expand Up @@ -423,7 +423,7 @@ auto val = read(json_str_insitu, json_str.size(), heap_alloc, ReadFlag::ReadInsi

#### `yyjson::reader::value`

The immutable JSON value class is returned from `yyjson::read` function. See the reference of yyjson for the information of [writer flags](https://ibireme.github.io/yyjson/doc/doxygen/html/md_doc__a_p_i.html#autotoc_md40).
The immutable JSON value class is returned from `yyjson::read` function.

**Construtor**

Expand Down Expand Up @@ -473,7 +473,7 @@ template<typename T>
explicit operator T() const;
// Output JSON string
std::shared_ptr<std::string_view> write(WriteFlag write_flag = WriteFlag::NoFlag) const;
yyjson::json_string write(WriteFlag write_flag = WriteFlag::NoFlag) const;
enum class yyjson::WriteFlag : yyjson_write_flag
{
Expand All @@ -487,6 +487,8 @@ enum class yyjson::WriteFlag : yyjson_write_flag
};
```

The `write` function returns a read-only string which is wrapped by and inherited from `std::string_view`. See the reference of yyjson for the information of [writer flags](https://ibireme.github.io/yyjson/doc/doxygen/html/md_doc__a_p_i.html#autotoc_md40).

**Example**

See also [Overview](#json-reader).
Expand All @@ -509,7 +511,7 @@ std::string_view json_str = R"(
})";

auto val = read(json_str);
std::cout << *val.write(WriteFlag::Prety) << std::endl;
std::cout << val.write(WriteFlag::Prety) << std::endl;
// {
// "id": 1,
// "pi": 3.141592,
Expand Down Expand Up @@ -569,7 +571,7 @@ template<typename T>
explicit operator T() const;
// Output JSON string (inherited)
std::shared_ptr<std::string_view> write(WriteFlag write_flag = WriteFlag::NoFlag) const;
yyjson::json_string write(WriteFlag write_flag = WriteFlag::NoFlag) const;
// Range concept
std::ranges::iterator_t<yyjson::reader::const_array_ref> -> yyjson::reader::const_array_iter
Expand All @@ -592,7 +594,7 @@ assert(val.is_array());
// for (const auto& v : *val.as_array()) { ... } // 💀 UB
for (const auto arr = *val.as_array(); const auto& v : arr) // ✅ OK
{
std::cout << *v.write() << std::endl;
std::cout << v.write() << std::endl;
}
// 0
// "1"
Expand Down Expand Up @@ -636,7 +638,7 @@ template<typename T>
explicit operator T() const;

// Output JSON string (inherited)
std::shared_ptr<std::string_view> write(WriteFlag write_flag = WriteFlag::NoFlag) const;
yyjson::json_string write(WriteFlag write_flag = WriteFlag::NoFlag) const;

// Range concept
using yyjson::reader::const_key_value_ref_pair = std::pair<std::string_view, yyjson::reader::const_value_ref>;
Expand Down Expand Up @@ -775,7 +777,7 @@ template<typename T>
explicit operator T() const;
// Output JSON string
std::shared_ptr<std::string_view> write(WriteFlag write_flag = WriteFlag::NoFlag) const;
yyjson::json_string write(WriteFlag write_flag = WriteFlag::NoFlag) const;
```

Concepts `value_constructible`, `array_constructible`, and `object_constructible` are **NOT** defined in the library but described in the above for explanation hereafter.
Expand Down Expand Up @@ -816,9 +818,9 @@ auto v_viw = value(strviw);
// If the original string is modified, the uncopied JSON string seems to be also modified.
// (but string length is not changed; it may occur memory access violation)
stdstr = "modified string";
std::cout << *v_str_cp.write() << std::endl;
std::cout << v_str_cp.write() << std::endl;
// "string example"
std::cout << *v_str.write() << std::endl;
std::cout << v_str.write() << std::endl;
// "modified strin"

// Implicitly copy string if the argument type is `std::string&&` for safety
Expand Down Expand Up @@ -906,7 +908,7 @@ template<typename T>
explicit operator T() const;

// Output JSON string
std::shared_ptr<std::string_view> write(WriteFlag write_flag = WriteFlag::NoFlag) const;
yyjson::json_string write(WriteFlag write_flag = WriteFlag::NoFlag) const;

// Range concept
std::ranges::range_value_t<yyjson::array&> -> yyjson::writer::value_ref
Expand Down Expand Up @@ -936,7 +938,7 @@ nested.emplace_back(5.0);
nested.emplace_back("6");
nested.emplace_back(7);
std::cout << *arr.write() << std::endl;
std::cout << arr.write() << std::endl;
// [1,2,3,"4",[5.0,"6",7]]
// Range-based for loop
Expand All @@ -945,7 +947,7 @@ for (auto&& v : arr)
if (v.is_int()) v = *v.as_int() * 2;
}
std::cout << *arr.write() << std::endl;
std::cout << arr.write() << std::endl;
// [2,4,6,"4",[5.0,"6",7]]
```

Expand Down Expand Up @@ -1020,7 +1022,7 @@ template<typename T>
explicit operator T() const;
// Output JSON string
std::shared_ptr<std::string_view> write(WriteFlag write_flag = WriteFlag::NoFlag) const;
yyjson::json_string write(WriteFlag write_flag = WriteFlag::NoFlag) const;
// Range concept
using yyjson::writer::key_value_ref_pair = std::pair<std::string_view, yyjson::reader::value_ref>;
Expand Down Expand Up @@ -1055,13 +1057,13 @@ auto nested = obj.emplace("key3", empty_object);
nested.emplace("g", 6);
nested.emplace("h", 7);

std::cout << *obj.write() << std::endl;
std::cout << obj.write() << std::endl;
// {"key0":{"a":0,"b":1},"key1":{"c":2,"d":3},"key2":[4,5],"key3":{"g":6,"h":7}}

// Key access and modify
obj["key2"] = std::map<std::string, int>{{"e", 4}, {"f", 5}};

std::cout << *obj.write() << std::endl;
std::cout << obj.write() << std::endl;
// {"key0":{"a":0,"b":1},"key1":{"c":2,"d":3},"key2":{"e":4,"f":5},"key3":{"e":6,"f":7}}
```
Expand Down
33 changes: 16 additions & 17 deletions include/cpp_yyjson.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,17 @@ namespace yyjson
return json.template cast<T>();
}

class json_string : public std::string_view
{
std::shared_ptr<char> str_ptr_;

public:
json_string(char* ptr, std::size_t len)
: std::string_view(ptr, len), str_ptr_(std::shared_ptr<char>(ptr, [](auto* ptr) { std::free(ptr); }))
{
}
};

class key_string : public std::string_view
{
using base = std::string_view;
Expand Down Expand Up @@ -1300,11 +1311,7 @@ namespace yyjson
auto result = write_func(magic_enum::enum_integer(write_flag), nullptr, &len, &err);
if (result != nullptr) [[likely]]
{
auto sv_ptr = new std::string_view(result, len);
return std::shared_ptr<std::string_view>(sv_ptr, [result](auto* ptr) {
delete ptr;
std::free(result);
});
return json_string(result, len);
}
throw std::runtime_error(fmt::format("write JSON error: {}", err.msg));
}
Expand Down Expand Up @@ -2770,11 +2777,7 @@ namespace yyjson
auto result = yyjson_val_write_opts(val_, magic_enum::enum_integer(write_flag), nullptr, &len, &err);
if (result != nullptr)
{
auto sv_ptr = new std::string_view(result, len);
return std::shared_ptr<std::string_view>(sv_ptr, [result](auto* ptr) {
delete ptr;
std::free(result);
});
return json_string(result, len);
}
throw std::runtime_error(fmt::format("write JSON error: {}", err.msg));
}
Expand Down Expand Up @@ -3256,11 +3259,7 @@ namespace yyjson
auto result = yyjson_write_opts(doc_.get(), magic_enum::enum_integer(write_flag), nullptr, &len, &err);
if (result != nullptr)
{
auto sv_ptr = new std::string_view(result, len);
return std::shared_ptr<std::string_view>(sv_ptr, [result](auto* ptr) {
delete ptr;
std::free(result);
});
return json_string(result, len);
}
throw std::runtime_error(fmt::format("write JSON error: {}", err.msg));
}
Expand Down Expand Up @@ -3907,7 +3906,7 @@ namespace yyjson

template <typename T> // clang-format off
requires requires(const T& t) {
{t.write()} -> std::same_as<std::shared_ptr<std::string_view>>;
{t.write()} -> std::same_as<yyjson::json_string>;
}
class fmt::formatter<T> // clang-format on
{
Expand All @@ -3925,7 +3924,7 @@ class fmt::formatter<T> // clang-format on
template <typename FmtContext>
auto format(const T& t, FmtContext& ctx) const -> decltype(ctx.out())
{
return fmt::format_to(ctx.out(), "{}", *t.write());
return fmt::format_to(ctx.out(), "{}", t.write());
}
};

Expand Down
4 changes: 2 additions & 2 deletions test/bench_read.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ struct json_count

VISITABLE_STRUCT(json_count, cnt_array, cnt_object, cnt_string, cnt_int, cnt_real, cnt_null, cnt_bool);

auto json_count::str() { return fmt::format("{}", *yyjson::object(*this).write()); }
auto json_count::str() { return fmt::format("{}", yyjson::object(*this).write()); }

struct json_stats
{
Expand All @@ -58,7 +58,7 @@ struct json_stats
VISITABLE_STRUCT(json_stats, total_arr_elm_cnt, total_obj_elm_cnt, total_str_len, total_int, total_real, total_true_cnt,
total_false_cnt);

auto json_stats::str() { return fmt::format("{}", *yyjson::object(*this).write()); }
auto json_stats::str() { return fmt::format("{}", yyjson::object(*this).write()); }

auto json_files = std::array{
std::tuple<std::string, json_count, json_stats>{"./external/yyjson_benchmark/data/json/canada.json",
Expand Down
24 changes: 12 additions & 12 deletions test/bench_write.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ void write_cpp_yyjson_array_int64(benchmark::State& state)
for (auto _ : state)
{
auto array = yyjson::array(vec_int64);
auto result = *array.write();
auto result = array.write();
if (result.size() != json_size_arr_int64)
{
state.SkipWithError("Invalid JSON string");
Expand Down Expand Up @@ -135,7 +135,7 @@ void write_cpp_yyjson_array_double(benchmark::State& state)
for (auto _ : state)
{
auto array = yyjson::array(vec_double);
auto result = *array.write();
auto result = array.write();
if (result.size() != json_size_arr_double)
{
state.SkipWithError("Invalid JSON string");
Expand Down Expand Up @@ -213,7 +213,7 @@ void write_cpp_yyjson_array_string(benchmark::State& state)
for (auto _ : state)
{
auto array = yyjson::array(vec_string);
auto result = *array.write();
auto result = array.write();
if (result.size() != json_size_arr_string)
{
state.SkipWithError("Invalid JSON string");
Expand Down Expand Up @@ -276,7 +276,7 @@ void write_cpp_yyjson_array_string_copy(benchmark::State& state)
for (auto _ : state)
{
auto array = yyjson::array(vec_string, copy_string);
auto result = *array.write();
auto result = array.write();
if (result.size() != json_size_arr_string)
{
state.SkipWithError("Invalid JSON string");
Expand Down Expand Up @@ -376,7 +376,7 @@ void write_cpp_yyjson_array_tuple(benchmark::State& state)
for (auto _ : state)
{
auto array = yyjson::array(vec_tuple);
auto result = *array.write();
auto result = array.write();
if (result.size() != json_size_arr_tuple)
{
state.SkipWithError("Invalid JSON string");
Expand Down Expand Up @@ -490,7 +490,7 @@ void write_cpp_yyjson_array_object(benchmark::State& state)
for (auto _ : state)
{
auto array = yyjson::array(vec_object);
auto result = *array.write();
auto result = array.write();
if (result.size() != json_size_arr_object)
{
state.SkipWithError("Invalid JSON string");
Expand Down Expand Up @@ -593,7 +593,7 @@ void write_cpp_yyjson_array_double_append_range(benchmark::State& state)
for (auto _ : state)
{
auto array = yyjson::array(vec_double | std::ranges::views::transform([](const auto n) { return 1.5 * n; }));
auto result = *array.write();
auto result = array.write();
if (result.size() != json_size_arr_double_append)
{
state.SkipWithError("Invalid JSON string");
Expand All @@ -610,7 +610,7 @@ void write_cpp_yyjson_array_double_append(benchmark::State& state)
{
auto array = yyjson::array();
for (const auto n : vec_double) array.emplace_back(1.5 * n);
auto result = *array.write();
auto result = array.write();
if (result.size() != json_size_arr_double_append)
{
state.SkipWithError("Invalid JSON string");
Expand Down Expand Up @@ -692,7 +692,7 @@ void write_cpp_yyjson_object_int64(benchmark::State& state)
{
auto object = yyjson::object();
for (auto n : vec_int64) object.emplace(fmt::format("{}", n), n);
auto result = *object.write();
auto result = object.write();
if (result.size() != json_size_obj_int64)
{
state.SkipWithError("Invalid JSON string");
Expand Down Expand Up @@ -777,7 +777,7 @@ void write_cpp_yyjson_object_double(benchmark::State& state)
{
auto object = yyjson::object();
for (auto n : vec_double) object.emplace(fmt::format("{}", n), n);
auto result = *object.write();
auto result = object.write();
if (result.size() != json_size_obj_double)
{
state.SkipWithError("Invalid JSON string");
Expand Down Expand Up @@ -866,7 +866,7 @@ void write_cpp_yyjson_object_string(benchmark::State& state)
{
object.emplace(n, n);
}
auto result = *object.write();
auto result = object.write();
if (result.size() != json_size_obj_string)
{
state.SkipWithError("Invalid JSON string");
Expand Down Expand Up @@ -941,7 +941,7 @@ void write_cpp_yyjson_object_string_copy(benchmark::State& state)
{
object.emplace(n, n, copy_string);
}
auto result = *object.write();
auto result = object.write();
if (result.size() != json_size_obj_string)
{
state.SkipWithError("Invalid JSON string");
Expand Down
Loading

0 comments on commit ac859b8

Please sign in to comment.