From: Dylan Yudaken Date: Tue, 28 Mar 2017 15:02:42 +0000 (-0700) Subject: Allow custom sorting function for JSON serializer X-Git-Tag: v2017.04.03.00~17 X-Git-Url: http://plrg.eecs.uci.edu/git/?p=folly.git;a=commitdiff_plain;h=43a79f74cfdeac62198fc4dbdda7a04d4d14ece6 Allow custom sorting function for JSON serializer Summary: In some situations it is useful to be able to sort the JSON keys according to some different scheme for readability, so allow the sorting function to be changed by the serializer_opts Reviewed By: yfeldblum Differential Revision: D4782077 fbshipit-source-id: 032fa60a38804452bd1c22c67ba897521cb2cd1d --- diff --git a/folly/json.cpp b/folly/json.cpp index 48ef486e..867392f4 100644 --- a/folly/json.cpp +++ b/folly/json.cpp @@ -113,12 +113,17 @@ private: out_ += '{'; indent(); newline(); - if (opts_.sort_keys) { + if (opts_.sort_keys || opts_.sort_keys_by) { using ref = std::reference_wrapper; std::vector refs(o.items().begin(), o.items().end()); - std::sort(refs.begin(), refs.end(), [](ref a, ref b) { + + using SortByRef = FunctionRef; + auto const& sort_keys_by = opts_.sort_keys_by + ? SortByRef(opts_.sort_keys_by) + : SortByRef(std::less()); + std::sort(refs.begin(), refs.end(), [&](ref a, ref b) { // Only compare keys. No ordering among identical keys. - return a.get().first < b.get().first; + return sort_keys_by(a.get().first, b.get().first); }); printKVPairs(refs.cbegin(), refs.cend()); } else { diff --git a/folly/json.h b/folly/json.h index 87a90788..788587a8 100644 --- a/folly/json.h +++ b/folly/json.h @@ -43,8 +43,9 @@ #include #include -#include +#include #include +#include namespace folly { @@ -95,8 +96,14 @@ namespace json { bool allow_trailing_comma; // Sort keys of all objects before printing out (potentially slow) + // using dynamic::operator<. + // Has no effect if sort_keys_by is set. bool sort_keys; + // Sort keys of all objects before printing out (potentially slow) + // using the provided less functor. + Function sort_keys_by; + // Replace invalid utf8 characters with U+FFFD and continue bool skip_invalid_utf8; diff --git a/folly/test/JsonTest.cpp b/folly/test/JsonTest.cpp index df283134..f6dfc354 100644 --- a/folly/test/JsonTest.cpp +++ b/folly/test/JsonTest.cpp @@ -438,10 +438,17 @@ TEST(Json, ParseNumbersAsStrings) { } TEST(Json, SortKeys) { - folly::json::serialization_opts opts_on, opts_off; + folly::json::serialization_opts opts_on, opts_off, opts_custom_sort; opts_on.sort_keys = true; opts_off.sort_keys = false; + opts_custom_sort.sort_keys = false; // should not be required + opts_custom_sort.sort_keys_by = []( + folly::dynamic const& a, folly::dynamic const& b) { + // just an inverse sort + return b < a; + }; + dynamic value = dynamic::object ("foo", "bar") ("junk", 12) @@ -462,10 +469,18 @@ TEST(Json, SortKeys) { R"({"a":[{"a":"b","c":"d"},12.5,"Yo Dawg",["heh"],null],)" R"("another":32.2,"foo":"bar","junk":12})"; + std::string inverse_sorted_keys = + R"({"junk":12,"foo":"bar","another":32.2,)" + R"("a":[{"c":"d","a":"b"},12.5,"Yo Dawg",["heh"],null]})"; + EXPECT_EQ(value, parseJson(folly::json::serialize(value, opts_on))); EXPECT_EQ(value, parseJson(folly::json::serialize(value, opts_off))); + EXPECT_EQ(value, parseJson(folly::json::serialize(value, opts_custom_sort))); EXPECT_EQ(sorted_keys, folly::json::serialize(value, opts_on)); + EXPECT_NE(sorted_keys, folly::json::serialize(value, opts_off)); + EXPECT_EQ( + inverse_sorted_keys, folly::json::serialize(value, opts_custom_sort)); } TEST(Json, PrintTo) {