Skip to content
This repository has been archived by the owner on Sep 21, 2020. It is now read-only.

Commit

Permalink
Switch Storage save/load to use raw_ostream/raw_istream.
Browse files Browse the repository at this point in the history
  • Loading branch information
PeterJohnson committed Sep 7, 2017
1 parent d707a07 commit 8e01b68
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 80 deletions.
11 changes: 7 additions & 4 deletions src/main/native/cpp/Storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@
#include <atomic>
#include <condition_variable>
#include <cstddef>
#include <fstream>
#include <functional>
#include <iosfwd>
#include <memory>
#include <mutex>

Expand All @@ -26,8 +24,13 @@

#include "IStorage.h"

namespace llvm {
class raw_ostream;
}

namespace wpi {
class Logger;
class raw_istream;
}

namespace nt {
Expand Down Expand Up @@ -113,9 +116,9 @@ class Storage : public IStorage {

// Stream-based save/load functions (exposed for testing purposes). These
// implement the guts of the filename-based functions.
void SavePersistent(std::ostream& os, bool periodic) const;
void SavePersistent(llvm::raw_ostream& os, bool periodic) const;
bool LoadPersistent(
std::istream& is,
wpi::raw_istream& is,
std::function<void(std::size_t line, const char* msg)> warn);

// RPC configuration needs to come through here as RPC definitions are
Expand Down
86 changes: 43 additions & 43 deletions src/main/native/cpp/Storage_load.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@
#include <cctype>
#include <string>

#include "llvm/SmallString.h"
#include "llvm/StringExtras.h"
#include "support/Base64.h"
#include "support/raw_istream.h"

#include "IDispatcher.h"
#include "IEntryNotifier.h"
Expand All @@ -25,7 +27,7 @@ class LoadPersistentImpl {
typedef std::pair<std::string, std::shared_ptr<Value>> Entry;
typedef std::function<void(std::size_t line, const char* msg)> WarnFunc;

LoadPersistentImpl(std::istream& is, WarnFunc warn)
LoadPersistentImpl(wpi::raw_istream& is, WarnFunc warn)
: m_is(is), m_warn(warn) {}

bool Load(std::vector<Entry>* entries);
Expand All @@ -34,7 +36,7 @@ class LoadPersistentImpl {
bool ReadLine();
bool ReadHeader();
NT_Type ReadType();
bool ReadName(std::string* name);
llvm::StringRef ReadName(llvm::SmallVectorImpl<char>& buf);
std::shared_ptr<Value> ReadValue(NT_Type type);
std::shared_ptr<Value> ReadBooleanValue();
std::shared_ptr<Value> ReadDoubleValue();
Expand All @@ -48,14 +50,13 @@ class LoadPersistentImpl {
if (m_warn) m_warn(m_line_num, msg);
}

std::istream& m_is;
wpi::raw_istream& m_is;
WarnFunc m_warn;

llvm::StringRef m_line;
std::string m_line_buf;
llvm::SmallString<128> m_line_buf;
std::size_t m_line_num = 0;

std::string m_buf_str;
std::vector<int> m_buf_boolean_array;
std::vector<double> m_buf_double_array;
std::vector<std::string> m_buf_string_array;
Expand Down Expand Up @@ -98,52 +99,51 @@ static int fromxdigit(char ch) {
return ch - '0';
}

static void UnescapeString(llvm::StringRef source, std::string* dest) {
static llvm::StringRef UnescapeString(llvm::StringRef source,
llvm::SmallVectorImpl<char>& buf) {
assert(source.size() >= 2 && source.front() == '"' && source.back() == '"');
dest->clear();
dest->reserve(source.size() - 2);
buf.clear();
buf.reserve(source.size() - 2);
for (auto s = source.begin() + 1, end = source.end() - 1; s != end; ++s) {
if (*s != '\\') {
dest->push_back(*s);
buf.push_back(*s);
continue;
}
switch (*++s) {
case '\\':
case '"':
dest->push_back(s[-1]);
buf.push_back(s[-1]);
break;
case 't':
dest->push_back('\t');
buf.push_back('\t');
break;
case 'n':
dest->push_back('\n');
buf.push_back('\n');
break;
case 'x': {
if (!isxdigit(*(s + 1))) {
dest->push_back('x'); // treat it like a unknown escape
buf.push_back('x'); // treat it like a unknown escape
break;
}
int ch = fromxdigit(*++s);
if (isxdigit(*(s + 1))) {
ch <<= 4;
ch |= fromxdigit(*++s);
}
dest->push_back(static_cast<char>(ch));
buf.push_back(static_cast<char>(ch));
break;
}
default:
dest->push_back(s[-1]);
buf.push_back(s[-1]);
break;
}
}
return llvm::StringRef{buf.data(), buf.size()};
}

bool LoadPersistentImpl::Load(std::vector<Entry>* entries) {
if (!ReadHeader()) return false; // header

// declare this outside the loop to reduce reallocs
std::string name;

while (ReadLine()) {
// type
NT_Type type = ReadType();
Expand All @@ -153,7 +153,9 @@ bool LoadPersistentImpl::Load(std::vector<Entry>* entries) {
}

// name
if (!ReadName(&name)) continue;
llvm::SmallString<128> buf;
llvm::StringRef name = ReadName(buf);
if (name.empty()) continue;

// =
m_line = m_line.ltrim(" \t");
Expand All @@ -167,17 +169,16 @@ bool LoadPersistentImpl::Load(std::vector<Entry>* entries) {
auto value = ReadValue(type);

// move to entries
if (!name.empty() && value)
entries->emplace_back(std::move(name), std::move(value));
if (value) entries->emplace_back(name, std::move(value));
}
return true;
}

bool LoadPersistentImpl::ReadLine() {
// ignore blank lines and lines that start with ; or # (comments)
while (std::getline(m_is, m_line_buf)) {
while (!m_is.has_error()) {
++m_line_num;
m_line = llvm::StringRef(m_line_buf).trim();
m_line = m_is.getline(m_line_buf, INT_MAX).trim();
if (!m_line.empty() && m_line.front() != ';' && m_line.front() != '#')
return true;
}
Expand Down Expand Up @@ -217,19 +218,18 @@ NT_Type LoadPersistentImpl::ReadType() {
return NT_UNASSIGNED;
}

bool LoadPersistentImpl::ReadName(std::string* name) {
llvm::StringRef LoadPersistentImpl::ReadName(llvm::SmallVectorImpl<char>& buf) {
llvm::StringRef tok;
std::tie(tok, m_line) = ReadStringToken(m_line);
if (tok.empty()) {
Warn("missing name");
return false;
return llvm::StringRef{};
}
if (tok.back() != '"') {
Warn("unterminated name string");
return false;
return llvm::StringRef{};
}
UnescapeString(tok, name);
return true;
return UnescapeString(tok, buf);
}

std::shared_ptr<Value> LoadPersistentImpl::ReadValue(NT_Type type) {
Expand Down Expand Up @@ -263,10 +263,9 @@ std::shared_ptr<Value> LoadPersistentImpl::ReadBooleanValue() {

std::shared_ptr<Value> LoadPersistentImpl::ReadDoubleValue() {
// need to convert to null-terminated string for strtod()
m_buf_str.clear();
m_buf_str += m_line;
llvm::SmallString<64> buf;
char* end;
double v = std::strtod(m_buf_str.c_str(), &end);
double v = std::strtod(m_line.c_str(buf), &end);
if (*end != '\0') {
Warn("invalid double value");
return nullptr;
Expand All @@ -285,13 +284,14 @@ std::shared_ptr<Value> LoadPersistentImpl::ReadStringValue() {
Warn("unterminated string value");
return nullptr;
}
UnescapeString(tok, &m_buf_str);
return Value::MakeString(std::move(m_buf_str));
llvm::SmallString<128> buf;
return Value::MakeString(UnescapeString(tok, buf));
}

std::shared_ptr<Value> LoadPersistentImpl::ReadRawValue() {
wpi::Base64Decode(m_line, &m_buf_str);
return Value::MakeRaw(std::move(m_buf_str));
llvm::SmallString<128> buf;
std::size_t nr;
return Value::MakeRaw(wpi::Base64Decode(m_line, &nr, buf));
}

std::shared_ptr<Value> LoadPersistentImpl::ReadBooleanArrayValue() {
Expand Down Expand Up @@ -319,10 +319,9 @@ std::shared_ptr<Value> LoadPersistentImpl::ReadDoubleArrayValue() {
std::tie(tok, m_line) = m_line.split(',');
tok = tok.trim(" \t");
// need to convert to null-terminated string for strtod()
m_buf_str.clear();
m_buf_str += tok;
llvm::SmallString<64> buf;
char* end;
double v = std::strtod(m_buf_str.c_str(), &end);
double v = std::strtod(tok.c_str(buf), &end);
if (*end != '\0') {
Warn("invalid double value");
return nullptr;
Expand All @@ -347,8 +346,8 @@ std::shared_ptr<Value> LoadPersistentImpl::ReadStringArrayValue() {
return nullptr;
}

UnescapeString(tok, &m_buf_str);
m_buf_string_array.push_back(std::move(m_buf_str));
llvm::SmallString<128> buf;
m_buf_string_array.push_back(UnescapeString(tok, buf));

m_line = m_line.ltrim(" \t");
if (m_line.empty()) break;
Expand All @@ -363,7 +362,7 @@ std::shared_ptr<Value> LoadPersistentImpl::ReadStringArrayValue() {
}

bool Storage::LoadPersistent(
std::istream& is,
wpi::raw_istream& is,
std::function<void(std::size_t line, const char* msg)> warn) {
// entries to add
std::vector<LoadPersistentImpl::Entry> entries;
Expand Down Expand Up @@ -434,8 +433,9 @@ bool Storage::LoadPersistent(
const char* Storage::LoadPersistent(
StringRef filename,
std::function<void(std::size_t line, const char* msg)> warn) {
std::ifstream is(filename);
if (!is) return "could not open file";
std::error_code ec;
wpi::raw_fd_istream is(filename, ec);
if (ec.value() != 0) return "could not open file";
if (!LoadPersistent(is, warn)) return "error reading file";
return nullptr;
}
34 changes: 17 additions & 17 deletions src/main/native/cpp/Storage_save.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@
#include <cctype>
#include <string>

#include "llvm/Format.h"
#include "llvm/SmallString.h"
#include "llvm/StringExtras.h"
#include "llvm/raw_ostream.h"
#include "support/Base64.h"

#include "Log.h"
Expand All @@ -23,7 +26,7 @@ class SavePersistentImpl {
public:
typedef std::pair<std::string, std::shared_ptr<Value>> Entry;

SavePersistentImpl(std::ostream& os) : m_os(os) {}
SavePersistentImpl(llvm::raw_ostream& os) : m_os(os) {}

void Save(llvm::ArrayRef<Entry> entries);

Expand All @@ -35,7 +38,7 @@ class SavePersistentImpl {
bool WriteType(NT_Type type);
void WriteValue(const Value& value);

std::ostream& m_os;
llvm::raw_ostream& m_os;
};

} // anonymous namespace
Expand Down Expand Up @@ -131,15 +134,13 @@ void SavePersistentImpl::WriteValue(const Value& value) {
m_os << (value.GetBoolean() ? "true" : "false");
break;
case NT_DOUBLE:
m_os << value.GetDouble();
m_os << llvm::format("%g", value.GetDouble());
break;
case NT_STRING:
WriteString(value.GetString());
break;
case NT_RAW: {
std::string base64_encoded;
wpi::Base64Encode(value.GetRaw(), &base64_encoded);
m_os << base64_encoded;
wpi::Base64Encode(m_os, value.GetRaw());
break;
}
case NT_BOOLEAN_ARRAY: {
Expand All @@ -156,7 +157,7 @@ void SavePersistentImpl::WriteValue(const Value& value) {
for (auto elem : value.GetDoubleArray()) {
if (!first) m_os << ',';
first = false;
m_os << elem;
m_os << llvm::format("%g", elem);
}
break;
}
Expand All @@ -174,17 +175,17 @@ void SavePersistentImpl::WriteValue(const Value& value) {
}
}

void Storage::SavePersistent(std::ostream& os, bool periodic) const {
void Storage::SavePersistent(llvm::raw_ostream& os, bool periodic) const {
std::vector<SavePersistentImpl::Entry> entries;
if (!GetPersistentEntries(periodic, &entries)) return;
SavePersistentImpl(os).Save(entries);
}

const char* Storage::SavePersistent(StringRef filename, bool periodic) const {
std::string fn = filename;
std::string tmp = filename;
llvm::SmallString<128> fn = filename;
llvm::SmallString<128> tmp = filename;
tmp += ".tmp";
std::string bak = filename;
llvm::SmallString<128> bak = filename;
bak += ".bak";

// Get entries before creating file
Expand All @@ -194,21 +195,20 @@ const char* Storage::SavePersistent(StringRef filename, bool periodic) const {
const char* err = nullptr;

// start by writing to temporary file
std::ofstream os(tmp);
if (!os) {
std::error_code ec;
llvm::raw_fd_ostream os(tmp, ec, llvm::sys::fs::F_Text);
if (ec.value() != 0) {
err = "could not open file";
goto done;
}
DEBUG("saving persistent file '" << filename << "'");
SavePersistentImpl(os).Save(entries);
os.flush();
if (!os) {
os.close();
os.close();
if (os.has_error()) {
std::remove(tmp.c_str());
err = "error saving file";
goto done;
}
os.close();

// Safely move to real file. We ignore any failures related to the backup.
std::remove(bak.c_str());
Expand Down
Loading

0 comments on commit 8e01b68

Please sign in to comment.