mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-07-06 03:31:43 +00:00
Finish LoadPersistent().
Change-Id: I5c4c439dc3d2585f2edae74f78c14f826b091186
This commit is contained in:
163
src/Storage.cpp
163
src/Storage.cpp
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
91
src/Value.h
91
src/Value.h
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user