How to use a Judy array - c++

I am interested in Judy Arrays and try to use it. But i had unable to do any useful thing using it. Every time it gives me casting errors.. Sample c++ code and the error given below.
#include "Judy.h"
#include <iostream>
using namespace std;
int main()
{
int Rc_int; // return code - integer
Word_t Rc_word; // return code - unsigned word
Word_t Index = 12, Index1 = 34, Index2 = 55, Nth;
Word_t PValue; // pointer to return value
//Pvoid_t PJLArray = NULL; // initialize JudyL array
Pvoid_t JudyArray = NULL;
char String[100];
PWord_t _PValue;
JSLI( JudyArray, _PValue, (uint8_t *) String);
return(0);
} // main()
This gives me the error
m.cpp: In function ‘int main()’:
m.cpp:19: error: invalid conversion from ‘long unsigned int**’ to ‘void**’
m.cpp:19: error: initializing argument 1 of ‘void** JudySLIns(void**, const uint8_t*, J_UDY_ERROR_STRUCT*)’
Please anyone help me to figure out what is the error what i'm doing..
Thanks

According to the documentation, you have the _PValue and JudyArray parameters reversed. Make your call look like this:
JSLI( _PValue, JudyArray, (uint8_t *) String);
Also, try not compiling it as C++ code. So far, your test uses no C++ features. I bet it will compile as C code. It looks like JudyArray relies on the fact that C will do certain kinds of implicit conversions between void * and other pointer types.
If this is the case, I'm not sure what to do about it. The error messages you're getting tell me that JSLI is a macro. In order to fix the error message you have in the comments on this answer, you'd have to reach inside the macro and add a typecast.
These kinds of implicit conversions are allowed in C because otherwise using malloc would always require ugly casts. C++ purposely disallows them because the semantics of new make the requirement that the result of malloc be cast to the correct type unimportant.
I don't think this library can be used effectively in C++ for this reason.

It seems that, you pass JudySLIns(void**, const uint8_t*, J_UDY_ERROR_STRUCT*) a wrong parameter, the first one, you'b better check it!

For integer keys there is a C++ wrapper at http://judyhash.sourceforge.net/

Related

Trying to get past std::bind compile errors

I've used std::bind before and I think am close on this usage but not quite there and I don't have a clue how to resolve the compile error.
The ultimate goal is a medium-sized array of pointers to a small number of functions, with different parameters in each array element. At this point I just have one function and one table entry. If I can get that right I think I can solve the rest. I want to use std::function so that I can put the varied parameters into the array.
Here's declaration of the one function so far:
static Get *MakeGArrayStatic(void *Subscript, const void **array, unsigned int sizeOfArray);
Here's the declaration of the single pointer that will be typical of the array:
typedef std::tr1::function<Get *(void *, const void**, unsigned int)> GetMaker;
static GetMaker *gm1;
Here's the definition of the pointer:
Get::GetMaker *Get::gm1 = std::tr1::bind(&MakeGArrayStatic, &OutMsg::CurrentSeverity, FacSevTbls::SyslogSeveritiesForMessages, FacSevTbls::NumberOfTrueSeverities);
(Get is a class, CurrentSeverity is an enum, SyslogSeveritiesForMessages is a const char **, and NumberOfTrueSeverities is a size_t.)
The error I am getting (VS 2010) is
error C2440: 'initializing' : cannot convert from 'std::tr1::_Bind<_Result_type,_Ret,_BindN>' to 'Get::GetMaker *'
with
[
_Result_type=Get *,
_Ret=Get *,
_BindN=std::tr1::_Bind3,SyslogEnums::SeverityEnum *,const char **,size_t>
]
No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
Can anyone please point out where I am going wrong?
Thank you again to #PlinyTheElder but I think we have left the question "officially" unanswered. Closing the loop, here are the declarations with the first cut at an array of functions:
static Get *MakeGArrayStatic(void *Subscript, const char **array, size_t sizeOfArray);
static Get *MakeGStatic(void *field, size_t sizeOfField);
typedef std::tr1::function<Get *()> GetMaker;
static GetMaker gm[];
and here is the definition of the array so far:
std::tr1::function<Get *()> Get::gm[] = {
std::tr1::bind(&Get::MakeGArrayStatic, &OutMsg::CurrentSeverity, FacSevTbls::SyslogSeveritiesForMessages, FacSevTbls::NumberOfTrueSeverities),
std::tr1::bind(&MakeGStatic, Msg::MessageID, 8) } ;
And here is a trivial example of a call to a function:
Get *g = Get::gm[0]();
Came out better than I had hoped. I had pictured that all of the "little functions" were going to have to have the same signature (like overloads). Compiles cleanly on both target compilers. (Have not tested execution yet, but I am confident.) Thanks again!
Update: yes, it executes.

