how to pack multi-key map with msgpack-c - c++

I am trying to use msgpack (in c version, not c++) to replace our own serialization method, which is in primary xml based. It is quite straight forward to pack some ordinary data. However, we have a lot of k-v based structures like
struct Table {
struct Key {
// Multi-keys
int key1;
int key2;
};
struct Attr {
// Attributes
int attr1;
bool attr2;
char[8] attr3;
};
}
How to pack multi-key table with msg_pack_map in msgpack-c? (unfortunately, our system is exception disabled, so I cannot use the c++ version "msgpack.hpp")
my code snippet:
msgpack_sbuffer sbuf;
msgpack_sbuffer_init(&sbuf);
msgpack_packer pk;
msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write);
msgpack_packer_map(&pk, 10) // 10 pairs
for(int i= 0; i<10; ++i) {
// key
msgpack_pack_array(&pk, 2);
msgpack_pack_int(&pk, i);
msgpack_pack_int(&pk, 100+i);
// attr
msgpack_pack_array(&pk, 3);
msgpack_pack_int(&pk, 1);
msgpack_pack_true(&pk);
msgpack_pack_str(&pk, 7);
msgpack_pack_str_body(&pk, "example");
}
I assume in msgpack, we have to use msgpack_pack_array to pack struct.
Is my code right, or is there any better way to do that?

Yes, you are right. There are two subtle mistake in your code snippet.
msgpack_packer_map should be msgpack_pack_map. msgpack_pack_str_body requires a length of the string as the third argument.
I updated your code snippet, and added test codes.
See:
http://melpon.org/wandbox/permlink/RuZKLmzwStHej5TP
#include <msgpack.h>
#include <msgpack.hpp>
#include <map>
#include <iostream>
struct Key {
// Multi-keys
int key1;
int key2;
MSGPACK_DEFINE(key1, key2);
};
inline bool operator<(Key const& lhs, Key const& rhs) {
if (lhs.key1 < rhs.key1) return true;
if (lhs.key1 > rhs.key1) return false;
if (lhs.key2 < rhs.key2) return true;
return false;
}
struct Attr {
// Attributes
int attr1;
bool attr2;
std::string attr3;
MSGPACK_DEFINE(attr1, attr2, attr3);
};
int main() {
msgpack_sbuffer sbuf;
msgpack_sbuffer_init(&sbuf);
msgpack_packer pk;
msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write);
msgpack_pack_map(&pk, 10); // 10 pairs
for(int i= 0; i<10; ++i) {
// key
msgpack_pack_array(&pk, 2);
msgpack_pack_int(&pk, i);
msgpack_pack_int(&pk, 100+i);
// attr
msgpack_pack_array(&pk, 3);
msgpack_pack_int(&pk, 1);
msgpack_pack_true(&pk);
msgpack_pack_str(&pk, 7);
msgpack_pack_str_body(&pk, "example", 7);
}
{
auto upd = msgpack::unpack(sbuf.data, sbuf.size);
std::cout << upd.get() << std::endl;
auto tbl = upd.get().as<std::map<Key, Attr>>();
}
msgpack_sbuffer_destroy(&sbuf);
}
That is a c++ code but I use C API in the packing part. You can check the unpacked msgpack object. It is also converted as C++ map successfully.
Here is C API documentation:
https://github.com/msgpack/msgpack-c/wiki/v1_1_c_overview

Related

How do I access elements of multiset within a vector in the format "vector<multiset<char> vp;"?

