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/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