Getting a pointer of a primitive type in a function

I have a union (ValueDefinition) with pointers of different datatypes in it and functions to create it. With String it works fine:
ValueDefinition CreateValDefString(String value){
ValueDefinition valDef = {.ValueString = new String(value)};
return valDef;
}
But when I do the same with e.g. uint8_t it compiles, but at runtime I get this error:
[E][WString.cpp:185] changeBuffer(): realloc failed! Buffer unchanged
That's the code for the uint8_t:
ValueDefinition CreateValDefUint8(uint8_t value){
ValueDefinition valDef = {.ValueUInt8 = new uint8_t(value)};
return valDef;
}
What am I doing wrong? I tried it without "new" and with malloc, but I still get the same error.
Edit: As requested, the definition of ValueDefinition:
union ValueDefinition{
bool* ValueBool;
int8_t* ValueInt8;
int16_t* ValueInt16;
int32_t* ValueInt32;
uint8_t* ValueUInt8;
uint16_t* ValueUInt16;
uint32_t* ValueUInt32;
float* ValueFloat;
ulong* ValueULong;
String* ValueString;
};
In your code, it looks like C++ is throwing an error to a function to create a WString instead of uint8_t, hence the stacktrace in a completely separate header. Searching the source code in the repository for arduino shows that there is an error in WString.cpp here, which is what your compiler's detecting.
The github users suggest using a different string library, and since the bug hasn't been fixed you'll have to change, probably to the standard string library defined by C++ and not arduino. As the users have stated on github, arduino strings are notoriously unreliable.
In other words, this error has nothing to do with your code, but a question that I'd like to ask is "Why use unions in C++?" If you want to define a generic type just use templates, ex:
template<class T>
class ValueDefinition<T> {
private:
T typeDat;
public:
Valuedefinition(T t);
/* etc. */
}
Unions were made so that C could have a way to use generic typing by having several types share the data in the union. Another common use is taking advantage of the data types using the same memory to find the underlying binary of more complex types, such as using individual uint8_t values underlying a long long to find the value of its bits or using an int to get the binary value of a float, ex:
union foo {
uint8_t bits[4]; /* Represent the bits of 'data' */
long long int data;
}
union foo myLong = {.data = 12378591249169278l};
printf("%d\n", myLong.bits[0]); // Returns the value of the high bit of myLong
However note that this is undefined behavior because unions are usually padded and architectures use a different form of endianess. Whatever you're doing, if you're using C++ there's a better way to implement your solution than using unions, since this was a feature meant for a language that had no generic typing in order to save memory.
Edit:
Initialize ValueDefinition using C's malloc like so:
union ValueDefinition *value = malloc(sizeof(union ValueDefinition));
value->ValueUInt8 = malloc(sizeof(uint8_t));
/* more code */
Or with C++'s new:
union ValueDefinition *value = new ValueDefinition();
value->ValueUInt8 = new uint8_t(/* Some number */);
/* more code */

Understanding casting a struct as a void pointer