I am creating a program that receives a value in multiset in the form of vector<multisetvp; and stores it in multiset inside the vector when the number of it becomes five. If you store values from 1 to 10, when you print out vector,
1 2 3 4 5
6 7 8 9 10
I want it to come out like this.
However, it is difficult to output the value stored in multiset inside the vector. Ask for help in how to solve this problem.
I also tried to output the value of 'sp' using overlapping 'range-based for statements', but it ended up outputting only one multiset of vector. I want to store and output multisets with up to five elements in the vector.
#include <iostream>
#include <set>
#include <vector>
#include <array>
using namespace std;
class MyCharector {
vector<multiset<char>> vp;
vector<multiset<char>>::iterator vit;
multiset<char>* sp;
multiset<char>::iterator sit;
public:
~MyCharector() { }
void ininven(multiset<char> s) {
vp.push_back(s);
}
void getItem(char* item) {
sp = new multiset<char>;
for (int i = 0; i < 10; i++) {
sp->insert(item[i]);
if (sp->size() == 5) {
ininven(*sp);
}
}
delete sp;
}
void dropItem() { // is not use
vit = vp.begin();
vit = vp.erase(vit);
}
void showItem() {
for (vit = vp.begin(); vit != vp.end(); vit++) {
// problems.....
}
}
};
int main(int argc, const char* argv[]) {
MyCharector my;
array<char,10> item = { 'a','a','e','d','g','f','c','c','h','b' };
my.getItem(item.data());
my.showItem();
return 0;
}
Of course you can make it work with iterators but what's wrong with simple range based loops?
for (const auto& ms : vp)
for (char c : ms)
cout << c;
Also why use new and delete in getItem? And why declare class variables when you should use local variables?
void getItem(char* item) {
multiset<char> sp;
for (int i = 0; i < 10; i++) {
sp.insert(item[i]);
if (sp.size() == 5) {
ininven(sp);
}
}
}
sp doesn't need to be a pointer, and it should be a local variable.
EDIT
Also I think getItem has a bug. I'm guessing that you want a new multiset every five character, but that's not what the code does. Maybe this is what you want
void getItem(char* item) {
multiset<char> sp;
for (int i = 0; i < 10; i++) {
sp.insert(item[i]);
if (sp.size() == 5) {
ininven(sp);
sp.clear(); // start again
}
}
}

Table Representation in C++

Basically, say, I have the following data:
(let me note that the columns change with every piece of data I get, i.e. I need to keep things general and cannot restrict my solution to only Tenor, Date, etc.)
Now I want to be able to represent and conveniently access this data in an object/class in C++.
I have been playing around with map a bit:
#include <iostream>
#include <map>
#include <string>
using namespace std;
class my_table {
private:
map<string, map<string, string>> c;
public:
void set(string key1, string key2, string value){ this->c[key1][key2] = value; }
string get(string key1, string key2){
map<string, map<string, string>>::iterator it = this->c.find(key1);
if (it != this->c.end()){
map<string, string>::iterator it2 = this->c[key1].find(key2);
if (it2 != this->c[key1].end()){
return c[key1][key2];
}
return "n/a";
}
return "n/a";
}
};
void main() {
my_table a;
a.set("1", "Tenor", "1D");
cout << a.get("1", "Tenor") << endl; // returns '1D'
cout << a.get("2", "Tenor") << endl; // returns 'n/a'
cout << a.get("1", "Rate") << endl; // returns 'n/a'
}
But I am not overly satisfied with this implemenation. In particular, I would want to be able to do things like:
a.get("Tenor","3M", "Rate") // should return '1.6%'
a.get("Date","01-Jan-2016", "Responsibility") // should return 'MG'
a.get_all("Type","Forward", "Rate") // should return an array {1.3%,2.4%}
a.get_row(4) // should return an array {4M,...,2.0%,MG}
And:
I am wondering whether there are there any standard packages that could help me simplify this implementation overall?
In particular, my get function seems unnecessarily cumbersome.
And generally, is map is even the right way to go in terms of storing data like this?
And what if I wanted to generalise this implemenation to more than just 2 keys? Maybe 3 keys. My solution is quite rigid
enum struct Type {
Spot
Forward
}
struct Row {
string tenor;
Date date;
int convention;
Type type;
double rate;
ResposibilityType responsibility;
};
std::vector<Row> table = {
[...]
}
access you do with std::find_if. Tables in databases might be stored like this internally. If you want multiple primary keys you can create for each key a map that maps from the primary key to an element in table. If you want a combined key, you need tuple like this std::map<std::pair<Key1,Key2>, Row*>
How about the matrix type from boost.ublas? You can create a simple enum type to easily reference columns.
For querying you can probably build something quick via the filter_iterator.
Hope this helps!
Edit: Sorry didn't notice your comment. A quick hack I can think of to support dynamic column size is using a hash map for storing column name to column index mapping in a separate hash map. Good luck!
Limiting yourself to maps could overcomplicate this somewhat. If I understand this correctly, the data structure is completely undefined at compile time. In that case perhaps a simpler way to implement it is as a vector of hash-key-value triples, like this:
#include "stdafx.h"
#include <string>
#include <vector>
#include <iostream>
using namespace std;
class HashKeyValue
{
private:
string hash;
string key;
string value;
public:
HashKeyValue() {}
HashKeyValue(string h, string k, string v)
{
hash = h;
key = k;
value = v;
}
string getHash() { return hash; }
string getKey() { return key; }
string getValue() { return value; }
};
class my_table
{
private:
vector<HashKeyValue> hkv;
public:
my_table() {}
void set(string h, string k, string v)
{
hkv.push_back(HashKeyValue(h, k, v));
}
string getV(string h, string k)
{
for (unsigned int i = 0; i < hkv.size(); i++)
{
if (hkv[i].getHash() == h && hkv[i].getKey() == k)
return hkv[i].getValue();
}
return "n/a";
}
string getByColValue(string col1, string val, string col2)
{
string hash;
int got = 0;
for (unsigned int i = 0; i < hkv.size() && !got; i++)
{
if (hkv[i].getKey() == col1 && hkv[i].getValue() == val)
{
hash = hkv[i].getHash();
got = 1;
}
}
if (got)
{
for (unsigned int i = 0; i < hkv.size(); i++)
{
if (hkv[i].getHash() == hash && hkv[i].getKey() == col2)
return hkv[i].getValue();
}
return "n/a";
}
else return "n/a";
}
};
int main()
{
my_table m;
m.set("1", "Tenor", "1D");
m.set("3", "Tenor", "3M");
m.set("3", "Rate", "1.6%");
cout << "get-1-Tenor(1D): " << m.getV("1", "Tenor") << endl;
cout << "get-1-Alto(n/a): " << m.getV("1", "Alto") << endl;
cout << "get-3-Rate(1.6%): " << m.getV("3", "Rate") << endl;
cout << "getBCV-Tenor-3M-Rate(1.6%): " << m.getByColValue("Tenor", "3M", "Rate") << endl;
return 0;
}
Hopefully getByColValue() makes sense; it first looks up the hash, then looks up the Rate for that hash. The hash is what relates each key-value pair to others on the same row. It shouldn't be too tricky to change getByColValue() to return a vector<string> instead, for the getByColValue("Type","Forward","Rate") case: just make hash a vector<string> instead, define the return type as another vector<string>, and a few other tweaks.
This also makes the implementation of getRow() fairly trivial; just loop over hkv where hash==rowid and bung the key/value pairs (or just the values) into a vector.

