Get unique IDs by reading the Instruction Pointer Register

Started by
27 comments, last by Tispe 11 years, 1 month ago

Because the IDs must be the same everytime I get to the same line of calling code. And I don't want to keep statics, globals or singletons around to keep track of them.

Advertisement

When I wanted to make such a function for IMGUI I tried to use the __LINE__ makro too, but found out it didnt really work cause if you call some widget from two places it would get the same id again. I also considered mangling the __FILE__ makro but that got same problem and felt too complicated for the little gain. Also just adding to the line number seems to produce less unique numbers.
So I made a custom hash function which started with somehow combining the parentid and the number of needed child ids and then wrote a bunch of unittests to verify uniqueness and that led to a number of additions and bit twiddling tweaks to the function to make it behave as good as possible even on grandchild widgets, bit overflow and wrong inputs. I'm still not convinced its completely done so I'll be looking for more improvedments later.

Why not use name your UI elements and hash that particular name into a uint32 or uint64, the only thing you need to remember is to use unique identifiers and generate them as well. This is easier on you as well no need to remember pesky numbers or ids, just use a proper name like button_1, you could extend this with including the parent id like screen_1.button_1 so you can reuse names.
Because you are using the same hash function it will be guaranteed to return the same value for both the ID on the object and the retrieving id.

Worked on titles: CMR:DiRT2, DiRT 3, DiRT: Showdown, GRID 2, theHunter, theHunter: Primal, Mad Max, Watch Dogs: Legion

In IMGUI the UI elements are not stored anywhere, they are just created when called on, for each frame.

I still don't understand why you can't just say int id=random()*random()>>random() or something similar if you absolutely must have a totally random and unique ID every time and do checks to make sure you're not getting identical ids every time, and of course you can map the results of your random id assignment to some meaningful array of structs describing the widget or whatever


This is IMGUI. The widget isn't defined until it is called. The ID is the only thing that identifies it from one frame to the next.

I also think that using the IP for IDs is a bad idea but just for reference, here is how to get it (untested):

call my_label
my_label:
pop %eax   # IP is now in eax register

The problem is that in x86 you can't read the IP, like you can for example in ARM. You have to make a function call which will automatically push the return address onto the stack. Then you can pop it back off.

But again: This is probably a bad idea for IDs.

You need to use Load effective address instruction instead of a move this is less hassle then jumping to a label and then popping the stack, in masm this looks as following

LEA RAX, [RIP] ;this would load the address of RIP into RAX this only works on a 64-bit CPU
LEA EAX, [EIP] ;32-bit version of the above instructions

Still I wouldn't advise you to do it this way as this will be extremely difficult to debug, using a string and a hash function is easier to debug as you can input the string name of the item your interested into the hash function and presto you have your ID.

Worked on titles: CMR:DiRT2, DiRT 3, DiRT: Showdown, GRID 2, theHunter, theHunter: Primal, Mad Max, Watch Dogs: Legion

I'm really wondering what is insufficient about hashing the combination of __FILE__ and __LINE__. It's worked well enough for my IMGUI needs...


#include <iostream>
#include <tr1/unordered_map>
#include <string>

#define _STRINGIFY(X) #X
#define _TOSTRING(X) _STRINGIFY(X)
#define UNIQUE_ID() std::tr1::hash<std::string>()(std::string(__FILE__ ":" _TOSTRING(__LINE__)))

void func() {
	std::cout << UNIQUE_ID() << std::endl;
}

int main() {
	std::cout << UNIQUE_ID() << std::endl;

	for (int i = 0; i < 10; i++)
		func();

	std::cout << UNIQUE_ID() << std::endl;
}

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

The thing that fails (with all of the IP/FILE/LINE/etc...) tricks is that it completely prevents the user of the library from saving themselves time, ever. Maybe I find myself making lots of buttons with similar behavior/logic/etc... So I make a helper function to eliminate the boiler-plate parts of the API. Oops, nothing works anymore. It ties an implementation detail of the library to the public interface, in a non-obvious way.

Maybe I find myself making lots of buttons with similar behavior/logic/etc... So I make a helper function to eliminate the boiler-plate parts of the API.

Is that even a reasonable idea in an IMGUI context? How will you deal with the logic introduced by the immediate result values?

My impression is that if you try to do this, you will end up having to build an entire retained-mode wrapper around your IMGUI, and you'd be better off using an RMGUI in the first place.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

http://en.wikipedia.org/wiki/KISS_principle
void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

This topic is closed to new replies.

Advertisement