blob: 522328e5dfab388a00c27d5a1b8d97b04e2d1528 [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/Types.h"
16#include "HAL/cpp/make_unique.h"
17#include "HAL/cpp/priority_mutex.h"
18#include "HandlesInternal.h"
19
20namespace hal {
21
22/**
23 * The LimitedHandleResource class is a way to track handles. This version
24 * allows a limited number of handles that are allocated sequentially.
25 *
26 * @tparam THandle The Handle Type (Must be typedefed from HAL_Handle)
27 * @tparam TStruct The struct type held by this resource
28 * @tparam size The number of resources allowed to be allocated
29 * @tparam enumValue The type value stored in the handle
30 *
31 */
32template <typename THandle, typename TStruct, int16_t size,
33 HAL_HandleEnum enumValue>
34class LimitedHandleResource {
35 friend class LimitedHandleResourceTest;
36
37 public:
38 LimitedHandleResource() = default;
39 LimitedHandleResource(const LimitedHandleResource&) = delete;
40 LimitedHandleResource& operator=(const LimitedHandleResource&) = delete;
41
42 THandle Allocate();
43 std::shared_ptr<TStruct> Get(THandle handle);
44 void Free(THandle handle);
45
46 private:
47 std::array<std::shared_ptr<TStruct>, size> m_structures;
48 std::array<priority_mutex, size> m_handleMutexes;
49 priority_mutex m_allocateMutex;
50};
51
52template <typename THandle, typename TStruct, int16_t size,
53 HAL_HandleEnum enumValue>
54THandle LimitedHandleResource<THandle, TStruct, size, enumValue>::Allocate() {
55 // globally lock to loop through indices
56 std::lock_guard<priority_mutex> sync(m_allocateMutex);
57 int16_t i;
58 for (i = 0; i < size; i++) {
59 if (m_structures[i] == nullptr) {
60 // if a false index is found, grab its specific mutex
61 // and allocate it.
62 std::lock_guard<priority_mutex> sync(m_handleMutexes[i]);
63 m_structures[i] = std::make_shared<TStruct>();
64 return static_cast<THandle>(createHandle(i, enumValue));
65 }
66 }
67 return HAL_kInvalidHandle;
68}
69
70template <typename THandle, typename TStruct, int16_t size,
71 HAL_HandleEnum enumValue>
72std::shared_ptr<TStruct>
73LimitedHandleResource<THandle, TStruct, size, enumValue>::Get(THandle handle) {
74 // get handle index, and fail early if index out of range or wrong handle
75 int16_t index = getHandleTypedIndex(handle, enumValue);
76 if (index < 0 || index >= size) {
77 return nullptr;
78 }
79 std::lock_guard<priority_mutex> sync(m_handleMutexes[index]);
80 // return structure. Null will propogate correctly, so no need to manually
81 // check.
82 return m_structures[index];
83}
84
85template <typename THandle, typename TStruct, int16_t size,
86 HAL_HandleEnum enumValue>
87void LimitedHandleResource<THandle, TStruct, size, enumValue>::Free(
88 THandle handle) {
89 // get handle index, and fail early if index out of range or wrong handle
90 int16_t index = getHandleTypedIndex(handle, enumValue);
91 if (index < 0 || index >= size) return;
92 // lock and deallocated handle
93 std::lock_guard<priority_mutex> sync(m_allocateMutex);
94 std::lock_guard<priority_mutex> lock(m_handleMutexes[index]);
95 m_structures[index].reset();
96}
97} // namespace hal