[JSONSerialization] Introduce ScalarReferenceTraits

For ScalarTraits, a buffer was always created on the heap to which the
scalar string value was written just to be copied to the output buffer
again. In case the value already exists in a memory buffer it is way
cheaper to avoid the heap allocation and copy it straight to the output
buffer.
This commit is contained in:
Alex Hoppen
2018-06-01 13:12:07 -07:00
parent 48eb400a93
commit 07b449bbd5
5 changed files with 117 additions and 31 deletions

View File

@@ -21,6 +21,7 @@
#define SWIFT_BASIC_JSONSERIALIZATION_H #define SWIFT_BASIC_JSONSERIALIZATION_H
#include "swift/Basic/LLVM.h" #include "swift/Basic/LLVM.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringRef.h"
#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ErrorHandling.h"
@@ -110,6 +111,27 @@ struct ScalarTraits {
//static bool mustQuote(StringRef); //static bool mustQuote(StringRef);
}; };
/// This is an optimized form of ScalarTraits in case the scalar value is
/// already present in a memory buffer. For example:
///
/// template<>
/// struct ScalarReferenceTraits<MyType> {
/// static StringRef stringRef(const MyType &val) {
/// // Retrieve scalar value from memory
/// return value.stringValue;
/// }
/// static bool mustQuote(StringRef) { return true; }
/// };
template<typename T>
struct ScalarReferenceTraits {
// Must provide:
//
// Function to return a string representation of the value.
// static StringRef stringRef(const T &value);
//
// Function to determine if the value should be quoted.
// static bool mustQuote(StringRef);
};
/// This class should be specialized by any type that can be 'null' in JSON. /// This class should be specialized by any type that can be 'null' in JSON.
/// For example: /// For example:
@@ -218,6 +240,24 @@ public:
(sizeof(test<ScalarTraits<T>>(nullptr, nullptr)) == 1); (sizeof(test<ScalarTraits<T>>(nullptr, nullptr)) == 1);
}; };
// Test if ScalarReferenceTraits<T> is defined on type T.
template <class T>
struct has_ScalarReferenceTraits
{
using Signature_stringRef = StringRef (*)(const T &);
using Signature_mustQuote = bool (*)(StringRef);
template <typename U>
static char test(SameType<Signature_stringRef, &U::stringRef> *,
SameType<Signature_mustQuote, &U::mustQuote> *);
template <typename U>
static double test(...);
public:
static bool const value =
(sizeof(test<ScalarReferenceTraits<T>>(nullptr, nullptr)) == 1);
};
// Test if ObjectTraits<T> is defined on type T. // Test if ObjectTraits<T> is defined on type T.
template <class T> template <class T>
@@ -327,6 +367,7 @@ struct missingTraits : public std::integral_constant<bool,
!has_ScalarEnumerationTraits<T>::value !has_ScalarEnumerationTraits<T>::value
&& !has_ScalarBitSetTraits<T>::value && !has_ScalarBitSetTraits<T>::value
&& !has_ScalarTraits<T>::value && !has_ScalarTraits<T>::value
&& !has_ScalarReferenceTraits<T>::value
&& !has_NullableTraits<T>::value && !has_NullableTraits<T>::value
&& !has_ObjectTraits<T>::value && !has_ObjectTraits<T>::value
&& !has_ArrayTraits<T>::value> {}; && !has_ArrayTraits<T>::value> {};
@@ -512,20 +553,20 @@ template <typename T> struct ArrayTraits<std::vector<T>> {
}; };
template<> template<>
struct ScalarTraits<bool> { struct ScalarReferenceTraits<bool> {
static void output(const bool &, llvm::raw_ostream &); static StringRef stringRef(const bool &);
static bool mustQuote(StringRef) { return false; } static bool mustQuote(StringRef) { return false; }
}; };
template<> template<>
struct ScalarTraits<StringRef> { struct ScalarReferenceTraits<StringRef> {
static void output(const StringRef &, llvm::raw_ostream &); static StringRef stringRef(const StringRef &);
static bool mustQuote(StringRef S) { return true; } static bool mustQuote(StringRef S) { return true; }
}; };
template<> template<>
struct ScalarTraits<std::string> { struct ScalarReferenceTraits<std::string> {
static void output(const std::string &, llvm::raw_ostream &); static StringRef stringRef(const std::string &);
static bool mustQuote(StringRef S) { return true; } static bool mustQuote(StringRef S) { return true; }
}; };
@@ -624,14 +665,21 @@ template<typename T>
typename std::enable_if<has_ScalarTraits<T>::value,void>::type typename std::enable_if<has_ScalarTraits<T>::value,void>::type
jsonize(Output &out, T &Val, bool) { jsonize(Output &out, T &Val, bool) {
{ {
std::string Storage; SmallString<64> Storage;
llvm::raw_string_ostream Buffer(Storage); llvm::raw_svector_ostream Buffer(Storage);
Buffer.SetUnbuffered();
ScalarTraits<T>::output(Val, Buffer); ScalarTraits<T>::output(Val, Buffer);
StringRef Str = Buffer.str(); StringRef Str = Buffer.str();
out.scalarString(Str, ScalarTraits<T>::mustQuote(Str)); out.scalarString(Str, ScalarTraits<T>::mustQuote(Str));
} }
} }
template <typename T>
typename std::enable_if<has_ScalarReferenceTraits<T>::value, void>::type
jsonize(Output &out, T &Val, bool) {
StringRef Str = ScalarReferenceTraits<T>::stringRef(Val);
out.scalarString(Str, ScalarReferenceTraits<T>::mustQuote(Str));
}
template<typename T> template<typename T>
typename std::enable_if<has_NullableTraits<T>::value,void>::type typename std::enable_if<has_NullableTraits<T>::value,void>::type

