PROTOBUFF INT64 check aganist previously entered data c++ - c++

message HealthOccurrenceCount
{
required int64 HealthID=1;
required int32 OccCount=2;
optional bytes wci=3;
}
I would like to add data based on HealthID; If HealthID is already entered then instead of adding a new entry, the program should instead just increment the existing entry's OccCount.
HealthOccurrenceCount objHelthOccCount;
if(objHelthOccCount.healthid() == healthID) // Is this right or do I need to iterate all the nodes?
{
occCount++;
objHelthOccCount.set_occcount(occCount);
}
else
occCount = 1;
Is this code correct or I should convert HealthID into string?
Generated Code:
// required int64 HealthID = 1;
inline bool has_healthid() const;
inline void clear_healthid();
static const int kHealthIDFieldNumber = 1;
inline ::google::protobuf::int64 healthid() const;
inline void set_healthid(::google::protobuf::int64 value);

According to the doc there is a has_ methods for each singular (required or optional) field which return true if that field has been set.
Your code would then be something like:
HealthOccurrenceCount objHelthOccCount;
if(objHelthOccCount.has_healthid())
{
occCount++;
objHelthOccCount.set_occcount(occCount);
}
else
occCount = 1;

Related

Create a lookup table for array of classes in C++/Arduino

I have multiple types of classes.
Each type has an array and an index in the array.
If an outside function knows only a string ID of a class and wants to use it's public function,
it must search for that particular class by ID in it's array.
This is really inefficient.
All my classes created at runtime and a function which creates it, puts it into an array.
I want to create a lookup table of some sort for this when the classes are created, so any outside
function if wants to use one class it does not have to for loop on the class's array and check each ID if it matches but to be able to reach the class by some struct or array.
Here how it is done now:
#define MAX_ONE_TYPES 20
int createdOneTypesCounter = 0;
// Create one type of classes in one for loop and put it into an array.
// We must keep track of the index because a class can be created later
// at runtime so we must keep increasing the index. I don't check for max index now...
// oneTypes is a JSON OBJECT
for (JsonPair oneTypeRef: oneTypes) {
const char* oneTypeID = oneTypeRef.key().c_str();
JsonObject oneTypeOptions = oneTypes[oneTypeID];
oneTypeClasses[createdOneTypesCounter ] = new oneTypeClass(oneTypeOptions);
createdOneTypesCounter++;
}
class oneTypeClass{
private:
// using an external ram for this kinda stuffs.
const size_t IDS_AND_NAMES_SIZE = 500;
const char * id = (char *) ps_malloc (IDS_AND_NAMES_SIZE * sizeof (char));
public:
thermHandler(JsonObject options){
// She got an ID on creation.
id = strdup(options["id"]);
}
void setModes(boolean mode){
// set some mode...
}
boolean isMyID(const char* packetID){
if( strcmp(id, packetID) == 0 ){return true;}
return false;
}
};
oneTypeClass* oneTypeClasses[MAX_ONE_TYPES] EXT_RAM_ATTR;
// Here comes an outside function. Wants to set a boolean in a class with specific ID.
static const inline void setOneTypeMode(JsonObject packet){
for(int i = 0; i < MAX_ONE_TYPES; i++){
if(oneTypeClasses[i] != NULL && oneTypeClasses[i]->isMyID(packet["id"])){
oneTypeClasses[i]->setModes(packet["mode"]);
break;
}
}
}
And here is my problem. I must search for a class by ID every time some outside function wants to do something with one of the classes.
I don't know how would i do it.
In JS i would create an object for a lookup table and every time a class is created i would put it's ID for the key and it's index to the value like this:
var oneTypeClass_Lookup{
"CLASS ID STRING" : "CLASS INDEX IN ARRAY"
};
//And a function would do it like this:
static const inline void setOneTypeMode(JsonObject packet){
int myClassIndex = oneTypeClass_Lookup[ packet["id"] ];
oneTypeClasses[myClassIndex]->setModes(packet["mode"]);
}
I'm doing this for "mass operation":
static const inline int getOneTypeClassIndex(const char* packetID){
for(int i = 0; i < MAX_THERMS; i++){
if(oneTypeClasses[i] != NULL && oneTypeClasses[i]->isMyID(packetID)){
return i;
}
}
return -1;
}
static const inline void setThing(int newThing, const char* packetID){
int index = getOneTypeClassIndex(packetID);
if( index > -1 ){
oneTypeClasses[index]->setNewThing(newThing);
}
}
static const inline void setThing_Two(int newThing, const char* packetID){
int index = getOneTypeClassIndex(packetID);
if( index > -1 ){
oneTypeClasses[index]->setNewThing(newThing);
}
}
But i can't do this in C or Arduino C++. I hope i was clear.
UI: Class id consist of numbers and characrers. The id can never start with a number. Example: "v_kw62ffss_xg0syjlvrokbxciv65a8y"