Where is the operator "<" used in this sample?

I tried STL sample program using "map".
http://ideone.com/LB8xvh
#include <iostream>
#include <map>
#include <cstring>
using namespace std;
class ItemName
{
char name[80];
public:
ItemName(char *s) { strcpy(name, s); }
char *get() { return name; }
};
bool operator<(ItemName a, ItemName b)
{
return strcmp(a.get(), b.get()) < 0;
}
class ItemObj
{
char str[80];
public:
ItemObj(char *s) { strcpy(str, s); }
char *get() { return str; }
};
char itemdata[][80] = {
"potion", "heal HP",
"key", "unlock a door",
"lamp", "light",
};
int main() {
map<ItemName, ItemObj> items;
for(int i=0; i<3; i++) {
items.insert(
pair<ItemName, ItemObj>(
ItemName(itemdata[i*2]),
ItemObj(itemdata[i*2+1]))); // ***** pair *****
}
map<ItemName, ItemObj>::iterator p;
char str[80];
const int kMaxLoop = 5;
int nLoop = 0;
while(nLoop < kMaxLoop) {
cout << "> ";
cin >> str;
p = items.find(str);
if(p != items.end() ) {
cout << p->second.get() << endl;
} else {
cout << "unknown item." << endl;
}
nLoop++;
}
return 0;
}
In this example, I am not quite sure where the operator "<" is used.
If I comment out the definition of the operator "<", I receive lots of errors.
std::map has a parameter to specify how to compare elements in the map (needed because a map always maintains its contents sorted in order by key). By default, that's std::less<T>.
std::less<T>, in turn, will do the comparison using operator<.
You can create a map of items for which operator< isn't defined, but to do it you need to specify the comparison function/functor explicitly.
That said: your ItemData and ItemObj are both really just doing things that std::string can already do. You could reduce most of the code above to something like this:
std::map<std::string, std::string> items{
{ "potion", "heal HP" },
{ "key", "unlock a door" },
{ "lamp", "light" }
};
It is used internally by the map to place and find entries. Otherwise, find would have to compare the key you supply it against literally every single other entry one by one and you couldn't iterate the map in key order.
Basically, maps efficiently store elements in order. To do that, they have to have some way to know what the order is, and they do that by calling operator< (unless you specify otherwise).

