118 lines
2.9 KiB
C++
118 lines
2.9 KiB
C++
#pragma once
|
|
#ifndef _NB_CORE_TYPES
|
|
#define _NB_CORE_TYPES
|
|
|
|
#include <mutex>
|
|
#include <vector>
|
|
|
|
#include "Errors.hpp"
|
|
|
|
namespace nb {
|
|
|
|
template<typename T>
|
|
using SharedVector = std::vector<std::shared_ptr<T>>;
|
|
|
|
template<typename T>
|
|
using RValueVector = std::vector<T&&>;
|
|
|
|
using ByteVector = std::vector<uint8_t>;
|
|
|
|
class ObjectManagerError : public Error<ObjectManagerError> {
|
|
using Base = Error<ObjectManagerError>;
|
|
|
|
public:
|
|
using Base::Base;
|
|
|
|
enum Codes : unsigned int {
|
|
UNDEFINED, NO_MANAGER, MANAGER_MISMATCH, LOCK_OVERFLOW, BAD_THREAD
|
|
};
|
|
|
|
static const std::string type;
|
|
static const ErrorCodeMap ErrorMessages;
|
|
};
|
|
|
|
template<typename T>
|
|
ByteVector vectorToBytes(const std::vector<T>& vec) {
|
|
unsigned int num_bytes = vec.size() * sizeof(T);
|
|
ByteVector ret(num_bytes);
|
|
memcpy(ret.data(), vec.data(), num_bytes);
|
|
return ret;
|
|
}
|
|
|
|
template<typename T, typename S>
|
|
ByteVector concatVectorBytes(const std::vector<T>& vec1, const std::vector<S>& vec2) {
|
|
ByteVector vec1_raw = vectorToBytes<T>(vec1);
|
|
ByteVector vec2_raw = vectorToBytes<S>(vec2);
|
|
unsigned int vec1_raw_size = vec1_raw.size();
|
|
unsigned int vec2_raw_size = vec2_raw.size();
|
|
ByteVector ret(vec1_raw_size + vec2_raw_size);
|
|
memcpy(ret.data(), vec1_raw.data(), vec1_raw_size);
|
|
memcpy(ret.data() + vec1_raw_size, vec2_raw.data(), vec2_raw_size);
|
|
return ret;
|
|
}
|
|
|
|
template<typename T>
|
|
std::vector<T> bytesToVector(const ByteVector& vec) {
|
|
if (vec.size() % sizeof(T) != 0) {
|
|
THROW(std::runtime_error("Data size does not align to std::vector<" + std::string(typeid(T).name()) + ">."));
|
|
}
|
|
unsigned int num_elmts = vec.size() / sizeof(T);
|
|
std::vector<T> ret(num_elmts);
|
|
memcpy(ret.data(), vec.data(), vec.size());
|
|
|
|
return ret;
|
|
}
|
|
|
|
template <typename T>
|
|
class ThreadsafeObjectLock;
|
|
|
|
template <typename T>
|
|
class ThreadsafeObject {
|
|
using Codes = ObjectManagerError::Codes;
|
|
|
|
public:
|
|
ThreadsafeObject(T&& obj)
|
|
: _obj(std::make_shared<T>(obj)) {}
|
|
|
|
ThreadsafeObjectLock<T> lock() {
|
|
return ThreadsafeObjectLock<T>(this);
|
|
}
|
|
|
|
friend ThreadsafeObjectLock<T>;
|
|
|
|
protected:
|
|
std::shared_ptr<T> _obj;
|
|
mutable std::recursive_mutex _mutex;
|
|
|
|
};
|
|
|
|
template <typename T>
|
|
class ThreadsafeObjectLock {
|
|
public:
|
|
ThreadsafeObjectLock(const ThreadsafeObjectLock&) = delete;
|
|
ThreadsafeObjectLock operator=(const ThreadsafeObjectLock&) = delete;
|
|
~ThreadsafeObjectLock() {
|
|
_manager->_mutex.unlock();
|
|
}
|
|
|
|
T* operator->() {
|
|
return _manager->_obj.get();
|
|
}
|
|
|
|
friend ThreadsafeObject<T>;
|
|
|
|
protected:
|
|
ThreadsafeObjectLock(
|
|
ThreadsafeObject<T>* const manager_
|
|
) : _manager(manager_) {
|
|
if (!_manager) {
|
|
using Codes = ObjectManagerError::Codes;
|
|
THROW(ObjectManagerError(Codes::NO_MANAGER));
|
|
}
|
|
_manager->_mutex.lock();
|
|
}
|
|
ThreadsafeObject<T>* const _manager;
|
|
};
|
|
|
|
} // namespace nb
|
|
#endif // _NB_CORE_TYPES
|