// Unmanaged Delegate Template Library version 1.10
//
// Copylight (C) 2006 mocchi
//
//  This software is provided 'as-is', without any express or implied
//  warranty.  In no event will the authors be held liable for any damages
//  arising from the use of this software.
//
//  Permission is granted to anyone to use this software for any purpose,
//  including commercial applications, and to alter it and redistribute it
//  freely, subject to the following restrictions:
//
//  1. The origin of this software must not be misrepresented; you must not
//     claim that you wrote the original software. If you use this software
//     in a product, an acknowledgment in the product documentation would be
//     appreciated but is not required.
//  2. Altered source versions must be plainly marked as such, and must not be
//     misrepresented as being the original software.
//  3. This notice may not be removed or altered from any source distribution.
//
// mocchi mocchi_2003@yahoo.co.jp
//

#ifndef IG_UMDELEGATE_H_INCLUDED_
#define IG_UMDELEGATE_H_INCLUDED_

#include <functional>

namespace umdelegate{
	namespace internal{
		enum DelegateType{
			Pointer, MemberPointer,
		};
		class shared_base{
		public:
			virtual void addref() = 0;
			virtual int subref() = 0;
			virtual ~shared_base(){};
		};
		template <typename T> class shared_ptr : public shared_base{
			int count;
			T *ptr_;
		public:
			T *get(){return ptr_;}
			shared_ptr(T *ptr) : ptr_(ptr){
				count = 1;
			}
			virtual void addref(){count++;};
			virtual int subref(){
				count--;
				if (count == 0) delete ptr_;
				return count;
			};
		};
		class delegateb{
		protected:
			shared_base *delebase;
			delegateb() : delebase(NULL){
			};
			delegateb(shared_base *db) : delebase(db){};
			delegateb(const delegateb &d){
				delebase = d.delebase;
				if (delebase) delebase->addref();
			}
			const delegateb &operator =(const delegateb &d){
				delebase = d.delebase;
				if (delebase) delebase->addref();
				return (*this);
			}
			virtual ~delegateb(){
				if (delebase && delebase->subref() == 0) delete delebase;
			}
		};
	};

