//Quick macro to replace my real Assert() function, just for this file.
#define Assert(condition, message) assert(condition && message)
//Holds any type of user-given pointer that can be cast to void, and does run-time checks on the type of the data when retrieving it.
//Ownership is *not* taken. It is the original owner's responsibillity to ensure the lifetime of the object when
//someone tries to retrieve the pointer later. The Userdata class itself never de-references the pointer.
Userdata() = default;
//Sets a user-spe
void Set(UserType *data)
//Save the pointer (cast to void*), and the type's RTTI information, so we can validate on retrieval.
this->type_info = &typeid(UserType);
this->userdata = data;
//Validate that we've actually set *anything*.
Assert(this->type_info, "We never set any data, so we can't retrieve any.");
//Validate that we are getting the same type that we initially set.
Assert((*this->type_info) == typeid(UserType), "The types don't match - we can't retrieve the userdata safely.");
this->type_info = nullptr;
this->userdata = nullptr;
//A pointer to the global compiler-specific (but standardized) type_info for this type (the type that Userdata's void* points to).
//C++11 guarantees that "The lifetime of the object referred to by [typeid()'s return value] extends to the end of the program." (N3337 5.2.8)
const std::type_info *type_info = nullptr;
//A pointer to the user-defined data.
void *userdata = nullptr;
//Manages a FILO stack of void pointers in a type-safe way.
//This class does not take any ownership of the data pointed to.
UserdataStack() = default;
~UserdataStack() = default;
void Push(UserType *userdata)
Assert(!this->stack.empty(), "The stack is empty - we can't retrieve any userdata.");
//Pops the stack, and returns the pointer previously pointed to.
UserType *data = this->Get<UserType>();
int myInt = 357;
float myFloat = 7.53f;
std::string myString = "Test";
//Asserts, because it's the wrong type.
//int *test = stack.Get<int>();
std::cout << "std::string:\t" << *(stack.Take<std::string>()) << " (should be " << myString << ")" << std::endl;
std::cout << "float:\t\t" << *(stack.Take<float>()) << " (should be " << myFloat << ")" << std::endl;
std::cout << "int:\t\t" << *(stack.Take<int>()) << " (should be " << myInt << ")" << std::endl;
//Asserts, because the stack is now empty: