/*----------------------------------------------------------------------------*/ /* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */ /* Open Source Software - may be modified and shared by FRC teams. The code */ /* must be accompanied by the FIRST BSD license file in the root directory of */ /* the project. */ /*----------------------------------------------------------------------------*/ #ifndef CSCORE_UNLIMITEDHANDLERESOURCE_H_ #define CSCORE_UNLIMITEDHANDLERESOURCE_H_ #include #include #include #include #include #include namespace cs { // The UnlimitedHandleResource class is a way to track handles. This version // allows an unlimted number of handles that are allocated sequentially. When // possible, indices are reused to save memory usage and keep the array length // down. // However, automatic array management has not been implemented, but might be in // the future. // Because we have to loop through the allocator, we must use a global mutex. // // THandle needs to have the following attributes: // Type : enum or typedef // kIndexMax : static, constexpr, or enum value for the maximum index value // int GetTypedIndex() const : function that returns the index of the handle // THandle(int index, HandleType[int] type) : constructor for index and type // // @tparam THandle The Handle Type // @tparam TStruct The struct type held by this resource // @tparam typeValue The type value stored in the handle // @tparam TMutex The mutex type to use template class UnlimitedHandleResource { public: UnlimitedHandleResource(const UnlimitedHandleResource&) = delete; UnlimitedHandleResource operator=(const UnlimitedHandleResource&) = delete; UnlimitedHandleResource() = default; template THandle Allocate(Args&&... args); THandle Allocate(std::shared_ptr structure); std::shared_ptr Get(THandle handle); std::shared_ptr Free(THandle handle); template wpi::ArrayRef GetAll(wpi::SmallVectorImpl& vec); std::vector> FreeAll(); // @param func functor with (THandle, const TStruct&) parameters template void ForEach(F func); // @pram func functor with (const TStruct&) parameter and bool return value template std::pair> FindIf(F func); private: THandle MakeHandle(size_t i) { return THandle{static_cast(i), static_cast(typeValue)}; } std::vector> m_structures; TMutex m_handleMutex; }; template template THandle UnlimitedHandleResource::Allocate( Args&&... args) { #ifdef _MSC_VER // work around VS2019 16.4.0 bug std::scoped_lock lock(m_handleMutex); #else std::scoped_lock sync(m_handleMutex); #endif size_t i; for (i = 0; i < m_structures.size(); i++) { if (m_structures[i] == nullptr) { m_structures[i] = std::make_shared(std::forward(args)...); return MakeHandle(i); } } if (i >= THandle::kIndexMax) return 0; m_structures.emplace_back( std::make_shared(std::forward(args)...)); return MakeHandle(i); } template THandle UnlimitedHandleResource::Allocate( std::shared_ptr structure) { std::scoped_lock sync(m_handleMutex); size_t i; for (i = 0; i < m_structures.size(); i++) { if (m_structures[i] == nullptr) { m_structures[i] = structure; return MakeHandle(i); } } if (i >= THandle::kIndexMax) return 0; m_structures.push_back(structure); return MakeHandle(i); } template inline std::shared_ptr UnlimitedHandleResource::Get( THandle handle) { auto index = handle.GetTypedIndex(static_cast(typeValue)); if (index < 0) return nullptr; std::scoped_lock sync(m_handleMutex); if (index >= static_cast(m_structures.size())) return nullptr; return m_structures[index]; } template inline std::shared_ptr UnlimitedHandleResource::Free( THandle handle) { auto index = handle.GetTypedIndex(static_cast(typeValue)); if (index < 0) return nullptr; std::scoped_lock sync(m_handleMutex); if (index >= static_cast(m_structures.size())) return nullptr; auto rv = std::move(m_structures[index]); m_structures[index].reset(); return rv; } template template inline wpi::ArrayRef UnlimitedHandleResource::GetAll( wpi::SmallVectorImpl& vec) { ForEach([&](THandle handle, const TStruct& data) { vec.push_back(handle); }); return vec; } template inline std::vector> UnlimitedHandleResource::FreeAll() { std::scoped_lock sync(m_handleMutex); auto rv = std::move(m_structures); m_structures.clear(); return rv; } template template inline void UnlimitedHandleResource::ForEach(F func) { std::scoped_lock sync(m_handleMutex); for (size_t i = 0; i < m_structures.size(); i++) { if (m_structures[i] != nullptr) func(MakeHandle(i), *(m_structures[i])); } } template template inline std::pair> UnlimitedHandleResource::FindIf(F func) { std::scoped_lock sync(m_handleMutex); for (size_t i = 0; i < m_structures.size(); i++) { auto& structure = m_structures[i]; if (structure != nullptr && func(*structure)) return std::make_pair(MakeHandle(i), structure); } return std::make_pair(0, nullptr); } } // namespace cs #endif // CSCORE_UNLIMITEDHANDLERESOURCE_H_