blob: cfe06688bc1e9576cf90055f7b8989e770515f0f [file] [log] [blame]
Brian Silvermanf7f267a2017-02-04 16:16:08 -08001/*----------------------------------------------------------------------------*/
2/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
3/* Open Source Software - may be modified and shared by FRC teams. The code */
4/* must be accompanied by the FIRST BSD license file in the root directory of */
5/* the project. */
6/*----------------------------------------------------------------------------*/
7
8#pragma once
9
10#include <stdint.h>
11
12#include <array>
13#include <memory>
14
15#include "HAL/Errors.h"
16#include "HAL/Types.h"
17#include "HAL/cpp/make_unique.h"
18#include "HAL/cpp/priority_mutex.h"
19#include "HAL/handles/HandlesInternal.h"
20
21namespace hal {
22
23/**
24 * The IndexedHandleResource class is a way to track handles. This version
25 * allows a limited number of handles that are allocated by index.
26 * Because they are allocated by index, each individual index holds its own
27 * mutex, which reduces contention heavily.]
28 *
29 * @tparam THandle The Handle Type (Must be typedefed from HAL_Handle)
30 * @tparam TStruct The struct type held by this resource
31 * @tparam size The number of resources allowed to be allocated
32 * @tparam enumValue The type value stored in the handle
33 *
34 */
35template <typename THandle, typename TStruct, int16_t size,
36 HAL_HandleEnum enumValue>
37class IndexedHandleResource {
38 friend class IndexedHandleResourceTest;
39
40 public:
41 IndexedHandleResource() = default;
42 IndexedHandleResource(const IndexedHandleResource&) = delete;
43 IndexedHandleResource& operator=(const IndexedHandleResource&) = delete;
44
45 THandle Allocate(int16_t index, int32_t* status);
46 std::shared_ptr<TStruct> Get(THandle handle);
47 void Free(THandle handle);
48
49 private:
50 std::array<std::shared_ptr<TStruct>, size> m_structures;
51 std::array<priority_mutex, size> m_handleMutexes;
52};
53
54template <typename THandle, typename TStruct, int16_t size,
55 HAL_HandleEnum enumValue>
56THandle IndexedHandleResource<THandle, TStruct, size, enumValue>::Allocate(
57 int16_t index, int32_t* status) {
58 // don't aquire the lock if we can fail early.
59 if (index < 0 || index >= size) {
60 *status = RESOURCE_OUT_OF_RANGE;
61 return HAL_kInvalidHandle;
62 }
63 std::lock_guard<priority_mutex> sync(m_handleMutexes[index]);
64 // check for allocation, otherwise allocate and return a valid handle
65 if (m_structures[index] != nullptr) {
66 *status = RESOURCE_IS_ALLOCATED;
67 return HAL_kInvalidHandle;
68 }
69 m_structures[index] = std::make_shared<TStruct>();
70 return static_cast<THandle>(hal::createHandle(index, enumValue));
71}
72
73template <typename THandle, typename TStruct, int16_t size,
74 HAL_HandleEnum enumValue>
75std::shared_ptr<TStruct>
76IndexedHandleResource<THandle, TStruct, size, enumValue>::Get(THandle handle) {
77 // get handle index, and fail early if index out of range or wrong handle
78 int16_t index = getHandleTypedIndex(handle, enumValue);
79 if (index < 0 || index >= size) {
80 return nullptr;
81 }
82 std::lock_guard<priority_mutex> sync(m_handleMutexes[index]);
83 // return structure. Null will propogate correctly, so no need to manually
84 // check.
85 return m_structures[index];
86}
87
88template <typename THandle, typename TStruct, int16_t size,
89 HAL_HandleEnum enumValue>
90void IndexedHandleResource<THandle, TStruct, size, enumValue>::Free(
91 THandle handle) {
92 // get handle index, and fail early if index out of range or wrong handle
93 int16_t index = getHandleTypedIndex(handle, enumValue);
94 if (index < 0 || index >= size) return;
95 // lock and deallocated handle
96 std::lock_guard<priority_mutex> sync(m_handleMutexes[index]);
97 m_structures[index].reset();
98}
99} // namespace hal