Insert an array of tables into one table SQLite C/C++

I made my own database format, and it sadly required too much memory and the size of it got horrendous and upkeep was horrible.
So I'm looking for a way to store an array of a struct that's in an object into a table.
I'm guessing I need to use a blob, but all other options are welcome. An easy way to implement a blob would be helpful as well.
I've attached my saving code and related structures(Updated from my horrible post earlier)
#include "stdafx.h"
#include <string>
#include <stdio.h>
#include <vector>
#include "sqlite3.h"
using namespace std;
struct PriceEntry{
float cardPrice;
string PriceDate;
int Edition;
int Rarity;
};
struct cardEntry{
string cardName;
long pesize;
long gsize;
vector<PriceEntry> cardPrices;
float vThreshold;
int fav;
};
vector<cardEntry> Cards;
void FillCards(){
int i=0;
int j=0;
char z[32]={0};
for(j=0;j<3;j++){
cardEntry tmpStruct;
sprintf(z, "Card Name: %d" , i);
tmpStruct.cardName=z;
tmpStruct.vThreshold=1.00;
tmpStruct.gsize=0;
tmpStruct.fav=1;
for(i=0;i<3;i++){
PriceEntry ss;
ss.cardPrice=i+1;
ss.Edition=i;
ss.Rarity=i-1;
sprintf(z,"This is struct %d", i);
ss.PriceDate=z;
tmpStruct.cardPrices.push_back(ss);
}
tmpStruct.pesize=tmpStruct.cardPrices.size();
Cards.push_back(tmpStruct);
}
}
int SaveCards(){
// Create an int variable for storing the return code for each call
int retval;
int CardCounter=0;
int PriceEntries=0;
char tmpQuery[256]={0};
int q_cnt = 5,q_size = 256;
sqlite3_stmt *stmt;
sqlite3 *handle;
retval = sqlite3_open("sampledb.sqlite3",&handle);
if(retval)
{
printf("Database connection failed\n");
return -1;
}
printf("Connection successful\n");
//char create_table[100] = "CREATE TABLE IF NOT EXISTS users (uname TEXT PRIMARY KEY,pass TEXT NOT NULL,activated INTEGER)";
char create_table[] = "CREATE TABLE IF NOT EXISTS Cards (CardName TEXT, PriceNum NUMERIC, Threshold NUMERIC, Fav NUMERIC);";
retval = sqlite3_exec(handle,create_table,0,0,0);
printf( "could not prepare statemnt: %s\n", sqlite3_errmsg(handle) );
for(CardCounter=0;CardCounter<Cards.size();CardCounter++){
char Query[512]={0};
for(PriceEntries=0;PriceEntries<Cards[CardCounter].cardPrices.size();PriceEntries++){
//Here is where I need to find out the process of storing the vector of PriceEntry for Cards then I can modify this loop to process the data
}
sprintf(Query,"INSERT INTO Cards VALUES('%s', %d, %f, %d)",
Cards[CardCounter].cardName.c_str(),
Cards[CardCounter].pesize,
Cards[CardCounter].vThreshold,
Cards[CardCounter].fav); //My insert command
retval = sqlite3_exec(handle,Query,0,0,0);
if(retval){
printf( "Could not prepare statement: %s\n", sqlite3_errmsg(handle) );
}
}
// Insert first row and second row
sqlite3_close(handle);
return 0;
}
I tried googling but my results didn't suffice.
You have two types here: Cards and PriceEntries. And for each Card there can be many PriceEntries.
You can store Cards in one table, one Card per row. But you're puzzled about how to store the PriceEntries, right?
What you'd normally do here is have a second table for PriceEntries, keyed off a unique column (or columns) of the Cards table. I guess the CardName is unique to each card? Let's go with that. So your PriceEntry table would have a column CardName, followed by columns of PriceEntry information. You'll have a row for each PriceEntry, even if there are duplicates in the CardName column.
The PriceEntry table might look like:
CardName | Some PE value | Some other PE value
Ace | 1 | 1
Ace | 1 | 5
2 | 2 | 3
and so on. So when you want to find the array of PriceEntries for a card, you'd do
select * from PriceEntry where CardName = 'Ace'
And from the example data above you'd get back 2 rows, which you could shove into an array (if you wanted to).
No need for BLOBs!
This is a simple serialization and deserialization system. The class PriceEntry has been extended with serialization support (very simply). Now all you have to do is serialize a PriceEntry (or a set of them) to binary data and store it in a blob column. Later on, you get the blob data and from that deserialize a new PriceEntry with the same values. An example of how it is used is given at the bottom. Enjoy.
#include <iostream>
#include <vector>
#include <string>
#include <cstring> // for memcpy
using std::vector;
using std::string;
// deserialization archive
struct iarchive
{
explicit iarchive(vector<unsigned char> data)
: _data(data)
, _cursor(0)
{}
void read(float& v) { read_var(v); }
void read(int& v) { read_var(v); }
void read(size_t& v) { read_var(v); }
void read(string& v) { read_string(v); }
vector<unsigned char> data() { return _data; }
private:
template <typename T>
void read_var(T& v)
{
// todo: check that the cursor will not be past-the-end after the operation
// read the binary data
std::memcpy(reinterpret_cast<void*>(&v), reinterpret_cast<const void*>(&_data[_cursor]), sizeof(T));
// advance the cursor
_cursor += sizeof(T);
}
inline
void
read_string(string& v)
{
// get the array size
size_t sz;
read_var(sz);
// get alignment padding
size_t padding = sz % 4;
if (padding == 1) padding = 3;
else if (padding == 3) padding = 1;
// todo: check that the cursor will not be past-the-end after the operation
// resize the string
v.resize(sz);
// read the binary data
std::memcpy(reinterpret_cast<void*>(&v[0]), reinterpret_cast<const void*>(&_data[_cursor]), sz);
// advance the cursor
_cursor += sz + padding;
}
vector<unsigned char> _data; // archive data
size_t _cursor; // current position in the data
};
// serialization archive
struct oarchive
{
void write(float v) { write_var(v); }
void write(int v) { write_var(v); }
void write(size_t v) { write_var(v); }
void write(const string& v) { write_string(v); }
vector<unsigned char> data() { return _data; }
private:
template <typename T>
void write_var(const T& v)
{
// record the current data size
size_t s(_data.size());
// enlarge the data
_data.resize(s + sizeof(T));
// store the binary data
std::memcpy(reinterpret_cast<void*>(&_data[s]), reinterpret_cast<const void*>(&v), sizeof(T));
}
void write_string(const string& v)
{
// write the string size
write(v.size());
// get alignment padding
size_t padding = v.size() % 4;
if (padding == 1) padding = 3;
else if (padding == 3) padding = 1;
// record the data size
size_t s(_data.size());
// enlarge the data
_data.resize(s + v.size() + padding);
// store the binary data
std::memcpy(reinterpret_cast<void*>(&_data[s]), reinterpret_cast<const void*>(&v[0]), v.size());
}
vector<unsigned char> _data; /// archive data
};
struct PriceEntry
{
PriceEntry()
{}
PriceEntry(iarchive& in) // <<< deserialization support
{
in.read(cardPrice);
in.read(PriceDate);
in.read(Edition);
in.read(Rarity);
}
void save(oarchive& out) const // <<< serialization support
{
out.write(cardPrice);
out.write(PriceDate);
out.write(Edition);
out.write(Rarity);
}
float cardPrice;
string PriceDate;
int Edition;
int Rarity;
};
int main()
{
// create a PriceEntry
PriceEntry x;
x.cardPrice = 1;
x.PriceDate = "hi";
x.Edition = 3;
x.Rarity = 0;
// serialize it
oarchive out;
x.save(out);
// create a deserializer archive, from serialized data
iarchive in(out.data());
// deserialize a PriceEntry
PriceEntry y(in);
std::cout << y.cardPrice << std::endl;
std::cout << y.PriceDate << std::endl;
std::cout << y.Edition << std::endl;
std::cout << y.Rarity << std::endl;
}

