src: move JSONWriter into its own file

The JSONWriter feature is not inherently related to the report
feature in any way.

As a drive-by fix, remove a number of unused header includes.

PR-URL: https://github.com/nodejs/node/pull/32552
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Gus Caplan <me@gus.host>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Richard Lau <riclau@uk.ibm.com>
This commit is contained in:
Anna Henningsen 2020-03-29 20:11:56 +02:00 committed by Michaël Zasso
parent e066584d94
commit f284d599bb
No known key found for this signature in database
GPG Key ID: 770F7A9A5AE15600
7 changed files with 238 additions and 225 deletions

View File

@ -560,6 +560,7 @@
'src/js_native_api_v8.h',
'src/js_native_api_v8_internals.h',
'src/js_stream.cc',
'src/json_utils.cc',
'src/module_wrap.cc',
'src/node.cc',
'src/node_api.cc',
@ -644,6 +645,7 @@
'src/histogram.h',
'src/histogram-inl.h',
'src/js_stream.h',
'src/json_utils.h',
'src/large_pages/node_large_page.cc',
'src/large_pages/node_large_page.h',
'src/memory_tracker.h',
@ -1141,7 +1143,7 @@
'test/cctest/test_linked_binding.cc',
'test/cctest/test_per_process.cc',
'test/cctest/test_platform.cc',
'test/cctest/test_report_util.cc',
'test/cctest/test_json_utils.cc',
'test/cctest/test_sockaddr.cc',
'test/cctest/test_traced_value.cc',
'test/cctest/test_util.cc',

67
src/json_utils.cc Normal file
View File

@ -0,0 +1,67 @@
#include "json_utils.h"
namespace node {
std::string EscapeJsonChars(const std::string& str) {
const std::string control_symbols[0x20] = {
"\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005",
"\\u0006", "\\u0007", "\\b", "\\t", "\\n", "\\v", "\\f", "\\r",
"\\u000e", "\\u000f", "\\u0010", "\\u0011", "\\u0012", "\\u0013",
"\\u0014", "\\u0015", "\\u0016", "\\u0017", "\\u0018", "\\u0019",
"\\u001a", "\\u001b", "\\u001c", "\\u001d", "\\u001e", "\\u001f"
};
std::string ret;
size_t last_pos = 0;
size_t pos = 0;
for (; pos < str.size(); ++pos) {
std::string replace;
char ch = str[pos];
if (ch == '\\') {
replace = "\\\\";
} else if (ch == '\"') {
replace = "\\\"";
} else {
size_t num = static_cast<size_t>(ch);
if (num < 0x20) replace = control_symbols[num];
}
if (!replace.empty()) {
if (pos > last_pos) {
ret += str.substr(last_pos, pos - last_pos);
}
last_pos = pos + 1;
ret += replace;
}
}
// Append any remaining symbols.
if (last_pos < str.size()) {
ret += str.substr(last_pos, pos - last_pos);
}
return ret;
}
std::string Reindent(const std::string& str, int indent_depth) {
std::string indent;
for (int i = 0; i < indent_depth; i++) indent += ' ';
std::string out;
std::string::size_type pos = 0;
do {
std::string::size_type prev_pos = pos;
pos = str.find('\n', pos);
out.append(indent);
if (pos == std::string::npos) {
out.append(str, prev_pos, std::string::npos);
break;
} else {
pos++;
out.append(str, prev_pos, pos - prev_pos);
}
} while (true);
return out;
}
} // namespace node

160
src/json_utils.h Normal file
View File

