Skip to content
Snippets Groups Projects
ExtPreAlloc.hpp 8.31 KiB
Newer Older
/* ExtPreAlloc.hpp
 *
 *  Created on: Apr 3, 2015
 *      Author: Pietro Incardona
 */

#ifndef EXTPREALLOC_HPP_
#define EXTPREALLOC_HPP_

#include <stddef.h>
#include "memory.hpp"
#include <iostream>
/*! Preallocated memory sequence
 *
 * External pre-allocated memory, is a class that preallocate memory and than it answer
 * to a particular allocation pattern
 *
 * \warning zero sized allocation are removed from the request pattern
 *
 * \tparam Base memory allocation class [Example] HeapMemory or CudaMemory
 *
 *
 */

template<typename Mem>
class ExtPreAlloc : public memory
{
	//! Actual allocation pointer
	size_t a_seq ;
	//! Last allocation size
Yaroslav's avatar
Yaroslav committed
	size_t l_size;
	//! Main class for memory allocation
	Mem * mem;
	//! Reference counter
	long int ref_cnt;

public:

	{
		if (ref_cnt != 0)
			std::cerr << "Error: " << __FILE__ << " " << __LINE__ << " destroying a live object" << "\n";
	}

	//! Default constructor
	ExtPreAlloc()
Yaroslav's avatar
Yaroslav committed
	:a_seq(0),l_size(0),mem(NULL),ref_cnt(0)
tonynsyde's avatar
tonynsyde committed
	/*! \brief Preallocated memory sequence
	 *
	 * \param size number of bytes
	 * \param mem external memory, used if you want to keep the memory
	 *
	 */
	ExtPreAlloc(size_t size, Mem & mem)
Yaroslav's avatar
Yaroslav committed
	:a_seq(0),l_size(0),mem(&mem),ref_cnt(0)
tonynsyde's avatar
tonynsyde committed
	{
		// Allocate the total size of memory
		mem.resize(size);
tonynsyde's avatar
tonynsyde committed
	}

	/*! \brief Set the internal memory if you did not do it in the constructor
     *
	 * \param size number of bytes
	 * \param mem external memory, used if you want to keep the memory
     *
	 */
	void setMemory(size_t size, Mem & mem)
	{
		this->mem = &mem;
		mem.resize(size);
	}

	/*! \brief Get the internal memory if you did not do it in the constructor
     *
	 * \return the internal memory
     *
	 */
	Mem * getMemory()
	{
		return this->mem;
	}
Pietro Incardona's avatar
Pietro Incardona committed
	/*! \brief Copy the memory from device to device
	 *
	 * \param m memory from where to copy
	 *
	 */
	bool copyDeviceToDevice(const ExtPreAlloc<Mem> & m)
	{
		return mem->copyDeviceToDevice(*m.mem);
	}

	/*! \brief special function to move memory from a raw device pointer
	 *
	 * \param start byte
	 * \param stop byte
	 *
	 * \param offset destination byte
	 *
	 */
	void deviceToDevice(void * ptr, size_t start, size_t stop, size_t offset)
	{
		mem->deviceToDevice(ptr,start,stop,offset);
	}

Pietro Incardona's avatar
Pietro Incardona committed
	constexpr static bool isDeviceHostSame()
Pietro Incardona's avatar
Pietro Incardona committed
	{
		return Mem::isDeviceHostSame();
	}

	//! Increment the reference counter
	virtual void incRef()
	{ref_cnt++;}

	//! Decrement the reference counter
	virtual void decRef()
	{ref_cnt--;}

	//! Return the reference counter
	virtual long int ref()
	{
		return ref_cnt;
	}

Pietro Incardona's avatar
Pietro Incardona committed
	//! flush the memory
	virtual bool flush() {return mem->flush();};

Pietro Incardona's avatar
Pietro Incardona committed
	/*! \brief fill host and device memory with the selected byte
	 *
	 *
	 */
	virtual void fill(unsigned char c)
	{
		mem->fill(c);
	}

