#include <stdio.h>
#include <functional>
#include <map> /* for map */
/**
* This class lets you specify access patterns using C++11 lambdas.
*/
template <typename T>
class property {
private:
std::function<void(const T&)> setFunction;
std::function<T()> getFunction;
public:
/**
* Constructor taking the access methods
*
* @param getf A function to set the value
* @param setf A function to get the value
*/
property(std::function<T()> getf, std::function<void(const T&)> setf) {
getFunction = getf;
setFunction = setf;
}
/**
* Gets the data
*/
operator T () {
return getFunction();
}
/**
* Sets the data
*/
T operator = (const T &i) {
setFunction(i);
return i;
}
};
/**
* Contains data elements we wish to adorn to a class
*/
struct Adornment {
int Attribute = 8;
char* Type = "Unknown";
};
/**
* A class to adorn other classes
*/
class Adorner {
private:
void* adorned = NULL;
Adornment* adornment = NULL;
static std::map<void*, Adornment*> adorners;
/**
* Creates a new instance of an adorner form a pointer
*
* The adornment will be re-used if the pointer is recognized
*
* @param pointer A pointer to the adorned instance
*/
Adorner(void* pointer) {
if (Adorner::adorners.find(pointer) == Adorner::adorners.end()) {
Adorner::adorners[pointer] = new Adornment();
printf("Adorner created on 0x%p\n", pointer);
}
else {
printf("Adorner re-used on 0x%p\n", pointer);
}
adornment = Adorner::adorners[pointer];
adorned = pointer;
};
public:
/**
* Erases an Adornment for an instance
*
* This method searches through the adornments and erases
* the one specific to the pointer
*
* @param pointer A pointer to the adorned instance
* @return true if erased, false if unable to erase
*/
static bool Erase(void* pointer) {
if (Adorner::adorners.find(pointer) != Adorner::adorners.end()) {
Adornment* a = Adorner::adorners[pointer];
delete a;
a = NULL;
Adorner::adorners.erase(pointer);
printf("Adorner deleted on 0x%p\n", pointer);
return true;
}
return false;
}
/**
* Creates a new instance of an adorner form a pointer
*
* Calls the class constructor for a general pointer
*
* @param pointer A pointer to the adorned instance
*/
template<typename T>
Adorner(T* ptr) : Adorner((void*)(ptr)) {
printf("Implicit pointer cast using 0x%p\n", ptr);
this->adornment->Type = "Unknown";
}
/**
* Allows for implicit cast to the original type
*/
template<typename T>
operator T*() { return (T*)adorned; }
/**
* Property to get the "Attribute" adornment
*/
property<int> Attribute = property<int>([this]() { return this->adornment->Attribute; }, [this](int val) {this->adornment->Attribute = val; });
/**
* Property to get the "Type" adornment
*/
property<char*> Type = property<char*>([this]() { return this->adornment->Type; }, [this](char* type) {this->adornment->Type = type; });
};
/**
* Static members are defined out of the class scope.
*/
std::map<void*, Adornment*> Adorner::adorners;
/**
* Define a new delete method
*/
void operator delete(void * p)
{
if (!Adorner::Erase(p)) {
printf("No adorner found on 0x%p\n", p);
}
free(p);
p = NULL;
}
/**
* An example class
*/
class NormalClass {
private:
int val = 0;
public:
/**
* Property to get the Value
*/
property<int> Value = property<int>([this]() { return this->val; }, [this](int val) {this->val = val; });
};
/**
* constructor template specialization
*/
template <>
Adorner::Adorner(NormalClass* obj) : Adorner((void*)(obj)) {
printf("Implicit NormalClass instance cast using 0x%p\n", (void*)(obj));
this->adornment->Type = "NormalClass";
}
/// <summary>
/// The main function
/// </summary>
int main()
{
// Create a normal class and set its value to something non-default
printf("\nCreate a new NormalClass instance and set the Val:\n");
NormalClass* normalClassPointer = new NormalClass();
normalClassPointer->Value = 50;
printf("pointer->Value = %d\n", (int)normalClassPointer->Value);
// Adorn our NormalClass different ways
printf("\nNow add adorners in different ways:\n");
Adorner explicitCastPointer = (Adorner)(normalClassPointer);
Adorner implicitCastPointer = normalClassPointer;
NormalClass* normalClassPointer2 = new NormalClass();
Adorner implicitCastPointer2 = normalClassPointer2;
// Set the value of the adornment attributes
explicitCastPointer.Attribute = 5;
implicitCastPointer.Attribute = 7;
implicitCastPointer2.Attribute = 17;
implicitCastPointer2.Type = "Custom";
// Check the adornment property values (they should be the same)
printf("\nFor an adorner, all adornment properties should be the same:\n");
printf("explicitCastPointer.Attribute = %d\n", (int)explicitCastPointer.Attribute);
printf("explicitCastPointer.Type = %s\n", (char*)explicitCastPointer.Type);
printf("implicitCastPointer.Attribute = %d\n", (int)implicitCastPointer.Attribute);
printf("implicitCastPointer2.Attribute = %d\n", (int)implicitCastPointer2.Attribute);
printf("implicitCastPointer2.Type = %s\n", (char*)implicitCastPointer2.Type);
// Now get the original class back form the adorner
NormalClass* ncPointerFromImplicitCast = explicitCastPointer;
// Even though the value was only set once, both instance and pointer should have the same value
printf("pointer->Value = %d\n", (int)ncPointerFromImplicitCast->Value);
printf("\nDelete instances believed to have Adorners:\n");
delete normalClassPointer;
delete normalClassPointer2;
// Make a class we never adorn just so we can see what happens when we delete it
printf("\nDelete instnaces having no Adorners:\n");
NormalClass* normalClassPointerNoAdorn = new NormalClass();
delete normalClassPointerNoAdorn;
return 0;
}