	template <typename R> class delegate0 : public internal::delegateb{
		class delegatebase{
		protected:
			internal::DelegateType type;
		public:
			virtual R doIt(void) = 0;
			virtual ~delegatebase(){};
			virtual int compare(delegatebase *db) = 0;
		};
		class delegate_ptr : public delegatebase{
		protected:
			typedef R (*ptr_t)(void);
			ptr_t ptr_;
		public:
			delegate_ptr(ptr_t ptr) : ptr_(ptr){type = internal::Pointer;};
			virtual R doIt(void){return ptr_();};
			virtual ~delegate_ptr(){};
			virtual int compare(delegatebase *db){
				if (type != ((delegate_ptr *)db)->type){
					return (type < ((delegate_ptr *)db)->type) ? -1 : 1;
				}else if (ptr_ != ((delegate_ptr *)db)->ptr_){
					return ptr_ < ((delegate_ptr *)db)->ptr_ ? -1 : 1;
				}else return 0;
			}
		};
		template <typename C> class delegate_member : public delegatebase{
		protected:
			typedef R (C::*ptr_t)(void);
			C *obj_;
			ptr_t ptr_;
		public:
			delegate_member(C *obj, ptr_t ptr) : obj_(obj), ptr_(ptr){type = internal::MemberPointer;};
			delegate_member(C *obj) : obj_(obj), ptr_(&C::operator ()){type = internal::MemberPointer;};
			virtual R doIt(void){return (obj_->*ptr_)();};
			virtual ~delegate_member(){};
			virtual int compare(delegatebase *db){
				if (type != ((delegate_member *)db)->type){
					return (type < ((delegate_member *)db)->type) ? -1 : 1;
				}else if (obj_ != ((delegate_member *)db)->obj_){
					return obj_ < ((delegate_member *)db)->obj_ ? -1 : 1;
				}else if (ptr_ != ((delegate_member *)db)->ptr_){
					return -1;
//					return ptr_ < ((delegate_member *)db)->ptr_ ? -1 : 1;
				}else return 0;
			}
		};

		typedef delegatebase delegate_type;
		typedef R (*ptr_type)(void);
		typedef internal::shared_ptr<delegate_type> shared_ptr_type;
	public:
		delegate0(){
		}
		delegate0(ptr_type ptr)
			: internal::delegateb(new shared_ptr_type(new delegate_ptr(ptr))){};
		template <typename C> delegate0(C *obj, R (C::*ptr)(void))
			: internal::delegateb(new shared_ptr_type(new delegate_member<C>(obj, ptr))){};
		template <typename C> delegate0(C *obj)
			: internal::delegateb(new shared_ptr_type(new delegate_member<C>(obj))){};
		~delegate0(){};
		bool operator ==(const delegate0 &dele) const {
			if (delebase == NULL || dele.delebase == NULL) return (dele.delebase == delebase)
			return ((shared_ptr_type *)delebase)->get()->compare(((shared_ptr_type *)dele.delebase)->get()) == 0;
		}
		bool operator !=(const delegate0 &dele) const { return !((*this) == dele);}

		bool operator <(const delegate0 &dele) const {
			if (delebase == NULL) return (dele.delebase != NULL);
			if (dele.delebase == NULL) return false;
			return ((shared_ptr_type *)delebase)->get()->compare(((shared_ptr_type *)dele.delebase)->get()) < 0;
		}
		bool operator >(const delegate0 &dele) const {
			if (delebase == NULL) return false;
			if (dele.delebase == NULL) return (delebase != NULL);
			return ((shared_ptr_type *)delebase)->get()->compare(((shared_ptr_type *)dele.delebase)->get()) > 0;
		}
		bool operator >=(const delegate0 &dele) const { return !((*this) < dele);}
		bool operator <=(const delegate0 &dele) const { return !((*this) > dele);}

		R operator ()(void){
			if (delebase == NULL) return R();
			return ((shared_ptr_type *)delebase)->get()->doIt();
		}
	};
	template <typename Iter> void do_delegate0(Iter begin_, Iter end_){
		for (Iter iter = begin_; iter != end_; iter++){
			(*iter)();
		}
	}