	/*! \brief Allocate a chunk of memory
	 *
	 * Allocate a chunk of memory
	 *
	 * \param sz size of the chunk of memory to allocate in byte
	 *
	 */
	virtual bool allocate(size_t sz)
	{
		// Zero sized allocation are ignored
		if (sz == 0)
			return true;

Yaroslav's avatar
Yaroslav committed
		a_seq = l_size;
		l_size += sz;
		// Check we do not overflow the allocated memory
Pietro Incardona's avatar
Pietro Incardona committed
#ifdef SE_CLASS1
Pietro Incardona's avatar
Pietro Incardona committed
		if (l_size > mem->size())
			std::cerr << __FILE__ << ":" << __LINE__ << " Error requesting more memory than the allocated one" << std::endl;
	/*! \brief Allocate a chunk of memory
	 *
	 * Allocate a chunk of memory
	 *
	 * \param sz size of the chunk of memory to allocate in byte
	 *
	 */
	bool allocate_nocheck(size_t sz)
	{
		// Zero sized allocation are ignored
		if (sz == 0)
			return true;

		a_seq = l_size;
		l_size += sz;

		return true;
	}

Yaroslav's avatar
Yaroslav committed
	/*! \brief Return the end pointer of the previous allocated memory
	 * \return the pointer
Yaroslav's avatar
Yaroslav committed
	void * getPointerEnd()
Yaroslav's avatar
Yaroslav committed
		return (char *)mem->getPointer() + l_size;
	}
	/*! \brief Return the device end pointer of the previous allocated memory
	 *
	 * \return the pointer
	 *
	 */
	void * getDevicePointerEnd()
	{
		return (char *)mem->getDevicePointer() + l_size;
	}

Yaroslav's avatar
Yaroslav committed
	/*! \brief The the base pointer of the preallocate memory
	 *
	 * \return the base pointer
	 *
	 */
	void * getPointerBase()
	{
		return mem->getPointer();
	/*! \brief Return the pointer of the last allocation
	 *
Pietro Incardona's avatar
Pietro Incardona committed
	 * NULL if memory has not been allocated
	 * 
	 * \return the pointer
	 *
	 */
	virtual void * getDevicePointer()
	{
Pietro Incardona's avatar
Pietro Incardona committed
		if (mem != NULL)
		{return (((unsigned char *)mem->getDevicePointer()) + a_seq );}
		else {return NULL;}
	}

	/*! \brief Return the pointer of the last allocation
	 *
	 * \return the pointer
	 *
	 */
	virtual void hostToDevice()
		mem->hostToDevice();
	}

	/*! \brief Return the pointer of the last allocation
	 *
	 * \return the pointer
	 *
	 */
	virtual void hostToDevice(size_t start, size_t stop)
	{
		mem->hostToDevice(start,stop);
	virtual void deviceToHost()
	{
		mem->deviceToHost();
	};
Pietro Incardona's avatar
Pietro Incardona committed
	//! Do nothing
	virtual void deviceToHost(size_t start, size_t stop)
	{
		mem->deviceToHost(start,stop);
	};
	/*! \brief Return the pointer of the last allocation
	 *
	 * \return the pointer
	 *
	 */
Yaroslav's avatar
Yaroslav committed
	virtual void * getPointer()
Yaroslav's avatar
Yaroslav committed
		return (((unsigned char *)mem->getPointer()) + a_seq );
Yaroslav's avatar
Yaroslav committed
	/*! \brief Return the pointer of the last allocation
Yaroslav's avatar
Yaroslav committed
	 * \return the pointer
Yaroslav's avatar
Yaroslav committed
	virtual const void * getPointer() const
Yaroslav's avatar
Yaroslav committed
		return (((unsigned char *)mem->getPointer()) + a_seq);
	}

	/*! \brief Get the base memory pointer increased with an offset
	 *
	 * \param offset memory offset
	 *
	 */
	void * getPointerOffset(size_t offset)
		return (((unsigned char *)mem->getPointer()) + offset);
	/*! \brief Allocate or resize the allocated memory
	 *
	 * Resize the allocated memory, if request is smaller than the allocated, memory
	 * is not resized
	 *
	 * \param sz size
	 * \return true if the resize operation complete correctly
	 *
	 */

	virtual bool resize(size_t sz)
	{
		return allocate(sz);
	}

tonynsyde's avatar
tonynsyde committed
	/*! \brief Get the size of the LAST allocated memory
	 *
	 * Get the size of the allocated memory
	 *
	 * \return the size of the allocated memory
	 *
	 */

	virtual size_t size() const
Yaroslav's avatar
Yaroslav committed
		return l_size;
	}

	/*! \brief Destroy memory
	 *
	 */

	void destroy()
	{
		mem->destroy();
	}

	/*! \brief Copy memory
	 *
	 */

	virtual bool copy(const memory & m)
	{
		return mem->copy(m);
	}

	/*! \brief Allocated Memory is never initialized
	 *
	 * \return false
	 *
	 */
	bool isInitialized()
	{
		return false;
	}

	/*! \brief Calculate the total memory required to pack the message
	 *
	 * \return the total required memory
	 *
	 */
	static size_t calculateMem(std::vector<size_t> & mm)
	{
		size_t s = 0;

		for (size_t i = 0 ; i < mm.size() ; i++)
			s += mm[i];

		return s;
	}

	/*! \brief shift the pointer backward
	 *
	 * \warning when you shift backward the pointer, the last allocation is lost
	 * 			this mean that you have to do again an allocation.
	 *
	 * This function is useful to go ahead in memory and fill the memory later on
	 *
	 * \code

	  mem.allocate(16); <------ Here we allocate 16 byte but we do not fill it because
	  	  	  	  	  	  	    subsequently we do another allocation without using mem
	  unsigned char * start = (unsigned char *)mem.getPointer()
	  mem.allocate(100)

	  // ...
	  // ...
	  // Code that fill mem in some way and do other mem.allocate(...)
	  // ...
	  // ...

	  unsigned char * final = (unsigned char *)mem.getPointer()
	  mem.shift_backward(final - start);
	  mem.allocate(16);  <------ Here I am getting the same memory that I request for the
	  	  	  	  	  	  	  	 first allocate

	  // we now fill the memory

	  \endcode
	 *
	 *
	 *
	 * \param how many byte to shift
	 *
	 */
	void shift_backward(size_t sz)
	{
		a_seq -= sz;
		l_size = a_seq;
	}

	/*! \brief shift the pointer forward
	 *
	 * The same as shift backward, but in this case it move the pointer forward
	 *
	 * In general you use this function after the you went back with shift_backward
	 * and you have to move forward again
	 *
	 * \warning when you shift forward the pointer, the last allocation is lost
	 * 			this mean that you have to do again an allocation.
	 *
	 */
	void shift_forward(size_t sz)
	{
		a_seq += sz;
		l_size = a_seq;
	}

	/*! \brief Get offset
	 *
	 * \return the offset
	 *
	 */
	size_t getOffset()
	{
		return a_seq;
	}

	/*! \brief Get offset
	 *
	 * \return the offset
	 *
	 */
	size_t getOffsetEnd()
	{
		return l_size;
	}

	/*! \brief Reset the internal counters
	 *
	 *
	 */
	void reset()
	{
		a_seq = 0;
		l_size = 0;
	}
};

#endif /* PREALLOCHEAPMEMORY_HPP_ */