summaryrefslogblamecommitdiffstatshomepage
path: root/src/lib/netlist/plib/palloc.h
blob: 0a79302787d1bb88dbc452609ee8fb5b0d042398 (plain) (tree)
1
2
3
4
5
6
7
8
9
10

                               



                 



                  
                    
                    
                   
 
                                                                   
                 






                                                           
 
                
 








                                                                                                    
 
                                                        

                                                                                               
 

                                                                                             
                                                          




                                      
                                                                                             

                            


                                                                                     

                                                                      
     

                                                                                     

                                                                                 
                                              
                 
                                          

























                                                                      
                                                


                                                          
                                                           







                                                                 
                                                                         



























                                                             
                                                
























                                                             


                                                                            






























                                                                                                                     
         











                                                                                         
                                                        
 




                                                                 
                                                                                     



                              

                                  








                                                                                         
                                                             








                                                                                                   


                                                           














                                                                                           
         
 




                                                                      
         




                                                                                


                                                                                            

                                                                                           
                                                                






                                                                             
                                                     
















                                                                                   
                                                                   
                 
                                                     







                                                                              
                                                              

                                                                    









                                                                                                        
                 
 
                                                      
                                                            






                                                                                                             
                                   

                                                
                                      

                         
 
                                                                         




                                              


                                                
                                                         





                                                                                                       
                        



                                                                                 

         

                                                                  
         

                                                                                                       
                        



                                                                                       

         


                                              
         

                                                                         
         

                            
                                            
         

                                               

         





                                                                               
         
                                                                                 
         
 

                                                                          
 



                                                                      
 



                                                  
         


                                                                                                          

          

                                                                                        
         


                                                                                                          
          
 


                                                                      
 
                                       
                                                                









                                                                                 
 
                                 
 


                                                                       







                                                                                       
 



                                                                                                          
 
                   
 
                   
// license:GPL-2.0+
// copyright-holders:Couriersud

#ifndef PALLOC_H_
#define PALLOC_H_

///
/// \file palloc.h
///

#include "pconfig.h"
#include "pstring.h"
#include "ptypes.h"

#include <cstddef>      // for std::max_align_t (usually long long)
#include <memory>
#include <type_traits>
#include <utility>
#include <vector>

#if defined(_WIN32) || defined(_WIN64) || defined(_MSC_VER)
#include <malloc.h>
#endif

namespace plib {

	//============================================================
	// Standard arena_deleter
	//============================================================

	template <typename P, typename T>
	struct arena_deleter
	{
		//using arena_storage_type = P *;
		using arena_storage_type = typename std::conditional<P::is_stateless, P, P *>::type;

		template <typename X, typename Y = void>
		typename std::enable_if<!X::is_stateless, X&>::type getref(X *x) const noexcept
		{ return *x;}

		template <typename X, typename Y = void *>
		typename std::enable_if<std::remove_pointer<X>::type::is_stateless, X&>::type
		getref(X &x, Y y = nullptr) const noexcept
		{
			unused_var(y);
			return x;
		}

		constexpr arena_deleter(arena_storage_type a = arena_storage_type()) noexcept
		: m_a(a) { }

#if 1
		template<typename U, typename = typename
			   std::enable_if<std::is_convertible< U*, T*>::value>::type>
		arena_deleter(const arena_deleter<P, U> &rhs) noexcept
		: m_a(rhs.m_a) { }
#else
		template<typename PU, typename U, typename = typename
			   std::enable_if<std::is_convertible< U*, T*>::value>::type>
		arena_deleter(const arena_deleter<PU, U> &rhs) : m_a(rhs.m_a) { }
#endif
		void operator()(T *p) noexcept
		{
			// call destructor
			p->~T();
			getref(m_a).deallocate(p);
		}
	//private:
		arena_storage_type m_a;
	};

	//============================================================
	// owned_ptr: smart pointer with ownership information
	//============================================================

	template <typename SC, typename D>
	class owned_ptr
	{
	public:

		using pointer = SC *;
		using element_type = SC;
		using deleter_type = D;

