feat: Implement a custom MetaAllocator for uLib::Vector to enable GPU memory management and integrate CUDA support into the build system.
This commit is contained in:
@@ -23,156 +23,386 @@
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
|
||||
|
||||
#ifndef U_CORE_VECTOR_H
|
||||
#define U_CORE_VECTOR_H
|
||||
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
#include <Core/DataAllocator.h>
|
||||
|
||||
#include <Core/StaticInterface.h>
|
||||
#include <Core/SmartPointer.h>
|
||||
#include <Core/CommaInitializer.h>
|
||||
|
||||
#include <Core/SmartPointer.h>
|
||||
#include <Core/StaticInterface.h>
|
||||
|
||||
namespace uLib {
|
||||
|
||||
// Vector Implemetation ... wraps std::vector
|
||||
template <typename T>
|
||||
class Vector : public std::vector<T, std::allocator<T> >
|
||||
{
|
||||
typedef std::vector< T,std::allocator<T> > BaseClass;
|
||||
typedef std::allocator<T> Allocator;
|
||||
public:
|
||||
typedef T TypeData;
|
||||
typedef __gnu_cxx::__normal_iterator<T*, BaseClass > Iterator;
|
||||
typedef __gnu_cxx::__normal_iterator<const T*, BaseClass> ConstIterator;
|
||||
|
||||
typedef CommaInitializer< Vector<T> , T > VectorCommaInit;
|
||||
|
||||
Vector(unsigned int size) : BaseClass(size) {}
|
||||
Vector(unsigned int size, T &value) : BaseClass(size,value) {}
|
||||
Vector() : BaseClass(0) {}
|
||||
|
||||
inline VectorCommaInit operator <<(T scalar) {
|
||||
return VectorCommaInit(this, scalar);
|
||||
}
|
||||
|
||||
inline void PrintSelf(std::ostream &o);
|
||||
|
||||
void remove_element(unsigned int index) {
|
||||
std::swap(this->at(index),this->back());
|
||||
this->pop_back();
|
||||
}
|
||||
|
||||
void remove_element(T &t) {
|
||||
std::swap(t, this->back());
|
||||
this->pop_back();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
void Vector<T>::PrintSelf(std::ostream &o)
|
||||
{
|
||||
o << " *** uLib Vector *** \n";
|
||||
o << " n. of items = " << this->size() << "\n";
|
||||
for(int i=0; i< this->size(); ++i)
|
||||
o << (T)this->at(i) << " ";
|
||||
o << "\n";
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::ostream & operator << (std::ostream &o, const Vector<T> &v) {
|
||||
for(int i=0; i< v.size(); ++i)
|
||||
o << (T)v.at(i) << " ";
|
||||
o << "\n";
|
||||
return o;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::ofstream & operator << (std::ofstream &o, const Vector<T> &v) {
|
||||
for(int i=0; i< v.size(); ++i)
|
||||
o << (T)v.at(i) << " ";
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
template < typename T >
|
||||
std::istream & operator >> (std::istream &is, Vector<T> &v) {
|
||||
T value;
|
||||
while( is >> value ) {
|
||||
if(is.fail()) v.push_back(0);
|
||||
else v.push_back( value );
|
||||
}
|
||||
return is;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Smart pointer Vector Implementation //
|
||||
|
||||
|
||||
template <typename T>
|
||||
class SmartVector : public SmartPointer< Vector<T> > {
|
||||
typedef SmartPointer< Vector<T> > Base;
|
||||
// MetaAllocator Implementation ...
|
||||
template <typename T> class MetaAllocator {
|
||||
public:
|
||||
using value_type = T;
|
||||
using pointer = T *;
|
||||
using const_pointer = const T *;
|
||||
using reference = T &;
|
||||
using const_reference = const T &;
|
||||
using size_type = std::size_t;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
|
||||
SmartVector() : Base(new Vector<T>()) { }
|
||||
SmartVector( const SmartVector ©) : Base(copy) { }
|
||||
SmartVector(unsigned int size) : Base(new Vector<T>((int)size)) { }
|
||||
template <class U> struct rebind {
|
||||
using other = MetaAllocator<U>;
|
||||
};
|
||||
|
||||
virtual ~SmartVector() {}
|
||||
MetaAllocator() noexcept = default;
|
||||
|
||||
T& operator[](int p) {
|
||||
return Base::get()->at(p);
|
||||
template <class U>
|
||||
constexpr MetaAllocator(const MetaAllocator<U> &) noexcept {}
|
||||
|
||||
T *allocate(std::size_t n) {
|
||||
if (n == 0)
|
||||
return nullptr;
|
||||
|
||||
DataAllocator<T> *da = new DataAllocator<T>(n, false);
|
||||
T *ptr = da->GetRAMData();
|
||||
|
||||
std::lock_guard<std::mutex> lock(GetMutex());
|
||||
GetAllocationMap()[ptr] = da;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void swap_elements(unsigned int first, unsigned int second) {
|
||||
std::swap(Base::get()->at(first),Base::get()->at(second));
|
||||
void deallocate(T *p, std::size_t /*n*/) noexcept {
|
||||
if (!p)
|
||||
return;
|
||||
|
||||
std::lock_guard<std::mutex> lock(GetMutex());
|
||||
auto &map = GetAllocationMap();
|
||||
auto it = map.find(p);
|
||||
if (it != map.end()) {
|
||||
delete it->second;
|
||||
map.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
static DataAllocator<T> *GetDataAllocator(T *p) {
|
||||
if (!p)
|
||||
return nullptr;
|
||||
std::lock_guard<std::mutex> lock(GetMutex());
|
||||
auto &map = GetAllocationMap();
|
||||
auto it = map.find(p);
|
||||
if (it != map.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
static std::map<T *, DataAllocator<T> *> &GetAllocationMap() {
|
||||
static std::map<T *, DataAllocator<T> *> allocMap;
|
||||
return allocMap;
|
||||
}
|
||||
|
||||
static std::mutex &GetMutex() {
|
||||
static std::mutex mtx;
|
||||
return mtx;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class U>
|
||||
bool operator==(const MetaAllocator<T> &, const MetaAllocator<U> &) {
|
||||
return true;
|
||||
}
|
||||
template <class T, class U>
|
||||
bool operator!=(const MetaAllocator<T> &, const MetaAllocator<U> &) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Vector Implemetation ... wraps std::vector
|
||||
template <typename T> class Vector : public std::vector<T, MetaAllocator<T>> {
|
||||
typedef std::vector<T, MetaAllocator<T>> BaseClass;
|
||||
typedef MetaAllocator<T> Allocator;
|
||||
|
||||
public:
|
||||
typedef T TypeData;
|
||||
typedef __gnu_cxx::__normal_iterator<T *, BaseClass> Iterator;
|
||||
typedef __gnu_cxx::__normal_iterator<const T *, BaseClass> ConstIterator;
|
||||
|
||||
typedef CommaInitializer<Vector<T>, T> VectorCommaInit;
|
||||
typedef typename BaseClass::iterator iterator;
|
||||
typedef typename BaseClass::const_iterator const_iterator;
|
||||
typedef typename BaseClass::size_type size_type;
|
||||
typedef typename BaseClass::reference reference;
|
||||
|
||||
Vector(unsigned int size) : BaseClass(size) {}
|
||||
Vector(unsigned int size, T &value) : BaseClass(size, value) {}
|
||||
Vector() : BaseClass(0) {}
|
||||
|
||||
inline VectorCommaInit operator<<(T scalar) {
|
||||
return VectorCommaInit(this, scalar);
|
||||
}
|
||||
|
||||
void MoveToVRAM() {
|
||||
if (auto alloc = MetaAllocator<T>::GetDataAllocator(BaseClass::data())) {
|
||||
alloc->MoveToVRAM();
|
||||
}
|
||||
}
|
||||
|
||||
void MoveToRAM() {
|
||||
if (auto alloc = MetaAllocator<T>::GetDataAllocator(BaseClass::data())) {
|
||||
alloc->MoveToRAM();
|
||||
}
|
||||
}
|
||||
|
||||
T *GetVRAMData() {
|
||||
if (auto alloc = MetaAllocator<T>::GetDataAllocator(BaseClass::data())) {
|
||||
return alloc->GetVRAMData();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const T *GetVRAMData() const {
|
||||
if (auto alloc = MetaAllocator<T>::GetDataAllocator(
|
||||
const_cast<T *>(BaseClass::data()))) {
|
||||
return alloc->GetVRAMData();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline void PrintSelf(std::ostream &o);
|
||||
|
||||
// Overrides for auto-sync //
|
||||
T &operator[](size_t i) {
|
||||
this->MoveToRAM();
|
||||
return BaseClass::operator[](i);
|
||||
}
|
||||
const T &operator[](size_t i) const {
|
||||
const_cast<Vector *>(this)->MoveToRAM();
|
||||
return BaseClass::operator[](i);
|
||||
}
|
||||
T &at(size_t i) {
|
||||
this->MoveToRAM();
|
||||
return BaseClass::at(i);
|
||||
}
|
||||
const T &at(size_t i) const {
|
||||
const_cast<Vector *>(this)->MoveToRAM();
|
||||
return BaseClass::at(i);
|
||||
}
|
||||
T &front() {
|
||||
this->MoveToRAM();
|
||||
return BaseClass::front();
|
||||
}
|
||||
const T &front() const {
|
||||
const_cast<Vector *>(this)->MoveToRAM();
|
||||
return BaseClass::front();
|
||||
}
|
||||
T &back() {
|
||||
this->MoveToRAM();
|
||||
return BaseClass::back();
|
||||
}
|
||||
const T &back() const {
|
||||
const_cast<Vector *>(this)->MoveToRAM();
|
||||
return BaseClass::back();
|
||||
}
|
||||
T *data() noexcept {
|
||||
this->MoveToRAM();
|
||||
return BaseClass::data();
|
||||
}
|
||||
const T *data() const noexcept {
|
||||
const_cast<Vector *>(this)->MoveToRAM();
|
||||
return BaseClass::data();
|
||||
}
|
||||
Iterator begin() noexcept {
|
||||
this->MoveToRAM();
|
||||
return BaseClass::begin();
|
||||
}
|
||||
ConstIterator begin() const noexcept {
|
||||
const_cast<Vector *>(this)->MoveToRAM();
|
||||
return BaseClass::begin();
|
||||
}
|
||||
Iterator end() noexcept {
|
||||
this->MoveToRAM();
|
||||
return BaseClass::end();
|
||||
}
|
||||
ConstIterator end() const noexcept {
|
||||
const_cast<Vector *>(this)->MoveToRAM();
|
||||
return BaseClass::end();
|
||||
}
|
||||
auto rbegin() noexcept {
|
||||
this->MoveToRAM();
|
||||
return BaseClass::rbegin();
|
||||
}
|
||||
auto rbegin() const noexcept {
|
||||
const_cast<Vector *>(this)->MoveToRAM();
|
||||
return BaseClass::rbegin();
|
||||
}
|
||||
auto rend() noexcept {
|
||||
this->MoveToRAM();
|
||||
return BaseClass::rend();
|
||||
}
|
||||
auto rend() const noexcept {
|
||||
const_cast<Vector *>(this)->MoveToRAM();
|
||||
return BaseClass::rend();
|
||||
}
|
||||
|
||||
void push_back(const T &x) {
|
||||
this->MoveToRAM();
|
||||
BaseClass::push_back(x);
|
||||
}
|
||||
void push_back(T &&x) {
|
||||
this->MoveToRAM();
|
||||
BaseClass::push_back(std::move(x));
|
||||
}
|
||||
template <typename... Args> reference emplace_back(Args &&...args) {
|
||||
this->MoveToRAM();
|
||||
return BaseClass::emplace_back(std::forward<Args>(args)...);
|
||||
}
|
||||
void pop_back() {
|
||||
this->MoveToRAM();
|
||||
BaseClass::pop_back();
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
iterator emplace(const_iterator pos, Args &&...args) {
|
||||
this->MoveToRAM();
|
||||
return BaseClass::emplace(pos, std::forward<Args>(args)...);
|
||||
}
|
||||
iterator insert(const_iterator pos, const T &x) {
|
||||
this->MoveToRAM();
|
||||
return BaseClass::insert(pos, x);
|
||||
}
|
||||
iterator insert(const_iterator pos, T &&x) {
|
||||
this->MoveToRAM();
|
||||
return BaseClass::insert(pos, std::move(x));
|
||||
}
|
||||
iterator erase(const_iterator pos) {
|
||||
this->MoveToRAM();
|
||||
return BaseClass::erase(pos);
|
||||
}
|
||||
iterator erase(const_iterator first, const_iterator last) {
|
||||
this->MoveToRAM();
|
||||
return BaseClass::erase(first, last);
|
||||
}
|
||||
|
||||
void resize(size_t n) {
|
||||
this->MoveToRAM();
|
||||
BaseClass::resize(n);
|
||||
}
|
||||
void resize(size_t n, const T &x) {
|
||||
this->MoveToRAM();
|
||||
BaseClass::resize(n, x);
|
||||
}
|
||||
void reserve(size_t n) {
|
||||
this->MoveToRAM();
|
||||
BaseClass::reserve(n);
|
||||
}
|
||||
void clear() noexcept {
|
||||
this->MoveToRAM();
|
||||
BaseClass::clear();
|
||||
}
|
||||
template <typename InputIt> void assign(InputIt first, InputIt last) {
|
||||
this->MoveToRAM();
|
||||
BaseClass::assign(first, last);
|
||||
}
|
||||
void assign(size_type count, const T &value) {
|
||||
this->MoveToRAM();
|
||||
BaseClass::assign(count, value);
|
||||
}
|
||||
|
||||
void remove_element(unsigned int index) {
|
||||
std::swap(Base::get()->at(index),Base::get()->back());
|
||||
Base::get()->pop_back();
|
||||
this->MoveToRAM();
|
||||
std::swap(this->at(index), this->back());
|
||||
this->pop_back();
|
||||
}
|
||||
|
||||
void remove_element(T &t) {
|
||||
this->MoveToRAM();
|
||||
std::swap(t, this->back());
|
||||
this->pop_back();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> void Vector<T>::PrintSelf(std::ostream &o) {
|
||||
o << " *** uLib Vector *** \n";
|
||||
o << " n. of items = " << this->size() << "\n";
|
||||
for (int i = 0; i < this->size(); ++i)
|
||||
o << (T)this->at(i) << " ";
|
||||
o << "\n";
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::ostream &operator<<(std::ostream &o, const Vector<T> &v) {
|
||||
for (int i = 0; i < v.size(); ++i)
|
||||
o << (T)v.at(i) << " ";
|
||||
o << "\n";
|
||||
return o;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::ofstream &operator<<(std::ofstream &o, const Vector<T> &v) {
|
||||
for (int i = 0; i < v.size(); ++i)
|
||||
o << (T)v.at(i) << " ";
|
||||
return o;
|
||||
}
|
||||
|
||||
template <typename T> std::istream &operator>>(std::istream &is, Vector<T> &v) {
|
||||
T value;
|
||||
while (is >> value) {
|
||||
if (is.fail())
|
||||
v.push_back(0);
|
||||
else
|
||||
v.push_back(value);
|
||||
}
|
||||
return is;
|
||||
}
|
||||
|
||||
// Smart pointer Vector Implementation //
|
||||
|
||||
template <typename T> class SmartVector : public SmartPointer<Vector<T>> {
|
||||
typedef SmartPointer<Vector<T>> Base;
|
||||
|
||||
public:
|
||||
SmartVector() : Base(new Vector<T>()) {}
|
||||
SmartVector(const SmartVector ©) : Base(copy) {}
|
||||
SmartVector(unsigned int size) : Base(new Vector<T>((int)size)) {}
|
||||
|
||||
virtual ~SmartVector() {}
|
||||
|
||||
T &operator[](int p) { return Base::get()->at(p); }
|
||||
|
||||
void swap_elements(unsigned int first, unsigned int second) {
|
||||
std::swap(Base::get()->at(first), Base::get()->at(second));
|
||||
}
|
||||
|
||||
void remove_element(unsigned int index) {
|
||||
std::swap(Base::get()->at(index), Base::get()->back());
|
||||
Base::get()->pop_back();
|
||||
}
|
||||
|
||||
void remove_element(T &t) {
|
||||
std::swap(t, Base::get()->back());
|
||||
Base::get()->pop_back();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// ------ Utils ------------------------------------------------------------- //
|
||||
|
||||
|
||||
|
||||
// RIFARE con iteratore !
|
||||
template <typename _Tp, class _CmpT>
|
||||
inline const unsigned long
|
||||
VectorSplice(const _Tp &_it, const _Tp &_end, const float value, _CmpT _comp)
|
||||
{
|
||||
_Tp it = _it;
|
||||
_Tp end = _end-1;
|
||||
for(it; it != end;)
|
||||
{
|
||||
if (_comp(*it,value)) ++it;
|
||||
else if(_comp(*end,value)) std::swap(*it,*end--);
|
||||
else --end;
|
||||
}
|
||||
return it - _it;
|
||||
inline unsigned long VectorSplice(const _Tp &_it, const _Tp &_end,
|
||||
const float value, _CmpT _comp) {
|
||||
_Tp it = _it;
|
||||
_Tp end = _end - 1;
|
||||
for (; it != end;) {
|
||||
if (_comp(*it, value))
|
||||
++it;
|
||||
else if (_comp(*end, value))
|
||||
std::swap(*it, *end--);
|
||||
else
|
||||
--end;
|
||||
}
|
||||
return it - _it;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // uLib
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace uLib
|
||||
|
||||
#endif // VECTOR_H
|
||||
|
||||
Reference in New Issue
Block a user