I found this code in the rendering library for Quake 3. There is this function:
void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, int fogIndex, int dlightMap );`
It is being called in a loop somehwere else like this:
R_AddDrawSurf( ( void * )poly, sh, poly->fogIndex, qfalse );
The weird part is that poly was declared as srfPoly_t *poly. What is going on
here? It is casting a srfPoly_t object to (void *) and then entering the
function as a surfaceType_t object.
Here are the declaration for the relevant structs:
typedef enum {
SF_BAD,
SF_SKIP, // ignore
SF_FACE,
SF_GRID,
SF_TRIANGLES,
SF_POLY,
SF_MD3,
SF_MD4,
SF_FLARE,
SF_ENTITY, // beams, rails, lightning, etc that can be determined by entity
SF_DISPLAY_LIST,
SF_NUM_SURFACE_TYPES,
SF_MAX = 0x7fffffff // ensures that sizeof( surfaceType_t ) == sizeof( int )
} surfaceType_t;
typedef struct srfPoly_s {
surfaceType_t surfaceType;
qhandle_t hShader;
int fogIndex;
int numVerts;
polyVert_t *verts;
} srfPoly_t;
This is working in C, but I am trying to implement something similar in C++,
but I get the following error:
Error 1 error C2664: 'int RefDef::AddDrawSurf(surfaceType_t *)' : cannot convert argument 1 from 'void *' to 'surfaceType_t *'
It would appear I cannot perform this type of cast in C++, or maybe there is
something else I am unable to understand. I am not very familiar with C++ and
would love to figure out how to set up something similar using it.
I am assuming this has something to do with type checking in C++, so it is not
allowed. How can I implement something similar in C++ in a safe way?
This works in C because structs are simply blocks of memory with each element in the struct laid out consecutively. This cast works because the first n bytes of a srfPoly_t struct consist of the surfaceType_t enum within that struct. The called function tries to interpret the passed-in srfPoly_t as a surfaceType_t, and succeeds because the first n bytes of the argument are, in fact, a surfaceType_t. Do not do this without a very good reason.
Casts from void*'s do not automatically occur in C++ as they do in C. You can use reinterpret_cast to explicitly cast between two different types of structs:
srfPoly_t* mySrfPoly_t;
surfaceType_t* mySurfaceType = reinterpret_cast<surfaceType_t*>(mySrfPoly_t);

C++ equivalent to taking address of a constant?

I've got some code written in C (specifically targeted to gcc) that needs to also compile as C++ (g++). I've run into a construct I'm having difficulty dealing with.
There are some macros used in a lot of places which basically take the address of a constant, although they also work on non-constants. The construct winds up looking something like this:
int *iptr = (&(int){5});
What this essentially lets happen is a constant be specified, and then a pointer to that constant can be taken for use in a function that requires an int pointer, but only a constant is specified. Multiple values can also be specified inside the curley braces to construct an actual temporary array, too. And it works great.
Problem in, g++ does not like this at all, throwing
error: non-lvalue in unary `&'
Update: Looks like I can take the address of a constant in C++ by doing something like:
const int & ref = 5;
So that's the starting point for the direction I'm trying to take.
The following appears to work in both C and C++, although it only compiles under C++11, not C++03.
#ifdef __cplusplus
#define A(type,x) (&(const type &)(type)x)
#define Of(...) { __VA_ARGS__ }
#else
#define A(type,x) (&(type){x})
#define Of(...) __VA_ARGS__
#endif
Test Code:
int test(const void *ptr,int len) {
char *str = (char *)ptr;
int i;
for (i=0;i<len;i++) {
printf("%02X ",str[i]);
}
printf("\n");
return 0;
}
int main() {
test(A(int,5),4);
test(A(x,Of(5,6)),8);
int i=1,j=2;
test(A(x,Of(i,j)),8);
}
Edit: Whoops, not quite there. Doesn't work if the type is a pointer!
test(A(char *,9),4);
=>
error: invalid cast of an rvalue expression of type 'char*' to type 'const char*&'
Note: I'm abandoning this approach in favor of a different approach (compiling C code as C and linking it via C++) but will keep this answer up in case it is useful to somebody.

