StringRef will call strlen on the C string which is inefficient (as ConstString already knows the string lenght and so does StringRef). This patch replaces all those calls with GetStringRef() which doesn't recompute the length.
173 lines
5.1 KiB
C++
173 lines
5.1 KiB
C++
//===-- StructuredData.cpp ------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "lldb/Utility/StructuredData.h"
|
|
#include "lldb/Utility/FileSpec.h"
|
|
#include "lldb/Utility/Status.h"
|
|
#include "llvm/Support/MemoryBuffer.h"
|
|
#include <cerrno>
|
|
#include <cstdlib>
|
|
#include <inttypes.h>
|
|
|
|
using namespace lldb_private;
|
|
using namespace llvm;
|
|
|
|
static StructuredData::ObjectSP ParseJSONValue(json::Value &value);
|
|
static StructuredData::ObjectSP ParseJSONObject(json::Object *object);
|
|
static StructuredData::ObjectSP ParseJSONArray(json::Array *array);
|
|
|
|
StructuredData::ObjectSP StructuredData::ParseJSON(std::string json_text) {
|
|
llvm::Expected<json::Value> value = json::parse(json_text);
|
|
if (!value) {
|
|
llvm::consumeError(value.takeError());
|
|
return nullptr;
|
|
}
|
|
return ParseJSONValue(*value);
|
|
}
|
|
|
|
StructuredData::ObjectSP
|
|
StructuredData::ParseJSONFromFile(const FileSpec &input_spec, Status &error) {
|
|
StructuredData::ObjectSP return_sp;
|
|
|
|
auto buffer_or_error = llvm::MemoryBuffer::getFile(input_spec.GetPath());
|
|
if (!buffer_or_error) {
|
|
error.SetErrorStringWithFormatv("could not open input file: {0} - {1}.",
|
|
input_spec.GetPath(),
|
|
buffer_or_error.getError().message());
|
|
return return_sp;
|
|
}
|
|
return ParseJSON(buffer_or_error.get()->getBuffer().str());
|
|
}
|
|
|
|
static StructuredData::ObjectSP ParseJSONValue(json::Value &value) {
|
|
if (json::Object *O = value.getAsObject())
|
|
return ParseJSONObject(O);
|
|
|
|
if (json::Array *A = value.getAsArray())
|
|
return ParseJSONArray(A);
|
|
|
|
std::string s;
|
|
if (json::fromJSON(value, s))
|
|
return std::make_shared<StructuredData::String>(s);
|
|
|
|
bool b;
|
|
if (json::fromJSON(value, b))
|
|
return std::make_shared<StructuredData::Boolean>(b);
|
|
|
|
int64_t i;
|
|
if (json::fromJSON(value, i))
|
|
return std::make_shared<StructuredData::Integer>(i);
|
|
|
|
double d;
|
|
if (json::fromJSON(value, d))
|
|
return std::make_shared<StructuredData::Float>(d);
|
|
|
|
return StructuredData::ObjectSP();
|
|
}
|
|
|
|
static StructuredData::ObjectSP ParseJSONObject(json::Object *object) {
|
|
auto dict_up = std::make_unique<StructuredData::Dictionary>();
|
|
for (auto &KV : *object) {
|
|
StringRef key = KV.first;
|
|
json::Value value = KV.second;
|
|
if (StructuredData::ObjectSP value_sp = ParseJSONValue(value))
|
|
dict_up->AddItem(key, value_sp);
|
|
}
|
|
return std::move(dict_up);
|
|
}
|
|
|
|
static StructuredData::ObjectSP ParseJSONArray(json::Array *array) {
|
|
auto array_up = std::make_unique<StructuredData::Array>();
|
|
for (json::Value &value : *array) {
|
|
if (StructuredData::ObjectSP value_sp = ParseJSONValue(value))
|
|
array_up->AddItem(value_sp);
|
|
}
|
|
return std::move(array_up);
|
|
}
|
|
|
|
StructuredData::ObjectSP
|
|
StructuredData::Object::GetObjectForDotSeparatedPath(llvm::StringRef path) {
|
|
if (this->GetType() == lldb::eStructuredDataTypeDictionary) {
|
|
std::pair<llvm::StringRef, llvm::StringRef> match = path.split('.');
|
|
std::string key = match.first.str();
|
|
ObjectSP value = this->GetAsDictionary()->GetValueForKey(key);
|
|
if (value.get()) {
|
|
// Do we have additional words to descend? If not, return the value
|
|
// we're at right now.
|
|
if (match.second.empty()) {
|
|
return value;
|
|
} else {
|
|
return value->GetObjectForDotSeparatedPath(match.second);
|
|
}
|
|
}
|
|
return ObjectSP();
|
|
}
|
|
|
|
if (this->GetType() == lldb::eStructuredDataTypeArray) {
|
|
std::pair<llvm::StringRef, llvm::StringRef> match = path.split('[');
|
|
if (match.second.empty()) {
|
|
return this->shared_from_this();
|
|
}
|
|
errno = 0;
|
|
uint64_t val = strtoul(match.second.str().c_str(), nullptr, 10);
|
|
if (errno == 0) {
|
|
return this->GetAsArray()->GetItemAtIndex(val);
|
|
}
|
|
return ObjectSP();
|
|
}
|
|
|
|
return this->shared_from_this();
|
|
}
|
|
|
|
void StructuredData::Object::DumpToStdout(bool pretty_print) const {
|
|
json::OStream stream(llvm::outs(), pretty_print ? 2 : 0);
|
|
Serialize(stream);
|
|
}
|
|
|
|
void StructuredData::Array::Serialize(json::OStream &s) const {
|
|
s.arrayBegin();
|
|
for (const auto &item_sp : m_items) {
|
|
item_sp->Serialize(s);
|
|
}
|
|
s.arrayEnd();
|
|
}
|
|
|
|
void StructuredData::Integer::Serialize(json::OStream &s) const {
|
|
s.value(static_cast<int64_t>(m_value));
|
|
}
|
|
|
|
void StructuredData::Float::Serialize(json::OStream &s) const {
|
|
s.value(m_value);
|
|
}
|
|
|
|
void StructuredData::Boolean::Serialize(json::OStream &s) const {
|
|
s.value(m_value);
|
|
}
|
|
|
|
void StructuredData::String::Serialize(json::OStream &s) const {
|
|
s.value(m_value);
|
|
}
|
|
|
|
void StructuredData::Dictionary::Serialize(json::OStream &s) const {
|
|
s.objectBegin();
|
|
for (const auto &pair : m_dict) {
|
|
s.attributeBegin(pair.first.GetStringRef());
|
|
pair.second->Serialize(s);
|
|
s.attributeEnd();
|
|
}
|
|
s.objectEnd();
|
|
}
|
|
|
|
void StructuredData::Null::Serialize(json::OStream &s) const {
|
|
s.value(nullptr);
|
|
}
|
|
|
|
void StructuredData::Generic::Serialize(json::OStream &s) const {
|
|
s.value(llvm::formatv("{0:X}", m_object));
|
|
}
|