Import CSV into Vertica using Rfc4180CsvParser and exclude header row

Is there a way to exclude the header row when importing data via the Rfc4180CsvParser? The COPY command has a SKIP option but the option doesn't seem to work when using the CSV parsers provided in the Vertica SDK.
Background
As background, the COPY command does not read CSV files by itself. For simple CSV files, one can say COPY schema.table FROM '/data/myfile.csv' DELIMITER ',' ENCLOSED BY '"'; but this will fail with data files which have string values with embedded quotes.
Adding ESCAPE AS '"' will generate an error ERROR 3169: ENCLOSED BY and ESCAPE AS can not be the same value . This is a problem as CSV values are enclosed and escaped by ".
Vertica SDK CsvParser extensions to the rescue
Vertica provides an SDK under /opt/vertica/sdk/examples with C++ programs that can be compiled into extensions. One of these is /opt/vertica/sdk/examples/ParserFunctions/Rfc4180CsvParser.cpp.
This works great as follows:
cd /opt/vertica/sdk/examples
make clean
vsql
==> CREATE LIBRARY Rfc4180CsvParserLib AS '/opt/vertica/sdk/examples/build/Rfc4180CsvParser.so';
==> COPY myschema.mytable FROM '/data/myfile.csv' WITH PARSER Rfc4180CsvParser();
Problem
The above works great except that it imports the first row of the data file as a row. The COPY command has a SKIP 1 option but this does not work with the parser.
Question
Is it possble to edit Rfc4180CsvParser.cpp to skip the first row, or better yet, take some parameter to specify number of rows to skip?
The program is just 135 lines but I don't see where/how to make this incision. Hints?
Copying the entire program below as I don't see a public repo to link to...
Rfc4180CsvParser.cpp
/* Copyright (c) 2005 - 2012 Vertica, an HP company -*- C++ -*- */
#include "Vertica.h"
#include "StringParsers.h"
#include "csv.h"
using namespace Vertica;
// Note, the class template is mostly for demonstration purposes,
// so that the same class can use each of two string-parsers.
// Custom parsers can also just pick a string-parser to use.
/**
* A parser that parses something approximating the "official" CSV format
* as defined in IETF RFC-4180: <http://tools.ietf.org/html/rfc4180>
* Oddly enough, many "CSV" files don't actually conform to this standard
* for one reason or another. But for sources that do, this parser should
* be able to handle the data.
* Note that the CSV format does not specify how to handle different
* data types; it is entirely a string-based format.
* So we just use standard parsers based on the corresponding column type.
*/
template <class StringParsersImpl>
class LibCSVParser : public UDParser {
public:
LibCSVParser() : colNum(0) {}
// Keep a copy of the information about each column.
// Note that Vertica doesn't let us safely keep a reference to
// the internal copy of this data structure that it shows us.
// But keeping a copy is fine.
SizedColumnTypes colInfo;
// An instance of the class containing the methods that we're
// using to parse strings to the various relevant data types
StringParsersImpl sp;
/// Current column index
size_t colNum;
/// Parsing state for libcsv
struct csv_parser parser;
// Format strings
std::vector<std::string> formatStrings;
/**
* Given a field in string form (a pointer to the first character and
* a length), submit that field to Vertica.
* `colNum` is the column number from the input file; how many fields
* it is into the current record.
*/
bool handleField(size_t colNum, char* start, size_t len) {
if (colNum >= colInfo.getColumnCount()) {
// Ignore column overflow
return false;
}
// Empty colums are null.
if (len==0) {
writer->setNull(colNum);
return true;
} else {
return parseStringToType(start, len, colNum, colInfo.getColumnType(c
olNum), writer, sp);
}
}
static void handle_record(void *data, size_t len, void *p) {
static_cast<LibCSVParser*>(p)->handleField(static_cast<LibCSVParser*>(p)
->colNum++, (char*)data, len);
}
static void handle_end_of_row(int c, void *p) {
// Ignore 'c' (the terminating character); trust that it's correct
static_cast<LibCSVParser*>(p)->colNum = 0;
static_cast<LibCSVParser*>(p)->writer->next();
}
virtual StreamState process(ServerInterface &srvInterface, DataBuffer &input
, InputState input_state) {
size_t processed;
while ((processed = csv_parse(&parser, input.buf + input.offset, input.s
ize - input.offset,
handle_record, handle_end_of_row, this)) > 0) {
input.offset += processed;
}
if (input_state == END_OF_FILE && input.size == input.offset) {
csv_fini(&parser, handle_record, handle_end_of_row, this);
return DONE;
}
return INPUT_NEEDED;
}
virtual void setup(ServerInterface &srvInterface, SizedColumnTypes &returnTy
pe);
virtual void destroy(ServerInterface &srvInterface, SizedColumnTypes &return
Type) {
csv_free(&parser);
}
};
template <class StringParsersImpl>
void LibCSVParser<StringParsersImpl>::setup(ServerInterface &srvInterface, Sized
ColumnTypes &returnType) {
csv_init(&parser, CSV_APPEND_NULL);
colInfo = returnType;
}
template <>
void LibCSVParser<FormattedStringParsers>::setup(ServerInterface &srvInterface,
SizedColumnTypes &returnType) {
csv_init(&parser, CSV_APPEND_NULL);
colInfo = returnType;
if (formatStrings.size() != returnType.getColumnCount()) {
formatStrings.resize(returnType.getColumnCount(), "");
}
sp.setFormats(formatStrings);
}
template <class StringParsersImpl>
class LibCSVParserFactoryTmpl : public ParserFactory {
public:
virtual void plan(ServerInterface &srvInterface,
PerColumnParamReader &perColumnParamReader,
PlanContext &planCtxt) {}
virtual UDParser* prepare(ServerInterface &srvInterface,
PerColumnParamReader &perColumnParamReader,
PlanContext &planCtxt,
const SizedColumnTypes &returnType)
{
return vt_createFuncObj(srvInterface.allocator,
LibCSVParser<StringParsersImpl>);
}
};
typedef LibCSVParserFactoryTmpl<StringParsers> LibCSVParserFactory;
RegisterFactory(LibCSVParserFactory);
typedef LibCSVParserFactoryTmpl<FormattedStringParsers> FormattedLibCSVParserFac
tory;
RegisterFactory(FormattedLibCSVParserFactory);
The quick and dirty way would be to just hardcode it. It's using a callback to handle_end_of_row. Track the row number and just don't process the first row . Something like:
static void handle_end_of_row(int c, void *ptr) {
// Ignore 'c' (the terminating character); trust that it's correct
LibCSVParser *p = static_cast<LibCSVParser*>(ptr);
p->colNum = 0;
if (rowcnt <= 0) {
p->bad_field = "";
rowcnt++;
} else if (p->bad_field.empty()) {
p->writer->next();
} else {
// libcsv doesn't give us the whole row to reject.
// So just write to the log.
// TODO: Come up with something more clever.
if (p->currSrvInterface) {
p->currSrvInterface->log("Invalid CSV field value: '%s' Row skipped.",
p->bad_field.c_str());
}
p->bad_field = "";
}
}
Also, best to initialize rownum = 0 in process since I think it will call this for each file in your COPY statement. There might be more clever ways of doing this. Basically, this will just process the record and then discard it.
As for supporting SKIP generically... look at TraditionalCSVParser for how to handle parameter passing. You'd have to add it to the parser factor prepare and send in the value to the LibCSVParser class and override getParameterType. Then in LibCSVParser you need to accept the parameter in the constructor, and modify process to skip the first skip rows. Then use that value instead of the hardcoded 0 above.