@ -0,0 +1,160 @@
#ifndef SRC_JSON_UTILS_H_
#define SRC_JSON_UTILS_H_
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
#include <iomanip>
#include <ostream>
#include <limits>
namespace node {
std::string EscapeJsonChars(const std::string& str);
std::string Reindent(const std::string& str, int indentation);
// JSON compiler definitions.
class JSONWriter {
public:
JSONWriter(std::ostream& out, bool compact)
: out_(out), compact_(compact) {}
private:
inline void indent() { indent_ += 2; }
inline void deindent() { indent_ -= 2; }
inline void advance() {
if (compact_) return;
for (int i = 0; i < indent_; i++) out_ << ' ';
}
inline void write_one_space() {
if (compact_) return;
out_ << ' ';
}
inline void write_new_line() {
if (compact_) return;
out_ << '\n';
}
public:
inline void json_start() {
if (state_ == kAfterValue) out_ << ',';
write_new_line();
advance();
out_ << '{';
indent();
state_ = kObjectStart;
}
inline void json_end() {
write_new_line();
deindent();
advance();
out_ << '}';
state_ = kAfterValue;
}
template <typename T>
inline void json_objectstart(T key) {
if (state_ == kAfterValue) out_ << ',';
write_new_line();
advance();
write_string(key);
out_ << ':';
write_one_space();
out_ << '{';
indent();
state_ = kObjectStart;
}
template <typename T>
inline void json_arraystart(T key) {
if (state_ == kAfterValue) out_ << ',';
write_new_line();
advance();
write_string(key);
out_ << ':';
write_one_space();
out_ << '[';
indent();
state_ = kObjectStart;
}
inline void json_objectend() {
write_new_line();
deindent();
advance();
out_ << '}';
if (indent_ == 0) {
// Top-level object is complete, so end the line.
out_ << '\n';
}
state_ = kAfterValue;
}
inline void json_arrayend() {
write_new_line();
deindent();
advance();
out_ << ']';
state_ = kAfterValue;
}
template <typename T, typename U>
inline void json_keyvalue(const T& key, const U& value) {
if (state_ == kAfterValue) out_ << ',';
write_new_line();
advance();
write_string(key);
out_ << ':';
write_one_space();
write_value(value);
state_ = kAfterValue;
}
template <typename U>
inline void json_element(const U& value) {
if (state_ == kAfterValue) out_ << ',';
write_new_line();
advance();
write_value(value);
state_ = kAfterValue;
}
struct Null {}; // Usable as a JSON value.
struct ForeignJSON {
std::string as_string;
};
private:
template <typename T,
typename test_for_number = typename std::
enable_if<std::numeric_limits<T>::is_specialized, bool>::type>
inline void write_value(T number) {
if (std::is_same<T, bool>::value)
out_ << (number ? "true" : "false");
else
out_ << number;
}
inline void write_value(Null null) { out_ << "null"; }
inline void write_value(const char* str) { write_string(str); }
inline void write_value(const std::string& str) { write_string(str); }
inline void write_value(const ForeignJSON& json) {
out_ << Reindent(json.as_string, indent_);
}
inline void write_string(const std::string& str) {
out_ << '"' << EscapeJsonChars(str) << '"';
}
inline void write_string(const char* str) { write_string(std::string(str)); }
enum JSONState { kObjectStart, kAfterValue };
std::ostream& out_;
bool compact_;
int indent_ = 0;
int state_ = kObjectStart;
};
} // namespace node
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
#endif // SRC_JSON_UTILS_H_

View File

@ -1,4 +1,5 @@
#include "env-inl.h"
#include "json_utils.h"
#include "node_report.h"
#include "debug_utils-inl.h"
#include "diagnosticfilename-inl.h"
@ -16,6 +17,7 @@
#include <dlfcn.h>
#endif
#include <iostream>
#include <cstring>
#include <ctime>
#include <cwctype>
@ -30,6 +32,7 @@ using node::arraysize;
using node::ConditionVariable;
using node::DiagnosticFilename;
using node::Environment;
using node::JSONWriter;
using node::Mutex;
using node::NativeSymbolDebuggingContext;
using node::TIME_TYPE;

View File