		owned_ptr()
		: m_ptr(nullptr), m_deleter(), m_is_owned(true) { }

		template <typename, typename>
		friend class owned_ptr;

		owned_ptr(pointer p, bool owned)
		: m_ptr(p), m_deleter(), m_is_owned(owned)
		{ }

		owned_ptr(pointer p, bool owned, D deleter)
		: m_ptr(p), m_deleter(deleter), m_is_owned(owned)
		{ }


		owned_ptr(const owned_ptr &r) = delete;
		owned_ptr & operator =(owned_ptr &r) = delete;

		template<typename DC, typename DC_D>
		owned_ptr & operator =(owned_ptr<DC, DC_D> &&r)  noexcept
		{
			if (m_is_owned && (m_ptr != nullptr))
				//delete m_ptr;
				m_deleter(m_ptr);
			m_is_owned = r.m_is_owned;
			m_ptr = r.m_ptr;
			m_deleter = r.m_deleter;
			r.m_is_owned = false;
			r.m_ptr = nullptr;
			return *this;
		}

		owned_ptr(owned_ptr &&r) noexcept
		: m_ptr(r.m_ptr)
		, m_deleter(r.m_deleter)
		, m_is_owned(r.m_is_owned)
		{
			r.m_is_owned = false;
			r.m_ptr = nullptr;
		}

		owned_ptr &operator=(owned_ptr &&r) noexcept
		{
			if (m_is_owned && (m_ptr != nullptr))
				//delete m_ptr;
				m_deleter(m_ptr);
			m_is_owned = r.m_is_owned;
			m_ptr = r.m_ptr;
			m_deleter = r.m_deleter;
			r.m_is_owned = false;
			r.m_ptr = nullptr;
			return *this;
		}

		template<typename DC, typename DC_D>
		owned_ptr(owned_ptr<DC, DC_D> &&r) noexcept
		: m_ptr(static_cast<pointer >(r.get()))
		, m_deleter(r.m_deleter)
		, m_is_owned(r.is_owned())
		{
			r.release();
		}

		~owned_ptr() noexcept
		{
			if (m_is_owned && (m_ptr != nullptr))
			{
				//delete m_ptr;
				m_deleter(m_ptr);
			}
			m_is_owned = false;
			m_ptr = nullptr;
		}

		///
		/// \brief Return \c true if the stored pointer is not null.
		///
		explicit operator bool() const noexcept { return m_ptr != nullptr; }

		pointer  release()
		{
			pointer tmp = m_ptr;
			m_is_owned = false;
			m_ptr = nullptr;
			return tmp;
		}

		bool is_owned() const { return m_is_owned; }

		pointer  operator ->() const noexcept { return m_ptr; }
		typename std::add_lvalue_reference<element_type>::type operator *() const noexcept { return *m_ptr; }
		pointer  get() const noexcept { return m_ptr; }

		deleter_type& get_deleter() noexcept { return m_deleter; }
		const deleter_type& get_deleter() const noexcept { return m_deleter; }

	private:
		pointer m_ptr;
		D m_deleter;
		bool m_is_owned;
	};

	//============================================================
	// Arena allocator for use with containers
	//============================================================

	template <class ARENA, class T, std::size_t ALIGN = alignof(T)>
	class arena_allocator
	{
	public:
		using value_type = T;
		static constexpr const std::size_t align_size = ALIGN;
		using arena_type = ARENA;

		static_assert(align_size >= alignof(T) && (align_size % alignof(T)) == 0,
			"ALIGN must be greater than alignof(T) and a multiple");

		arena_allocator() noexcept
		: m_a(arena_type::instance())
		{ }

		//~arena_allocator() noexcept = default;

		arena_allocator(arena_type & a) noexcept : m_a(a)
		{
		}

		template <class U>
		arena_allocator(const arena_allocator<ARENA, U, ALIGN>& rhs) noexcept
		: m_a(rhs.m_a)
		{
		}

