complex array type

For all of my classes I have properties, i.e. :

int deviceNum = 0
bool flipHorz = true
string name = “camera”
float fadeVal = 0.95

However what I’d ideally like to do is this:

properties[“deviceNum”] = 0
properties[“flipHorz”] = true
properties[“name”] = “camera”
properties[“fadeVal”] = 0.95

Back in the days of Director Lingo you could do this as there were loose definitions.

Andreas has pointed out to me the map type
http://is.gd/qzMw

Has anyone used these before? Will I end up with a big hit on performance if I use this method for storing vars in classes?

Thanks

the performance of the map-type is good, it’s basically a binary tree. But you can’t store values of different types into a map, they must have the same base-class.

Most STL implementations do have a hash-class, which is an alternative to the map-template.

If you want to store values of different types into vectors or maps you can try the |variant-class (http://www.boost.org/doc/libs/1-38-0/doc/html/variant/tutorial.html#variant.tutorial.basic) of the boost-libs. Most of the boost libs are header only, so all you need is to include the boost headers and ready to go.

cheers,
Stephan

I’ve been looking for a similar solution. I use NSMutableArray in Cocoa and it’s brilliant.

My hackish attempt in C++ was:

to create an ofxParam class which could take any type

  
class ofxParam {  
public:  
	union {  
		float	floatValue;  
		int		intValue;  
		bool	boolValue;  
		char*	stringValue;  
	};  
};  
  

and then:

  
  
map <string, ofxParam> params;  
ofxParam param1;  
param1.floatValue = 5.3f;  
params.insert(make_pair("param1", param1)); // thx arturo for the tip!  
  

I didn’t get very far with it, and I really disliked the syntax of using maps. So for another project I went with using a normal array, and using an enum for the index:

  
enum {  
   param1,  
   param2,  
   param3,  
   param4,  
   paramCount  
}  
  
ofxParam *params;  
  
params = new ofxParam[paramCount];  
  
params[param1].floatValue = 4.3;  
params[param2].boolValue = false;  
  

The advantage of the latter is you get compile-time spelling checking. e.g. if you type params[paraM4] it’ll give an error, where as if it was params[“paraM4”] it wouldn’t

[/code]

you can extend the example of Memo so you’ll get closer to that what you want:

  
  
#include <iostream>  
#include <map>  
#include <string>  
  
class ofxParam {   
public:   
   union {   
      float   floatValue;   
      int      intValue;   
      const char* stringValue;   
   };  
	ofxParam() {}  
	ofxParam(float f) : floatValue(f) {}  
	ofxParam(int f) : intValue(f) {}  
	ofxParam(const char* f) : stringValue(f) {}  
};   
  
  
int main (int argc, char * const argv[]) {  
  
	typedef std::map<std::string, ofxParam> ofxParamMap;  
	  
	ofxParamMap params;  
	  
	params["float"]  = 5.3f;  
	params["string"] = "hello";  
	params["int"]    = 42;  
	  
	std::cout << "float  : " << params["float"].floatValue << std::endl;  
	std::cout << "string : " << params["string"].stringValue << std::endl;  
	std::cout << "int    : " << params["int"].intValue << std::endl;  
	  
	  
    return 0;  
}  
  
  

One note: the string handling will only work for static strings as the ofxParam-class does not take ownership of the string, it doesn’t copy the contents…

cheers
Stephan

Stephan

  1. Can you use a bool in a union type?

  2. Is there no way to get a string contents in there? Does it have to be a const?

i.e.

  
  
union {  
      float   floatValue;  
      int      intValue;  
      string stringValue;  
   };   
  
std::string tempString = "chris";  
params["string"] = tempString;   
  

  1. For a param, i’d like to store min & max values. Would this work ok?
  
  
class ofxParam {  
public:  
   union {  
      float   floatValue;  
      int      intValue;  
      const char* stringValue;  
   };  
  
   int    intMinValue;  
   int    intMaxValue;  
   float  floatMinValue;  
   float  floatMaxValue;  
  
   ofxParam() {}  
   ofxParam(float f) : floatValue(f) {}  
   ofxParam(int f) : intValue(f) {}  
   ofxParam(const char* f) : stringValue(f) {}  
};   
  

or am i better of using another union?

  
  
class ofxParam {  
public:  
   union {  
      float   floatValue;  
      int      intValue;  
      const char* stringValue;  
   };  
  
   union {  
      float   floatMinValue;  
      int      intMinValue;  
   };  
   union {  
      float   floatMaxValue;  
      int      intMaxValue;  
   };  
  
   ofxParam() {}  
   ofxParam(float f) : floatValue(f) {}  
   ofxParam(int f) : intValue(f) {}  
   ofxParam(const char* f) : stringValue(f) {}  
};   
  

For example, when setting a param up, I might want to do:
params[“float”] = 5.3f;
params[“float”].floatMinValue = 0.0f;
params[“float”].floatMaxValue = 10.0f;

Thanks

It may feel like it, but I wouldn’t consider this a hack at all in C/C++ as they are strictly typed languages. A perfect example of this kind of structure in C is the t_atom struct in Pd:

  
typedef union word  
{  
    t_float w_float;  
    t_symbol *w_symbol;  
    t_gpointer *w_gpointer;  
    t_array *w_array;  
    struct _glist *w_list;  
    int w_index;  
} t_word;  
  
typedef enum  
{  
    A_NULL,  
    A_FLOAT,  
    A_SYMBOL,  
    A_POINTER,  
    A_SEMI,  
    A_COMMA,  
    A_DEFFLOAT,  
    A_DEFSYM,  
    A_DOLLAR,   
    A_DOLLSYM,  
    A_GIMME,  
    A_CANT  
}  t_atomtype;  
  
#define A_DEFSYMBOL A_DEFSYM	/* better name for this */  
  
typedef struct _atom  
{  
    t_atomtype a_type;  
    union word a_w;  
} t_atom;  
  

Compared you the above examples, the only thing missing is a type flag, so there’s potential to miung up the data since you have to know ahead of time what it is and can’t ask the data itself (i.e. there’s no introspection).

actually, you can get the type using the typeid() function. See here:
http://www.cplusplus.com/doc/tutorial/typecasting.html

it’s a bit involved, but it can help a lot!

[quote author=“chrisoshea”]Stephan

  1. Can you use a bool in a union type?
    [/quote]

bools are basically ints in c++: if (aInt) { /* true */ } else { /* false */ }

  1. Is there no way to get a string contents in there? Does it have to be a const?

just add the string to the class, not to the union-part. You can’t add the string declaration into the unit-part. But that should be ok, the size

  1. For a param, i’d like to store min & max values. Would this work ok?

Hmm, perhaps this would work, but it makes the class-declaration fat and monolithic, and I am not a fan of such classes. I would use a struct instead, and a range-class holding the min-max-values.

For my own code i modelled a class named PropertyList which is a mixture of std::vector and std::map so I can access elements by an integer index and by a string as key. The Values are modelled by a class hierarchy, where the base-class has all accessors declared virtual and the child-classes implement the needed accessors. But this hase some caveats: You have to create the classes storing the values dynamically so the virtual methods do work, accessing elements is not that fast, because virtual functions are used (the compiler can’t inline the code) but it’s convenient and I am using these classes to store all sort of data, which can be read from and written to xml.

cheers,
Stephan

For stings in this kind of situation (union types), all of the implementations I’ve seen use “symbols” where a symbol is a pointer to a string that is unique. Behind the scenes is a hash map (could be std::map for instance). The idea is that for every unique string, there is a unique pointer so you can simply slap the pointer in to a union and have access to the string. The other nice property of symbols is that if 2 symbols are equivalent, their pointers are the same so instead of comparing an entire string for equality, you simply compare pointers. Here’s a sample implementation:

  
#include <map>  
#include <string>  
  
using namespace std;  
  
class Symbol {  
	public:  
		typedef map<string, Symbol *>				SymTab;  
		typedef map<string, Symbol *>::iterator		SymTabIterator;  
  
	protected:  
		static SymTab		*c_symTab;  
  
	private:  
		Symbol(string &sym)  
			: mSym(sym)  
		{}  
  
		// this currently never gets called!!  
		~Symbol() {  
			SymTabIterator it = c_symTab->find(mSym);  
			if(it != c_symTab->end()) {  
				c_symTab->erase(it);  
			}  
		}  
  
		Symbol(const Symbol &s);  
		Symbol & operator=(const Symbol &);  
  
	public:  
  
		static Symbol * getsym(const char *sym);  
		const char * data();  
  
	protected:  
		string				mSym;  
};  
  
  
// .cpp  
#include "Symbol.h"  
  
Symbol::SymTab * Symbol::c_symTab = 0;  
  
Symbol * Symbol :: getsym(const char *sym) {  
	if(!c_symTab) {  
		c_symTab = new SymTab();  
	}  
	string s(sym);  
	SymTabIterator it = c_symTab->find(s);  
	if(it == c_symTab->end()) {  
		Symbol *symbol = new Symbol(s);  
		(*c_symTab)[s] = symbol;  
		return symbol;  
	}  
	else {  
		return it->second;  
	}  
}  
  
const char * Symbol :: data() {  
	return mSym.data();  
}