Finish LoadPersistent().

Change-Id: I5c4c439dc3d2585f2edae74f78c14f826b091186
This commit is contained in:
Peter Johnson
2015-06-29 23:08:35 -07:00
parent cb30bb5d70
commit b66fb68f29
3 changed files with 288 additions and 50 deletions

View File

@@ -236,10 +236,21 @@ bool Storage::LoadPersistent(std::istream& is,
void (*warn)(std::size_t line, const char* msg)) {
std::string line_str;
std::size_t line_num = 1;
std::string name;
// declare these outside the loop to reduce reallocs
std::string name, str;
std::vector<int> boolean_array;
std::vector<double> double_array;
std::vector<StringValue> string_array;
// ignore blank lines and lines that start with ; or # (comments)
while (std::getline(is, line_str)) {
llvm::StringRef line = llvm::StringRef(line_str).trim();
if (!line.empty() && line.front() != ';' && line.front() != '#')
break;
}
// header
std::getline(is, line_str);
if (line_str != "[NetworkTables Storage 3.0]") {
if (warn) warn(line_num, "header line mismatch, ignoring rest of file");
return false;
@@ -249,6 +260,10 @@ bool Storage::LoadPersistent(std::istream& is,
llvm::StringRef line = llvm::StringRef(line_str).trim();
++line_num;
// ignore blank lines and lines that start with ; or # (comments)
if (line.empty() || line.front() == ';' || line.front() == '#')
continue;
// type
llvm::StringRef type_tok;
std::tie(type_tok, line) = line.split(' ');
@@ -294,50 +309,124 @@ bool Storage::LoadPersistent(std::istream& is,
StorageEntry entry;
switch (type) {
case NT_BOOLEAN:
//os << (v.data.v_boolean ? "true" : "false");
//if (line == "true")
//entry.value.
// only true or false is accepted
if (line == "true")
entry.value().SetBoolean(true);
else if (line == "false")
entry.value().SetBoolean(false);
else {
if (warn)
warn(line_num, "unrecognized boolean value, not 'true' or 'false'");
goto next_line;
}
break;
case NT_DOUBLE:
//os << v.data.v_double;
break;
case NT_STRING:
//WriteString(os, MakeStringRef(v.data.v_string));
break;
case NT_RAW: {
//char* buf = new char[Base64EncodeLen(v.data.v_raw.len)];
//Base64Encode(buf,
//reinterpret_cast<const unsigned char*>(v.data.v_raw.str),
//v.data.v_raw.len);
//os << buf;
//delete[] buf;
case NT_DOUBLE: {
// need to convert to null-terminated string for strtod()
str.clear();
str += line;
char* end;
double v = std::strtod(str.c_str(), &end);
if (*end != '\0') {
if (warn) warn(line_num, "invalid double value");
goto next_line;
}
entry.value().SetDouble(v);
break;
}
case NT_BOOLEAN_ARRAY:
//for (size_t i = 0; i < v.data.arr_boolean.size; ++i) {
//os << (v.data.arr_boolean.arr[i] ? "true" : "false");
//if (i != (v.data.arr_boolean.size - 1))
//os << ',';
//}
case NT_STRING: {
llvm::StringRef str_tok;
std::tie(str_tok, line) = ReadStringToken(line);
if (str_tok.empty()) {
if (warn) warn(line_num, "missing string value");
goto next_line;
}
if (str_tok.back() != '"') {
if (warn) warn(line_num, "unterminated string value");
goto next_line;
}
UnescapeString(str_tok, &str);
entry.value().SetString(str);
break;
case NT_DOUBLE_ARRAY:
//for (size_t i = 0; i < v.data.arr_double.size; ++i) {
//os << v.data.arr_double.arr[i];
//if (i != (v.data.arr_double.size - 1))
//os << ',';
//}
}
case NT_RAW:
Base64Decode(line, &str);
entry.value().SetRaw(str);
break;
case NT_STRING_ARRAY:
//for (size_t i = 0; i < v.data.arr_double.size; ++i) {
//WriteString(os, MakeStringRef(v.data.arr_string.arr[i]));
//if (i != (v.data.arr_double.size - 1))
//os << ',';
//}
case NT_BOOLEAN_ARRAY: {
llvm::StringRef elem_tok;
boolean_array.clear();
while (!line.empty()) {
std::tie(elem_tok, line) = line.split(',');
elem_tok = elem_tok.trim(" \t");
if (elem_tok == "true")
boolean_array.push_back(1);
else if (elem_tok == "false")
boolean_array.push_back(0);
else {
if (warn)
warn(line_num,
"unrecognized boolean value, not 'true' or 'false'");
goto next_line;
}
}
entry.value().SetBooleanArray(boolean_array);
break;
}
case NT_DOUBLE_ARRAY: {
llvm::StringRef elem_tok;
double_array.clear();
while (!line.empty()) {
std::tie(elem_tok, line) = line.split(',');
elem_tok = elem_tok.trim(" \t");
// need to convert to null-terminated string for strtod()
str.clear();
str += elem_tok;
char* end;
double v = std::strtod(str.c_str(), &end);
if (*end != '\0') {
if (warn) warn(line_num, "invalid double value");
goto next_line;
}
double_array.push_back(v);
}
entry.value().SetDoubleArray(double_array);
break;
}
case NT_STRING_ARRAY: {
llvm::StringRef elem_tok;
double_array.clear();
while (!line.empty()) {
std::tie(elem_tok, line) = ReadStringToken(line);
if (elem_tok.empty()) {
if (warn) warn(line_num, "missing string value");
goto next_line;
}
if (elem_tok.back() != '"') {
if (warn) warn(line_num, "unterminated string value");
goto next_line;
}
line = line.ltrim(" \t");
if (line.empty()) break;
if (line.front() != ',') {
if (warn) warn(line_num, "expected comma between strings");
goto next_line;
}
line = line.drop_front().ltrim(" \t");
UnescapeString(elem_tok, &str);
string_array.push_back(StringValue(str));
}
entry.value().SetStringArray(string_array);
break;
}
default:
break;
}
next_line:
;
}
return true;
}

View File

@@ -8,10 +8,94 @@
#include "Value.h"
#include <cassert>
#include <cstdlib>
#include <cstring>
#include "ntcore.h"
using namespace ntimpl;
StringValue::StringValue(llvm::StringRef val) {
len = val.size();
str = static_cast<char*>(std::malloc(len+1));
std::memcpy(str, val.data(), len);
str[len] = '\0';
}
void Value::SetBooleanArray(llvm::ArrayRef<int> value) {
// handle type change
if (NT_Value::type != NT_BOOLEAN_ARRAY) {
NT_DisposeValue(this);
data.arr_boolean.arr = nullptr;
data.arr_boolean.size = 0; // set to zero so size change is hit below
NT_Value::type = NT_BOOLEAN_ARRAY;
}
// handle size change
if (data.arr_boolean.size != value.size()) {
std::free(data.arr_boolean.arr);
data.arr_boolean.arr =
static_cast<int*>(std::malloc(value.size()*sizeof(int)));
data.arr_boolean.size = value.size();
}
std::copy(value.begin(), value.end(), data.arr_boolean.arr);
}
void Value::SetBooleanArray(llvm::ArrayRef<bool> value) {
// handle type change
if (NT_Value::type != NT_BOOLEAN_ARRAY) {
NT_DisposeValue(this);
data.arr_boolean.arr = nullptr;
data.arr_boolean.size = 0; // set to zero so size change is hit below
NT_Value::type = NT_BOOLEAN_ARRAY;
}
// handle size change
if (data.arr_boolean.size != value.size()) {
std::free(data.arr_boolean.arr);
data.arr_boolean.arr =
static_cast<int*>(std::malloc(value.size()*sizeof(int)));
data.arr_boolean.size = value.size();
}
std::copy(value.begin(), value.end(), data.arr_boolean.arr);
}
void Value::SetDoubleArray(llvm::ArrayRef<double> value) {
// handle type change
if (NT_Value::type != NT_DOUBLE_ARRAY) {
NT_DisposeValue(this);
data.arr_double.arr = nullptr;
data.arr_double.size = 0; // set to zero so size change is hit below
NT_Value::type = NT_DOUBLE_ARRAY;
}
// handle size change
if (data.arr_double.size != value.size()) {
std::free(data.arr_double.arr);
data.arr_double.arr =
static_cast<double*>(std::malloc(value.size()*sizeof(double)));
data.arr_double.size = value.size();
}
std::copy(value.begin(), value.end(), data.arr_double.arr);
}
void Value::SetStringArray(std::vector<StringValue>& value) {
// handle type change
if (NT_Value::type != NT_STRING_ARRAY) {
NT_DisposeValue(this);
data.arr_string.arr = nullptr;
data.arr_string.size = 0; // set to zero so size change is hit below
NT_Value::type = NT_STRING_ARRAY;
}
// handle size change
if (data.arr_string.size != value.size()) {
std::free(data.arr_string.arr);
data.arr_string.arr =
static_cast<NT_String*>(std::malloc(value.size()*sizeof(NT_String)));
data.arr_string.size = value.size();
}
std::move(value.begin(), value.end(),
static_cast<StringValue*>(data.arr_string.arr));
value.clear();
}
bool ntimpl::operator==(const Value& lhs, const Value& rhs) {
if (lhs.type() != rhs.type()) return false;
switch (lhs.type()) {

View File

@@ -9,6 +9,7 @@
#define NT_VALUE_H_
#include <cassert>
#include <vector>
#include "ntcore.h"
@@ -27,12 +28,31 @@ class StringValue : private NT_String {
friend class Value;
public:
StringValue() { NT_InitString(this); }
/*implicit*/ StringValue(llvm::StringRef val);
~StringValue() { NT_DisposeString(this); }
operator llvm::StringRef() const { return llvm::StringRef(str, len); }
StringValue(const StringValue&) = delete;
StringValue& operator=(const StringValue&) = delete;
StringValue(StringValue&& other) {
str = other.str;
len = other.len;
other.str = nullptr;
other.len = 0;
}
StringValue& operator=(StringValue&& other) {
if (this != &other) {
NT_DisposeString(this);
str = other.str;
len = other.len;
other.str = nullptr;
other.len = 0;
}
return *this;
}
};
/*
@@ -85,26 +105,71 @@ class Value : private NT_Value {
/*
* Type-Safe Setters
*/
void SetBoolean(bool value);
void SetDouble(double value);
void SetString(llvm::StringRef value);
void SetRaw(llvm::StringRef value);
template<typename It>
void SetBooleanArray(It begin, It end) {
void SetBoolean(bool value) {
if (NT_Value::type != NT_BOOLEAN) {
NT_DisposeValue(this);
NT_Value::type = NT_BOOLEAN;
}
data.v_boolean = value ? 1 : 0;
}
void SetDouble(double value) {
if (NT_Value::type != NT_DOUBLE) {
NT_DisposeValue(this);
NT_Value::type = NT_DOUBLE;
}
data.v_double = value;
}
void SetString(llvm::StringRef value) { SetString(StringValue(value)); }
void SetString(StringValue&& value) {
if (NT_Value::type != NT_STRING) {
NT_DisposeValue(this);
data.v_string.str = nullptr;
data.v_string.len = 0;
NT_Value::type = NT_STRING;
}
data.v_string = value;
}
void SetRaw(llvm::StringRef value) { SetRaw(StringValue(value)); }
void SetRaw(StringValue&& value) {
if (NT_Value::type != NT_RAW) {
NT_DisposeValue(this);
data.v_raw.str = nullptr;
data.v_raw.len = 0;
NT_Value::type = NT_RAW;
}
data.v_raw = value;
}
template<typename It>
void SetDoubleArray(It begin, It end) {
}
void SetBooleanArray(llvm::ArrayRef<int> value);
void SetBooleanArray(llvm::ArrayRef<bool> value);
void SetDoubleArray(llvm::ArrayRef<double> value);
template<typename It>
void SetStringArray(It begin, It end) {
}
// Note: This function moves the values out of the vector.
void SetStringArray(std::vector<StringValue>& value);
Value(const Value&) = delete;
Value& operator=(const Value&) = delete;
Value(Value&& other) {
NT_Value::type = static_cast<NT_Value&>(other).type;
last_change = other.last_change;
data = other.data;
static_cast<NT_Value&>(other).type = NT_UNASSIGNED;
other.last_change = 0;
}
Value& operator=(Value&& other) {
if (this != &other) {
NT_DisposeValue(this);
NT_Value::type = static_cast<NT_Value&>(other).type;
last_change = other.last_change;
data = other.data;
static_cast<NT_Value&>(other).type = NT_UNASSIGNED;
other.last_change = 0;
}
return *this;
}
friend bool operator==(const Value& lhs, const Value& rhs);
};