Adding a string or char array to a byte vector

I'm currently working on a class to create and read out packets send through the network, so far I have it working with 16bit and 8bit integers (Well unsigned but still).
Now the problem is I've tried numerous ways of copying it over but somehow the _buffer got mangled, it segfaulted, or the result was wrong.
I'd appreciate if someone could show me a working example.
My current code can be seen below.
Thanks, Xeross
Main
#include <iostream>
#include <stdio.h>
#include "Packet.h"
using namespace std;
int main(int argc, char** argv)
{
cout << "#################################" << endl;
cout << "# Internal Use Only #" << endl;
cout << "# Codename PACKETSTORM #" << endl;
cout << "#################################" << endl;
cout << endl;
Packet packet = Packet();
packet.SetOpcode(0x1f4d);
cout << "Current opcode is: " << packet.GetOpcode() << endl << endl;
packet.add(uint8_t(5))
.add(uint16_t(4000))
.add(uint8_t(5));
for(uint8_t i=0; i<10;i++)
printf("Byte %u = %x\n", i, packet._buffer[i]);
printf("\nReading them out: \n1 = %u\n2 = %u\n3 = %u\n4 = %s",
packet.readUint8(),
packet.readUint16(),
packet.readUint8());
return 0;
}
Packet.h
#ifndef _PACKET_H_
#define _PACKET_H_
#include <iostream>
#include <vector>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
using namespace std;
class Packet
{
public:
Packet() : m_opcode(0), _buffer(0), _wpos(0), _rpos(0) {}
Packet(uint16_t opcode) : m_opcode(opcode), _buffer(0), _wpos(0), _rpos(0) {}
uint16_t GetOpcode() { return m_opcode; }
void SetOpcode(uint16_t opcode) { m_opcode = opcode; }
Packet& add(uint8_t value)
{
if(_buffer.size() < _wpos + 1)
_buffer.resize(_wpos + 1);
memcpy(&_buffer[_wpos], &value, 1);
_wpos += 1;
return *this;
}
Packet& add(uint16_t value)
{
if(_buffer.size() < _wpos + 2)
_buffer.resize(_wpos + 2);
memcpy(&_buffer[_wpos], &value, 2);
_wpos += 2;
return *this;
}
uint8_t readUint8()
{
uint8_t result = _buffer[_rpos];
_rpos += sizeof(uint8_t);
return result;
}
uint16_t readUint16()
{
uint16_t result;
memcpy(&result, &_buffer[_rpos], sizeof(uint16_t));
_rpos += sizeof(uint16_t);
return result;
}
uint16_t m_opcode;
std::vector<uint8_t> _buffer;
protected:
size_t _wpos; // Write position
size_t _rpos; // Read position
};
#endif // _PACKET_H_
Since you're using an std::vector for your buffer, you may as well let it keep track of the write position itself and avoid having to keep manually resizing it. You can also avoid writing multiple overloads of the add function by using a function template:
template <class T>
Packet& add(T value) {
std::copy((uint8_t*) &value, ((uint8_t*) &value) + sizeof(T), std::back_inserter(_buffer));
return *this;
}
Now you can write any POD type to your buffer.
implicitly:
int i = 5;
o.write(i);
or explictly:
o.write<int>(5);
To read from the buffer, you will need to keep track of a read position:
template <class T>
T read() {
T result;
uint8_t *p = &_buffer[_rpos];
std::copy(p, p + sizeof(T), (uint8_t*) &result);
_rpos += sizeof(T);
return result;
}
You will need to explicitly pass a type parameter to read. i.e.
int i = o.read<int>();
Caveat: I have used this pattern often, but since I am typing this off the top of my head, there may be a few errors in the code.
Edit: I just noticed that you want to be able to add strings or other non-POD types to your buffer. You can do that via template specialization:
template <>
Packet& add(std::string s) {
add(string.length());
for (size_t i = 0; i < string.length(); ++i)
add(string[i]);
return *this;
}
This tells the compiler: if add is called with a string type, use this function instead of the generic add() function.
and to read a string:
template <>
std::string read<>() {
size_t len = read<size_t>();
std::string s;
while (len--)
s += read<char>();
return s;
}
You could use std::string as internal buffer and use append() when adding new elements.
Thus adding strings or const char* would be trivial.
Adding/writing uint8 can be done with casting it to char, writing uint16 - to char* with length sizeof(uint16_t).
void write_uint16( uint16_t val )
{
m_strBuffer.append( (char*)(&var), sizeof(val) );
}
Reading uint16:
uint16_t read_int16()
{
return ( *(uint16_t*)(m_strBuffer.c_str() + m_nOffset) );
}
You appear to be attempting to print ten bytes out of the buffer when you've only added four, and thus you're running off the end of the vector. This could be causing your seg fault.
Also your printf is trying to print a character as an unsigned int with %x. You need to use static_cast<unsigned>(packet._buffer[i]) as the parameter.
Stylistically:
Packet packet = Packet(); could potentially result in two objects being constructed. Just use Packet packet;
Generally try to avoid protected attributes (protected methods are fine) as they reduce encapsulation of your class.