From c2537c83b906219a3b1a7ad0f612e77a6e89bd54 Mon Sep 17 00:00:00 2001
From: tholenst <tholenst@google.com>
Date: Tue, 9 Apr 2019 08:08:03 -0700
Subject: [PATCH] Add a template trait class HasDuplicates<...> for internal
 use. This is made such that HasDuplicates<...>::value is true iff the given
 list has a duplicate. We will use this later in the generalized key managers.

PiperOrigin-RevId: 242668181
GitOrigin-RevId: 9df38ddf4bafe0396f8ba7d084729aa0e54507e6
---
 cc/BUILD.bazel                 | 17 ++++++++
 cc/CMakeLists.txt              | 15 +++++++
 cc/core/template_util.h        | 71 ++++++++++++++++++++++++++++++++++
 cc/core/template_utils_test.cc | 43 ++++++++++++++++++++
 4 files changed, 146 insertions(+)
 create mode 100644 cc/core/template_util.h
 create mode 100644 cc/core/template_utils_test.cc

diff --git a/cc/BUILD.bazel b/cc/BUILD.bazel
index 193d0ed8d..4d51c49ee 100644
--- a/cc/BUILD.bazel
+++ b/cc/BUILD.bazel
@@ -601,6 +601,14 @@ cc_library(
     ],
 )
 
+cc_library(
+    name = "core/template_util",
+    include_prefix = "tink",
+    strip_include_prefix = "/cc",
+    hdrs = ["core/template_util.h"],
+    deps = ["@com_google_absl//absl/meta:type_traits"],
+)
+
 # Settings for building in various environments.
 config_setting(
     name = "linux_x86_64",
@@ -975,3 +983,12 @@ cc_test(
         "@com_google_googletest//:gtest_main",
     ],
 )
+
+cc_test(
+    name = "core/template_utils_test",
+    srcs = ["core/template_utils_test.cc"],
+    deps = [
+        ":core/template_util",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
diff --git a/cc/CMakeLists.txt b/cc/CMakeLists.txt
index 5e6e814fc..01c1f3da2 100644
--- a/cc/CMakeLists.txt
+++ b/cc/CMakeLists.txt
@@ -507,6 +507,14 @@ tink_cc_library(
     absl::synchronization
 )
 
+tink_cc_library(
+  NAME template_util
+  SRCS
+    core/template_util.h
+  DEPS
+    absl::meta
+)
+
 if (TINK_BUILD_SHARED_LIB)
   add_library(tink SHARED
     ${TINK_PUBLIC_APIS}
@@ -736,3 +744,10 @@ tink_cc_test(
     tink::util::test_util
 )
 
+tink_cc_test(
+  NAME template_utils_test
+  SRCS core/template_utils_test.cc
+  DEPS
+    tink::core::template_utils
+)
+
diff --git a/cc/core/template_util.h b/cc/core/template_util.h
new file mode 100644
index 000000000..0c55aa036
--- /dev/null
+++ b/cc/core/template_util.h
@@ -0,0 +1,71 @@
+// Copyright 2019 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+#ifndef TINK_CORE_TEMPLATE_UTIL_H
+#define TINK_CORE_TEMPLATE_UTIL_H
+
+#include <tuple>
+#include <type_traits>
+
+#include "absl/meta/type_traits.h"
+
+namespace crypto {
+namespace tink {
+
+namespace internal {
+
+// A helper class template which decides if the TestType occurs in the Tuple
+// For example, OccursInTuple<int, std::tuple<float, float>>::value == false,
+// and OccursInTuple<int, std::tuple<float, int>>::value == true. Not intended
+// to be used directly.
+
+// First declare the template which always takes two parameters.
+template <typename TestType, typename Tuple>
+class OccursInList;
+
+// In the special case where the tuple is empty, the result is false.
+template <typename TestType>
+class OccursInList<TestType, std::tuple<>> : public std::false_type {};
+
+// If the list is not empty, the result is true if TestType equals the first in
+// the list, or  TestType occurs in the rest of the list.
+template <typename TestType, typename First, typename... List>
+class OccursInList<TestType, std::tuple<First, List...>>
+    : public absl::disjunction<
+          std::is_same<TestType, First>,
+          OccursInList<TestType, typename std::tuple<List...>>> {};
+
+// The class HasDuplicates. Defines ::value as true in case the given list has
+// a duplicate, false otherwise.
+template <typename... Args>
+class HasDuplicates;
+
+// Empty list has no duplicates.
+template <>
+class HasDuplicates<> : public std::false_type {};
+
+// Non-empty list has a duplicate if the first appears in the rest, or if the
+// rest has a duplicate.
+template <typename First, typename... List>
+class HasDuplicates<First, List...>
+    : public absl::disjunction<
+          OccursInList<First, typename std::tuple<List...>>,
+          HasDuplicates<List...>> {};
+
+}  // namespace internal
+}  // namespace tink
+}  // namespace crypto
+
+#endif  // TINK_CORE_TEMPLATE_UTIL_H
diff --git a/cc/core/template_utils_test.cc b/cc/core/template_utils_test.cc
new file mode 100644
index 000000000..8323c8a62
--- /dev/null
+++ b/cc/core/template_utils_test.cc
@@ -0,0 +1,43 @@
+// Copyright 2019 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "tink/core/template_util.h"
+
+namespace crypto {
+namespace tink {
+namespace internal {
+
+class C0 {};
+class C1 {};
+class C2 {};
+class C3 {};
+class C4 {};
+
+static_assert(!HasDuplicates<>::value, "");
+static_assert(!HasDuplicates<C0>::value, "");
+static_assert(!HasDuplicates<C0, C1>::value, "");
+static_assert(!HasDuplicates<C0, C1, C2>::value, "");
+static_assert(!HasDuplicates<C0, C1, C2, C3>::value, "");
+
+static_assert(HasDuplicates<C0, C0>::value, "");
+static_assert(HasDuplicates<C0, C1, C0>::value, "");
+static_assert(HasDuplicates<C0, C1, C1>::value, "");
+static_assert(HasDuplicates<C0, C0, C1>::value, "");
+static_assert(HasDuplicates<C0, C1, C2, C3, C1, C4>::value, "");
+
+}  // namespace internal
+}  // namespace tink
+}  // namespace crypto
-- 
GitLab