	template <typename R, typename T> class delegate1
		: public internal::delegateb{
	protected:
		class delegatebase{
		protected:
			internal::DelegateType type;
		public:
			virtual R doIt(T t) = 0;
			virtual ~delegatebase(){};
			virtual int compare(delegatebase *db) = 0;
		};
		class delegate_ptr : public delegatebase{
		protected:
			typedef R (*ptr_t)(T t);
			ptr_t ptr_;
		public:
			delegate_ptr(ptr_t ptr) : ptr_(ptr){type = internal::Pointer;};
			virtual R doIt(T t){return ptr_(t);};
			virtual ~delegate_ptr(){};
			virtual int compare(delegatebase *db){
				if (type != ((delegate_ptr *)db)->type){
					return (type < ((delegate_ptr *)db)->type) ? -1 : 1;
				}else if (ptr_ != ((delegate_ptr *)db)->ptr_){
					return ptr_ < ((delegate_ptr *)db)->ptr_ ? -1 : 1;
				}else return 0;
			}
		};
		template <typename C> class delegate_member : public delegatebase{
		protected:
			typedef R (C::*ptr_t)(T t);
			C *obj_;
			ptr_t ptr_;
		public:
			delegate_member(C *obj, ptr_t ptr) : obj_(obj), ptr_(ptr){type = internal::MemberPointer;};
			delegate_member(C *obj) : obj_(obj), ptr_(&C::operator ()){type = internal::MemberPointer;};
			virtual R doIt(T t){return (obj_->*ptr_)(t);};
			virtual ~delegate_member(){};
			virtual int compare(delegatebase *db){
				if (type != ((delegate_member *)db)->type){
					return (type < ((delegate_member *)db)->type) ? -1 : 1;
				}else if (obj_ != ((delegate_member *)db)->obj_){
					return obj_ < ((delegate_member *)db)->obj_ ? -1 : 1;
				}else if (ptr_ != ((delegate_member *)db)->ptr_){
					return -1;
//					return ptr_ < ((delegate_member *)db)->ptr_ ? -1 : 1;
				}else return 0;
			}
		};

		typedef delegatebase delegate_type;
		typedef R (*ptr_type)(T t);
		typedef internal::shared_ptr<delegate_type> shared_ptr_type;
	public:
		delegate1(){
		}
		delegate1(ptr_type ptr)
			: internal::delegateb(new shared_ptr_type(new delegate_ptr(ptr))){};
		template <typename C> delegate1(C *obj, R (C::*ptr)(T))
			: internal::delegateb(new shared_ptr_type(new delegate_member<C>(obj, ptr))){};
		template <typename C> delegate1(C *obj)
			: internal::delegateb(new shared_ptr_type(new delegate_member<C>(obj))){};
		~delegate1(){};

		bool operator ==(const delegate1 &dele) const {
			if (delebase == NULL || dele.delebase == NULL) return (dele.delebase == delebase)
			return ((shared_ptr_type *)delebase)->get()->compare(((shared_ptr_type *)dele.delebase)->get()) == 0;
		}
		bool operator !=(const delegate1 &dele) const { return !((*this) == dele);}

		bool operator <(const delegate1 &dele) const {
			if (delebase == NULL) return (dele.delebase != NULL);
			if (dele.delebase == NULL) return false;
			return ((shared_ptr_type *)delebase)->get()->compare(((shared_ptr_type *)dele.delebase)->get()) < 0;
		}
		bool operator >(const delegate1 &dele) const {
			if (delebase == NULL) return false;
			if (dele.delebase == NULL) return (delebase != NULL);
			return ((shared_ptr_type *)delebase)->get()->compare(((shared_ptr_type *)dele.delebase)->get()) > 0;
		}
		bool operator >=(const delegate1 &dele) const { return !((*this) < dele);}
		bool operator <=(const delegate1 &dele) const { return !((*this) > dele);}

		R operator ()(T t){ 
			if (delebase == NULL) return R();
			return ((shared_ptr_type *)delebase)->get()->doIt(t);
		}
	};
	template <typename Iter, typename T1> void do_delegate1(Iter begin_, Iter end_, T1 t1){
		for (Iter iter = begin_; iter != end_; iter++){
			(*iter)(t1);
		}
	}

