#ifndef INCLUDED_AI_BOOST_SHARED_ARRAY
#define INCLUDED_AI_BOOST_SHARED_ARRAY

#ifndef BOOST_SCOPED_ARRAY_HPP_INCLUDED

// ------------------------------
// Internal stub
namespace boost {
	namespace array_detail {
		class controller {
		public:

			controller()
				: cnt(1)
			{}
		
		public:

			template <typename T>
			controller* decref(T* pt) {
				if (--cnt <= 0) {
					delete this;
					delete[] pt;
				}
				return NULL;
			}
		
			controller* incref() {
				++cnt;
				return this;
			}

			long get() const {
				return cnt;
			}

		private:
			long cnt;
		};

		struct empty {};
		
		template <typename DEST, typename SRC>
		struct is_convertible_stub {
			
			struct yes {char s[1];};
			struct no  {char s[2];};

			static yes foo(DEST*);
			static no  foo(...);

			enum {result = (sizeof(foo((SRC*)0)) == sizeof(yes) ? 1 : 0)};	
		};

		template <bool> struct enable_if {};
		template <> struct enable_if<true> {
			typedef empty result;
		};

		template <typename DEST, typename SRC>
		struct is_convertible : public enable_if<is_convertible_stub<DEST,SRC>::result > {
		};
	}

// ------------------------------
// Small replacement for boost::shared_array, not threadsafe because no
// atomic reference counter is in use.
// ------------------------------
template <class T>
class shared_array
{
	template <typename TT> friend class shared_array;

	template<class TT> friend bool operator== (const shared_array<TT>& a, const shared_array<TT>& b);
	template<class TT> friend bool operator!= (const shared_array<TT>& a, const shared_array<TT>& b);
	template<class TT> friend bool operator<  (const shared_array<TT>& a, const shared_array<TT>& b);

public:

	typedef T element_type;

public:

	// provide a default constructor
	shared_array()
		: ptr()
		, ctr(NULL)
	{
	}

	// construction from an existing object of type T
	explicit shared_array(T* ptr)
		: ptr(ptr)
		, ctr(ptr ? new array_detail::controller() : NULL)
	{
	}

	shared_array(const shared_array& r)
		: ptr(r.ptr)
		, ctr(r.ctr ? r.ctr->incref() : NULL)
	{
	}

	template <typename Y>
	shared_array(const shared_array<Y>& r,typename detail::is_convertible<T,Y>::result = detail::empty())
		: ptr(r.ptr)
		, ctr(r.ctr ? r.ctr->incref() : NULL)
	{
	}

	// automatic destruction of the wrapped object when all
	// references are freed.
	~shared_array()	{
		if (ctr) {
			ctr = ctr->decref(ptr);
		}
	}

	shared_array& operator=(const shared_array& r) {
		if (this == &r) {
			return *this;
		}
		if (ctr) {
			ctr->decref(ptr);
		}
		ptr = r.ptr;
		ctr = ptr?r.ctr->incref():NULL;
		return *this;
	}

	template <typename Y>
	shared_array& operator=(const shared_array<Y>& r) {
		if (this == &r) {
			return *this;
		}
		if (ctr) {
			ctr->decref(ptr);
		}
		ptr = r.ptr;
		ctr = ptr?r.ctr->incref():NULL;
		return *this;
	}

	// pointer access
	inline operator T*()	{
		return ptr;
	}

	inline T* operator-> () const	{
		return ptr;
	}

	// standard semantics
	inline T* get() {
		return ptr;
	}

	T& operator[] (std::ptrdiff_t index) const {
		return ptr[index];
	}

	inline const T* get() const	{
		return ptr;
	}

	inline operator bool () const {
		return ptr != NULL;
	}

	inline bool unique() const {
		return use_count() == 1;
	}

	inline long use_count() const {
		return ctr->get();
	}

	inline void reset (T* t = 0)	{
		if (ctr) {
			ctr->decref(ptr);
		}
		ptr = t;
		ctr = ptr?new array_detail::controller():NULL;
	}

	void swap(shared_array & b)	{
		std::swap(ptr, b.ptr);
		std::swap(ctr, b.ctr);
	}


private:

	// encapsulated object pointer
	T* ptr;

	// control block
	array_detail::controller* ctr;
};

template<class T>
inline void swap(shared_array<T> & a, shared_array<T> & b)
{
	a.swap(b);
}

template<class T>
bool operator== (const shared_array<T>& a, const shared_array<T>& b) {
	return a.ptr == b.ptr;
}
template<class T>
bool operator!= (const shared_array<T>& a, const shared_array<T>& b) {
	return a.ptr != b.ptr;
}
	
template<class T>
bool operator< (const shared_array<T>& a, const shared_array<T>& b) {
	return a.ptr < b.ptr;
}


} // end of namespace boost

#else
#	error "shared_array.h was already included"
#endif
#endif // INCLUDED_AI_BOOST_SHARED_ARRAY