View File

@@ -33,20 +33,39 @@ static void *DontSerializeNodeIdsUserInfoKey = &DontSerializeNodeIdsUserInfoKey;
/// Serialization traits for SourcePresence. /// Serialization traits for SourcePresence.
template <> template <>
struct ScalarEnumerationTraits<syntax::SourcePresence> { struct ScalarReferenceTraits<syntax::SourcePresence> {
static void enumeration(json::Output &out, syntax::SourcePresence &value) { static StringRef stringRef(const syntax::SourcePresence &value) {
out.enumCase(value, "Present", syntax::SourcePresence::Present); switch (value) {
out.enumCase(value, "Missing", syntax::SourcePresence::Missing); case syntax::SourcePresence::Present:
return "\"Present\"";
case syntax::SourcePresence::Missing:
return "\"Missing\"";
}
}
static bool mustQuote(StringRef) {
// The string is already quoted. This is more efficient since it does not
// check for characters that need to be escaped
return false;
} }
}; };
/// Serialization traits for swift::tok. /// Serialization traits for swift::tok.
template <> template <>
struct ScalarEnumerationTraits<tok> { struct ScalarReferenceTraits<tok> {
static void enumeration(Output &out, tok &value) { static StringRef stringRef(const tok &value) {
switch (value) {
#define TOKEN(name) \ #define TOKEN(name) \
out.enumCase(value, #name, tok::name); case tok::name: return "\"" #name "\"";
#include "swift/Syntax/TokenKinds.def" #include "swift/Syntax/TokenKinds.def"
default: llvm_unreachable("Unknown token kind");
}
}
static bool mustQuote(StringRef) {
// The string is already quoted. This is more efficient since it does not
// check for characters that need to be escaped
return false;
} }
}; };

View File

@@ -80,13 +80,24 @@ namespace json {
/// Serialization traits for SyntaxKind. /// Serialization traits for SyntaxKind.
template <> template <>
struct ScalarEnumerationTraits<syntax::SyntaxKind> { struct ScalarReferenceTraits<syntax::SyntaxKind> {
static void enumeration(Output &out, syntax::SyntaxKind &value) { static StringRef stringRef(const syntax::SyntaxKind &value) {
out.enumCase(value, "Token", syntax::SyntaxKind::Token); switch (value) {
out.enumCase(value, "Unknown", syntax::SyntaxKind::Unknown); case syntax::SyntaxKind::Token:
return "\"Token\"";
case syntax::SyntaxKind::Unknown:
return "\"Unknown\"";
% for node in SYNTAX_NODES: % for node in SYNTAX_NODES:
out.enumCase(value, "${node.syntax_kind}", syntax::SyntaxKind::${node.syntax_kind}); case syntax::SyntaxKind::${node.syntax_kind}:
return "\"${node.syntax_kind}\"";
% end % end
}
}
static bool mustQuote(StringRef) {
// The string is already quoted. This is more efficient since it does not
// check for characters that need to be escaped
return false;
} }
}; };

View File

@@ -405,11 +405,20 @@ struct ObjectTraits<syntax::TriviaPiece> {
/// Serialization traits for TriviaKind. /// Serialization traits for TriviaKind.
template <> template <>
struct ScalarEnumerationTraits<syntax::TriviaKind> { struct ScalarReferenceTraits<syntax::TriviaKind> {
static void enumeration(Output &out, syntax::TriviaKind &value) { static StringRef stringRef(const syntax::TriviaKind &value) {
switch (value) {
% for trivia in TRIVIAS: % for trivia in TRIVIAS:
out.enumCase(value, "${trivia.name}", syntax::TriviaKind::${trivia.name}); case syntax::TriviaKind::${trivia.name}:
return "\"${trivia.name}\"";
% end % end
}
}
static bool mustQuote(StringRef) {
// The string is already quoted. This is more efficient since it does not
// check for characters that need to be escaped
return false;
} }
}; };
} // namespace json } // namespace json

View File

@@ -231,18 +231,17 @@ void Output::indent() {
// traits for built-in types // traits for built-in types
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
void ScalarTraits<bool>::output(const bool &Val, raw_ostream &Out) { StringRef ScalarReferenceTraits<bool>::stringRef(const bool &Val) {
Out << (Val ? "true" : "false"); return (Val ? "true" : "false");
} }
void ScalarTraits<StringRef>::output(const StringRef &Val, StringRef ScalarReferenceTraits<StringRef>::stringRef(const StringRef &Val) {
raw_ostream &Out) { return Val;
Out << Val;
} }
void ScalarTraits<std::string>::output(const std::string &Val, StringRef
raw_ostream &Out) { ScalarReferenceTraits<std::string>::stringRef(const std::string &Val) {
Out << Val; return Val;
} }
void ScalarTraits<uint8_t>::output(const uint8_t &Val, void ScalarTraits<uint8_t>::output(const uint8_t &Val,