/***************************** PDI STD File ***********************************
This file is taken from external sources. this is taken from open source uClibc++ 
library available on github. below is reference link. Thanking to author for
providing this .

This is free software. you can redistribute it and/or modify it but without any
warranty.

referred from   : https://github.com/mike-matera/ArduinoSTL
added Date      : 1st Dec 2024
added by        : Suraj I.
******************************************************************************/

// todo : check when to use new file version of new operator or standard <new>
// #include "new"
#include <new>
#include "cstddef"
#include "cstdlib"
#include "iterator_base"
#include "utility"
#include "cstdio"
#include "basic_definitions"

#ifndef HEADER_PDISTD_MEMORY
#define HEADER_PDISTD_MEMORY 1

#pragma GCC visibility push(default)

namespace pdistd{

template <class T> class allocator;
	// Specialize for void:

template <> class _UCXXEXPORT allocator<void> {
public:
	typedef void*       pointer;
	typedef const void* const_pointer;
	typedef void  value_type;
	template <class U> struct rebind { typedef allocator<U> other; };
};

template <class T> class _UCXXEXPORT allocator{
public:
	typedef T value_type;
	typedef size_t size_type;
	typedef ptrdiff_t difference_type;
	
	typedef T* pointer;
	typedef const T* const_pointer;

	typedef T& reference;
	typedef const T& const_reference;

	pointer address(reference r) const { return &r; }
	const_pointer address(const_reference r) const { return &r; }
	
	allocator() _UCXX_USE_NOEXCEPT{}
	template <class U> allocator(const allocator<U>& ) _UCXX_USE_NOEXCEPT;
	~allocator() _UCXX_USE_NOEXCEPT{}

	//Space for n Ts
	pointer allocate(size_type n, typename allocator<void>::const_pointer = 0){
		return static_cast<T*>(::operator new( n * sizeof(T) ));
	}
	void deallocate(pointer p, size_type){
		::operator delete(p);
	}

	//Use placement new to engage the constructor
	void construct(pointer p, const T& val) { new(static_cast<void*>(p)) T(val); }
	void destroy(pointer p){ p->~T(); }	//Call destructor

	size_type max_size() const _UCXX_USE_NOEXCEPT;
	template<class U> struct rebind { typedef allocator<U> other; };

};

template <class Out, class T> class _UCXXEXPORT raw_storage_iterator
	: public iterator<output_iterator_tag, void, void, void, void>
{
		Out p;

public:
	explicit raw_storage_iterator(Out pp) : p (pp) {  }
	raw_storage_iterator & operator*() { return *this; }
	raw_storage_iterator & operator=(const T& val) {
		T* pp = &*p;
		new(pp) T(val);
		return *this;
	}

	raw_storage_iterator & operator++() { ++p; return *this; }
	raw_storage_iterator operator++(int) {
		raw_storage_iterator t = *this;
		++p;
		return t;
	}
};

template <class T> _UCXXEXPORT pair<T*, ptrdiff_t> get_temporary_buffer(ptrdiff_t n){
	pair<T*, ptrdiff_t> retval;
	retval.first = static_cast<T*>(malloc(n * sizeof(T)));
	if(retval.first == 0){
		retval.second = 0;
	}else{
		retval.second = n;
	}
	return retval;
}

template <class T> _UCXXEXPORT void return_temporary_buffer(T* p){
	free(p);
}


template <class T> class _UCXXEXPORT auto_ptr{

private:
	T * object;
	template <class Y> struct auto_ptr_ref{
		Y * p;
	};

public:

	typedef T element_type;

	explicit auto_ptr(T* p =0) _UCXX_USE_NOEXCEPT : object(p){  }
	auto_ptr(auto_ptr& p) _UCXX_USE_NOEXCEPT : object(p.release()){ }
	auto_ptr(auto_ptr_ref<T> r) _UCXX_USE_NOEXCEPT : object(r.p){
		r.p = 0;
	}
	template<class Y> auto_ptr(auto_ptr<Y>& p) _UCXX_USE_NOEXCEPT : object(p.release()){ }
	auto_ptr& operator=(auto_ptr& p) _UCXX_USE_NOEXCEPT{
		if(&p == this){
			return *this;
		}
		delete object;
		object = p.release();
		return *this;
	}
	auto_ptr& operator=(nullptr_t p) _UCXX_USE_NOEXCEPT{
		if( nullptr != object ){
			delete object;
			object = nullptr;
		}
		return *this;
	}
	template<class Y> auto_ptr& operator=(auto_ptr<Y>& p) _UCXX_USE_NOEXCEPT{
		if(&p == this){
			return *this;
		}
		delete object;
		object = p.release();
		return *this;
	}
	~auto_ptr(){
		delete object;
	}

	T& operator*() const _UCXX_USE_NOEXCEPT{
		return *object;
	}
	T* operator->() const _UCXX_USE_NOEXCEPT{
		return object;
	}
	T* get() const _UCXX_USE_NOEXCEPT{
		return object;
	}
	T* release() _UCXX_USE_NOEXCEPT{
		T * temp(object);
		object = 0;
		return temp;
	}
	void reset(T * p=0) _UCXX_USE_NOEXCEPT{
		if(p != object){
			delete object;
			object = p;
		}
	}
	template<class Y> operator auto_ptr_ref<Y>() _UCXX_USE_NOEXCEPT{
		auto_ptr_ref<Y> retval;
		retval.p = object;
		object = 0;
		return retval;
	}
	template<class Y> operator auto_ptr<Y>() _UCXX_USE_NOEXCEPT{
		auto_ptr<Y> retval(object);
		object = 0;
		return retval;
	}

    inline bool operator!=(const auto_ptr<T>& rhs)
    { return get() != rhs.get(); }

    inline bool operator!=(nullptr_t rhs)
    { return get() != nullptr; }

    inline bool operator==(nullptr_t rhs)
    { return get() == nullptr; }
};

// template <typename lhs, typename rhs>
// inline bool
// operator!=(const auto_ptr<lhs> &__x,
// 		   const auto_ptr<rhs> &__y)
// {
// 	return __x.get() != __y.get();
// }

    /// auto_ptr comparison with nullptr
    template <typename _Tp>
    inline bool
    operator!=(const auto_ptr<_Tp> &__a, nullptr_t) noexcept
    {
        return __a != nullptr;
    }

    /// auto_ptr comparison with nullptr
    template <typename _Tp>
    inline bool
    operator!=(nullptr_t, const auto_ptr<_Tp> &__a) noexcept
    {
        return __a != nullptr;
    }


}	//namespace pdistd

#pragma GCC visibility pop

#endif

