static const T *cur_obj;
Bindable() { }
+ ~Bindable() { if(cur_obj==this) T::unbind(); }
static bool set_current(const T *obj)
{
const T *Bindable<T>::cur_obj;
+/**
+A helper class for Bindables that revert to a default object on unbind.
+*/
+template<typename T>
+class BindableWithDefault: protected Bindable<T>
+{
+ friend class Bindable<T>;
+
+protected:
+ BindableWithDefault() { }
+ ~BindableWithDefault() { if(this==&default_object()) Bindable<T>::set_current(0); }
+
+public:
+ static const T *current()
+ {
+ if(!Bindable<T>::cur_obj)
+ Bindable<T>::cur_obj = &default_object();
+ return Bindable<T>::cur_obj;
+ }
+
+ static void unbind()
+ {
+ if(Bindable<T>::cur_obj)
+ default_object().bind();
+ }
+
+ static const T &default_object()
+ {
+ static T obj;
+ return obj;
+ }
+};
+
+
/**
RAII class for binding things. Binds the thing upon construction and unbinds
it upon destruction. If a null pointer is given, unbinds upon construction and
-does nothing upon destruction. Optionally can restore the previous binding.
+does nothing upon destruction.
*/
class Bind
{
private:
- struct Base
- {
- virtual ~Base() { }
- };
+ typedef void CleanupFunc(int);
+
+ int slot;
+ CleanupFunc *cleanup;
+
+public:
+ template<typename T>
+ Bind(T *o) { init(o); }
+
+ template<typename T>
+ Bind(const T *o) { init(o); }
+
+ template<typename T>
+ Bind(const T &o) { init(&o); }
+
+ template<typename T, typename S>
+ Bind(T *o, S s) { init(o, s); }
+
+ template<typename T, typename S>
+ Bind(const T *o, S s) { init(o, s); }
+
+ template<typename T, typename S>
+ Bind(const T &o, S s) { init(&o, s); }
+private:
template<typename T>
- struct Binder1: Base
+ void init(const T *o)
{
- const T *obj;
-
- Binder1(const T *o):
- obj(o)
- {
- if(obj)
- obj->bind();
- else
- T::unbind();
- }
-
- ~Binder1()
- {
- if(obj)
- obj->unbind();
- }
- };
-
- template<typename T, typename U>
- struct Binder2: Base
+ cleanup = (o ? static_cast<CleanupFunc *>(&unbind<T>) : 0);
+ slot = 0;
+ if(o)
+ o->bind();
+ else
+ T::unbind();
+ }
+
+ template<typename T, typename S>
+ void init(const T *o, S s)
{
- const T *obj;
- const U *old;
-
- Binder2(const T *o, const U *l):
- obj(o),
- old(l)
- {
- if(obj)
- obj->bind();
- else
- T::unbind();
- }
-
- ~Binder2()
- {
- if(old)
- old->bind();
- else if(obj)
- obj->unbind();
- }
- };
-
- Base *binder;
+ cleanup = (o ? static_cast<CleanupFunc *>(&unbind_from<T, S>) : 0);
+ slot = s;
+ if(o)
+ o->bind_to(s);
+ else
+ T::unbind_from(s);
+ }
public:
+ ~Bind()
+ { if(cleanup) cleanup(slot); }
+
+private:
template<typename T>
- Bind(const T &o, bool r = false):
- binder(r ? create(&o, T::current()) : create(&o))
- { }
+ static void unbind(int)
+ { T::unbind(); }
+
+ template<typename T, typename S>
+ static void unbind_from(int s)
+ { T::unbind_from(static_cast<S>(s)); }
+};
+
+/**
+Similar to Bind, but restores previous binding upon destruction.
+*/
+class BindRestore
+{
+private:
+ typedef void CleanupFunc(const void *, int);
+
+ const void *old;
+ int slot;
+ CleanupFunc *cleanup;
+
+public:
template<typename T>
- Bind(const T *o, bool r = false):
- binder(r ? create(o, T::current()) : create(o))
- { }
+ BindRestore(T *o) { init(o); }
template<typename T>
- Bind(T *o, bool r = false):
- binder(r ? create(o, T::current()) : create(o))
- { }
+ BindRestore(const T *o) { init(o); }
+
+ template<typename T>
+ BindRestore(const T &o) { init(&o); }
+
+ template<typename T, typename S>
+ BindRestore(T *o, S s) { init(o, s); }
+
+ template<typename T, typename S>
+ BindRestore(const T *o, S s) { init(o, s); }
+
+ template<typename T, typename S>
+ BindRestore(const T &o, S s) { init(&o, s); }
private:
- Bind(const Bind &);
- Bind &operator=(const Bind &);
+ template<typename T>
+ void init(T *o)
+ {
+ old = T::current();
+ slot = 0;
+ cleanup = (o!=old ? static_cast<CleanupFunc *>(&restore<T>) : 0);
+ if(o)
+ o->bind();
+ else if(old)
+ T::unbind();
+ }
+
+ template<typename T, typename S>
+ void init(T *o, S s)
+ {
+ old = T::current(s);
+ slot = s;
+ cleanup = (o!=old ? static_cast<CleanupFunc *>(&restore_to<T, S>) : 0);
+ if(o)
+ o->bind_to(s);
+ else if(old)
+ T::unbind_from(s);
+ }
public:
- ~Bind() { delete binder; }
+ ~BindRestore()
+ { if(cleanup) cleanup(old, slot); }
private:
template<typename T>
- Base *create(const T *o)
- { return new Binder1<T>(o); }
+ static void restore(const void *o, int)
+ {
+ if(o)
+ reinterpret_cast<const T *>(o)->bind();
+ else
+ T::unbind();
+ }
- template<typename T, typename U>
- Base *create(const T *o, const U *l)
- { return new Binder2<T, U>(o, l); }
+ template<typename T, typename S>
+ static void restore_to(const void *o, int si)
+ {
+ S s = static_cast<S>(si);
+ if(o)
+ reinterpret_cast<const T *>(o)->bind_to(s);
+ else
+ T::unbind_from(s);
+ }
};
} // namespace GL