Introducing NamedEnum to parse enum value as string names.
Add support for parsing enum definition from enum value to string as
per the enum class definition. Including the parsing for enum value zero,
to be able to use enum name parsing for all enum class include value of 0.
Bug: 160010896
Test: atest inputflinger, atest libinput_tests
Change-Id: I717fefd46eddf49cea1ba69429bdd6c856e6bc45
diff --git a/include/input/Flags.h b/include/input/Flags.h
index 4ad9056..072dd18 100644
--- a/include/input/Flags.h
+++ b/include/input/Flags.h
@@ -22,6 +22,7 @@
#include <string>
#include <type_traits>
+#include "NamedEnum.h"
#include "utils/BitSet.h"
#ifndef __UI_INPUT_FLAGS_H
@@ -30,38 +31,6 @@
namespace android {
namespace details {
-template <typename F, F V>
-constexpr std::optional<std::string_view> enum_value_name() {
- // Should look something like (but all on one line):
- // std::optional<std::string_view>
- // android::details::enum_value_name()
- // [F = android::test::TestFlags, V = android::test::TestFlags::ONE]
- std::string_view view = __PRETTY_FUNCTION__;
- size_t templateStart = view.rfind("[");
- size_t templateEnd = view.rfind("]");
- if (templateStart == std::string::npos || templateEnd == std::string::npos) {
- return std::nullopt;
- }
-
- // Extract the template parameters without the enclosing braces.
- // Example (cont'd): F = android::test::TestFlags, V = android::test::TestFlags::ONE
- view = view.substr(templateStart + 1, templateEnd - templateStart - 1);
- size_t valStart = view.rfind("V = ");
- if (valStart == std::string::npos) {
- return std::nullopt;
- }
-
- // Example (cont'd): V = android::test::TestFlags::ONE
- view = view.substr(valStart);
- size_t nameStart = view.rfind("::");
- if (nameStart == std::string::npos) {
- return std::nullopt;
- }
-
- // Chop off the initial "::"
- nameStart += 2;
- return view.substr(nameStart);
-}
template <typename F>
inline constexpr auto flag_count = sizeof(F) * __CHAR_BIT__;
diff --git a/include/input/NamedEnum.h b/include/input/NamedEnum.h
new file mode 100644
index 0000000..42cfb12
--- /dev/null
+++ b/include/input/NamedEnum.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * 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 <android-base/stringprintf.h>
+
+#include <array>
+#include <cstdint>
+#include <optional>
+#include <string>
+
+#ifndef __UI_INPUT_NAMEDENUM_H
+#define __UI_INPUT_NAMEDENUM_H
+
+namespace android {
+
+namespace details {
+template <typename E, E V>
+constexpr std::optional<std::string_view> enum_value_name() {
+ // Should look something like (but all on one line):
+ // std::optional<std::string_view>
+ // android::details::enum_value_name()
+ // [E = android::test::TestEnums, V = android::test::TestEnums::ONE]
+ std::string_view view = __PRETTY_FUNCTION__;
+ size_t templateStart = view.rfind("[");
+ size_t templateEnd = view.rfind("]");
+ if (templateStart == std::string::npos || templateEnd == std::string::npos) {
+ return std::nullopt;
+ }
+
+ // Extract the template parameters without the enclosing braces.
+ // Example (cont'd): E = android::test::TestEnums, V = android::test::TestEnums::ONE
+ view = view.substr(templateStart + 1, templateEnd - templateStart - 1);
+ size_t valStart = view.rfind("V = ");
+ if (valStart == std::string::npos) {
+ return std::nullopt;
+ }
+
+ // Example (cont'd): V = android::test::TestEnums::ONE
+ view = view.substr(valStart);
+ size_t nameStart = view.rfind("::");
+ if (nameStart == std::string::npos) {
+ return std::nullopt;
+ }
+
+ // Chop off the initial "::"
+ nameStart += 2;
+ return view.substr(nameStart);
+}
+
+template <typename E, typename T, T... I>
+constexpr auto generate_enum_values(std::integer_sequence<T, I...> seq) {
+ constexpr size_t count = seq.size();
+
+ std::array<E, count> values{};
+ for (size_t i = 0, v = 0; v < count; ++i) {
+ values[v++] = static_cast<E>(T{0} + i);
+ }
+
+ return values;
+}
+
+template <typename E, std::size_t N>
+inline constexpr auto enum_values =
+ generate_enum_values<E>(std::make_integer_sequence<std::underlying_type_t<E>, N>{});
+
+template <typename E, std::size_t N, std::size_t... I>
+constexpr auto generate_enum_names(std::index_sequence<I...>) noexcept {
+ return std::array<std::optional<std::string_view>, sizeof...(I)>{
+ {enum_value_name<E, enum_values<E, N>[I]>()...}};
+}
+
+template <typename E, std::size_t N>
+inline constexpr auto enum_names = generate_enum_names<E, N>(std::make_index_sequence<N>{});
+
+} // namespace details
+
+class NamedEnum {
+public:
+ // By default allowed enum value range is 0 ~ 7.
+ template <typename E>
+ static constexpr size_t max = 8;
+
+ template <auto V>
+ static constexpr auto enum_name() {
+ using E = decltype(V);
+ return details::enum_value_name<E, V>();
+ }
+
+ template <typename E>
+ static constexpr std::optional<std::string_view> enum_name(E val) {
+ auto idx = static_cast<size_t>(val);
+ return idx < max<E> ? details::enum_names<E, max<E>>[idx] : std::nullopt;
+ }
+
+ // Helper function for parsing enum value to string.
+ // Example : enum class TestEnums { ZERO = 0x0 };
+ // NamedEnum::string(TestEnums::ZERO) returns string of "ZERO".
+ // Note the default maximum enum is 8, if the enum ID to be parsed if greater than 8 like 16,
+ // it should be declared to specialized the maximum enum by below:
+ // template <> constexpr size_t NamedEnum::max<TestEnums> = 16;
+ // If the enum class definition is sparse and contains enum values starting from a large value,
+ // Do not specialize it to a large number to avoid performance issues.
+ // The recommended maximum enum number to specialize is 64.
+ template <typename E>
+ static const std::string string(E val) {
+ std::string result;
+ std::optional<std::string_view> enumString = enum_name(val);
+ result += enumString ? enumString.value() : base::StringPrintf("0x%08x", val);
+ return result;
+ }
+};
+
+} // namespace android
+
+#endif // __UI_INPUT_NAMEDENUM_H
\ No newline at end of file