/**
@file Pointer.h
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
@created 2007-05-16
@edited 2009-03-26
Copyright 2000-2009, Morgan McGuire.
All rights reserved.
*/
#ifndef G3D_Pointer_h
#define G3D_Pointer_h
#include "G3D/debugAssert.h"
#include "G3D/ReferenceCount.h"
namespace G3D {
/**
Acts like a pointer to a value of type ValueType (i.e.,
ValueType*), but can operate through accessor methods as well as on
a value in memory. This is useful for implementing scripting
languages and other applications that need to connect existing APIs
by reference.
Because the accessors require values to be passed by value (instead of by reference)
this is primarily useful for objects whose memory size is small.
class Foo {
public:
void setEnabled(bool b);
bool getEnabled() const;
};
Foo f;
bool b;
Pointer p1(&b);
Pointer p2(&f, &Foo::getEnabled, &Foo::setEnabled);
*p1 = true;
*p2 = false;
*p2 = *p1; \/\/ Value assignment
p2 = p1; \/\/ Pointer aliasing
\/\/ Or, equivalently:
p1.setValue(true);
p2.setValue(false);
p2.setValue(p1.getValue());
p2 = p1;
Note: Because of the way that dereference is implemented, you cannot pass *p
through a function
that takes varargs (...), e.g., printf("%d", *p)
will produce a compile-time error. Instead use
printf("%d",(bool)*p)
or printf("%d", p.getValue())
.
*/
template
class Pointer {
private:
class Interface {
public:
virtual ~Interface() {};
virtual void set(ValueType b) = 0;
virtual ValueType get() const = 0;
virtual Interface* clone() const = 0;
virtual bool isNull() const = 0;
};
class Memory : public Interface {
private:
ValueType* value;
public:
Memory(ValueType* value) : value(value) {
//debugAssert(value != NULL);
}
virtual void set(ValueType v) {
*value = v;
}
virtual ValueType get() const {
return *value;
}
virtual Interface* clone() const {
return new Memory(value);
}
virtual bool isNull() const {
return value == NULL;
}
};
template
class Accessor : public Interface {
private:
T* object;
GetMethod getMethod;
SetMethod setMethod;
public:
Accessor(T* object,
GetMethod getMethod,
SetMethod setMethod) : object(object), getMethod(getMethod), setMethod(setMethod) {
debugAssert(object != NULL);
}
virtual void set(ValueType v) {
(object->*setMethod)(v);
}
virtual ValueType get() const {
return (object->*getMethod)();
}
virtual Interface* clone() const {
return new Accessor(object, getMethod, setMethod);
}
virtual bool isNull() const {
return object == NULL;
}
};
template
class RefAccessor : public Interface {
private:
ReferenceCountedPointer object;
GetMethod getMethod;
SetMethod setMethod;
public:
RefAccessor(
const ReferenceCountedPointer& object,
GetMethod getMethod,
SetMethod setMethod) : object(object), getMethod(getMethod), setMethod(setMethod) {
debugAssert(object != NULL);
}
virtual void set(ValueType v) {
(object.pointer()->*setMethod)(v);
}
virtual ValueType get() const {
return (object.pointer()->*getMethod)();
}
virtual Interface* clone() const {
return new RefAccessor(object, getMethod, setMethod);
}
virtual bool isNull() const {
return object.isNull();
}
};
Interface* m_interface;
public:
Pointer() : m_interface(NULL) {};
/** Allows implicit cast from real pointer */
Pointer(ValueType* v) : m_interface(new Memory(v)) {}
inline bool isNull() const {
return (m_interface == NULL) || m_interface->isNull();
}
// Assignment
inline Pointer& operator=(const Pointer& r) {
delete m_interface;
if (r.m_interface != NULL) {
m_interface = r.m_interface->clone();
} else {
m_interface = NULL;
}
return this[0];
}
Pointer(const Pointer& p) : m_interface(NULL) {
this[0] = p;
}
template
Pointer(const ReferenceCountedPointer& object,
ValueType (Class::*getMethod)() const,
void (Class::*setMethod)(ValueType)) :
m_interface(new RefAccessor(object, getMethod, setMethod)) {}
template
Pointer(const ReferenceCountedPointer& object,
const ValueType& (Class::*getMethod)() const,
void (Class::*setMethod)(ValueType)) :
m_interface(new RefAccessor(object, getMethod, setMethod)) {}
template
Pointer(const ReferenceCountedPointer& object,
ValueType (Class::*getMethod)() const,
void (Class::*setMethod)(const ValueType&)) :
m_interface(new RefAccessor(object, getMethod, setMethod)) {}
template
Pointer(const ReferenceCountedPointer& object,
const ValueType& (Class::*getMethod)() const,
void (Class::*setMethod)(const ValueType&)) :
m_interface(new RefAccessor(object, getMethod, setMethod)) {}
template
Pointer(Class* object,
const ValueType& (Class::*getMethod)() const,
void (Class::*setMethod)(const ValueType&)) :
m_interface(new Accessor(object, getMethod, setMethod)) {}
template
Pointer(Class* object,
ValueType (Class::*getMethod)() const,
void (Class::*setMethod)(const ValueType&)) :
m_interface(new Accessor(object, getMethod, setMethod)) {}
template
Pointer(Class* object,
const ValueType& (Class::*getMethod)() const,
void (Class::*setMethod)(ValueType)) :
m_interface(new Accessor(object, getMethod, setMethod)) {}
template
Pointer(Class* object,
ValueType (Class::*getMethod)() const,
void (Class::*setMethod)(ValueType)) :
m_interface(new Accessor(object, getMethod, setMethod)) {}
~Pointer() {
delete m_interface;
}
inline const ValueType getValue() const {
debugAssert(m_interface != NULL);
return m_interface->get();
}
inline void setValue(const ValueType& v) {
debugAssert(m_interface != NULL);
m_interface->set(v);
}
class IndirectValue {
private:
friend class Pointer;
Pointer* pointer;
IndirectValue(Pointer* p) : pointer(p) {}
public:
void operator=(const ValueType& v) {
pointer->setValue(v);
}
operator ValueType() const {
return pointer->getValue();
}
};
inline IndirectValue operator*() {
return IndirectValue(this);
}
inline const ValueType operator*() const {
return getValue();
}
};
}
#endif