		template <class U>
		struct rebind
		{
			using other = arena_allocator<ARENA, U, ALIGN>;
		};

		T* allocate(std::size_t n)
		{
			return reinterpret_cast<T *>(m_a.allocate(ALIGN, sizeof(T) * n));
		}

		void deallocate(T* p, std::size_t n) noexcept
		{
			unused_var(n);
			m_a.deallocate(p);
		}

		template <class AR1, class T1, std::size_t A1, class AR2, class T2, std::size_t A2>
		friend bool operator==(const arena_allocator<AR1, T1, A1>& lhs,
			const arena_allocator<AR2, T2, A2>& rhs) noexcept;

		template <class AU, class U, std::size_t A>
		friend class arena_allocator;

	private:
		arena_type &m_a;
	};

	template <class AR1, class T1, std::size_t A1, class AR2, class T2, std::size_t A2>
	inline bool operator==(const arena_allocator<AR1, T1, A1>& lhs,
		const arena_allocator<AR2, T2, A2>& rhs) noexcept
	{
		return A1 == A2 && rhs.m_a == lhs.m_a;
	}
	template <class AR1, class T1, std::size_t A1, class AR2, class T2, std::size_t A2>
	inline bool operator!=(const arena_allocator<AR1, T1, A1>& lhs,
		const arena_allocator<AR2, T2, A2>& rhs) noexcept
	{
		return !(lhs == rhs);
	}

	//============================================================
	//  Memory allocation
	//============================================================

	struct aligned_arena
	{
		static constexpr const bool is_stateless = true;
		template <class T, std::size_t ALIGN = alignof(T)>
		using allocator_type = arena_allocator<aligned_arena, T, ALIGN>;

		template <typename T>
		using unique_pool_ptr = std::unique_ptr<T, arena_deleter<aligned_arena, T>>;

		template <typename T>
		using owned_pool_ptr = plib::owned_ptr<T, arena_deleter<aligned_arena, T>>;

		static inline aligned_arena &instance() noexcept
		{
			static aligned_arena s_arena;
			return s_arena;
		}

		static inline void *allocate( size_t alignment, size_t size )
		{
			#if (PUSE_ALIGNED_ALLOCATION)
			#if defined(_WIN32) || defined(_WIN64) || defined(_MSC_VER)
				return _aligned_malloc(size, alignment);
			#elif defined(__APPLE__)
				void* p;
				if (::posix_memalign(&p, alignment, size) != 0) {
					p = nullptr;
				}
				return p;
			#else
				return aligned_alloc(alignment, size);
			#endif
			#else
				unused_var(alignment);
				return ::operator new(size);
			#endif
		}

		static inline void deallocate( void *ptr ) noexcept
		{
			#if (PUSE_ALIGNED_ALLOCATION)
				// NOLINTNEXTLINE(cppcoreguidelines-no-malloc)
				free(ptr);
			#else
				::operator delete(ptr);
			#endif
		}

		template<typename T, typename... Args>
		unique_pool_ptr<T> make_unique(Args&&... args)
		{
			auto *mem = allocate(alignof(T), sizeof(T));
			try
			{
				auto *mema = new (mem) T(std::forward<Args>(args)...);
				return unique_pool_ptr<T>(mema, arena_deleter<aligned_arena, T>(*this));
			}
			catch (...)
			{
				deallocate(mem);
				throw;
			}
		}

		template<typename T, typename... Args>
		owned_pool_ptr<T> make_owned(Args&&... args)
		{
			auto *mem = allocate(alignof(T), sizeof(T));
			try
			{
				auto *mema = new (mem) T(std::forward<Args>(args)...);
				return owned_pool_ptr<T>(mema, true, arena_deleter<aligned_arena, T>(*this));
			}
			catch (...)
			{
				deallocate(mem);
				throw;
			}
		}

		bool operator ==(const aligned_arena &rhs) const noexcept
		{
			plib::unused_var(rhs);
			return true;
		}

	};