	template <typename R, typename T1, typename T2> class delegate2 : public internal::delegateb{
		class delegatebase{
		protected:
			internal::DelegateType type;
		public:
			virtual R doIt(T1 t1, T2 t2) = 0;
			virtual ~delegatebase(){};
			virtual int compare(delegatebase *db) = 0;
		};
		class delegate_ptr : public delegatebase{
		protected:
			typedef R (*ptr_t)(T1 t1, T2 t2);
			ptr_t ptr_;
		public:
			delegate_ptr(ptr_t ptr) : ptr_(ptr){type = internal::Pointer;};
			virtual R doIt(T1 t1, T2 t2){return ptr_(t1, t2);};
			virtual ~delegate_ptr(){};
			virtual int compare(delegatebase *db){
				if (type != ((delegate_ptr *)db)->type){
					return (type < ((delegate_ptr *)db)->type) ? -1 : 1;
				}else if (ptr_ != ((delegate_ptr *)db)->ptr_){
					return ptr_ < ((delegate_ptr *)db)->ptr_ ? -1 : 1;
				}else return 0;
			}
		};
		template <typename C> class delegate_member : public delegatebase{
		protected:
			typedef R (C::*ptr_t)(T1 t1, T2 t2);
			C *obj_;
			ptr_t ptr_;
		public:
			delegate_member(C *obj, ptr_t ptr) : obj_(obj), ptr_(ptr){type = internal::MemberPointer;};
			delegate_member(C *obj) : obj_(obj), ptr_(&C::operator ()){type = internal::MemberPointer;};
			virtual R doIt(T1 t1, T2 t2){return (obj_->*ptr_)(t1, t2);};
			virtual ~delegate_member(){};
			virtual int compare(delegatebase *db){
				if (type != ((delegate_member *)db)->type){
					return (type < ((delegate_member *)db)->type) ? -1 : 1;
				}else if (obj_ != ((delegate_member *)db)->obj_){
					return obj_ < ((delegate_member *)db)->obj_ ? -1 : 1;
				}else if (ptr_ != ((delegate_member *)db)->ptr_){
					return -1;
//					return ptr_ < ((delegate_member *)db)->ptr_ ? -1 : 1;
				}else return 0;
			}
		};

		typedef delegatebase delegate_type;
		typedef R (*ptr_type)(T1 t1, T2 t2);
		typedef internal::shared_ptr<delegate_type> shared_ptr_type;
	public:
		delegate2(){
		}
		delegate2(ptr_type ptr)
			: internal::delegateb(new shared_ptr_type(new delegate_ptr(ptr))){};
		template <typename C> delegate2(C *obj, R (C::*ptr)(T1,T2))
			: internal::delegateb(new shared_ptr_type(new delegate_member<C>(obj, ptr))){};
		template <typename C> delegate2(C *obj)
			: internal::delegateb(new shared_ptr_type(new delegate_member<C>(obj))){};
		~delegate2(){};
		bool operator ==(const delegate2 &dele) const {
			if (delebase == NULL || dele.delebase == NULL) return (dele.delebase == delebase)
			return ((shared_ptr_type *)delebase)->get()->compare(((shared_ptr_type *)dele.delebase)->get()) == 0;
		}
		bool operator !=(const delegate2 &dele) const { return !((*this) == dele);}

		bool operator <(const delegate2 &dele) const {
			if (delebase == NULL) return (dele.delebase != NULL);
			if (dele.delebase == NULL) return false;
			return ((shared_ptr_type *)delebase)->get()->compare(((shared_ptr_type *)dele.delebase)->get()) < 0;
		}
		bool operator >(const delegate2 &dele) const {
			if (delebase == NULL) return false;
			if (dele.delebase == NULL) return (delebase != NULL);
			return ((shared_ptr_type *)delebase)->get()->compare(((shared_ptr_type *)dele.delebase)->get()) > 0;
		}
		bool operator >=(const delegate2 &dele) const { return !((*this) < dele);}
		bool operator <=(const delegate2 &dele) const { return !((*this) > dele);}

		R operator ()(T1 t1, T2 t2){
			if (delebase == NULL) return R();
			return ((shared_ptr_type *)delebase)->get()->doIt(t1, t2);
		}
	};
	template <typename Iter, typename T1, typename T2> void do_delegate2(Iter begin_, Iter end_, T1 t1, T2 t2){
		for (Iter iter = begin_; iter != end_; iter++){
			(*iter)(t1, t2);
		}
	}


