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:
AndreaRigoni
2026-03-04 20:52:01 +00:00
parent adedbcc37c
commit 9a59e031ed
10 changed files with 540 additions and 188 deletions

View File

@@ -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 &copy) : 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 &copy) : 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