// Copyright (c) FIRST and other WPILib contributors. // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. #ifndef CSCORE_UNLIMITEDHANDLERESOURCE_HPP_ #define CSCORE_UNLIMITEDHANDLERESOURCE_HPP_ #include #include #include #include #include "wpi/util/SmallVector.hpp" #include "wpi/util/mutex.hpp" namespace cs { // The UnlimitedHandleResource class is a way to track handles. This version // allows an unlimited 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 std::span 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) { 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] = 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 std::span UnlimitedHandleResource::GetAll( wpi::SmallVectorImpl& vec) { ForEach([&](THandle handle, const TStruct&) { 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::pair{MakeHandle(i), structure}; } } return std::pair{0, nullptr}; } } // namespace cs #endif // CSCORE_UNLIMITEDHANDLERESOURCE_HPP_