	template <typename R, typename T1, typename T2, typename T3> class delegate3 : public internal::delegateb{
		class delegatebase{
		protected:
			internal::DelegateType type;
		public:
			virtual R doIt(T1 t1, T2 t2, T3 t3) = 0;
			virtual ~delegatebase(){};
			virtual int compare(delegatebase *db) = 0;
		};
		class delegate_ptr : public delegatebase{
		protected:
			typedef R (*ptr_t)(T1 t1, T2 t2, T3 t3);
			ptr_t ptr_;
		public:
			delegate_ptr(ptr_t ptr) : ptr_(ptr){type = internal::Pointer;};
			virtual R doIt(T1 t1, T2 t2, T3 t3){return ptr_(t1, t2, t3);};
			virtual ~delegate_ptr(){};
			virtual int compare(delegatebase *db){
				if (type != ((delegate_ptr *)db)->type){
					return (type < ((delegate_ptr *)db)->type) ? -1 : 1;
				}else if (ptr_ != ((delegate_ptr *)db)->ptr_){
					return (ptr_ < ((delegate_ptr *)db)->ptr_) ? -1 : 1;
				}else return 0;
			}
		};
		template <typename C> class delegate_member : public delegatebase{
		protected:
			typedef R (C::*ptr_t)(T1 t1, T2 t2, T3 t3);
			C *obj_;
			ptr_t ptr_;
		public:
			delegate_member(C *obj, ptr_t ptr) : obj_(obj), ptr_(ptr){type = internal::MemberPointer;};
			delegate_member(C *obj) : obj_(obj), ptr_(&C::operator ()){type = internal::MemberPointer;};
			virtual R doIt(T1 t1, T2 t2, T3 t3){return (obj_->*ptr_)(t1, t2, t3);};
			virtual ~delegate_member(){};
			virtual int compare(delegatebase *db){
				if (type != ((delegate_member *)db)->type){
					return (type < ((delegate_member *)db)->type) ? -1 : 1;
				}else if (obj_ != ((delegate_member *)db)->obj_){
					return obj_ < ((delegate_member *)db)->obj_ ? -1 : 1;
				}else if (ptr_ != ((delegate_member *)db)->ptr_){
					return -1;
//					return ptr_ < ((delegate_member *)db)->ptr_ ? -1 : 1;
				}else return 0;
			}
		};

		typedef delegatebase delegate_type;
		typedef R (*ptr_type)(T1 t1, T2 t2, T3 t3);
		typedef internal::shared_ptr<delegate_type> shared_ptr_type;
	public:
		delegate3(){
		}
		delegate3(ptr_type ptr)
			: internal::delegateb(new shared_ptr_type(new delegate_ptr(ptr))){};
		template <typename C> delegate3(C *obj, R (C::*ptr)(T1,T2,T3))
			: internal::delegateb(new shared_ptr_type(new delegate_member<C>(obj, ptr))){};
		template <typename C> delegate3(C *obj)
			: internal::delegateb(new shared_ptr_type(new delegate_member<C>(obj))){};
		~delegate3(){};
		bool operator ==(const delegate3 &dele) const {
			if (delebase == NULL || dele.delebase == NULL) return (dele.delebase == delebase)
			return ((shared_ptr_type *)delebase)->get()->compare(((shared_ptr_type *)dele.delebase)->get()) == 0;
		}
		bool operator !=(const delegate3 &dele) const { return !((*this) == dele);}

		bool operator <(const delegate3 &dele) const {
			if (delebase == NULL) return (dele.delebase != NULL);
			if (dele.delebase == NULL) return false;
			return ((shared_ptr_type *)delebase)->get()->compare(((shared_ptr_type *)dele.delebase)->get()) < 0;
		}
		bool operator >(const delegate3 &dele) const {
			if (delebase == NULL) return false;
			if (dele.delebase == NULL) return (delebase != NULL);
			return ((shared_ptr_type *)delebase)->get()->compare(((shared_ptr_type *)dele.delebase)->get()) > 0;
		}
		bool operator >=(const delegate3 &dele) const { return !((*this) < dele);}
		bool operator <=(const delegate3 &dele) const { return !((*this) > dele);}

		R operator ()(T1 t1, T2 t2, T3 t3){
			if (delebase == NULL) return R();
			return ((shared_ptr_type *)delebase)->get()->doIt(t1, t2, t3);
		}
	};
	template <typename Iter, typename T1, typename T2, typename T3> void do_delegate3(Iter begin_, Iter end_, T1 t1, T2 t2, T3 t3){
		for (Iter iter = begin_; iter != end_; iter++){
			(*iter)(t1, t2, t3);
		}
	}

