Files
geant4/source/externals/ptl/include/PTL/TaskAllocator.hh
T
2020-06-26 10:23:25 +02:00

340 lines
10 KiB
C++

//
// MIT License
// Copyright (c) 2020 Jonathan R. Madsen
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED
// "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//
// ------------------------------------------------------------
// Tasking class header file
//
// Class Description:
//
// A class for fast allocation of objects to the heap through a pool of
// chunks organised as linked list. It's meant to be used by associating
// it to the object to be allocated and defining for it new and delete
// operators via MallocSingle() and FreeSingle() methods.
// ---------------- TaskAllocator ----------------
//
// ------------------------------------------------------------
#pragma once
#include <cstddef>
#include <typeinfo>
#include "PTL/TaskAllocatorPool.hh"
#include "PTL/Threading.hh"
namespace PTL
{
//--------------------------------------------------------------------------------------//
class TaskAllocatorBase
{
public:
TaskAllocatorBase();
virtual ~TaskAllocatorBase();
virtual void ResetStorage() = 0;
virtual size_t GetAllocatedSize() const = 0;
virtual int GetNoPages() const = 0;
virtual size_t GetPageSize() const = 0;
virtual void IncreasePageSize(unsigned int sz) = 0;
virtual const char* GetPoolType() const = 0;
};
//--------------------------------------------------------------------------------------//
template <class Type>
class TaskAllocatorImpl : public TaskAllocatorBase
{
public: // with description
TaskAllocatorImpl();
~TaskAllocatorImpl();
// Constructor & destructor
inline Type* MallocSingle();
inline void FreeSingle(Type* anElement);
// Malloc and Free methods to be used when overloading
// new and delete operators in the client <Type> object
inline void ResetStorage() override;
// Returns allocated storage to the free store, resets allocator.
// Note: contents in memory are lost using this call !
inline size_t GetAllocatedSize() const override;
// Returns the size of the total memory allocated
inline int GetNoPages() const override;
// Returns the total number of allocated pages
inline size_t GetPageSize() const override;
// Returns the current size of a page
inline void IncreasePageSize(unsigned int sz) override;
// Resets allocator and increases default page size of a given factor
inline const char* GetPoolType() const override;
// Returns the type_info Id of the allocated type in the pool
public: // without description
// This public section includes standard methods and types
// required if the allocator is to be used as alternative
// allocator for STL containers.
// NOTE: the code below is a trivial implementation to make
// this class an STL compliant allocator.
// It is anyhow NOT recommended to use this class as
// alternative allocator for STL containers !
typedef Type value_type;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef Type* pointer;
typedef const Type* const_pointer;
typedef Type& reference;
typedef const Type& const_reference;
template <class U>
TaskAllocatorImpl(const TaskAllocatorImpl<U>& right) throw()
: mem(right.mem)
, tname(right.name())
{}
// Copy constructor
pointer address(reference r) const { return &r; }
const_pointer address(const_reference r) const { return &r; }
// Returns the address of values
pointer allocate(size_type n, void* = 0)
{
// Allocates space for n elements of type Type, but does not initialise
//
Type* mem_alloc = 0;
if(n == 1)
mem_alloc = MallocSingle();
else
mem_alloc = static_cast<Type*>(::operator new(n * sizeof(Type)));
return mem_alloc;
}
void deallocate(pointer p, size_type n)
{
// Deallocates n elements of type Type, but doesn't destroy
//
if(n == 1)
FreeSingle(p);
else
::operator delete((void*) p);
return;
}
void construct(pointer p, const Type& val) { new((void*) p) Type(val); }
// Initialises *p by val
void destroy(pointer p) { p->~Type(); }
// Destroy *p but doesn't deallocate
size_type max_size() const throw()
{
// Returns the maximum number of elements that can be allocated
//
return 2147483647 / sizeof(Type);
}
template <class U>
struct rebind
{
typedef TaskAllocatorImpl<U> other;
};
// Rebind allocator to type U
TaskAllocatorPool mem;
// Pool of elements of sizeof(Type)
private:
const char* tname;
// Type name identifier
};
//--------------------------------------------------------------------------------------//
//
// Inherit from this class, e.g. MyClass : public TaskAllocator<MyClass>
//
//--------------------------------------------------------------------------------------//
template <typename Type>
class TaskAllocator : public TaskAllocatorImpl<Type>
{
public:
typedef Type value_type;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef Type* pointer;
typedef const Type* const_pointer;
typedef Type& reference;
typedef const Type& const_reference;
typedef TaskAllocatorImpl<Type> allocator_type;
public:
// define the new operator
void* operator new(size_type)
{
return static_cast<void*>(get_allocator()->MallocSingle());
}
// define the delete operator
void operator delete(void* ptr)
{
get_allocator()->FreeSingle(static_cast<pointer>(ptr));
}
private:
// currently disabled due to memory leak found via -fsanitize=leak
// static function to get allocator
static allocator_type* get_allocator()
{
typedef std::unique_ptr<allocator_type> allocator_ptr;
static thread_local allocator_ptr _allocator = allocator_ptr(new allocator_type);
return _allocator.get();
}
};
//--------------------------------------------------------------------------------------//
// Inline implementation
template <class Type>
TaskAllocatorImpl<Type>::TaskAllocatorImpl()
: mem(sizeof(Type))
, tname(typeid(Type).name())
{}
// ************************************************************
// TaskAllocatorImpl destructor
// ************************************************************
//
template <class Type>
TaskAllocatorImpl<Type>::~TaskAllocatorImpl()
{}
// ************************************************************
// MallocSingle
// ************************************************************
//
template <class Type>
Type*
TaskAllocatorImpl<Type>::MallocSingle()
{
return static_cast<Type*>(mem.Alloc());
}
// ************************************************************
// FreeSingle
// ************************************************************
//
template <class Type>
void
TaskAllocatorImpl<Type>::FreeSingle(Type* anElement)
{
mem.Free(anElement);
return;
}
// ************************************************************
// ResetStorage
// ************************************************************
//
template <class Type>
void
TaskAllocatorImpl<Type>::ResetStorage()
{
// Clear all allocated storage and return it to the free store
//
mem.Reset();
return;
}
// ************************************************************
// GetAllocatedSize
// ************************************************************
//
template <class Type>
size_t
TaskAllocatorImpl<Type>::GetAllocatedSize() const
{
return mem.Size();
}
// ************************************************************
// GetNoPages
// ************************************************************
//
template <class Type>
int
TaskAllocatorImpl<Type>::GetNoPages() const
{
return mem.GetNoPages();
}
// ************************************************************
// GetPageSize
// ************************************************************
//
template <class Type>
size_t
TaskAllocatorImpl<Type>::GetPageSize() const
{
return mem.GetPageSize();
}
// ************************************************************
// IncreasePageSize
// ************************************************************
//
template <class Type>
void
TaskAllocatorImpl<Type>::IncreasePageSize(unsigned int sz)
{
ResetStorage();
mem.GrowPageSize(sz);
}
// ************************************************************
// GetPoolType
// ************************************************************
//
template <class Type>
const char*
TaskAllocatorImpl<Type>::GetPoolType() const
{
return tname;
}
// ************************************************************
// operator==
// ************************************************************
//
template <class T1, class T2>
bool
operator==(const TaskAllocatorImpl<T1>&, const TaskAllocatorImpl<T2>&) throw()
{
return true;
}
// ************************************************************
// operator!=
// ************************************************************
//
template <class T1, class T2>
bool
operator!=(const TaskAllocatorImpl<T1>&, const TaskAllocatorImpl<T2>&) throw()
{
return false;
}
} // namespace PTL