Squashed 'third_party/ntcore_2016/' content from commit d8de5e4

Change-Id: Id4839f41b6a620d8bae58dcf1710016671cc4992
git-subtree-dir: third_party/ntcore_2016
git-subtree-split: d8de5e4f19e612e7102172c0dbf152ce82d3d63a
diff --git a/src/Value.cpp b/src/Value.cpp
new file mode 100644
index 0000000..8095fa9
--- /dev/null
+++ b/src/Value.cpp
@@ -0,0 +1,210 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2015. 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.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "nt_Value.h"
+#include "Value_internal.h"
+#include "support/timestamp.h"
+
+using namespace nt;
+
+Value::Value() {
+  m_val.type = NT_UNASSIGNED;
+  m_val.last_change = Now();
+}
+
+Value::Value(NT_Type type, const private_init&) {
+  m_val.type = type;
+  m_val.last_change = Now();
+  if (m_val.type == NT_BOOLEAN_ARRAY)
+    m_val.data.arr_boolean.arr = nullptr;
+  else if (m_val.type == NT_DOUBLE_ARRAY)
+    m_val.data.arr_double.arr = nullptr;
+  else if (m_val.type == NT_STRING_ARRAY)
+    m_val.data.arr_string.arr = nullptr;
+}
+
+Value::~Value() {
+  if (m_val.type == NT_BOOLEAN_ARRAY)
+    delete[] m_val.data.arr_boolean.arr;
+  else if (m_val.type == NT_DOUBLE_ARRAY)
+    delete[] m_val.data.arr_double.arr;
+  else if (m_val.type == NT_STRING_ARRAY)
+    delete[] m_val.data.arr_string.arr;
+}
+
+std::shared_ptr<Value> Value::MakeBooleanArray(llvm::ArrayRef<int> value) {
+  auto val = std::make_shared<Value>(NT_BOOLEAN_ARRAY, private_init());
+  val->m_val.data.arr_boolean.arr = new int[value.size()];
+  val->m_val.data.arr_boolean.size = value.size();
+  std::copy(value.begin(), value.end(), val->m_val.data.arr_boolean.arr);
+  return val;
+}
+
+std::shared_ptr<Value> Value::MakeDoubleArray(llvm::ArrayRef<double> value) {
+  auto val = std::make_shared<Value>(NT_DOUBLE_ARRAY, private_init());
+  val->m_val.data.arr_double.arr = new double[value.size()];
+  val->m_val.data.arr_double.size = value.size();
+  std::copy(value.begin(), value.end(), val->m_val.data.arr_double.arr);
+  return val;
+}
+
+std::shared_ptr<Value> Value::MakeStringArray(
+    llvm::ArrayRef<std::string> value) {
+  auto val = std::make_shared<Value>(NT_STRING_ARRAY, private_init());
+  val->m_string_array = value;
+  // point NT_Value to the contents in the vector.
+  val->m_val.data.arr_string.arr = new NT_String[value.size()];
+  val->m_val.data.arr_string.size = val->m_string_array.size();
+  for (std::size_t i=0; i<value.size(); ++i) {
+    val->m_val.data.arr_string.arr[i].str = const_cast<char*>(value[i].c_str());
+    val->m_val.data.arr_string.arr[i].len = value[i].size();
+  }
+  return val;
+}
+
+std::shared_ptr<Value> Value::MakeStringArray(
+    std::vector<std::string>&& value) {
+  auto val = std::make_shared<Value>(NT_STRING_ARRAY, private_init());
+  val->m_string_array = std::move(value);
+  value.clear();
+  // point NT_Value to the contents in the vector.
+  val->m_val.data.arr_string.arr = new NT_String[val->m_string_array.size()];
+  val->m_val.data.arr_string.size = val->m_string_array.size();
+  for (std::size_t i=0; i<val->m_string_array.size(); ++i) {
+    val->m_val.data.arr_string.arr[i].str =
+        const_cast<char*>(val->m_string_array[i].c_str());
+    val->m_val.data.arr_string.arr[i].len = val->m_string_array[i].size();
+  }
+  return val;
+}
+
+void nt::ConvertToC(const Value& in, NT_Value* out) {
+  out->type = NT_UNASSIGNED;
+  switch (in.type()) {
+    case NT_UNASSIGNED:
+      return;
+    case NT_BOOLEAN:
+      out->data.v_boolean = in.GetBoolean() ? 1 : 0;
+      break;
+    case NT_DOUBLE:
+      out->data.v_double = in.GetDouble();
+      break;
+    case NT_STRING:
+      ConvertToC(in.GetString(), &out->data.v_string);
+      break;
+    case NT_RAW:
+      ConvertToC(in.GetRaw(), &out->data.v_raw);
+      break;
+    case NT_RPC:
+      ConvertToC(in.GetRpc(), &out->data.v_raw);
+      break;
+    case NT_BOOLEAN_ARRAY: {
+      auto v = in.GetBooleanArray();
+      out->data.arr_boolean.arr =
+          static_cast<int*>(std::malloc(v.size() * sizeof(int)));
+      out->data.arr_boolean.size = v.size();
+      std::copy(v.begin(), v.end(), out->data.arr_boolean.arr);
+      break;
+    }
+    case NT_DOUBLE_ARRAY: {
+      auto v = in.GetDoubleArray();
+      out->data.arr_double.arr =
+          static_cast<double*>(std::malloc(v.size() * sizeof(double)));
+      out->data.arr_double.size = v.size();
+      std::copy(v.begin(), v.end(), out->data.arr_double.arr);
+      break;
+    }
+    case NT_STRING_ARRAY: {
+      auto v = in.GetStringArray();
+      out->data.arr_string.arr =
+          static_cast<NT_String*>(std::malloc(v.size()*sizeof(NT_String)));
+      for (size_t i = 0; i < v.size(); ++i)
+        ConvertToC(v[i], &out->data.arr_string.arr[i]);
+      out->data.arr_string.size = v.size();
+      break;
+    }
+    default:
+      // assert(false && "unknown value type");
+      return;
+  }
+  out->type = in.type();
+}
+
+void nt::ConvertToC(llvm::StringRef in, NT_String* out) {
+  out->len = in.size();
+  out->str = static_cast<char*>(std::malloc(in.size()+1));
+  std::memcpy(out->str, in.data(), in.size());
+  out->str[in.size()] = '\0';
+}
+
+std::shared_ptr<Value> nt::ConvertFromC(const NT_Value& value) {
+  switch (value.type) {
+    case NT_UNASSIGNED:
+      return nullptr;
+    case NT_BOOLEAN:
+      return Value::MakeBoolean(value.data.v_boolean != 0);
+    case NT_DOUBLE:
+      return Value::MakeDouble(value.data.v_double);
+    case NT_STRING:
+      return Value::MakeString(ConvertFromC(value.data.v_string));
+    case NT_RAW:
+      return Value::MakeRaw(ConvertFromC(value.data.v_raw));
+    case NT_RPC:
+      return Value::MakeRpc(ConvertFromC(value.data.v_raw));
+    case NT_BOOLEAN_ARRAY:
+      return Value::MakeBooleanArray(llvm::ArrayRef<int>(
+          value.data.arr_boolean.arr, value.data.arr_boolean.size));
+    case NT_DOUBLE_ARRAY:
+      return Value::MakeDoubleArray(llvm::ArrayRef<double>(
+          value.data.arr_double.arr, value.data.arr_double.size));
+    case NT_STRING_ARRAY: {
+      std::vector<std::string> v;
+      v.reserve(value.data.arr_string.size);
+      for (size_t i=0; i<value.data.arr_string.size; ++i)
+        v.push_back(ConvertFromC(value.data.arr_string.arr[i]));
+      return Value::MakeStringArray(std::move(v));
+    }
+    default:
+      // assert(false && "unknown value type");
+      return nullptr;
+  }
+}
+
+bool nt::operator==(const Value& lhs, const Value& rhs) {
+  if (lhs.type() != rhs.type()) return false;
+  switch (lhs.type()) {
+    case NT_UNASSIGNED:
+      return true;  // XXX: is this better being false instead?
+    case NT_BOOLEAN:
+      return lhs.m_val.data.v_boolean == rhs.m_val.data.v_boolean;
+    case NT_DOUBLE:
+      return lhs.m_val.data.v_double == rhs.m_val.data.v_double;
+    case NT_STRING:
+    case NT_RAW:
+    case NT_RPC:
+      return lhs.m_string == rhs.m_string;
+    case NT_BOOLEAN_ARRAY:
+      if (lhs.m_val.data.arr_boolean.size != rhs.m_val.data.arr_boolean.size)
+        return false;
+      return std::memcmp(lhs.m_val.data.arr_boolean.arr,
+                         rhs.m_val.data.arr_boolean.arr,
+                         lhs.m_val.data.arr_boolean.size *
+                             sizeof(lhs.m_val.data.arr_boolean.arr[0])) == 0;
+    case NT_DOUBLE_ARRAY:
+      if (lhs.m_val.data.arr_double.size != rhs.m_val.data.arr_double.size)
+        return false;
+      return std::memcmp(lhs.m_val.data.arr_double.arr,
+                         rhs.m_val.data.arr_double.arr,
+                         lhs.m_val.data.arr_double.size *
+                             sizeof(lhs.m_val.data.arr_double.arr[0])) == 0;
+    case NT_STRING_ARRAY:
+      return lhs.m_string_array == rhs.m_string_array;
+    default:
+      // assert(false && "unknown value type");
+      return false;
+  }
+}