/*
 * Copyright 2015 Telenav Inc. All rights reserved.
 */
#ifndef TN_FOUNDATION_MEMORY_HPP
#define TN_FOUNDATION_MEMORY_HPP

#include "foundation/cxx11compat.hpp"

#if _TN_FOUNDATION_USE_STD_MEMORY
#  include <memory>
#else
#  ifdef TN_PLATFORM_QNX
#    include <stddef.h>
#    include <string.h>
#  endif
#  include "boost/shared_ptr.hpp"
#  include "boost/smart_ptr/make_shared.hpp"
#  include "boost/smart_ptr/enable_shared_from_this.hpp"
#  include "boost/weak_ptr.hpp"
#  include "boost/thread/detail/memory.hpp"
#endif 

namespace tn {
    using _TN_FOUNDATION_STD_MEMORY_NS::shared_ptr;
    using _TN_FOUNDATION_STD_MEMORY_NS::dynamic_pointer_cast;
    using _TN_FOUNDATION_STD_MEMORY_NS::static_pointer_cast;
    using _TN_FOUNDATION_STD_MEMORY_NS::const_pointer_cast;
    using _TN_FOUNDATION_STD_MEMORY_NS::make_shared;
    using _TN_FOUNDATION_STD_MEMORY_NS::enable_shared_from_this;
    using _TN_FOUNDATION_STD_MEMORY_NS::weak_ptr;
    using _TN_FOUNDATION_STD_MEMORY_NS::default_delete;

#if _TN_FOUNDATION_USE_STD_MEMORY
    template<class T, class Deleter = default_delete<T> > 
    using shunique_ptr = ::std::unique_ptr<T,Deleter>;

    // template < typename T, typename... Ts > std:: unique_ptr < T > make_shunique( Ts&&... params) { 
    //     return shunique_ptr < T >( new T( std:: forward < Ts >( params)...)); 
    // }

#else
    /**
     *  shunique_ptr is a smart pointer that turns into unique_ptr on C++11 and into
     *  slightly modified shared_ptr on C++03. Note that it does not yet works with arrays. 
     */
    template<class T, class Deleter = default_delete<T> > 
    class shunique_ptr {
    public:
        shunique_ptr() {}
        shunique_ptr( T* p ) : ptr_( p, Deleter() ) {}
	   
        shunique_ptr& operator=( const shunique_ptr& rhs ) { ptr_ = rhs.ptr_; return *this; }

        T* release() { return ptr_.release(); }
        void reset( T* p = 0 ) { ptr_.reset(p); }
        void swap(shunique_ptr& other) { ptr_.swap(other.ptr_); }

        T* get() const { return ptr_.get(); }
        Deleter& get_deleter() { return ptr_.get_deleter(); }
        const Deleter& get_deleter() const { return ptr_.get_deleter(); }

        T& operator*() const { return *ptr_.get(); }
        T* operator->() const { return ptr_.get(); }

    private:
        shared_ptr<T> ptr_;
    };
#endif



}

#endif /* TN_FOUNDATION_MEMORY_HPP */
