Hi everybody, just an idea for a better(?) tinfo mechanism in ginac: if we added two static constants to every class like class SOMECLASS { public: const static char* tinfo_name; const static unsigned tinfo; // ... rest of class ... } const char* SOMECLASS::tinfo_name = "SOMECLASS"; const unsigned SOMECLASS::tinfo = (unsigned)SOMECLASS::idstring; it seems that we would get a tinfo mechanism for ginac without having to set the tinfo numbers by hand. But maybe I am mistaken. So I'd like to ask somebody who knows C++ better than me, if there might be some hidden pitfalls. Is the conversion a problem (what about 64bit machines)? Is it guaranteed that the address of the static string is unique to every class? Maybe some optimizer will break this? Does it only work with gcc on linux etc.? Regards, Jens
Dear Jens, On Thu, 10 Nov 2005, Jens Vollinga wrote:
But maybe I am mistaken. So I'd like to ask somebody who knows C++ better than me, if there might be some hidden pitfalls.
Sounds like something that could work. You could try it. But please run "make check" before you put it in CVS ;-).
Is the conversion a problem (what about 64bit machines)?
One should of course use the right type and on AMD 64 that would not be unsigned int because it is 32 bits, while pointers are 64 bits. Is there anything wrong with the SOMECLASS::tinfo being of type char*? That way you would need only one variable that you could typedef to something more descriptive (e.g. tinfo_t). Best, Chris
Dear Jens, On Thu, 10 Nov 2005, Jens Vollinga wrote:
if we added two static constants to every class like
class SOMECLASS { public: const static char* tinfo_name; const static unsigned tinfo; // ... rest of class ... } const char* SOMECLASS::tinfo_name = "SOMECLASS"; const unsigned SOMECLASS::tinfo = (unsigned)SOMECLASS::idstring;
On second thought, is it not a problem that these members are non-virtual in the sense that SOMECLASS x; basic*bp = &x; cout << bp->tinfo_name << endl; is always going to print "basic"? Best, Chris
Dear Chris, maybe I am obsessed ... but what about the following variant (I had this version first but then decided to put a more *polished* version on the list...): class SOMECLASS { public: const static char* tinfo_name; const static unsigned tinfo; virtual const unsigned int id() { return (unsigned int)SOMECLASS::tinfo_name; } }; const char* SOMECLASS::tinfo_name = "SOMECLASS"; const unsigned SOMECLASS::tinfo = (unsigned)SOMECLASS::tinfo_name; Well, the unsigned tinfo variable is maybe not necessary. And if tinfo() in every ginac class would return char* no casting would be necessary from the start. Regards, Jens
Hi! 1) You can't have virtual static members. 2) The main reason behind the TINFO mechanism was to avoid a virtual function call. This and some other optimizations sped up GiNaC by a factor of two. 3) If you're planning to re-introduce virtual functions to GiNaC's RTTI, you might as well use typeid() (maybe it works better now than it did five years ago). 4) structure<T> implements a dynamic TINFO assignment, if you want to look at one. Bye, Christian -- / Physics is an algorithm \/ www.cebix.net
Hi, Christian Bauer wrote:
2) The main reason behind the TINFO mechanism was to avoid a virtual function call. This and some other optimizations sped up GiNaC by a factor of two.
That's interesting information! Then of course, the proposed mechanism is no longer acceptable. But, "Never give up, never surrender" (Galaxy Quest), what about the folling code. There is no such overhead involved: class SOMECLASS { public: const static char* tinfo_name; unsigned tinfo; SOMECLASS() { tinfo = (unsigned)tinfo_name; } }; const char* SOMECLASS::tinfo_name= "SOMECLASS"; class daughter : public SOMECLASS { public: const static char* tinfo_name; daughter() { tinfo = (unsigned)tinfo_name; } }; const char* daughter::tinfo_name= "daughter"; Regards, Jens
Hi, Christian Bauer wrote:
On 11/11/2005, "Jens Vollinga" <vollinga@physik.uni-wuppertal.de> wrote:
tinfo = (unsigned)tinfo_name;
How do you guarantee that TINFOs are unique if sizeof(char *) > sizeof(unsigned)?
No guarantee, I guess. But tinfo could become a char*, couldn't it? Jens
Jens Vollinga wrote:
But tinfo could become a char*, couldn't it?
How about: typedef const void * tinfo_t; struct tinfo_static_t {}; class SOMECLASS { public: static const tinfo_static_t tinfo_static; SOMECLASS() : tinfo_key(&tinfo_static) {} SOMECLASS(tinfo_t ti) : tinfo_key(ti) {} tinfo_t tinfo() const { return tinfo_key; } protected: tinfo_t tinfo_key; }; const tinfo_static_t SOMECLASS::tinfo_static = {}; template<class T> inline bool is_exactly_a(const SOMECLASS & obj) { return obj.tinfo() == &T::tinfo_static; } This looks promising. No explicit specializations of is_exactly_a<> are needed any more. Bye, Christian -- / Physics is an algorithm \/ www.cebix.net
Hi, Christian Bauer wrote:
How about:
typedef const void * tinfo_t; struct tinfo_static_t {};
class SOMECLASS { public: static const tinfo_static_t tinfo_static;
SOMECLASS() : tinfo_key(&tinfo_static) {} SOMECLASS(tinfo_t ti) : tinfo_key(ti) {}
tinfo_t tinfo() const { return tinfo_key; }
protected: tinfo_t tinfo_key; };
const tinfo_static_t SOMECLASS::tinfo_static = {};
template<class T> inline bool is_exactly_a(const SOMECLASS & obj) { return obj.tinfo() == &T::tinfo_static; }
This looks promising. No explicit specializations of is_exactly_a<> are needed any more.
Why don't you want to use char* as a static source of address? Is it just a matter of taste? (If the class name is moved out of registered_class_options there is no duplication.) Or is something more involved I don't see? Is it guaranteed that no smart optimizer will merge all static tinfo_static_t into one (there are all the same, aren't they?) with the effect that all tinfo_keys will be the same? The char* version again (I just wrote it from memory. I hope I didn't make some silly mistakes): typedef const char* tinfo_t; class SOMECLASS { public: static tinfo_t tinfo_name; SOMECLASS() : tinfo_key(tinfo_name) {} SOMECLASS(tinfo_t ti) : tinfo_key(ti) {} tinfo_t tinfo() const { return tinfo_key; } protected: tinfo_t tinfo_key; }; const tinfo_t SOMECLASS::tinfo_name = "SOMECLASS"; template<class T> inline bool is_exactly_a(const SOMECLASS & obj) { return obj.tinfo() == T::tinfo_name; } BTW, maybe some disadvantage of both of the new ways: in order to avoid as much as possible hash clashes, which are costly, the seed for the hash calculation should be unique. With the new tinfos the bit pattern for them in most cases has just changing least significant bits. With a seed setup like tinfo^serial (serial a small number) for symbols as an example, one is likely to get more hash clashes, I guess. So the seed setup has to be changed for some classes as well, I think. Regards, Jens
Jens Vollinga wrote:
Is it guaranteed that no smart optimizer will merge all static tinfo_static_t into one (there are all the same, aren't they?) with the effect that all tinfo_keys will be the same?
Empty structs/classes have a guaranteed sizeof() > 0 so they won't end up at the same address if they are array or struct members, so I guess we're a little safer here. I do know, however, that compilers will merge string literals (which shouldn't matter since the class names are all different...). In any case, if the pointees are non-const, the compiler can't possibly merge the objects since a library user could (in theory) change the object through the pointer returned by tinfo(). Bye, Christian -- / Physics is an algorithm \/ www.cebix.net
participants (3)
-
Chris Dams
-
Christian Bauer
-
Jens Vollinga