Convert mixed JSON-Number-Array to int, uint, float using lib rapidjson - c++

As I understood this char* is a valid json-string.
const char* json = { "array":[14, -15, 3.17], "array_type": ["uint", "int", "float"] }
All numbers in the array shall be 4 bytes.
How could one loop through the array using rapidjson?
This is my code so far:
#include "rapidjson/document.h"
using namespace rapidjson;
int main(void)
{
int i_val; unsigned int ui_val; float f_val;
const char* json = "{ \"array\":[14, -15, 3.17], \"array_type\" : [\"uint\", \"int\", \"float\"] }";
Document d;
d.Parse<0>(json);
Value& a = d["array"];
Value& at = d["array_type"];
for (SizeType i = 0; i<a.Size(); i++)
{
if (a[i].IsInt() && (std::string)at[i].GetString() == "int")
{
i_val = a[i].GetInt();
//Do anything
}
if (a[i].IsUint() && (std::string)at[i].GetString() == "uint")
{
ui_val = a[i].GetUint();
//Do anything
}
if (a[i].IsDouble() && (std::string)at[i].GetString() == "float")
{
f_val = (float)a[i].GetDouble();
//Do anything
}
}//end for
return 0;
}
ERROR:
TestApp: /workspace/TestApp/src/include/rapidjson/document.h:1277: rapidjson::GenericValue<Encoding, Allocator>& rapidjson::GenericValue<Encoding, Allocator>::operator[](rapidjson::SizeType) [with Encoding = rapidjson::UTF8<>; Allocator = rapidjson::MemoryPoolAllocator<>; rapidjson::SizeType = unsigned int]: Assertion `index < data_.a.size' failed.
The code crashes at the function a.Size(), when it is executed after GetDouble. How could one solve this?
I know the last "if" is wrong and thats probably why the program crashes. Double is 8 bytes and the SizeType is 4 bytes by default.
Is there a solution to loop though the array?? If not I also would be good with other libs.. I need to transport these three different types of values by json. By the way the length of the array could be 1 to 500.
(There is no GetFloat() function.)
Thanks for any kind of help.
Regards

You can use JSONLint to validate json string.
Your example fixed:
int i_val; unsigned int ui_val; float f_val;
const char* json = "{ \"array\":[14, -15, 3.17], \"array_type\" : [\"uint\", \"int\", \"float\"] }";
rapidjson::Document d;
d.Parse<0>(json);
rapidjson::Value& a = d["array"];
rapidjson::Value& at = d["array_type"];
for (rapidjson::SizeType i = 0; i<a.Size(); i++)
{
if (a[i].IsInt() && (std::string)at[i].GetString() == "int")
{
i_val = a[i].GetInt();
//Do anything
}
if (a[i].IsUint() && (std::string)at[i].GetString() == "uint")
{
ui_val = a[i].GetUint();
//Do anything
}
if (a[i].IsDouble() && (std::string)at[i].GetString() == "float")
{
f_val = (float)a[i].GetDouble();
//Do anything
}
}

Related

Get all combinations of changing characters in a sring (C++)

Okay, I've been tearing my hair out for the past 5 hours on this.
I'm still new to C++, so bear with me if this is a stupid question.
I would like to get all possible character combinations, and put them in a string, in C++.
void changeCharInString(std::string &str, int index, char ch)
{
str[index] = ch;
}
for (int i = 0; i < globals::numOfValidChars; i++)
//numOfValidChars is just sizeof validChars
{
changeCharInString(test, 0, globals::validChars[i]);
//validChars is valid characters, which is an array of lowercase letters and some symbols
//'test' is just my testing string for this.
}
If I wanted all combinations of a three-letter string, manually, what I would do would be:
for (int a = 0; a < globals::numOfValidChars; a++)
{
changeCharInString(test, 0, globals::validChars[a]);
//index 0 because first for loop
//do something with string 'test'
for (int b = 0; b < globals::numOfValidChars; b++)
{
changeCharInString(test, 1, globals::validChars[b]);
//index 1 because second second loop
//do something with string 'test'
for (int c = 0; c < globals::numOfValidChars; c++)
{
changeCharInString(test, 2, globals::validChars[c]);
//index 2 because third for loop
//do something with string 'test'
}
}
}
This would print me "aaa" to "___" ('_' being the last special character in my validChars array), including duplicates, e.g. "aa_", "a_a", and "_aa".
But, as with all programmers,I want some efficiency, and don't want to manually type out the for loops for myself.
My question: does anyone have a method of doing this? I've seen some posts on Google, but didn't really understand them, including that most, if not all, were without duplicates...
Thank you all. I hope this wasn't too much of a bother to read <3
You tagged your question as "recursion", so here is an answer that uses recursion:
void generate(int idx, string& test) {
if (idx == test.size()) {
// do something with test
} else {
for (char c : globals::validChars) {
test[idx] = c;
generate(idx+1, test);
}
}
}
If the size is fixed and known at compile-time, you can use templates and if it is not too large the compiler will create a nice nested loop for you:
template <size_t idx>
void generate(string& test) {
for (char c : globals::validChars) {
test[test.size()-idx] = c;
generate<idx-1>(test);
}
}
template <>
void generate<0>(string& test) {
// do something with test
}
int main() {
string test("aaa");
generate<3>(test);
}
As you said hard coded way would be something like
for (char c1 : globals::validChars) {
for (char c2 : globals::validChars) {
for (char c3 : globals::validChars) {
std::string s {c1, c2, c3};
do_job(s);
}
}
}
or with range-v3
for (auto t : ranges::view::cartesian_product(globals::validChars,
globals::validChars,
globals::validChars)) {
std::string s{ std::get<0>(t), std::get<1>(t), std::get<2>(t)};
do_job(s);
// std::apply([](auto... args){ std::string s{args...}; do_job(s); }, t); // C++17
}
For arbitrary size, you might do
bool increase(const std::vector<char>& alphabet,
std::string& s,
std::vector<std::size_t>& it)
{
for (std::size_t i = 0, size = it.size(); i != size; ++i) {
const std::size_t index = size - 1 - i;
++it[index];
if (it[index] >= alphabet.size()) {
it[index] = 0;
s[index] = alphabet[it[index]];
} else {
s[index] = alphabet[it[index]];
return true;
}
}
return false;
}
template <typename F>
void iterate(F do_job, const std::vector<char>& alphabet, std::size_t size)
{
std::vector<std::size_t> it(size, 0);
std::string s(size, alphabet[0]);
do {
do_job(s);
} while (increase(alphabet, s, it));
}
Demo
You are describing next_permutation from the standard algorithms.

Passing char pointer to function ruins pointer

I am having some difficulties with a bluetooth/oled display displaying the right string. The goal is to read data from bluetooth, update a class variable(Music.setArtist()), and then read from that variable later(Music.getArtist()) to draw it using a draw text function.
If i only call drawText once, it works fine. More than one calls in a loop to drawText cause some undefined behavior though, which is usually the second pointer getting overwritten. This causes the pointer in drawText to be null, or some random characters, or something.
This is my music object.
#ifndef Music_h
#define Music_h
class Music {
private:
char *track,*artist,*length, *position;
int progressBar;
bool playing;
public:
Music(char* t, char* a, char* l, char* po, bool pl, int p): track(t), artist(a), length(l), position(po), playing(pl), progressBar(p){};
~Music(){};
char* getLength(){return length;}
char* getPosition(){return position;}
char* getArtist(){return artist;}
char* getTrack(){return track;}
bool getPlaying(){return playing;}
int getProgressBar(){return progressBar;}
void setLength(char * l){length = l;}
void setPosition(char *p){position = p;}
void setArtist(char *a){artist = a;}
void setTrack(char *t){track = t;}
void setPlaying(bool p){playing = p;}
void setProgressBar(int p){progressBar = p;}
};
#endif
This is my drawText function
void Display_obj::drawText(double xPos, double yPos,char str[], int stringSize, uint8_t asciiBuff)
{
bitmapLetter fnt_controller(0,0,0x00,0,0);
bitmapLetter sheldon_alph[0x5A];
fnt_controller.createDictionary(sheldon_alph,6,8);
int startX = xPos;
int startY = yPos;
for (int i=0; i < stringSize; i++){
char charAt = str[i];
uint8_t ascii = (uint8_t)charAt;
if (ascii > 0x60)
{
charAt = charAt & ~(0x20);
ascii = ascii & ~(0x20);
}
int width = sheldon_alph[ascii-asciiBuff].getWidth();
int height = sheldon_alph[ascii-asciiBuff].getHeight();
size_t siz = sheldon_alph[ascii-asciiBuff].getSize();
unsigned char* bitmap = sheldon_alph[ascii-asciiBuff].getLetter();
drawBitmap(startX,startY,width,height,bitmap,siz);
startX = startX - 8;
if (startX <= 0)
{
startX = xPos;
startY = startY+8;
}
}
}
and my main loop looks something like this
Music music("", "", "", "", false, 0);
RideTracking ride("", "", "", "", "", false);
Navigation nav("", "", "", "", "", false);
void loop(){
if (bt.getDataUpdated() == false)
{
bt.recvWithEndMarker(&bt,&music);
}
else
{
//Serial.println(music.getTrack());
musicUpdateTrack(music.getTrack());
//Serial.println(music.getArtist()); --> This returns gibberish. If the above update is commented out, it works.
musicUpdateArtist(music.getArtist());
bt.setDataUpdated(false);
}
}
Ive tried everything i can think of, which was a lot of messing around with pointers and addresses to see if it was allocated correctly. This is the closest ive gotten, but it seems like the drawText breaks the rest of the char pointers i call in the future. I dont believe the issue has to do with flash or SRAM, as both seem to be within normal values. Any help would be greatly appreciated.
EDIT: in my bluetooth object, there are two calls. one is receive the data, and the other updates the object. I originally didnt include this as it looks like data is set correctly. if i dont call drawtext, but just call print statements, the data is correct.
void blue::updateData(Music* music) {
if (getDataUpdated() == true) {
StaticJsonDocument<256> doc;
DeserializationError error = deserializeJson(doc, receivedChars);
else{
char s1[55];
char s2[55];
char s3[15];
char s4[15];
char s5[15];
if(doc["music"]) {
strlcpy(s1, doc["music"]["track"]);
music->setTrack(s1);
strlcpy(s2, doc["music"]["artist"]);
music->setArtist(s2);
strlcpy(s3, doc["music"]["track_length"]);
music->setLength(s3);
strlcpy(s4, doc["music"]["position"]);
music->setPosition(s4);
music->setProgressBar(doc["music"]["progressBar"]);
music->setPlaying(doc["music"]["playing"]);
}
}
void blue::recvWithEndMarker(blue* bt,Music* mu) {
char rc;
while (ble.available() > 0 && getDataUpdated() == false) {
rc = ble.read();;
if (rc != endMarker)
{
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars)
{
ndx = numChars - 1;
}
}
else
{
brackets++;
if(brackets != 2)
{
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars)
{
ndx = numChars - 1;
}
}
else
{
receivedChars[ndx] = rc;
receivedChars[ndx+1] = '\0'; // terminate the string
ndx = 0;
brackets = 0;
setDataUpdated(true);
}
}
}
bt->updateData(mu);
}
Found it! In the music class, i changed the variables such as *track, to a hardset track[50]. Then, in the set method, i changed it to
void setLength(char * l){
strlcpy(length,l,strlen(l)+1);
}
void setPosition(char *p){
strlcpy(position,p,strlen(p)+1);
}
void setArtist(char *a){
strlcpy(artist,a,strlen(a)+1);
}
void setTrack(char *t){
strlcpy(track,t,strlen(t)+1);
}
Along with a few changes in how its passed, it now works. Thanks! Ive been stuck on this for days.

Subset Sum, with backtracking and classes

Given a sequence of integers and a number, the program must say if there's any cobination in that sequence that sums the number. For example:
Input: 1 2 3 4 5 # 6
Output: true (because 1+5 = 6, or 2 + 4 = 6, or 1 + 2 + 3 = 6).
It doesn't matter what solution it finds, only if there's a solution.
For input: 1 2 3 4 5 # 100
Output: false. None of the combination of that numbers sums 100.
Now, for input:
243 5 35 24 412 325 346 24 243 432 # 1000
I'm getting
main: malloc.c:2401: sysmalloc: Assertion `(old_top == initial_top (av) && old_size == 0) || ((unsigned long) (old_size) >= MINSIZE && prev_inuse (old_top) && ((unsigned long) old_end & (pagesize - 1)) == 0)' failed.
When it's suppose to say false.
I must use 3 classes. Solver, solution and candidat.
Solver just calls the backtracking method.
Solution has a possible solution.
Candidat has the indeix of the number of the sequence which is being looked.
I don't understand how to use the integer _lvl of Solution class to move around the different candidates.
Class Solver is correct. The error must be in solution class and candidats.
My question is, how must I use candidats and _lvl to check the possible solutions?
How should I implement the following methods in solution class?:
Acceptable, complet, anotate, desanotate.
Im getting wrong answers and out_of_ranges errors.
class solver
{
public:
solver();
bool solve(const solution &initial);
solucio getSolution() const;
private:
void findASolution();
bool _found;
solution _sol;
};
solver.cpp
bool solver::solve(const solution &initial)
{
_found = false;
_sol = initial;
findASolution();
return (_found);
}
void solver::findASolution()
{
candidat iCan = _sol.inicializateCandidats();
while ((not iCan.isEnd()) and (!_found))
{
if (_sol.acceptable(iCan)) {
_sol.anotate(iCan);
if(not _sol.complet()) {
findASolution();
if (!_found) {
_sol.desanotate(iCan);
}
}
else {
_found = true;
}
}
iCan.next();
}
}
This class is supposed to be correct. Im having trouble with classes solution and candidat. Class solution have 5 important methods: Acceptable, Complet, inicializateCandidates(), anotate and desanotate.
Acceptable is true if a candidate can be part of the solution.
Complet if a solution is found.
Anotate to save the possible candidates.
Desanotate to remove candidates that no long can be part of the solution.
inicializateCandidates invoces the candidats constructor.
solution();
solution(const int sequence[], const int &n, const int &sum) {
_searchedSum = sum;
_n = n;
_sum = 0;
_lvl = 0;
reserve(); // bad_alloc. Makes space for vectors
for (int i = 0; i < n; i++) {
_sequence[i] = sequence[i];
_candidates[i] = - 1;
}
solution(const solution &o);
~solution();
solution & operator=(const solution &o);
candidat inicializateCandidats() const {
return candidat(_n);
}
bool acceptable(const candidat &iCan) const {
return (_sum + _sequence[iCan.actual()] <= _searchedSum);
}
bool complet() const {
return (_sum == _searchedSum);
}
void show() const;
void anotate(const candidat &iCan) {
_niv++;
_candidates[_niv] = iCan.actual();
_sum += _sequence[iCan.actual()];
}
void desanotate(const candidat &iCan) {
_candidates[_niv] = - 1;
_sum -= _sequence[iCan.actual()];
_niv--;
}
private:
// memory gestion methods
void solution::reserve() {
_sequence = new int[_n];
_candidates = new int[_n];
}
int *_sequence; // original sequence
int *_candidates; // possible subsequence part of solution
int _n; // size of the array
int _lvl; // lvl of the tree generated by backtracking
int _searchedSum;
int _sum; // total sum of actual solution
And class candidat, which is just a counter. Nothing else.
candidat::candidat(const int &n) {
_size = n;
_iCan = 0;
}
bool candidat::isEnd() const {
return (_iCan >= _size);
}
int candidat::actual() const {
if (esEnd()) {
throw ("No more candidates");
}
return _iCan;
}
void candidat::next() {
if (esFi()) {
throw ("No more candidates");
}
_iCan++;
}
I've found a possible solution but it does not fit the requirements at all.
In class solver, I create an attribute to save anterior candidate, inicializate at -1.
The constructor of candidat class changes at this way:
candidat::candidat(const int &n, const int &ant) {
_size = n;
_iCan = ant + 1;
}
In solution.h now there is a boolean array to save the candidates that can be part of the solution. _lvl is eliminated.
In solver.cpp, the backtracking changes a little, but it shouldn't be changed.
bool solver::solve(const solution &initial) {
_found = false;
_ant = -1;
_sol = initial;
findASolution();
return (_found);
}
void solver::findASolution() {
**candidat iCan = _sol.inicializateCandidats(_ant);**
while ((not iCan.isEnd()) and (!_found))
{
if (_sol.acceptable(iCan)) {
_sol.anotate(iCan);
if(not _sol.complet()) {
**_ant = iCan.actual();**
findASolution();
if (!_found) {
_sol.desanotate(iCan);
}
}
else {
_found = true;
}
}
iCan.next();
}
}
Differences remarked.
But this is not the best solution. The correct solution should be using _lvl attribute. The solver class shouldn't know aything about the attributes of solution. Just if it's found or not.

program crash in std::sort() sometimes, can't reproduce

Description:
My program crash sometimes in std::sort(), I write a minimal program to reproduce this situation, but everything is just alright. Here is the minimal example:
typedef struct st {
int it;
char ch;
char charr[100];
vector<string *> *vs;
} st;
bool function(st *&s1, st *&s2) {
static int i = 1;
cout<<i<<" "<<&s1<<" "<<&s2<<endl;
++i;
return s1->it > s2->it;
}
int main(int argc, char **argv) {
vector<st *> ar;
for (int i = 0; i < 100; ++i) {
st *s = new st;
s->it = urandom32();
ar.push_back(s);
}
ar.clear();
for (int i = 0; i < 100; ++i) {
st *s = new st;
s->it = urandom32();
ar.push_back(s);
}
sort(ar.begin(), ar.end(), function);
return 0;
}
Here is the GDB stack info:
0 0x00007f24244d9602 in article_cmp (cand_article_1=0x7f23fd297010, cand_article_2=0x4015)
at src/recom_frame_worker.h:47
1 0x00007f24244fc41b in std::__unguarded_partition<__gnu_cxx::__normal_iterator > >,
cand_article*, bool ()(cand_article, cand_article*)> (__first=,
__last=, __pivot=#0x7f230412b350: 0x7f23fd297010,
__comp=0x7f24244d95e1 )
at /usr/include/c++/4.8.3/bits/stl_algo.h:2266
2 0x00007f24244f829c in std::__unguarded_partition_pivot<__gnu_cxx::__normal_iterator > >, bool
()(cand_article, cand_article*)> (__first=, __last=,
__comp=0x7f24244d95e1 )
at /usr/include/c++/4.8.3/bits/stl_algo.h:2296
3 0x00007f24244f1d88 in std::__introsort_loop<__gnu_cxx::__normal_iterator > >, long,
bool ()(cand_article, cand_article*)> (__first=, __last=,
__depth_limit=18,
__comp=0x7f24244d95e1 )
at /usr/include/c++/4.8.3/bits/stl_algo.h:2337
4 0x00007f24244ed6e5 in std::sort<__gnu_cxx::__normal_iterator > >, bool
()(cand_article, cand_article*)> (
__first=, __last=, __comp=0x7f24244d95e1 )
at /usr/include/c++/4.8.3/bits/stl_algo.h:5489
article_cmp is called in sort(article_result->begin(), article_result->end(), article_cmp); and article_result is a vector<cand_article*> *. cand_article is a struct.
Here is the definition of article_cmp:
bool article_cmp(cand_article* cand_article_1, cand_article* cand_article_2) {
return cand_article_1 -> display_time >= cand_article_2 -> display_time;
}
Here is a piece of code where the crash happens:
article_result->clear();
for(vec_iter = _channel_data -> begin(); vec_iter != _channel_data -> end(); vec_iter++) {
cand_article* cand = to_cand_group(*vec_iter);
if(cand == NULL) continue;
// refresh open loadmore
if(m_request.req_type == 1) {
if(cand -> display_time > m_request.start){
article_result->push_back(cand);
}
}else if(m_request.req_type == 2){
if(cand -> display_time < m_request.end){
article_result->push_back(cand);
}
}else{
article_result->push_back(cand);
}
}
sort(article_result->begin(), article_result->end(), article_cmp);
Question:
I don't know how to handle this kind of coredump, cause 0x4015 is a kernel space address? Any suggestions on how to fix this kind of bug? sorry, I can't reproduce this situation with a minimal program. And this happened in a single thread, so you don't need to think about multi-thread situation.
The rule is "if std::sort crashes, you have an invalid comparison function". Your comparison function is:
bool article_cmp(cand_article* lhs, cand_article* rhs) {
return lhs -> display_time >= rhs -> display_time;
}
This is not a strict weak ordering. In particular, if the display times are equal it returns true, which means that if you swap the arguments it will still return true ... and that is not allowed. You need:
bool article_cmp(cand_article* lhs, cand_article* rhs) {
return lhs -> display_time > rhs -> display_time;
}
The reason your simplified example works (congratulations for at least trying to simplify), is that you simplified the comparison function so it is valid. If the return statement was return s1->it >= s2->it;, and you used a smaller range of values, it too would probably crash.
Incidentally, a much more natural C++ declaration of your example structure would look like:
struct st { // No need for that typedef in C++
int it;
char ch;
std::string charr; // ... or *possibly* std::array<char,100>.
std::vector<std::string> vs; // Strings and vectors best held by value
};
Also note that I have actually used the std:: prefix.
Your minimal program is making memory leaks. Because it just removes all the items from the list but did not release the memory used by them. In the case your items are big enough, your program might get crashed after eating up all the memory. That's why your minimal program is still okay, because the items there are very small.
I would change your program to:
typedef struct st {
int it;
char ch;
char charr[100];
vector *vs;
} st;
bool function(st *&s1, st *&s2) {
static int i = 1;
cout<it > s2->it;
}
int main(int argc, char **argv) {
vector ar;
for (int i = 0; i < 100; ++i) {
st *s = new st;
s->it = urandom32();
ar.push_back(s);
}
release all the memory used my ar's items first
for (vector::iterator it = ar.begin(); it != ar.end(); ++it)
delete *it;
ar.clear();
for (int i = 0; i < 100; ++i) {
st *s = new st;
s->it = urandom32();
ar.push_back(s);
}
sort(ar.begin(), ar.end(), function);
return 0;
}

Access violation writing location 0x000001C0

I'm working on this and have a problem that I cant figure out.
I got this in the header
class PGEnemy : Public CCSprite
{
private:
int pHP;
int pLoot;
int pAttack;
int pSpeed;
PGEnemy();
~PGEnemy();
public:
bool setSpeed (int speed);
static PGEnemy* factory(eType type); //create an enemy
void init(int type); //read info from json (json cpp)
};
And in the code I got this
void PGEnemy::init(int type)
{
try
{
Reader reader;
Value initial;
unsigned long size = 0;
unsigned char *config_doc = CCFileUtils::sharedFileUtils()->getFileData("enemy.json", "r", &size);
bool parsingSuccessful = reader.parse((char*)config_doc, initial);
string s = TO_STRING(type);
cout << s << endl;
if(parsingSuccessful)
{
this->pHP = initial[TO_STRING(type)]["hp"].asInt();
this->pLoot = initial[TO_STRING(type)]["loot"].asInt();
this->pAttack = initial[TO_STRING(type)]["attack"].asInt();
this->pSpeed = initial[TO_STRING(type)]["speed"].asInt();
}
}
catch (exception)
{
this->pHP = 100*type;
this->pAttack = 100*type;
this->pSpeed = 100*type;
this->pLoot = 100*type;
}
//*/
}
In the moment of doing this->pHP = initial[TO_STRING(type)]["hp"].asInt();
or any other that I shall put a value in those integers (even in the catch), it crash with the error
Access violation writing location 0x000001C0.
from a open source code for using json, file Json_value.cpp
Value::asInt() const
{
switch ( type_ )
{
case nullValue:
return 0;
case intValue:
JSON_ASSERT_MESSAGE( value_.int_ >= minInt && value_.int_ <= maxInt, "unsigned integer out of signed int range" );
return Int(value_.int_);
case uintValue:
JSON_ASSERT_MESSAGE( value_.uint_ <= UInt(maxInt), "unsigned integer out of signed int range" );
return Int(value_.uint_);
case realValue:
JSON_ASSERT_MESSAGE( value_.real_ >= minInt && value_.real_ <= maxInt, "Real out of signed integer range" );
return Int( value_.real_ );
case booleanValue:
return value_.bool_ ? 1 : 0;
case stringValue:
case arrayValue:
case objectValue:
JSON_FAIL_MESSAGE( "Type is not convertible to int" );
default:
JSON_ASSERT_UNREACHABLE;
}
return 0; // unreachable;
}
The most "unknow" is that the error also happened when I simply try to do this->pHP = anyIntegerValue
PGEnemy* PGEnemy::factory(eType type)
{
PGEnemy* enemy = (PGEnemy*)CCSprite::create("Target.png");
enemy->init(type);
return enemy;
}