Skip to content

Commit

Permalink
json_formatter: Add support for standard range containers
Browse files Browse the repository at this point in the history
This commit extends the JSON formatting capabilities to support all
standard range containers through the C++20 ranges concept.

Key improvements:
- Add generic range support using std::ranges::input_range concept
- Enable JSON formatting for any range type without materialization
- Maintain existing support for vector, map, and unordered_map
- Provide a flexible, type-agnostic serialization approach

Example use cases:
- Formatting std::span
- Serializing range views
- Converting filter and transform views directly to JSON

Signed-off-by: Kefu Chai <[email protected]>
  • Loading branch information
tchaikov committed Nov 21, 2024
1 parent e288351 commit aba3c83
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 20 deletions.
55 changes: 35 additions & 20 deletions include/seastar/json/formatter.hh
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#pragma once

#ifndef SEASTAR_MODULE
#include <ranges>
#include <string>
#include <vector>
#include <unordered_map>
Expand All @@ -37,6 +38,15 @@

namespace seastar {

namespace internal {

template<typename T>
concept is_map = requires {
typename T::mapped_type;
};

}

namespace json {

SEASTAR_MODULE_EXPORT
Expand Down Expand Up @@ -64,8 +74,18 @@ class formatter {
to_json(p.first) + ":" + to_json(p.second);
}

template<typename Iter>
static sstring to_json(state s, Iter i, Iter e) {
template<typename K, typename V>
static sstring to_json(state s, const std::tuple<K, V>& p) {
if (s == state::array) {
return "{" + to_json(state::none, p) + "}";
} else {
auto& [key, value] = p;
return to_json(key) + ":" + to_json(value);
}
}

template<typename Iterator, typename Sentinel>
static sstring to_json(state s, Iterator i, Sentinel e) {
std::stringstream res;
res << begin(s);
size_t n = 0;
Expand Down Expand Up @@ -100,8 +120,8 @@ class formatter {
}
}

template<typename Iter>
static future<> write(output_stream<char>& stream, state s, Iter i, Iter e) {
template<typename Iterator, typename Sentinel>
static future<> write(output_stream<char>& stream, state s, Iterator i, Sentinel e) {
return do_with(true, [&stream, s, i, e] (bool& first) {
return stream.write(begin(s)).then([&first, &stream, s, i, e] {
return do_for_each(i, e, [&first, &stream, s] (auto& m) {
Expand Down Expand Up @@ -191,23 +211,18 @@ public:
static sstring to_json(bool d);

/**
* return a json formatted list of a given vector of params
* @param vec the vector to format
* @return the given vector in a json format
* converts a given range to a JSON-formatted string
*
* @param range A standard range type
* @return A string containing the JSON representation of the input range
*/
template<typename... Args>
static sstring to_json(const std::vector<Args...>& vec) {
return to_json(state::array, vec.begin(), vec.end());
}

template<typename... Args>
static sstring to_json(const std::map<Args...>& map) {
return to_json(state::map, map.begin(), map.end());
}

template<typename... Args>
static sstring to_json(const std::unordered_map<Args...>& map) {
return to_json(state::map, map.begin(), map.end());
template<std::ranges::input_range Range>
static sstring to_json(const Range& range) {
if constexpr (internal::is_map<Range>) {
return to_json(state::map, std::ranges::begin(range), std::ranges::end(range));
} else {
return to_json(state::array, std::ranges::begin(range), std::ranges::end(range));
}
}

/**
Expand Down
8 changes: 8 additions & 0 deletions tests/unit/json_formatter_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,14 @@ SEASTAR_TEST_CASE(test_collections) {
return make_ready_future();
}

SEASTAR_TEST_CASE(test_ranges) {
BOOST_CHECK_EQUAL("[1,2,3,4]", formatter::to_json(std::views::iota(1, 5)));
#ifdef __cpp_lib_ranges_enumerate
BOOST_CHECK_EQUAL("[{0:5},{1:6},{2:7},{3:8}]", formatter::to_json(std::views::iota(5, 9) | std::views::enumerate));
#endif
return make_ready_future();
}

struct object_json : public json_base {
json_element<sstring> subject;
json_list<long> values;
Expand Down

0 comments on commit aba3c83

Please sign in to comment.