@ -3,7 +3,6 @@
#include "node.h"
#include "node_buffer.h"
#include "uv.h"
#include "v8.h"
#include "util.h"
#ifndef _WIN32
@ -11,19 +10,7 @@
#include <unistd.h>
#endif
#include <climits>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <limits>
#include <algorithm>
#include <queue>
#include <string>
#include <utility>
#include <vector>
namespace report {
@ -43,8 +30,6 @@ void GetNodeReport(v8::Isolate* isolate,
// Function declarations - utility functions in src/node_report_utils.cc
void WalkHandle(uv_handle_t* h, void* arg);
std::string EscapeJsonChars(const std::string& str);
std::string Reindent(const std::string& str, int indentation);
template <typename T>
std::string ValueToHexString(T value) {
@ -59,148 +44,4 @@ std::string ValueToHexString(T value) {
void WriteReport(const v8::FunctionCallbackInfo<v8::Value>& info);
void GetReport(const v8::FunctionCallbackInfo<v8::Value>& info);
// Node.js boot time - defined in src/node.cc
extern double prog_start_time;
// JSON compiler definitions.
class JSONWriter {
public:
JSONWriter(std::ostream& out, bool compact)
: out_(out), compact_(compact) {}
private:
inline void indent() { indent_ += 2; }
inline void deindent() { indent_ -= 2; }
inline void advance() {
if (compact_) return;
for (int i = 0; i < indent_; i++) out_ << ' ';
}
inline void write_one_space() {
if (compact_) return;
out_ << ' ';
}
inline void write_new_line() {
if (compact_) return;
out_ << '\n';
}
public:
inline void json_start() {
if (state_ == kAfterValue) out_ << ',';
write_new_line();
advance();
out_ << '{';
indent();
state_ = kObjectStart;
}
inline void json_end() {
write_new_line();
deindent();
advance();
out_ << '}';
state_ = kAfterValue;
}
template <typename T>
inline void json_objectstart(T key) {
if (state_ == kAfterValue) out_ << ',';
write_new_line();
advance();
write_string(key);
out_ << ':';
write_one_space();
out_ << '{';
indent();
state_ = kObjectStart;
}
template <typename T>
inline void json_arraystart(T key) {
if (state_ == kAfterValue) out_ << ',';
write_new_line();
advance();
write_string(key);
out_ << ':';
write_one_space();
out_ << '[';
indent();
state_ = kObjectStart;
}
inline void json_objectend() {
write_new_line();
deindent();
advance();
out_ << '}';
if (indent_ == 0) {
// Top-level object is complete, so end the line.
out_ << '\n';
}
state_ = kAfterValue;
}
inline void json_arrayend() {
write_new_line();
deindent();
advance();
out_ << ']';
state_ = kAfterValue;
}
template <typename T, typename U>
inline void json_keyvalue(const T& key, const U& value) {
if (state_ == kAfterValue) out_ << ',';
write_new_line();
advance();
write_string(key);
out_ << ':';
write_one_space();
write_value(value);
state_ = kAfterValue;
}
template <typename U>
inline void json_element(const U& value) {
if (state_ == kAfterValue) out_ << ',';
write_new_line();
advance();
write_value(value);
state_ = kAfterValue;
}
struct Null {}; // Usable as a JSON value.
struct ForeignJSON {
std::string as_string;
};
private:
template <typename T,
typename test_for_number = typename std::
enable_if<std::numeric_limits<T>::is_specialized, bool>::type>
inline void write_value(T number) {
if (std::is_same<T, bool>::value)
out_ << (number ? "true" : "false");
else
out_ << number;
}
inline void write_value(Null null) { out_ << "null"; }
inline void write_value(const char* str) { write_string(str); }
inline void write_value(const std::string& str) { write_string(str); }
inline void write_value(const ForeignJSON& json) {
out_ << Reindent(json.as_string, indent_);
}
inline void write_string(const std::string& str) {
out_ << '"' << EscapeJsonChars(str) << '"';
}
inline void write_string(const char* str) { write_string(std::string(str)); }
enum JSONState { kObjectStart, kAfterValue };
std::ostream& out_;
bool compact_;
int indent_ = 0;
int state_ = kObjectStart;
};
} // namespace report

View File

@ -1,9 +1,11 @@
#include "json_utils.h"
#include "node_internals.h"
#include "node_report.h"
#include "util-inl.h"
namespace report {
using node::JSONWriter;
using node::MallocedBuffer;
static constexpr auto null = JSONWriter::Null{};
@ -225,66 +227,4 @@ void WalkHandle(uv_handle_t* h, void* arg) {
writer->json_end();
}
std::string EscapeJsonChars(const std::string& str) {
const std::string control_symbols[0x20] = {
"\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005",
"\\u0006", "\\u0007", "\\b", "\\t", "\\n", "\\v", "\\f", "\\r",
"\\u000e", "\\u000f", "\\u0010", "\\u0011", "\\u0012", "\\u0013",
"\\u0014", "\\u0015", "\\u0016", "\\u0017", "\\u0018", "\\u0019",
"\\u001a", "\\u001b", "\\u001c", "\\u001d", "\\u001e", "\\u001f"
};
std::string ret;
size_t last_pos = 0;
size_t pos = 0;
for (; pos < str.size(); ++pos) {
std::string replace;
char ch = str[pos];
if (ch == '\\') {
replace = "\\\\";
} else if (ch == '\"') {
replace = "\\\"";
} else {
size_t num = static_cast<size_t>(ch);
if (num < 0x20) replace = control_symbols[num];
}
if (!replace.empty()) {
if (pos > last_pos) {
ret += str.substr(last_pos, pos - last_pos);
}
last_pos = pos + 1;
ret += replace;
}
}
// Append any remaining symbols.
if (last_pos < str.size()) {
ret += str.substr(last_pos, pos - last_pos);
}
return ret;
}
std::string Reindent(const std::string& str, int indent_depth) {
std::string indent;
for (int i = 0; i < indent_depth; i++) indent += ' ';
std::string out;
std::string::size_type pos = 0;
do {
std::string::size_type prev_pos = pos;
pos = str.find('\n', pos);
out.append(indent);
if (pos == std::string::npos) {
out.append(str, prev_pos, std::string::npos);
break;
} else {
pos++;
out.append(str, prev_pos, pos - prev_pos);
}
} while (true);
return out;
}
} // namespace report

View File

@ -1,9 +1,9 @@
#include "node_report.h"
#include "json_utils.h"
#include "gtest/gtest.h"
TEST(ReportUtilTest, EscapeJsonChars) {
using report::EscapeJsonChars;
TEST(JSONUtilsTest, EscapeJsonChars) {
using node::EscapeJsonChars;
EXPECT_EQ("abc", EscapeJsonChars("abc"));
EXPECT_EQ("abc\\n", EscapeJsonChars("abc\n"));
EXPECT_EQ("abc\\nabc", EscapeJsonChars("abc\nabc"));