Trouble with char* and char** (C --> C++)

Okay, I am trying to integrate some C code into a C++ project, and have run into a few problems. I will detail the first one here.
I keep running into this error:
error: cannot convert 'char*' to 'char**' in assignment|
here is the offending code (with the breakpoint marked):
char** space_getFactionPlanet( int *nplanets, int *factions, int nfactions )
{
int i,j,k;
Planet* planet;
char **tmp;
int ntmp;
int mtmp;
ntmp = 0;
mtmp = CHUNK_SIZE;
tmp = malloc(sizeof(char*) * mtmp); <--- Breakpt
The malloc function is derived from a C header. Here is the declaration:
_CRTIMP void* __cdecl __MINGW_NOTHROW malloc (size_t) __MINGW_ATTRIB_MALLOC;
I am using codeblocks, which is set to use MinGW. The above syntax is totally foreign to me.
I am totally stumped, since this code works fine in the C program I took it from.
Any Ideas?
EDIT 1:
Oops, just realized that the declaration is from stdlib.h.
EDIT 2:
I tried:
tmp = static_cast<char **>(malloc(sizeof(char*) * mtmp));
As suggested, but not I get error: invalid static_cast from type 'char*' to type 'char**'.
EDIT 3:
Okay, reinterpret_cast works, but the solution to replace mallocs seems much more elegantly simple, so I am going with that.
However, there is no free(tmp) at the end of the function. Is this a problem if I don't put in a delete tmp[]?
EDIT 4: I should add that tmp is returned by the function, so it is neccesary to delete tmp, or is this automatic?
Okay I am marking this solved. Thanks for your help.
C++ is not so free with pointer type conversions. You will have to do something like this:
tmp = static_cast<char **>(malloc(sizeof(char *) * mtmp));
That will work if your malloc() returns a void*. However, the errors you're getting indicate that your malloc() is declared to return a char*, and in this case you'd have to use reinterpret_cast instead:
tmp = reinterpret_cast<char **>(malloc(sizeof(char *) * mtmp));
This casts the return type of malloc() to a type suitable for assignment into tmp. You can read more about the different types of casts in C++ at Type Casting.
Note that if this code must still compile in C, you can use a C-style cast instead:
tmp = (char **)malloc(sizeof(char *) * mtmp);
If you're converting to C++, then let's do away with the malloc shall we?
tmp = new char*[mtmp];
But later on, you will probably find something like this:
free(tmp);
Which you need to change to this:
delete [] tmp;
If tmp is returned from the function, do not delete it. You need to trace the pointer. Somewhere, perhaps in multiple locations, free is going to be called. You need to replace that with delete if you are going with this solution. However, an even better solution would be to ditch the pointers all together, and replace it with a
vector<string>
malloc(3) returns void*, which could be assigned to any other pointer type in C, but not in C++. This is one of the places where C++ is not backward-compatible with C. You can either do what other posters said - cast it to char**, or go all the way to proper C++ free store usage with operators new[] and delete[]:
char** tmp = new char*[mtmp]; // was malloc(sizeof(char*) * mtmp);
// ... use tmp
delete [] tmp; // was free( tmp );
Perhaps a cast is in order:
tmp = static_cast<char **>(malloc(sizeof(char*) * mtmp));
Change tmp = malloc(sizeof(char*) * mtmp); to:
tmp = (char**)malloc(sizeof(char*) * mtmp);
And don't go around changing malloc's to new's, as some have wrongly suggested, because of two reasons:
1) its not broken, so don't fix it (!)
2) you could introduce subtle or flat out horrible bugs that will eat away hours of your life later on.
Do spend your time fixing broken code, not code that works...