Squashed 'third_party/allwpilib_2017/' content from commit 35ac87d
Change-Id: I7bb6f5556c30d3f5a092e68de0be9c710c60c9f4
git-subtree-dir: third_party/allwpilib_2017
git-subtree-split: 35ac87d6ff8b7f061c4f18c9ea316e5dccd4888a
diff --git a/hal/include/HAL/handles/DigitalHandleResource.h b/hal/include/HAL/handles/DigitalHandleResource.h
new file mode 100644
index 0000000..653011e
--- /dev/null
+++ b/hal/include/HAL/handles/DigitalHandleResource.h
@@ -0,0 +1,95 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2016-2017. 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. */
+/*----------------------------------------------------------------------------*/
+
+#pragma once
+
+#include <stdint.h>
+
+#include <array>
+#include <memory>
+
+#include "HAL/Errors.h"
+#include "HAL/Types.h"
+#include "HAL/cpp/make_unique.h"
+#include "HAL/cpp/priority_mutex.h"
+#include "HAL/handles/HandlesInternal.h"
+
+namespace hal {
+
+/**
+ * The DigitalHandleResource class is a way to track handles. This version
+ * allows a limited number of handles that are allocated by index.
+ * The enum value is seperate, as 2 enum values are allowed per handle
+ * Because they are allocated by index, each individual index holds its own
+ * mutex, which reduces contention heavily.]
+ *
+ * @tparam THandle The Handle Type (Must be typedefed from HAL_Handle)
+ * @tparam TStruct The struct type held by this resource
+ * @tparam size The number of resources allowed to be allocated
+ *
+ */
+template <typename THandle, typename TStruct, int16_t size>
+class DigitalHandleResource {
+ friend class DigitalHandleResourceTest;
+
+ public:
+ DigitalHandleResource() = default;
+ DigitalHandleResource(const DigitalHandleResource&) = delete;
+ DigitalHandleResource& operator=(const DigitalHandleResource&) = delete;
+
+ THandle Allocate(int16_t index, HAL_HandleEnum enumValue, int32_t* status);
+ std::shared_ptr<TStruct> Get(THandle handle, HAL_HandleEnum enumValue);
+ void Free(THandle handle, HAL_HandleEnum enumValue);
+
+ private:
+ std::array<std::shared_ptr<TStruct>, size> m_structures;
+ std::array<priority_mutex, size> m_handleMutexes;
+};
+
+template <typename THandle, typename TStruct, int16_t size>
+THandle DigitalHandleResource<THandle, TStruct, size>::Allocate(
+ int16_t index, HAL_HandleEnum enumValue, int32_t* status) {
+ // don't aquire the lock if we can fail early.
+ if (index < 0 || index >= size) {
+ *status = RESOURCE_OUT_OF_RANGE;
+ return HAL_kInvalidHandle;
+ }
+ std::lock_guard<priority_mutex> sync(m_handleMutexes[index]);
+ // check for allocation, otherwise allocate and return a valid handle
+ if (m_structures[index] != nullptr) {
+ *status = RESOURCE_IS_ALLOCATED;
+ return HAL_kInvalidHandle;
+ }
+ m_structures[index] = std::make_shared<TStruct>();
+ return static_cast<THandle>(hal::createHandle(index, enumValue));
+}
+
+template <typename THandle, typename TStruct, int16_t size>
+std::shared_ptr<TStruct> DigitalHandleResource<THandle, TStruct, size>::Get(
+ THandle handle, HAL_HandleEnum enumValue) {
+ // get handle index, and fail early if index out of range or wrong handle
+ int16_t index = getHandleTypedIndex(handle, enumValue);
+ if (index < 0 || index >= size) {
+ return nullptr;
+ }
+ std::lock_guard<priority_mutex> sync(m_handleMutexes[index]);
+ // return structure. Null will propogate correctly, so no need to manually
+ // check.
+ return m_structures[index];
+}
+
+template <typename THandle, typename TStruct, int16_t size>
+void DigitalHandleResource<THandle, TStruct, size>::Free(
+ THandle handle, HAL_HandleEnum enumValue) {
+ // get handle index, and fail early if index out of range or wrong handle
+ int16_t index = getHandleTypedIndex(handle, enumValue);
+ if (index < 0 || index >= size) return;
+ // lock and deallocated handle
+ std::lock_guard<priority_mutex> sync(m_handleMutexes[index]);
+ m_structures[index].reset();
+}
+} // namespace hal
diff --git a/hal/include/HAL/handles/HandlesInternal.h b/hal/include/HAL/handles/HandlesInternal.h
new file mode 100644
index 0000000..27596dc
--- /dev/null
+++ b/hal/include/HAL/handles/HandlesInternal.h
@@ -0,0 +1,98 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2016-2017. 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. */
+/*----------------------------------------------------------------------------*/
+
+#pragma once
+
+#include <stdint.h>
+
+#include "HAL/Types.h"
+
+/* General Handle Data Layout
+ * Bits 0-15: Handle Index
+ * Bits 16-23: Unused
+ * Bits 24-30: Handle Type
+ * Bit 31: 1 if handle error, 0 if no error
+ *
+ * Other specialized handles will use different formats, however Bits 24-31 are
+ * always reserved for type and error handling.
+ */
+
+namespace hal {
+
+constexpr int16_t InvalidHandleIndex = -1;
+
+enum class HAL_HandleEnum {
+ Undefined = 0,
+ DIO = 1,
+ Port = 2,
+ Notifier = 3,
+ Interrupt = 4,
+ AnalogOutput = 5,
+ AnalogInput = 6,
+ AnalogTrigger = 7,
+ Relay = 8,
+ PWM = 9,
+ DigitalPWM = 10,
+ Counter = 11,
+ FPGAEncoder = 12,
+ Encoder = 13,
+ Compressor = 14,
+ Solenoid = 15,
+ AnalogGyro = 16,
+ Vendor = 17
+};
+
+static inline int16_t getHandleIndex(HAL_Handle handle) {
+ // mask and return last 16 bits
+ return static_cast<int16_t>(handle & 0xffff);
+}
+static inline HAL_HandleEnum getHandleType(HAL_Handle handle) {
+ // mask first 8 bits and cast to enum
+ return static_cast<HAL_HandleEnum>((handle >> 24) & 0xff);
+}
+static inline bool isHandleType(HAL_Handle handle, HAL_HandleEnum handleType) {
+ return handleType == getHandleType(handle);
+}
+static inline int16_t getHandleTypedIndex(HAL_Handle handle,
+ HAL_HandleEnum enumType) {
+ if (!isHandleType(handle, enumType)) return InvalidHandleIndex;
+ return getHandleIndex(handle);
+}
+
+/* specialized functions for Port handle
+ * Port Handle Data Layout
+ * Bits 0-7: Channel Number
+ * Bits 8-15: Module Number
+ * Bits 16-23: Unused
+ * Bits 24-30: Handle Type
+ * Bit 31: 1 if handle error, 0 if no error
+ */
+
+// using a 16 bit value so we can store 0-255 and still report error
+static inline int16_t getPortHandleChannel(HAL_PortHandle handle) {
+ if (!isHandleType(handle, HAL_HandleEnum::Port)) return InvalidHandleIndex;
+ return static_cast<uint8_t>(handle & 0xff);
+}
+
+// using a 16 bit value so we can store 0-255 and still report error
+static inline int16_t getPortHandleModule(HAL_PortHandle handle) {
+ if (!isHandleType(handle, HAL_HandleEnum::Port)) return InvalidHandleIndex;
+ return static_cast<uint8_t>((handle >> 8) & 0xff);
+}
+
+// using a 16 bit value so we can store 0-255 and still report error
+static inline int16_t getPortHandleSPIEnable(HAL_PortHandle handle) {
+ if (!isHandleType(handle, HAL_HandleEnum::Port)) return InvalidHandleIndex;
+ return static_cast<uint8_t>((handle >> 16) & 0xff);
+}
+
+HAL_PortHandle createPortHandle(uint8_t channel, uint8_t module);
+
+HAL_PortHandle createPortHandleForSPI(uint8_t channel);
+
+HAL_Handle createHandle(int16_t index, HAL_HandleEnum handleType);
+} // namespace hal
diff --git a/hal/include/HAL/handles/IndexedClassedHandleResource.h b/hal/include/HAL/handles/IndexedClassedHandleResource.h
new file mode 100644
index 0000000..0f69b1d
--- /dev/null
+++ b/hal/include/HAL/handles/IndexedClassedHandleResource.h
@@ -0,0 +1,112 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2016-2017. 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. */
+/*----------------------------------------------------------------------------*/
+
+#pragma once
+
+#include <stdint.h>
+
+#include <memory>
+#include <vector>
+
+#include "HAL/Errors.h"
+#include "HAL/Types.h"
+#include "HAL/cpp/make_unique.h"
+#include "HAL/cpp/priority_mutex.h"
+#include "HAL/handles/HandlesInternal.h"
+
+namespace hal {
+
+/**
+ * The IndexedClassedHandleResource class is a way to track handles. This
+ * version
+ * allows a limited number of handles that are allocated by index.
+ * Because they are allocated by index, each individual index holds its own
+ * mutex, which reduces contention heavily.]
+ *
+ * @tparam THandle The Handle Type (Must be typedefed from HAL_Handle)
+ * @tparam TStruct The struct type held by this resource
+ * @tparam size The number of resources allowed to be allocated
+ * @tparam enumValue The type value stored in the handle
+ *
+ */
+template <typename THandle, typename TStruct, int16_t size,
+ HAL_HandleEnum enumValue>
+class IndexedClassedHandleResource {
+ friend class IndexedClassedHandleResourceTest;
+
+ public:
+ IndexedClassedHandleResource();
+ IndexedClassedHandleResource(const IndexedClassedHandleResource&) = delete;
+ IndexedClassedHandleResource& operator=(const IndexedClassedHandleResource&) =
+ delete;
+
+ THandle Allocate(int16_t index, std::shared_ptr<TStruct> toSet,
+ int32_t* status);
+ std::shared_ptr<TStruct> Get(THandle handle);
+ void Free(THandle handle);
+
+ private:
+ // Dynamic array to shrink HAL file size.
+ std::unique_ptr<std::shared_ptr<TStruct>[]> m_structures;
+ std::unique_ptr<priority_mutex[]> m_handleMutexes;
+};
+
+template <typename THandle, typename TStruct, int16_t size,
+ HAL_HandleEnum enumValue>
+IndexedClassedHandleResource<THandle, TStruct, size,
+ enumValue>::IndexedClassedHandleResource() {
+ m_structures = std::make_unique<std::shared_ptr<TStruct>[]>(size);
+ m_handleMutexes = std::make_unique<priority_mutex[]>(size);
+}
+
+template <typename THandle, typename TStruct, int16_t size,
+ HAL_HandleEnum enumValue>
+THandle
+IndexedClassedHandleResource<THandle, TStruct, size, enumValue>::Allocate(
+ int16_t index, std::shared_ptr<TStruct> toSet, int32_t* status) {
+ // don't aquire the lock if we can fail early.
+ if (index < 0 || index >= size) {
+ *status = RESOURCE_OUT_OF_RANGE;
+ return HAL_kInvalidHandle;
+ }
+ std::lock_guard<priority_mutex> sync(m_handleMutexes[index]);
+ // check for allocation, otherwise allocate and return a valid handle
+ if (m_structures[index] != nullptr) {
+ *status = RESOURCE_IS_ALLOCATED;
+ return HAL_kInvalidHandle;
+ }
+ m_structures[index] = toSet;
+ return static_cast<THandle>(hal::createHandle(index, enumValue));
+}
+
+template <typename THandle, typename TStruct, int16_t size,
+ HAL_HandleEnum enumValue>
+std::shared_ptr<TStruct> IndexedClassedHandleResource<
+ THandle, TStruct, size, enumValue>::Get(THandle handle) {
+ // get handle index, and fail early if index out of range or wrong handle
+ int16_t index = getHandleTypedIndex(handle, enumValue);
+ if (index < 0 || index >= size) {
+ return nullptr;
+ }
+ std::lock_guard<priority_mutex> sync(m_handleMutexes[index]);
+ // return structure. Null will propogate correctly, so no need to manually
+ // check.
+ return m_structures[index];
+}
+
+template <typename THandle, typename TStruct, int16_t size,
+ HAL_HandleEnum enumValue>
+void IndexedClassedHandleResource<THandle, TStruct, size, enumValue>::Free(
+ THandle handle) {
+ // get handle index, and fail early if index out of range or wrong handle
+ int16_t index = getHandleTypedIndex(handle, enumValue);
+ if (index < 0 || index >= size) return;
+ // lock and deallocated handle
+ std::lock_guard<priority_mutex> sync(m_handleMutexes[index]);
+ m_structures[index].reset();
+}
+} // namespace hal
diff --git a/hal/include/HAL/handles/IndexedHandleResource.h b/hal/include/HAL/handles/IndexedHandleResource.h
new file mode 100644
index 0000000..cfe0668
--- /dev/null
+++ b/hal/include/HAL/handles/IndexedHandleResource.h
@@ -0,0 +1,99 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2016-2017. 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. */
+/*----------------------------------------------------------------------------*/
+
+#pragma once
+
+#include <stdint.h>
+
+#include <array>
+#include <memory>
+
+#include "HAL/Errors.h"
+#include "HAL/Types.h"
+#include "HAL/cpp/make_unique.h"
+#include "HAL/cpp/priority_mutex.h"
+#include "HAL/handles/HandlesInternal.h"
+
+namespace hal {
+
+/**
+ * The IndexedHandleResource class is a way to track handles. This version
+ * allows a limited number of handles that are allocated by index.
+ * Because they are allocated by index, each individual index holds its own
+ * mutex, which reduces contention heavily.]
+ *
+ * @tparam THandle The Handle Type (Must be typedefed from HAL_Handle)
+ * @tparam TStruct The struct type held by this resource
+ * @tparam size The number of resources allowed to be allocated
+ * @tparam enumValue The type value stored in the handle
+ *
+ */
+template <typename THandle, typename TStruct, int16_t size,
+ HAL_HandleEnum enumValue>
+class IndexedHandleResource {
+ friend class IndexedHandleResourceTest;
+
+ public:
+ IndexedHandleResource() = default;
+ IndexedHandleResource(const IndexedHandleResource&) = delete;
+ IndexedHandleResource& operator=(const IndexedHandleResource&) = delete;
+
+ THandle Allocate(int16_t index, int32_t* status);
+ std::shared_ptr<TStruct> Get(THandle handle);
+ void Free(THandle handle);
+
+ private:
+ std::array<std::shared_ptr<TStruct>, size> m_structures;
+ std::array<priority_mutex, size> m_handleMutexes;
+};
+
+template <typename THandle, typename TStruct, int16_t size,
+ HAL_HandleEnum enumValue>
+THandle IndexedHandleResource<THandle, TStruct, size, enumValue>::Allocate(
+ int16_t index, int32_t* status) {
+ // don't aquire the lock if we can fail early.
+ if (index < 0 || index >= size) {
+ *status = RESOURCE_OUT_OF_RANGE;
+ return HAL_kInvalidHandle;
+ }
+ std::lock_guard<priority_mutex> sync(m_handleMutexes[index]);
+ // check for allocation, otherwise allocate and return a valid handle
+ if (m_structures[index] != nullptr) {
+ *status = RESOURCE_IS_ALLOCATED;
+ return HAL_kInvalidHandle;
+ }
+ m_structures[index] = std::make_shared<TStruct>();
+ return static_cast<THandle>(hal::createHandle(index, enumValue));
+}
+
+template <typename THandle, typename TStruct, int16_t size,
+ HAL_HandleEnum enumValue>
+std::shared_ptr<TStruct>
+IndexedHandleResource<THandle, TStruct, size, enumValue>::Get(THandle handle) {
+ // get handle index, and fail early if index out of range or wrong handle
+ int16_t index = getHandleTypedIndex(handle, enumValue);
+ if (index < 0 || index >= size) {
+ return nullptr;
+ }
+ std::lock_guard<priority_mutex> sync(m_handleMutexes[index]);
+ // return structure. Null will propogate correctly, so no need to manually
+ // check.
+ return m_structures[index];
+}
+
+template <typename THandle, typename TStruct, int16_t size,
+ HAL_HandleEnum enumValue>
+void IndexedHandleResource<THandle, TStruct, size, enumValue>::Free(
+ THandle handle) {
+ // get handle index, and fail early if index out of range or wrong handle
+ int16_t index = getHandleTypedIndex(handle, enumValue);
+ if (index < 0 || index >= size) return;
+ // lock and deallocated handle
+ std::lock_guard<priority_mutex> sync(m_handleMutexes[index]);
+ m_structures[index].reset();
+}
+} // namespace hal
diff --git a/hal/include/HAL/handles/LimitedClassedHandleResource.h b/hal/include/HAL/handles/LimitedClassedHandleResource.h
new file mode 100644
index 0000000..178bf1d
--- /dev/null
+++ b/hal/include/HAL/handles/LimitedClassedHandleResource.h
@@ -0,0 +1,101 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2016-2017. 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. */
+/*----------------------------------------------------------------------------*/
+
+#pragma once
+
+#include <stdint.h>
+
+#include <array>
+#include <memory>
+
+#include "HAL/Types.h"
+#include "HAL/cpp/make_unique.h"
+#include "HAL/cpp/priority_mutex.h"
+#include "HAL/handles/HandlesInternal.h"
+
+namespace hal {
+
+/**
+ * The LimitedClassedHandleResource class is a way to track handles. This
+ * version
+ * allows a limited number of handles that are allocated sequentially.
+ *
+ * @tparam THandle The Handle Type (Must be typedefed from HAL_Handle)
+ * @tparam TStruct The struct type held by this resource
+ * @tparam size The number of resources allowed to be allocated
+ * @tparam enumValue The type value stored in the handle
+ *
+ */
+template <typename THandle, typename TStruct, int16_t size,
+ HAL_HandleEnum enumValue>
+class LimitedClassedHandleResource {
+ friend class LimitedClassedHandleResourceTest;
+
+ public:
+ LimitedClassedHandleResource() = default;
+ LimitedClassedHandleResource(const LimitedClassedHandleResource&) = delete;
+ LimitedClassedHandleResource& operator=(const LimitedClassedHandleResource&) =
+ delete;
+
+ THandle Allocate(std::shared_ptr<TStruct> toSet);
+ std::shared_ptr<TStruct> Get(THandle handle);
+ void Free(THandle handle);
+
+ private:
+ std::array<std::shared_ptr<TStruct>, size> m_structures;
+ std::array<priority_mutex, size> m_handleMutexes;
+ priority_mutex m_allocateMutex;
+};
+
+template <typename THandle, typename TStruct, int16_t size,
+ HAL_HandleEnum enumValue>
+THandle
+LimitedClassedHandleResource<THandle, TStruct, size, enumValue>::Allocate(
+ std::shared_ptr<TStruct> toSet) {
+ // globally lock to loop through indices
+ std::lock_guard<priority_mutex> sync(m_allocateMutex);
+ int16_t i;
+ for (i = 0; i < size; i++) {
+ if (m_structures[i] == nullptr) {
+ // if a false index is found, grab its specific mutex
+ // and allocate it.
+ std::lock_guard<priority_mutex> sync(m_handleMutexes[i]);
+ m_structures[i] = toSet;
+ return static_cast<THandle>(createHandle(i, enumValue));
+ }
+ }
+ return HAL_kInvalidHandle;
+}
+
+template <typename THandle, typename TStruct, int16_t size,
+ HAL_HandleEnum enumValue>
+std::shared_ptr<TStruct> LimitedClassedHandleResource<
+ THandle, TStruct, size, enumValue>::Get(THandle handle) {
+ // get handle index, and fail early if index out of range or wrong handle
+ int16_t index = getHandleTypedIndex(handle, enumValue);
+ if (index < 0 || index >= size) {
+ return nullptr;
+ }
+ std::lock_guard<priority_mutex> sync(m_handleMutexes[index]);
+ // return structure. Null will propogate correctly, so no need to manually
+ // check.
+ return m_structures[index];
+}
+
+template <typename THandle, typename TStruct, int16_t size,
+ HAL_HandleEnum enumValue>
+void LimitedClassedHandleResource<THandle, TStruct, size, enumValue>::Free(
+ THandle handle) {
+ // get handle index, and fail early if index out of range or wrong handle
+ int16_t index = getHandleTypedIndex(handle, enumValue);
+ if (index < 0 || index >= size) return;
+ // lock and deallocated handle
+ std::lock_guard<priority_mutex> sync(m_allocateMutex);
+ std::lock_guard<priority_mutex> lock(m_handleMutexes[index]);
+ m_structures[index].reset();
+}
+} // namespace hal
diff --git a/hal/include/HAL/handles/LimitedHandleResource.h b/hal/include/HAL/handles/LimitedHandleResource.h
new file mode 100644
index 0000000..522328e
--- /dev/null
+++ b/hal/include/HAL/handles/LimitedHandleResource.h
@@ -0,0 +1,97 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2016-2017. 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. */
+/*----------------------------------------------------------------------------*/
+
+#pragma once
+
+#include <stdint.h>
+
+#include <array>
+#include <memory>
+
+#include "HAL/Types.h"
+#include "HAL/cpp/make_unique.h"
+#include "HAL/cpp/priority_mutex.h"
+#include "HandlesInternal.h"
+
+namespace hal {
+
+/**
+ * The LimitedHandleResource class is a way to track handles. This version
+ * allows a limited number of handles that are allocated sequentially.
+ *
+ * @tparam THandle The Handle Type (Must be typedefed from HAL_Handle)
+ * @tparam TStruct The struct type held by this resource
+ * @tparam size The number of resources allowed to be allocated
+ * @tparam enumValue The type value stored in the handle
+ *
+ */
+template <typename THandle, typename TStruct, int16_t size,
+ HAL_HandleEnum enumValue>
+class LimitedHandleResource {
+ friend class LimitedHandleResourceTest;
+
+ public:
+ LimitedHandleResource() = default;
+ LimitedHandleResource(const LimitedHandleResource&) = delete;
+ LimitedHandleResource& operator=(const LimitedHandleResource&) = delete;
+
+ THandle Allocate();
+ std::shared_ptr<TStruct> Get(THandle handle);
+ void Free(THandle handle);
+
+ private:
+ std::array<std::shared_ptr<TStruct>, size> m_structures;
+ std::array<priority_mutex, size> m_handleMutexes;
+ priority_mutex m_allocateMutex;
+};
+
+template <typename THandle, typename TStruct, int16_t size,
+ HAL_HandleEnum enumValue>
+THandle LimitedHandleResource<THandle, TStruct, size, enumValue>::Allocate() {
+ // globally lock to loop through indices
+ std::lock_guard<priority_mutex> sync(m_allocateMutex);
+ int16_t i;
+ for (i = 0; i < size; i++) {
+ if (m_structures[i] == nullptr) {
+ // if a false index is found, grab its specific mutex
+ // and allocate it.
+ std::lock_guard<priority_mutex> sync(m_handleMutexes[i]);
+ m_structures[i] = std::make_shared<TStruct>();
+ return static_cast<THandle>(createHandle(i, enumValue));
+ }
+ }
+ return HAL_kInvalidHandle;
+}
+
+template <typename THandle, typename TStruct, int16_t size,
+ HAL_HandleEnum enumValue>
+std::shared_ptr<TStruct>
+LimitedHandleResource<THandle, TStruct, size, enumValue>::Get(THandle handle) {
+ // get handle index, and fail early if index out of range or wrong handle
+ int16_t index = getHandleTypedIndex(handle, enumValue);
+ if (index < 0 || index >= size) {
+ return nullptr;
+ }
+ std::lock_guard<priority_mutex> sync(m_handleMutexes[index]);
+ // return structure. Null will propogate correctly, so no need to manually
+ // check.
+ return m_structures[index];
+}
+
+template <typename THandle, typename TStruct, int16_t size,
+ HAL_HandleEnum enumValue>
+void LimitedHandleResource<THandle, TStruct, size, enumValue>::Free(
+ THandle handle) {
+ // get handle index, and fail early if index out of range or wrong handle
+ int16_t index = getHandleTypedIndex(handle, enumValue);
+ if (index < 0 || index >= size) return;
+ // lock and deallocated handle
+ std::lock_guard<priority_mutex> sync(m_allocateMutex);
+ std::lock_guard<priority_mutex> lock(m_handleMutexes[index]);
+ m_structures[index].reset();
+}
+} // namespace hal
diff --git a/hal/include/HAL/handles/UnlimitedHandleResource.h b/hal/include/HAL/handles/UnlimitedHandleResource.h
new file mode 100644
index 0000000..ab77914
--- /dev/null
+++ b/hal/include/HAL/handles/UnlimitedHandleResource.h
@@ -0,0 +1,88 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2008-2017. 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. */
+/*----------------------------------------------------------------------------*/
+
+#pragma once
+
+#include <stdint.h>
+
+#include <memory>
+#include <vector>
+
+#include "HAL/Types.h"
+#include "HAL/cpp/priority_mutex.h"
+#include "HAL/handles/HandlesInternal.h"
+
+namespace hal {
+
+/**
+ * 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.
+
+ * @tparam THandle The Handle Type (Must be typedefed from HAL_Handle)
+ * @tparam TStruct The struct type held by this resource
+ * @tparam enumValue The type value stored in the handle
+ *
+ */
+template <typename THandle, typename TStruct, HAL_HandleEnum enumValue>
+class UnlimitedHandleResource {
+ friend class UnlimitedHandleResourceTest;
+
+ public:
+ UnlimitedHandleResource() = default;
+ UnlimitedHandleResource(const UnlimitedHandleResource&) = delete;
+ UnlimitedHandleResource& operator=(const UnlimitedHandleResource&) = delete;
+
+ THandle Allocate(std::shared_ptr<TStruct> structure);
+ std::shared_ptr<TStruct> Get(THandle handle);
+ void Free(THandle handle);
+
+ private:
+ std::vector<std::shared_ptr<TStruct>> m_structures;
+ priority_mutex m_handleMutex;
+};
+
+template <typename THandle, typename TStruct, HAL_HandleEnum enumValue>
+THandle UnlimitedHandleResource<THandle, TStruct, enumValue>::Allocate(
+ std::shared_ptr<TStruct> structure) {
+ std::lock_guard<priority_mutex> sync(m_handleMutex);
+ size_t i;
+ for (i = 0; i < m_structures.size(); i++) {
+ if (m_structures[i] == nullptr) {
+ m_structures[i] = structure;
+ return static_cast<THandle>(createHandle(i, enumValue));
+ }
+ }
+ if (i >= INT16_MAX) return HAL_kInvalidHandle;
+
+ m_structures.push_back(structure);
+ return static_cast<THandle>(createHandle(static_cast<int16_t>(i), enumValue));
+}
+
+template <typename THandle, typename TStruct, HAL_HandleEnum enumValue>
+std::shared_ptr<TStruct>
+UnlimitedHandleResource<THandle, TStruct, enumValue>::Get(THandle handle) {
+ int16_t index = getHandleTypedIndex(handle, enumValue);
+ std::lock_guard<priority_mutex> sync(m_handleMutex);
+ if (index < 0 || index >= static_cast<int16_t>(m_structures.size()))
+ return nullptr;
+ return m_structures[index];
+}
+
+template <typename THandle, typename TStruct, HAL_HandleEnum enumValue>
+void UnlimitedHandleResource<THandle, TStruct, enumValue>::Free(
+ THandle handle) {
+ int16_t index = getHandleTypedIndex(handle, enumValue);
+ std::lock_guard<priority_mutex> sync(m_handleMutex);
+ if (index < 0 || index >= static_cast<int16_t>(m_structures.size())) return;
+ m_structures[index].reset();
+}
+} // namespace hal