#pragma once #ifndef _NB_CORE_TYPES #define _NB_CORE_TYPES #include #include #include "Errors.hpp" namespace nb { template using SharedVector = std::vector>; template using RValueVector = std::vector; using ByteVector = std::vector; class ObjectManagerError : public Error { using Base = Error; 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 ByteVector vectorToBytes(const std::vector& vec) { unsigned int num_bytes = vec.size() * sizeof(T); ByteVector ret(num_bytes); memcpy(ret.data(), vec.data(), num_bytes); return ret; } template ByteVector concatVectorBytes(const std::vector& vec1, const std::vector& vec2) { ByteVector vec1_raw = vectorToBytes(vec1); ByteVector vec2_raw = vectorToBytes(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 std::vector 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 ret(num_elmts); memcpy(ret.data(), vec.data(), vec.size()); return ret; } template class ThreadsafeObjectLock; template class ThreadsafeObject { using Codes = ObjectManagerError::Codes; public: ThreadsafeObject(T&& obj) : _obj(std::make_shared(obj)) {} ThreadsafeObjectLock lock() { return ThreadsafeObjectLock(this); } friend ThreadsafeObjectLock; protected: std::shared_ptr _obj; mutable std::recursive_mutex _mutex; }; template class ThreadsafeObjectLock { public: ThreadsafeObjectLock(const ThreadsafeObjectLock&) = delete; ThreadsafeObjectLock operator=(const ThreadsafeObjectLock&) = delete; ~ThreadsafeObjectLock() { _manager->_mutex.unlock(); } T* operator->() { return _manager->_obj.get(); } friend ThreadsafeObject; protected: ThreadsafeObjectLock( ThreadsafeObject* const manager_ ) : _manager(manager_) { if (!_manager) { using Codes = ObjectManagerError::Codes; THROW(ObjectManagerError(Codes::NO_MANAGER)); } _manager->_mutex.lock(); } ThreadsafeObject* const _manager; }; } // namespace nb #endif // _NB_CORE_TYPES