Check and add data into protobuff using C++

message HealthOccurrenceCount
{
required int64 HealthID=1;
required int32 OccCount=2;
optional bytes wci=3;
}
I would like to add data based on HealthID; If HealthID is already entered then instead of adding a new entry, the program should instead just increment the existing entry's OccCount.
HealthOccurrenceCount objHelthOccCount;
if(objHelthOccCount.healthid() == healthID) // Is this right or do I need to iterate all the nodes?
{
occCount++;
objHelthOccCount.set_occcount(occCount);
}
else
occCount = 1;
Is this code correct or I should convert HealthID into string?
Generated Code:
// required int64 HealthID = 1;
inline bool has_healthid() const;
inline void clear_healthid();
static const int kHealthIDFieldNumber = 1;
inline ::google::protobuf::int64 healthid() const;
inline void set_healthid(::google::protobuf::int64 value);
HealthOccurrenceCount objHelthOccCount;
if(objHelthOccCount.has_healthid())
{
occCount++;
objHelthOccCount.set_occcount(occCount);
}
else
occCount = 1;

c++ protobuf: how to iterate through fields of message?

I'm new to protobuf and I'm stuck with simple task: I need to iterate through fields of message and check it's type. If type is message I will do same recursively for this message.
For example, I have such messages:
package MyTool;
message Configuration {
required GloablSettings globalSettings = 1;
optional string option1 = 2;
optional int32 option2 = 3;
optional bool option3 = 4;
}
message GloablSettings {
required bool option1 = 1;
required bool option2 = 2;
required bool option3 = 3;
}
Now, to explicitly access a field value in C++ I can do this:
MyTool::Configuration config;
fstream input("config", ios::in | ios::binary);
config.ParseFromIstream(&input);
bool option1val = config.globalSettings().option1();
bool option2val = config.globalSettings().option2();
and so on. This approach is not convenient in case when have big amount of fields.
Can I do this with iteration and get field's name and type? I know there are descriptors of type and somewhat called reflection, but I didn't have success in my attempts.
Can some one give me example of code if it's possible?
Thanks!
This is old but maybe someone will benefit. Here is a method that prints the contents of a protobuf message:
void Example::printMessageContents(std::shared_ptr<google::protobuf::Message> m)
{
const Descriptor *desc = m->GetDescriptor();
const Reflection *refl = m->GetReflection();
int fieldCount= desc->field_count();
fprintf(stderr, "The fullname of the message is %s \n", desc->full_name().c_str());
for(int i=0;i<fieldCount;i++)
{
const FieldDescriptor *field = desc->field(i);
fprintf(stderr, "The name of the %i th element is %s and the type is %s \n",i,field->name().c_str(),field->type_name());
}
}
You can find in FieldDescriptor Enum Values the possible values you get from field->type. For example for the message type you would have to check if type is equal to FieldDescriptor::TYPE_MESSAGE.
This function prints all the "metadata" of the protobuf message. However you need to check separately for each value what the type is and then call the corresponding getter function using Reflection.
So using this condition we could extract the strings :
if(field->type() == FieldDescriptor::TYPE_STRING && !field->is_repeated())
{
std::string g= refl->GetString(*m, field);
fprintf(stderr, "The value is %s ",g.c_str());
}
However fields can be either repeated or not repeated and different methods are used for both field types. So a check is used here to assure that we are using the right method. For repeated fields we have for example this method for strings :
GetRepeatedString(const Message & message, const FieldDescriptor * field, int index)
So it takes the index of the repeated field into consideration.
In the case of FieldDescriptor of type Message, the function provided will only print the name of the message, we better print its contents too.
if(field->type()==FieldDescriptor::TYPE_MESSAGE)
{
if(!field->is_repeated())
{
const Message &mfield = refl->GetMessage(*m, field);
Message *mcopy = mfield.New();
mcopy->CopyFrom(mfield);
void *ptr = new std::shared_ptr<Message>(mcopy);
std::shared_ptr<Message> *m =
static_cast<std::shared_ptr<Message> *>(ptr);
printMessageContents(*m);
}
}
And finally if the field is repeated you will have to call the FieldSize method on the reflection and iterate all repeated fields.
Take a look at how the Protobuf library implements the TextFormat::Printer class, which uses descriptors and reflection to iterate over fields and convert them to text:
https://github.com/google/protobuf/blob/master/src/google/protobuf/text_format.cc#L1473

