#pragma once
#include <stdint.h>
#include <array>
#include <memory>
#include <wpi/mutex.h>
#include "hal/Errors.h"
#include "hal/Types.h"
#include "hal/handles/HandlesInternal.h"
namespace hal {
template <typename THandle, typename TStruct, int16_t size,
HAL_HandleEnum enumValue>
class IndexedHandleResource : public HandleBase {
friend class IndexedHandleResourceTest;
public:
IndexedHandleResource() = default;
IndexedHandleResource(const IndexedHandleResource&) = delete;
IndexedHandleResource& operator=(const IndexedHandleResource&) = delete;
std::shared_ptr<TStruct> Allocate(int16_t index, THandle* handle,
int32_t* status);
int16_t GetIndex(THandle handle) {
return getHandleTypedIndex(handle, enumValue, m_version);
}
std::shared_ptr<TStruct> Get(THandle handle);
void Free(THandle handle);
void ResetHandles() override;
private:
std::array<std::shared_ptr<TStruct>, size> m_structures;
std::array<wpi::mutex, size> m_handleMutexes;
};
template <typename THandle, typename TStruct, int16_t size,
HAL_HandleEnum enumValue>
std::shared_ptr<TStruct>
IndexedHandleResource<THandle, TStruct, size, enumValue>::Allocate(
int16_t index, THandle* handle, int32_t* status) {
if (index < 0 || index >= size) {
*status = RESOURCE_OUT_OF_RANGE;
*handle = HAL_kInvalidHandle;
return nullptr;
}
std::scoped_lock lock(m_handleMutexes[index]);
if (m_structures[index] != nullptr) {
*status = RESOURCE_IS_ALLOCATED;
*handle = HAL_kInvalidHandle;
return m_structures[index];
}
m_structures[index] = std::make_shared<TStruct>();
*handle =
static_cast<THandle>(hal::createHandle(index, enumValue, m_version));
*status = HAL_SUCCESS;
return m_structures[index];
}
template <typename THandle, typename TStruct, int16_t size,
HAL_HandleEnum enumValue>
std::shared_ptr<TStruct>
IndexedHandleResource<THandle, TStruct, size, enumValue>::Get(THandle handle) {
int16_t index = GetIndex(handle);
if (index < 0 || index >= size) {
return nullptr;
}
std::scoped_lock lock(m_handleMutexes[index]);
return m_structures[index];
}
template <typename THandle, typename TStruct, int16_t size,
HAL_HandleEnum enumValue>
void IndexedHandleResource<THandle, TStruct, size, enumValue>::Free(
THandle handle) {
int16_t index = GetIndex(handle);
if (index < 0 || index >= size) {
return;
}
std::scoped_lock lock(m_handleMutexes[index]);
m_structures[index].reset();
}
template <typename THandle, typename TStruct, int16_t size,
HAL_HandleEnum enumValue>
void IndexedHandleResource<THandle, TStruct, size, enumValue>::ResetHandles() {
for (int i = 0; i < size; i++) {
std::scoped_lock lock(m_handleMutexes[i]);
m_structures[i].reset();
}
HandleBase::ResetHandles();
}
}