	template <typename T, std::size_t ALIGN>
	C14CONSTEXPR T *assume_aligned_ptr(T *p) noexcept
	{
		static_assert(ALIGN >= alignof(T), "Alignment must be greater or equal to alignof(T)");
		static_assert(is_pow2(ALIGN), "Alignment must be a power of 2");
		//auto t = reinterpret_cast<std::uintptr_t>(p);
		//if (t & (ALIGN-1))
		//  printf("alignment error!");
#if (PUSE_ALIGNED_HINTS)
		return reinterpret_cast<T *>(__builtin_assume_aligned(p, ALIGN));
#else
		return p;
#endif
	}

	template <typename T, std::size_t ALIGN>
	constexpr const T *assume_aligned_ptr(const T *p) noexcept
	{
		static_assert(ALIGN >= alignof(T), "Alignment must be greater or equal to alignof(T)");
		static_assert(is_pow2(ALIGN), "Alignment must be a power of 2");
#if (PUSE_ALIGNED_HINTS)
		return reinterpret_cast<const T *>(__builtin_assume_aligned(p, ALIGN));
#else
		return p;
#endif
	}

	// FIXME: remove
	template<typename T, typename... Args>
	inline T *pnew(Args&&... args)
	{
		auto *p = aligned_arena::allocate(alignof(T), sizeof(T));
		return new(p) T(std::forward<Args>(args)...);
	}

	template<typename T>
	inline void pdelete(T *ptr) noexcept
	{
		ptr->~T();
		aligned_arena::deallocate(ptr);
	}


	template <typename T>
	using unique_ptr = std::unique_ptr<T, arena_deleter<aligned_arena, T>>;

	template<typename T, typename... Args>
	plib::unique_ptr<T> make_unique(Args&&... args)
	{
		return plib::unique_ptr<T>(pnew<T>(std::forward<Args>(args)...));
	}

	template <class T, std::size_t ALIGN = alignof(T)>
	using aligned_allocator = aligned_arena::allocator_type<T, ALIGN>;

	//============================================================
	// traits to determine alignment size and stride size
	// from types supporting alignment
	//============================================================

	PDEFINE_HAS_MEMBER(has_align, align_size);

	template <typename T, typename X = void>
	struct align_traits
	{
		static constexpr const std::size_t align_size = alignof(std::max_align_t);
		static constexpr const std::size_t value_size = sizeof(typename T::value_type);
		static constexpr const std::size_t stride_size = lcm(align_size, value_size) / value_size;
	};

	template <typename T>
	struct align_traits<T, typename std::enable_if<has_align<T>::value, void>::type>
	{
		static constexpr const std::size_t align_size = T::align_size;
		static constexpr const std::size_t value_size = sizeof(typename T::value_type);
		static constexpr const std::size_t stride_size = lcm(align_size, value_size) / value_size;
	};

	//============================================================
	// Aligned vector
	//============================================================

	// FIXME: needs a separate file
	template <class T, std::size_t ALIGN = PALIGN_VECTOROPT>
	class aligned_vector : public std::vector<T, aligned_allocator<T, ALIGN>>
	{
	public:
		using base = std::vector<T, aligned_allocator<T, ALIGN>>;

		using reference = typename base::reference;
		using const_reference = typename base::const_reference;
		using pointer = typename base::pointer;
		using const_pointer = typename base::const_pointer;
		using size_type = typename base::size_type;

		using base::base;

		base & as_base() noexcept { return *this; }
		const base & as_base() const noexcept { return *this; }

		C14CONSTEXPR reference operator[](size_type i) noexcept
		{
			return assume_aligned_ptr<T, ALIGN>(&(base::operator[](0)))[i];
		}
		constexpr const_reference operator[](size_type i) const noexcept
		{
			return assume_aligned_ptr<T, ALIGN>(&(base::operator[](0)))[i];
		}

		pointer data() noexcept { return assume_aligned_ptr<T, ALIGN>(base::data()); }
		const_pointer data() const noexcept { return assume_aligned_ptr<T, ALIGN>(base::data()); }

	};

} // namespace plib

#endif // PALLOC_H_