C++ and writing enum values into Windows registry

I am writing a function as follows:
bool abc::GetLoggingStatus() {
//true or false is returned
int value;
if (regKey->HasValue("LoggingStatus")) {
regKey->QueryValue("LoggingStatus", &value);
if (value == 1)
return true; //no logging possible
else
return false;
}
regKey->SetValue("LoggingStatus", 1);
return true;
}
Logging level is defined as:
typedef enum {
Entry,
Exit,
Debug,
Warning,
Notification,
Error
} TYPE;
What I need if I select 1 the levels for logging must be shown namely debug,error ... In regedit and if 0 nothing should be shown and logging be disabled.
You can't create dropdown menus in regedit, but what you can do is create a new entry called LoggingLevel. This entry is ignored if LoggingStatus is 0. LoggingLevel is a string defining the level.
If you want to convert this string back to an enum, the easiest way is to create a map from string to your Enum type:
std::map<std::string, TYPE> typeMap;
typeMap["Warning"] = Warning;
...
In your code you query the logging level:
char* level;
regKey->QueryValue("LoggingLevel", level);
TYPE theLevel = typeMap[level];
Of course you need to do appropriate error checking.
edit
You should add two function to get the log settings, shouldLog() and getLevel().
The log function would then look like:
void log(Logger* logger, TYPE type, string sClassName, string sMethodName, string sMessage = "") {
if (!logger || !abc::shouldLog()) {
return;
}
TYPE curLevel = abc::getLevel();
bool shouldLog = false;
if (type == Warning && (curLevel == All || curLevel == Warning) ...) {
shouldLog = true;
}
if (shouldLog) {logger->WriteEntry(sClassName, sMethodName); }
}
If you want to avoid complicated if-structures, you could also try and map the enums to a value and compare that. For example Warning = 1 and ALL = 0. Then you can check if curLevel < type to see if the logger should log.