	template <typename R, typename T1, typename T2, typename T3, typename T4> class delegate4 : public internal::delegateb{
		class delegatebase{
		protected:
			internal::DelegateType type;
		public:
			virtual R doIt(T1 t1, T2 t2, T3 t3, T4 t4) = 0;
			virtual ~delegatebase(){};
			virtual int compare(delegatebase *db) = 0;
		};
		class delegate_ptr : public delegatebase{
		protected:
			typedef R (*ptr_t)(T1 t1, T2 t2, T3 t3, T4 t4);
			ptr_t ptr_;
		public:
			delegate_ptr(ptr_t ptr) : ptr_(ptr){type = internal::Pointer;};
			virtual R doIt(T1 t1, T2 t2, T3 t3, T4 t4){return ptr_(t1, t2, t3, t4);};
			virtual ~delegate_ptr(){};
			virtual int compare(delegatebase *db){
				if (type != ((delegate_ptr *)db)->type){
					return (type < ((delegate_ptr *)db)->type) ? -1 : 1;
				}else if (ptr_ != ((delegate_ptr *)db)->ptr_){
					return (ptr_ < ((delegate_ptr *)db)->ptr_) ? -1 : 1;
				}else return 0;
			}
		};
		template <typename C> class delegate_member : public delegatebase{
		protected:
			typedef R (C::*ptr_t)(T1 t1, T2 t2, T3 t3, T4 t4);
			C *obj_;
			ptr_t ptr_;
		public:
			delegate_member(C *obj, ptr_t ptr) : obj_(obj), ptr_(ptr){type = internal::MemberPointer;};
			delegate_member(C *obj) : obj_(obj), ptr_(&C::operator ()){type = internal::MemberPointer;};
			virtual R doIt(T1 t1, T2 t2, T3 t3, T4 t4){return (obj_->*ptr_)(t1, t2, t3, t4);};
			virtual ~delegate_member(){};
			virtual int compare(delegatebase *db){
				if (type != ((delegate_member *)db)->type){
					return (type < ((delegate_member *)db)->type) ? -1 : 1;
				}else if (obj_ != ((delegate_member *)db)->obj_){
					return obj_ < ((delegate_member *)db)->obj_ ? -1 : 1;
				}else if (ptr_ != ((delegate_member *)db)->ptr_){
					return -1;
//					return ptr_ < ((delegate_member *)db)->ptr_ ? -1 : 1;
				}else return 0;
			}
		};

		typedef delegatebase delegate_type;
		typedef R (*ptr_type)(T1 t1, T2 t2, T3 t3, T4 t4);
		typedef internal::shared_ptr<delegate_type> shared_ptr_type;
	public:
		delegate4(){
		}
		delegate4(ptr_type ptr)
			: internal::delegateb(new shared_ptr_type(new delegate_ptr(ptr))){};
		template <typename C> delegate4(C *obj, R (C::*ptr)(T1,T2,T3,T4))
			: internal::delegateb(new shared_ptr_type(new delegate_member<C>(obj, ptr))){};
		template <typename C> delegate4(C *obj)
			: internal::delegateb(new shared_ptr_type(new delegate_member<C>(obj))){};
		~delegate4(){};
		bool operator ==(const delegate4 &dele) const {
			if (delebase == NULL || dele.delebase == NULL) return (dele.delebase == delebase)
			return ((shared_ptr_type *)delebase)->get()->compare(((shared_ptr_type *)dele.delebase)->get()) == 0;
		}
		bool operator !=(const delegate4 &dele) const { return !((*this) == dele);}

		bool operator <(const delegate4 &dele) const {
			if (delebase == NULL) return (dele.delebase != NULL);
			if (dele.delebase == NULL) return false;
			return ((shared_ptr_type *)delebase)->get()->compare(((shared_ptr_type *)dele.delebase)->get()) < 0;
		}
		bool operator >(const delegate4 &dele) const {
			if (delebase == NULL) return false;
			if (dele.delebase == NULL) return (delebase != NULL);
			return ((shared_ptr_type *)delebase)->get()->compare(((shared_ptr_type *)dele.delebase)->get()) > 0;
		}
		bool operator >=(const delegate4 &dele) const { return !((*this) < dele);}
		bool operator <=(const delegate4 &dele) const { return !((*this) > dele);}

		R operator ()(T1 t1, T2 t2, T3 t3, T4 t4){
			if (delebase == NULL) return R();
			return ((shared_ptr_type *)delebase)->get()->doIt(t1, t2, t3, t4);
		}
	};
	template <typename Iter, typename T1, typename T2, typename T3, typename T4> void do_delegate4(Iter begin_, Iter end_, T1 t1, T2 t2, T3 t3, T4 t4){
		for (Iter iter = begin_; iter != end_; iter++){
			(*iter)(t1, t2, t3, t4);
		}
	}

}

// History
// Ver 1.25 2006/04/17
//  * define default constructors.
// Ver 1.20 2006/04/16
//  * add the template functions to invoke delegates in container.
//  * add the delegate with four arguments.
// Ver 1.10 2006/04/12
//  * implement comparison operators "==", "!=", "<", ">", "<=", and ">="
//  * change license to Boost License Version 1.00
// Ver 1.00 2006/04/11 first release

#endif // IG_UMDELEGATE_H_INCLUDED_

