diff options
Diffstat (limited to 'include')
| -rw-r--r-- | include/android/choreographer.h | 64 | ||||
| -rw-r--r-- | include/android/input.h | 14 | ||||
| -rw-r--r-- | include/android/sensor.h | 40 | ||||
| -rw-r--r-- | include/android/surface_control.h | 20 | ||||
| -rw-r--r-- | include/ftl/Flags.h | 99 | ||||
| -rw-r--r-- | include/ftl/NamedEnum.h | 129 | ||||
| -rw-r--r-- | include/ftl/cast.h | 84 | ||||
| -rw-r--r-- | include/ftl/concat.h | 84 | ||||
| -rw-r--r-- | include/ftl/details/array_traits.h (renamed from include/ftl/array_traits.h) | 6 | ||||
| -rw-r--r-- | include/ftl/details/cast.h | 57 | ||||
| -rw-r--r-- | include/ftl/details/concat.h | 62 | ||||
| -rw-r--r-- | include/ftl/enum.h | 301 | ||||
| -rw-r--r-- | include/ftl/initializer_list.h | 13 | ||||
| -rw-r--r-- | include/ftl/small_map.h | 157 | ||||
| -rw-r--r-- | include/ftl/small_vector.h | 33 | ||||
| -rw-r--r-- | include/ftl/static_vector.h | 24 | ||||
| -rw-r--r-- | include/ftl/string.h | 101 | ||||
| -rw-r--r-- | include/input/DisplayViewport.h | 10 | ||||
| -rw-r--r-- | include/input/Input.h | 93 | ||||
| -rw-r--r-- | include/input/InputDevice.h | 5 | ||||
| -rw-r--r-- | include/input/InputTransport.h | 58 | ||||
| -rw-r--r-- | include/powermanager/PowerHalWrapper.h | 4 | ||||
| -rw-r--r-- | include/private/surface_control_private.h | 6 |
23 files changed, 1134 insertions, 330 deletions
diff --git a/include/android/choreographer.h b/include/android/choreographer.h index b743f491e4..98f0eec8cc 100644 --- a/include/android/choreographer.h +++ b/include/android/choreographer.h @@ -39,6 +39,18 @@ struct AChoreographer; */ typedef struct AChoreographer AChoreographer; + +/** + * The identifier of a frame timeline. + */ +typedef int64_t AVsyncId; + +struct AChoreographerFrameCallbackData; +/** + * Opaque type that provides access to an AChoreographerFrameCallbackData object. + */ +typedef struct AChoreographerFrameCallbackData AChoreographerFrameCallbackData; + /** * Prototype of the function that is called when a new frame is being rendered. * It's passed the time that the frame is being rendered as nanoseconds in the @@ -60,6 +72,14 @@ typedef void (*AChoreographer_frameCallback)(long frameTimeNanos, void* data); typedef void (*AChoreographer_frameCallback64)(int64_t frameTimeNanos, void* data); /** + * Prototype of the function that is called when a new frame is being rendered. + * It's passed the frame data that should not outlive the callback, as well as the data pointer + * provided by the application that registered a callback. + */ +typedef void (*AChoreographer_extendedFrameCallback)( + const AChoreographerFrameCallbackData* callbackData, void* data); + +/** * Prototype of the function that is called when the display refresh rate * changes. It's passed the new vsync period in nanoseconds, as well as the data * pointer provided by the application that registered a callback. @@ -111,6 +131,14 @@ void AChoreographer_postFrameCallbackDelayed64(AChoreographer* choreographer, uint32_t delayMillis) __INTRODUCED_IN(29); /** + * Posts a callback to run on the next frame. The data pointer provided will + * be passed to the callback function when it's called. + */ +void AChoreographer_postExtendedFrameCallback(AChoreographer* choreographer, + AChoreographer_extendedFrameCallback callback, void* data) + __INTRODUCED_IN(33); + +/** * Registers a callback to be run when the display refresh rate changes. The * data pointer provided will be passed to the callback function when it's * called. The same callback may be registered multiple times, provided that a @@ -160,6 +188,42 @@ void AChoreographer_unregisterRefreshRateCallback(AChoreographer* choreographer, AChoreographer_refreshRateCallback, void* data) __INTRODUCED_IN(30); +/** + * The time in nanoseconds when the frame started being rendered. + */ +int64_t AChoreographerFrameCallbackData_getFrameTimeNanos( + const AChoreographerFrameCallbackData* data) __INTRODUCED_IN(33); + +/** + * The number of possible frame timelines. + */ +size_t AChoreographerFrameCallbackData_getFrameTimelinesLength( + const AChoreographerFrameCallbackData* data) __INTRODUCED_IN(33); + +/** + * Get index of the platform-preferred FrameTimeline. + */ +size_t AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex( + const AChoreographerFrameCallbackData* data) __INTRODUCED_IN(33); + +/** + * The vsync ID token used to map Choreographer data. + */ +AVsyncId AChoreographerFrameCallbackData_getFrameTimelineVsyncId( + const AChoreographerFrameCallbackData* data, size_t index) __INTRODUCED_IN(33); + +/** + * The time in nanoseconds which the frame at given index is expected to be presented. + */ +int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTimeNanos( + const AChoreographerFrameCallbackData* data, size_t index) __INTRODUCED_IN(33); + +/** + * The time in nanoseconds which the frame at given index needs to be ready by. + */ +int64_t AChoreographerFrameCallbackData_getFrameTimelineDeadlineNanos( + const AChoreographerFrameCallbackData* data, size_t index) __INTRODUCED_IN(33); + __END_DECLS #endif // ANDROID_CHOREOGRAPHER_H diff --git a/include/android/input.h b/include/android/input.h index 76422154f1..fbd61b53f4 100644 --- a/include/android/input.h +++ b/include/android/input.h @@ -169,6 +169,9 @@ enum { /** Drag event */ AINPUT_EVENT_TYPE_DRAG = 5, + + /** TouchMode event */ + AINPUT_EVENT_TYPE_TOUCH_MODE = 6, }; /** @@ -1382,6 +1385,17 @@ int32_t AInputQueue_preDispatchEvent(AInputQueue* queue, AInputEvent* event); */ void AInputQueue_finishEvent(AInputQueue* queue, AInputEvent* event, int handled); +/** + * Returns the AInputQueue* object associated with the supplied Java InputQueue + * object. The returned native object holds a weak reference to the Java object, + * and is only valid as long as the Java object has not yet been disposed. You + * should ensure that there is a strong reference to the Java object and that it + * has not been disposed before using the returned object. + * + * Available since API level 33. + */ +AInputQueue* AInputQueue_fromJava(JNIEnv* env, jobject inputQueue) __INTRODUCED_IN(33); + #ifdef __cplusplus } #endif diff --git a/include/android/sensor.h b/include/android/sensor.h index 9dc6983e50..45e8afc7de 100644 --- a/include/android/sensor.h +++ b/include/android/sensor.h @@ -256,6 +256,13 @@ enum { * The hinge angle sensor value is returned in degrees. */ ASENSOR_TYPE_HINGE_ANGLE = 36, + /** + * {@link ASENSOR_TYPE_HEAD_TRACKER} + * reporting-mode: continuous + * + * Measures the orientation and rotational velocity of a user's head. + */ + ASENSOR_TYPE_HEAD_TRACKER = 37, }; /** @@ -440,6 +447,38 @@ typedef struct AAdditionalInfoEvent { }; } AAdditionalInfoEvent; +typedef struct AHeadTrackerEvent { + /** + * The fields rx, ry, rz are an Euler vector (rotation vector, i.e. a vector + * whose direction indicates the axis of rotation and magnitude indicates + * the angle to rotate around that axis) representing the transform from + * the (arbitrary, possibly slowly drifting) reference frame to the + * head frame. Expressed in radians. Magnitude of the vector must be + * in the range [0, pi], while the value of individual axes are + * in the range [-pi, pi]. + */ + float rx; + float ry; + float rz; + + /** + * The fields vx, vy, vz are an Euler vector (rotation vector) representing + * the angular velocity of the head (relative to itself), in radians per + * second. The direction of this vector indicates the axis of rotation, and + * the magnitude indicates the rate of rotation. + */ + float vx; + float vy; + float vz; + + /** + * This value changes each time the reference frame is suddenly and + * significantly changed, for example if an orientation filter algorithm + * used for determining the orientation has had its state reset. + */ + int32_t discontinuity_count; +} AHeadTrackerEvent; + /** * Information that describes a sensor event, refer to * <a href="/reference/android/hardware/SensorEvent">SensorEvent</a> for additional @@ -476,6 +515,7 @@ typedef struct ASensorEvent { AHeartRateEvent heart_rate; ADynamicSensorEvent dynamic_sensor_meta; AAdditionalInfoEvent additional_info; + AHeadTrackerEvent head_tracker; }; union { uint64_t data[8]; diff --git a/include/android/surface_control.h b/include/android/surface_control.h index 059bc41f9a..9a36ecb537 100644 --- a/include/android/surface_control.h +++ b/include/android/surface_control.h @@ -28,6 +28,7 @@ #include <sys/cdefs.h> +#include <android/choreographer.h> #include <android/data_space.h> #include <android/hardware_buffer.h> #include <android/hdr_metadata.h> @@ -595,6 +596,25 @@ void ASurfaceTransaction_setEnableBackPressure(ASurfaceTransaction* transaction, bool enableBackPressure) __INTRODUCED_IN(31); +/** + * Sets the frame timeline to use in Surface Flinger. + * + * A frame timeline should be chosen based on what frame deadline the application + * can meet when rendering the frame and the application's desired present time. + * By setting a frame timeline, Surface Flinger tries to present the frame at the corresponding + * expected present time. + * + * To receive frame timelines, a callback must be posted to Choreographer using + * AChoreographer_postExtendedFrameCallback(). The \a vsnycId can then be extracted from the + * callback payload using AChoreographerFrameCallbackData_getFrameTimelineVsyncId(). + * + * \param vsyncId The vsync ID received from AChoreographer, setting the frame's present target to + * the corresponding expected present time and deadline from the frame to be rendered. A stale or + * invalid value will be ignored. + */ +void ASurfaceTransaction_setFrameTimeline(ASurfaceTransaction* transaction, + AVsyncId vsyncId) __INTRODUCED_IN(33); + __END_DECLS #endif // ANDROID_SURFACE_CONTROL_H diff --git a/include/ftl/Flags.h b/include/ftl/Flags.h index 27c84769cb..932af2d9f9 100644 --- a/include/ftl/Flags.h +++ b/include/ftl/Flags.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 The Android Open Source Project + * Copyright 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. @@ -14,79 +14,22 @@ * limitations under the License. */ -#include <android-base/stringprintf.h> +#pragma once + +#include <ftl/enum.h> +#include <ftl/string.h> -#include <array> #include <cstdint> -#include <optional> +#include <iterator> #include <string> #include <type_traits> -#include <ftl/NamedEnum.h> #include "utils/BitSet.h" -#pragma once +// TODO(b/185536303): Align with FTL style and namespace. namespace android { -namespace details { - -template <typename F> -inline constexpr auto flag_count = sizeof(F) * __CHAR_BIT__; - -template <typename F, typename T, T... I> -constexpr auto generate_flag_values(std::integer_sequence<T, I...> seq) { - constexpr size_t count = seq.size(); - - std::array<F, count> values{}; - for (size_t i = 0, v = 0; v < count; ++i) { - values[v++] = static_cast<F>(T{1} << i); - } - - return values; -} - -template <typename F> -inline constexpr auto flag_values = generate_flag_values<F>( - std::make_integer_sequence<std::underlying_type_t<F>, flag_count<F>>{}); - -template <typename F, std::size_t... I> -constexpr auto generate_flag_names(std::index_sequence<I...>) noexcept { - return std::array<std::optional<std::string_view>, sizeof...(I)>{ - {enum_value_name<F, flag_values<F>[I]>()...}}; -} - -template <typename F> -inline constexpr auto flag_names = - generate_flag_names<F>(std::make_index_sequence<flag_count<F>>{}); - -// A trait for determining whether a type is specifically an enum class or not. -template <typename T, bool = std::is_enum_v<T>> -struct is_enum_class : std::false_type {}; - -// By definition, an enum class is an enum that is not implicitly convertible to its underlying -// type. -template <typename T> -struct is_enum_class<T, true> - : std::bool_constant<!std::is_convertible_v<T, std::underlying_type_t<T>>> {}; - -template <typename T> -inline constexpr bool is_enum_class_v = is_enum_class<T>::value; -} // namespace details - -template <auto V> -constexpr auto flag_name() { - using F = decltype(V); - return details::enum_value_name<F, V>(); -} - -template <typename F> -constexpr std::optional<std::string_view> flag_name(F flag) { - using U = std::underlying_type_t<F>; - auto idx = static_cast<size_t>(__builtin_ctzl(static_cast<U>(flag))); - return details::flag_names<F>[idx]; -} - /* A class for handling flags defined by an enum or enum class in a type-safe way. */ template <typename F> class Flags { @@ -94,7 +37,7 @@ class Flags { // further to avoid this restriction but in general we want to encourage the use of enums // anyways. static_assert(std::is_enum_v<F>, "Flags type must be an enum"); - using U = typename std::underlying_type_t<F>; + using U = std::underlying_type_t<F>; public: constexpr Flags(F f) : mFlags(static_cast<U>(f)) {} @@ -106,11 +49,10 @@ public: // should force them to be explicitly constructed from their underlying types to make full use // of the type checker. template <typename T = U> - constexpr Flags(T t, typename std::enable_if_t<!details::is_enum_class_v<F>, T>* = nullptr) - : mFlags(t) {} + constexpr Flags(T t, std::enable_if_t<!ftl::is_scoped_enum_v<F>, T>* = nullptr) : mFlags(t) {} + template <typename T = U> - explicit constexpr Flags(T t, - typename std::enable_if_t<details::is_enum_class_v<F>, T>* = nullptr) + explicit constexpr Flags(T t, std::enable_if_t<ftl::is_scoped_enum_v<F>, T>* = nullptr) : mFlags(t) {} class Iterator { @@ -229,16 +171,16 @@ public: bool first = true; U unstringified = 0; for (const F f : *this) { - std::optional<std::string_view> flagString = flag_name(f); - if (flagString) { - appendFlag(result, flagString.value(), first); + if (const auto flagName = ftl::flag_name(f)) { + appendFlag(result, flagName.value(), first); } else { unstringified |= static_cast<U>(f); } } if (unstringified != 0) { - appendFlag(result, base::StringPrintf("0x%08x", unstringified), first); + constexpr auto radix = sizeof(U) == 1 ? ftl::Radix::kBin : ftl::Radix::kHex; + appendFlag(result, ftl::to_string(unstringified, radix), first); } if (first) { @@ -265,15 +207,14 @@ private: // as flags. In order to use these, add them via a `using namespace` declaration. namespace flag_operators { -template <typename F, typename = std::enable_if_t<details::is_enum_class_v<F>>> +template <typename F, typename = std::enable_if_t<ftl::is_scoped_enum_v<F>>> inline Flags<F> operator~(F f) { - using U = typename std::underlying_type_t<F>; - return static_cast<F>(~static_cast<U>(f)); + return static_cast<F>(~ftl::to_underlying(f)); } -template <typename F, typename = std::enable_if_t<details::is_enum_class_v<F>>> + +template <typename F, typename = std::enable_if_t<ftl::is_scoped_enum_v<F>>> Flags<F> operator|(F lhs, F rhs) { - using U = typename std::underlying_type_t<F>; - return static_cast<F>(static_cast<U>(lhs) | static_cast<U>(rhs)); + return static_cast<F>(ftl::to_underlying(lhs) | ftl::to_underlying(rhs)); } } // namespace flag_operators diff --git a/include/ftl/NamedEnum.h b/include/ftl/NamedEnum.h deleted file mode 100644 index 6e98feeb87..0000000000 --- a/include/ftl/NamedEnum.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * 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> - -#pragma once - -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); - // Check invalid enum values with cast, like V = (android::test::TestEnums)8. - if (view.find('(') != std::string::npos) { - return std::nullopt; - } - 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, const char* fallbackFormat = "%02d") { - std::string result; - std::optional<std::string_view> enumString = enum_name(val); - result += enumString ? enumString.value() : base::StringPrintf(fallbackFormat, val); - return result; - } -}; - -} // namespace android diff --git a/include/ftl/cast.h b/include/ftl/cast.h new file mode 100644 index 0000000000..ff1b58ad56 --- /dev/null +++ b/include/ftl/cast.h @@ -0,0 +1,84 @@ +/* + * Copyright 2021 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. + */ + +#pragma once + +#include <limits> +#include <type_traits> + +#include <ftl/details/cast.h> + +namespace android::ftl { + +enum class CastSafety { kSafe, kUnderflow, kOverflow }; + +// Returns whether static_cast<R>(v) is safe, or would result in underflow or overflow. +// +// static_assert(ftl::cast_safety<uint8_t>(-1) == ftl::CastSafety::kUnderflow); +// static_assert(ftl::cast_safety<int8_t>(128u) == ftl::CastSafety::kOverflow); +// +// static_assert(ftl::cast_safety<uint32_t>(-.1f) == ftl::CastSafety::kUnderflow); +// static_assert(ftl::cast_safety<int32_t>(static_cast<float>(INT32_MAX)) == +// ftl::CastSafety::kOverflow); +// +// static_assert(ftl::cast_safety<float>(-DBL_MAX) == ftl::CastSafety::kUnderflow); +// +template <typename R, typename T> +constexpr CastSafety cast_safety(T v) { + static_assert(std::is_arithmetic_v<T>); + static_assert(std::is_arithmetic_v<R>); + + constexpr bool kFromSigned = std::is_signed_v<T>; + constexpr bool kToSigned = std::is_signed_v<R>; + + using details::max_exponent; + + // If the R range contains the T range, then casting is always safe. + if constexpr ((kFromSigned == kToSigned && max_exponent<R> >= max_exponent<T>) || + (!kFromSigned && kToSigned && max_exponent<R> > max_exponent<T>)) { + return CastSafety::kSafe; + } + + using C = std::common_type_t<R, T>; + + if constexpr (kFromSigned) { + using L = details::safe_limits<R, T>; + + if constexpr (kToSigned) { + // Signed to signed. + if (v < L::lowest()) return CastSafety::kUnderflow; + return v <= L::max() ? CastSafety::kSafe : CastSafety::kOverflow; + } else { + // Signed to unsigned. + if (v < 0) return CastSafety::kUnderflow; + return static_cast<C>(v) <= static_cast<C>(L::max()) ? CastSafety::kSafe + : CastSafety::kOverflow; + } + } else { + using L = std::numeric_limits<R>; + + if constexpr (kToSigned) { + // Unsigned to signed. + return static_cast<C>(v) <= static_cast<C>(L::max()) ? CastSafety::kSafe + : CastSafety::kOverflow; + } else { + // Unsigned to unsigned. + return v <= L::max() ? CastSafety::kSafe : CastSafety::kOverflow; + } + } +} + +} // namespace android::ftl diff --git a/include/ftl/concat.h b/include/ftl/concat.h new file mode 100644 index 0000000000..ded48f7c8c --- /dev/null +++ b/include/ftl/concat.h @@ -0,0 +1,84 @@ +/* + * Copyright 2021 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. + */ + +#pragma once + +#include <ftl/details/concat.h> + +namespace android::ftl { + +// Lightweight (not allocating nor sprintf-based) concatenation. +// +// std::string_view name = "Volume"; +// ftl::Concat string(ftl::truncated<3>(name), ": ", -3, " dB"); +// +// assert(string.str() == "Vol: -3 dB"); +// assert(string.c_str()[string.size()] == '\0'); +// +template <std::size_t, typename... Ts> +struct Concat; + +template <std::size_t N, typename T, typename... Ts> +struct Concat<N, T, Ts...> : Concat<N + details::StaticString<T>::N, Ts...> { + explicit constexpr Concat(T v, Ts... args) { append(v, args...); } + + protected: + constexpr Concat() = default; + + constexpr void append(T v, Ts... args) { + using Str = details::StaticString<T>; + const Str str(v); + + // TODO: Replace with constexpr std::copy in C++20. + for (auto it = str.view.begin(); it != str.view.end();) { + *this->end_++ = *it++; + } + + using Base = Concat<N + Str::N, Ts...>; + this->Base::append(args...); + } +}; + +template <std::size_t N> +struct Concat<N> { + static constexpr std::size_t max_size() { return N; } + constexpr std::size_t size() const { return end_ - buffer_; } + + constexpr const char* c_str() const { return buffer_; } + + constexpr std::string_view str() const { + // TODO: Replace with {buffer_, end_} in C++20. + return {buffer_, size()}; + } + + protected: + constexpr Concat() : end_(buffer_) {} + constexpr void append() { *end_ = '\0'; } + + char buffer_[N + 1]; + char* end_; +}; + +// Deduction guide. +template <typename... Ts> +Concat(Ts&&...) -> Concat<0, Ts...>; + +template <std::size_t N> +constexpr auto truncated(std::string_view v) { + return details::Truncated<N>{v}; +} + +} // namespace android::ftl diff --git a/include/ftl/array_traits.h b/include/ftl/details/array_traits.h index 1265fa15fe..16e63eca74 100644 --- a/include/ftl/array_traits.h +++ b/include/ftl/details/array_traits.h @@ -21,9 +21,9 @@ #include <new> #include <type_traits> -#define FTL_ARRAY_TRAIT(T, U) using U = typename ArrayTraits<T>::U +#define FTL_ARRAY_TRAIT(T, U) using U = typename details::ArrayTraits<T>::U -namespace android::ftl { +namespace android::ftl::details { template <typename T> struct ArrayTraits { @@ -132,4 +132,4 @@ struct ArrayComparators { } }; -} // namespace android::ftl +} // namespace android::ftl::details diff --git a/include/ftl/details/cast.h b/include/ftl/details/cast.h new file mode 100644 index 0000000000..87b9f1e20a --- /dev/null +++ b/include/ftl/details/cast.h @@ -0,0 +1,57 @@ +/* + * Copyright 2021 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. + */ + +#pragma once + +#include <limits> +#include <type_traits> + +namespace android::ftl::details { + +// Exponent whose power of 2 is the (exclusive) upper bound of T. +template <typename T, typename L = std::numeric_limits<T>> +constexpr int max_exponent = std::is_floating_point_v<T> ? L::max_exponent : L::digits; + +// Extension of std::numeric_limits<T> that reduces the maximum for integral types T such that it +// has an exact representation for floating-point types F. For example, the maximum int32_t value +// is 2'147'483'647, but casting it to float commonly rounds up to 2'147'483'650.f, which cannot +// be safely converted back lest the signed overflow invokes undefined behavior. This pitfall is +// avoided by clearing the lower (31 - 24 =) 7 bits of precision to 2'147'483'520. Note that the +// minimum is representable. +template <typename T, typename F> +struct safe_limits : std::numeric_limits<T> { + static constexpr T max() { + using Base = std::numeric_limits<T>; + + if constexpr (std::is_integral_v<T> && std::is_floating_point_v<F>) { + // Assume the mantissa is 24 bits for float, or 53 bits for double. + using Float = std::numeric_limits<F>; + static_assert(Float::is_iec559); + + // If the integer is wider than the mantissa, clear the excess bits of precision. + constexpr int kShift = Base::digits - Float::digits; + if constexpr (kShift > 0) { + using U = std::make_unsigned_t<T>; + constexpr U kOne = static_cast<U>(1); + return static_cast<U>(Base::max()) & ~((kOne << kShift) - kOne); + } + } + + return Base::max(); + } +}; + +} // namespace android::ftl::details diff --git a/include/ftl/details/concat.h b/include/ftl/details/concat.h new file mode 100644 index 0000000000..8ce949ef05 --- /dev/null +++ b/include/ftl/details/concat.h @@ -0,0 +1,62 @@ +/* + * Copyright 2021 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. + */ + +#pragma once + +#include <functional> +#include <string_view> + +#include <ftl/string.h> + +namespace android::ftl::details { + +template <typename T, typename = void> +struct StaticString; + +template <typename T> +struct StaticString<T, std::enable_if_t<std::is_integral_v<T>>> { + static constexpr std::size_t N = to_chars_length_v<T>; + + explicit StaticString(T v) : view(to_chars(buffer, v)) {} + + to_chars_buffer_t<T> buffer; + const std::string_view view; +}; + +template <std::size_t M> +struct StaticString<const char (&)[M], void> { + static constexpr std::size_t N = M - 1; + + explicit constexpr StaticString(const char (&str)[M]) : view(str, N) {} + + const std::string_view view; +}; + +template <std::size_t N> +struct Truncated { + std::string_view view; +}; + +template <std::size_t M> +struct StaticString<Truncated<M>, void> { + static constexpr std::size_t N = M; + + explicit constexpr StaticString(Truncated<M> str) : view(str.view.substr(0, N)) {} + + const std::string_view view; +}; + +} // namespace android::ftl::details diff --git a/include/ftl/enum.h b/include/ftl/enum.h new file mode 100644 index 0000000000..5234c051b1 --- /dev/null +++ b/include/ftl/enum.h @@ -0,0 +1,301 @@ +/* + * Copyright 2021 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. + */ + +#pragma once + +#include <cstddef> +#include <limits> +#include <optional> +#include <string_view> +#include <type_traits> +#include <utility> + +#include <ftl/string.h> + +// Returns the name of enumerator E::V (i.e. "V") as std::optional<std::string_view> by parsing the +// compiler-generated string literal for the signature of this function. The function is defined in +// the global namespace with a short name and inferred return type to reduce bloat in the read-only +// data segment. +template <typename E, E V> +constexpr auto ftl_enum() { + static_assert(std::is_enum_v<E>); + + using R = std::optional<std::string_view>; + using namespace std::literals; + + // The "pretty" signature has the following format: + // + // auto ftl_enum() [E = android::test::Enum, V = android::test::Enum::kValue] + // + std::string_view view = __PRETTY_FUNCTION__; + const auto template_begin = view.rfind('['); + const auto template_end = view.rfind(']'); + if (template_begin == view.npos || template_end == view.npos) return R{}; + + // Extract the template parameters without the enclosing brackets. Example (cont'd): + // + // E = android::test::Enum, V = android::test::Enum::kValue + // + view = view.substr(template_begin + 1, template_end - template_begin - 1); + const auto value_begin = view.rfind("V = "sv); + if (value_begin == view.npos) return R{}; + + // Example (cont'd): + // + // V = android::test::Enum::kValue + // + view = view.substr(value_begin); + const auto name_begin = view.rfind("::"sv); + if (name_begin == view.npos) return R{}; + + // Chop off the leading "::". + const auto name = view.substr(name_begin + 2); + + // A value that is not enumerated has the format "Enum)42". + return name.find(')') == view.npos ? R{name} : R{}; +} + +namespace android::ftl { + +// Trait for determining whether a type is specifically a scoped enum or not. By definition, a +// scoped enum is one that is not implicitly convertible to its underlying type. +// +// TODO: Replace with std::is_scoped_enum in C++23. +// +template <typename T, bool = std::is_enum_v<T>> +struct is_scoped_enum : std::false_type {}; + +template <typename T> +struct is_scoped_enum<T, true> : std::negation<std::is_convertible<T, std::underlying_type_t<T>>> { +}; + +template <typename T> +inline constexpr bool is_scoped_enum_v = is_scoped_enum<T>::value; + +// Shorthand for casting an enumerator to its integral value. +// +// TODO: Replace with std::to_underlying in C++23. +// +// enum class E { A, B, C }; +// static_assert(ftl::to_underlying(E::B) == 1); +// +template <typename E> +constexpr auto to_underlying(E v) { + return static_cast<std::underlying_type_t<E>>(v); +} + +// Traits for retrieving an enum's range. An enum specifies its range by defining enumerators named +// ftl_first and ftl_last. If omitted, ftl_first defaults to 0, whereas ftl_last defaults to N - 1 +// where N is the bit width of the underlying type, but only if that type is unsigned, assuming the +// enumerators are flags. Also, note that unscoped enums must define both bounds, as casting out-of- +// range values results in undefined behavior if the underlying type is not fixed. +// +// enum class E { A, B, C, F = 5, ftl_last = F }; +// +// static_assert(ftl::enum_begin_v<E> == E::A); +// static_assert(ftl::enum_last_v<E> == E::F); +// static_assert(ftl::enum_size_v<E> == 6); +// +// enum class F : std::uint16_t { X = 0b1, Y = 0b10, Z = 0b100 }; +// +// static_assert(ftl::enum_begin_v<F> == F{0}); +// static_assert(ftl::enum_last_v<F> == F{15}); +// static_assert(ftl::enum_size_v<F> == 16); +// +template <typename E, typename = void> +struct enum_begin { + static_assert(is_scoped_enum_v<E>, "Missing ftl_first enumerator"); + static constexpr E value{0}; +}; + +template <typename E> +struct enum_begin<E, std::void_t<decltype(E::ftl_first)>> { + static constexpr E value = E::ftl_first; +}; + +template <typename E> +inline constexpr E enum_begin_v = enum_begin<E>::value; + +template <typename E, typename = void> +struct enum_end { + using U = std::underlying_type_t<E>; + static_assert(is_scoped_enum_v<E> && std::is_unsigned_v<U>, "Missing ftl_last enumerator"); + + static constexpr E value{std::numeric_limits<U>::digits}; +}; + +template <typename E> +struct enum_end<E, std::void_t<decltype(E::ftl_last)>> { + static constexpr E value = E{to_underlying(E::ftl_last) + 1}; +}; + +template <typename E> +inline constexpr E enum_end_v = enum_end<E>::value; + +template <typename E> +inline constexpr E enum_last_v = E{to_underlying(enum_end_v<E>) - 1}; + +template <typename E> +struct enum_size { + static constexpr auto kBegin = to_underlying(enum_begin_v<E>); + static constexpr auto kEnd = to_underlying(enum_end_v<E>); + static_assert(kBegin < kEnd, "Invalid range"); + + static constexpr std::size_t value = kEnd - kBegin; + static_assert(value <= 64, "Excessive range size"); +}; + +template <typename E> +inline constexpr std::size_t enum_size_v = enum_size<E>::value; + +namespace details { + +template <auto V> +struct Identity { + static constexpr auto value = V; +}; + +template <typename E> +using make_enum_sequence = std::make_integer_sequence<std::underlying_type_t<E>, enum_size_v<E>>; + +template <typename E, template <E> class = Identity, typename = make_enum_sequence<E>> +struct EnumRange; + +template <typename E, template <E> class F, typename T, T... Vs> +struct EnumRange<E, F, std::integer_sequence<T, Vs...>> { + static constexpr auto kBegin = to_underlying(enum_begin_v<E>); + static constexpr auto kSize = enum_size_v<E>; + + using R = decltype(F<E{}>::value); + const R values[kSize] = {F<static_cast<E>(Vs + kBegin)>::value...}; + + constexpr const auto* begin() const { return values; } + constexpr const auto* end() const { return values + kSize; } +}; + +template <auto V> +struct EnumName { + static constexpr auto value = ftl_enum<decltype(V), V>(); +}; + +template <auto I> +struct FlagName { + using E = decltype(I); + using U = std::underlying_type_t<E>; + + static constexpr E V{U{1} << to_underlying(I)}; + static constexpr auto value = ftl_enum<E, V>(); +}; + +} // namespace details + +// Returns an iterable over the range of an enum. +// +// enum class E { A, B, C, F = 5, ftl_last = F }; +// +// std::string string; +// for (E v : ftl::enum_range<E>()) { +// string += ftl::enum_name(v).value_or("?"); +// } +// +// assert(string == "ABC??F"); +// +template <typename E> +constexpr auto enum_range() { + return details::EnumRange<E>{}; +} + +// Returns a stringified enumerator at compile time. +// +// enum class E { A, B, C }; +// static_assert(ftl::enum_name<E::B>() == "B"); +// +template <auto V> +constexpr std::string_view enum_name() { + constexpr auto kName = ftl_enum<decltype(V), V>(); + static_assert(kName, "Unknown enumerator"); + return *kName; +} + +// Returns a stringified enumerator, possibly at compile time. +// +// enum class E { A, B, C, F = 5, ftl_last = F }; +// +// static_assert(ftl::enum_name(E::C).value_or("?") == "C"); +// static_assert(ftl::enum_name(E{3}).value_or("?") == "?"); +// +template <typename E> +constexpr std::optional<std::string_view> enum_name(E v) { + const auto value = to_underlying(v); + + constexpr auto kBegin = to_underlying(enum_begin_v<E>); + constexpr auto kLast = to_underlying(enum_last_v<E>); + if (value < kBegin || value > kLast) return {}; + + constexpr auto kRange = details::EnumRange<E, details::EnumName>{}; + return kRange.values[value - kBegin]; +} + +// Returns a stringified flag enumerator, possibly at compile time. +// +// enum class F : std::uint16_t { X = 0b1, Y = 0b10, Z = 0b100 }; +// +// static_assert(ftl::flag_name(F::Z).value_or("?") == "Z"); +// static_assert(ftl::flag_name(F{0b111}).value_or("?") == "?"); +// +template <typename E> +constexpr std::optional<std::string_view> flag_name(E v) { + const auto value = to_underlying(v); + + // TODO: Replace with std::popcount and std::countr_zero in C++20. + if (__builtin_popcountl(value) != 1) return {}; + + constexpr auto kRange = details::EnumRange<E, details::FlagName>{}; + return kRange.values[__builtin_ctzl(value)]; +} + +// Returns a stringified enumerator, or its integral value if not named. +// +// enum class E { A, B, C, F = 5, ftl_last = F }; +// +// assert(ftl::enum_string(E::C) == "C"); +// assert(ftl::enum_string(E{3}) == "3"); +// +template <typename E> +inline std::string enum_string(E v) { + if (const auto name = enum_name(v)) { + return std::string(*name); + } + return to_string(to_underlying(v)); +} + +// Returns a stringified flag enumerator, or its integral value if not named. +// +// enum class F : std::uint16_t { X = 0b1, Y = 0b10, Z = 0b100 }; +// +// assert(ftl::flag_string(F::Z) == "Z"); +// assert(ftl::flag_string(F{7}) == "0b111"); +// +template <typename E> +inline std::string flag_string(E v) { + if (const auto name = flag_name(v)) { + return std::string(*name); + } + constexpr auto radix = sizeof(E) == 1 ? Radix::kBin : Radix::kHex; + return to_string(to_underlying(v), radix); +} + +} // namespace android::ftl diff --git a/include/ftl/initializer_list.h b/include/ftl/initializer_list.h index 769c09ff11..2102c253f1 100644 --- a/include/ftl/initializer_list.h +++ b/include/ftl/initializer_list.h @@ -16,6 +16,7 @@ #pragma once +#include <functional> #include <tuple> #include <utility> @@ -65,18 +66,18 @@ struct InitializerList<T, std::index_sequence<Sizes...>, Types...> { std::tuple<Types...> tuple; }; -template <typename K, typename V> +template <typename K, typename V, typename KeyEqual = std::equal_to<K>> struct KeyValue {}; // Shorthand for key-value pairs that assigns the first argument to the key, and the rest to the // value. The specialization is on KeyValue rather than std::pair, so that ftl::init::list works // with the latter. -template <typename K, typename V, std::size_t... Sizes, typename... Types> -struct InitializerList<KeyValue<K, V>, std::index_sequence<Sizes...>, Types...> { +template <typename K, typename V, typename E, std::size_t... Sizes, typename... Types> +struct InitializerList<KeyValue<K, V, E>, std::index_sequence<Sizes...>, Types...> { // Accumulate the three arguments to std::pair's piecewise constructor. template <typename... Args> [[nodiscard]] constexpr auto operator()(K&& k, Args&&... args) && -> InitializerList< - KeyValue<K, V>, std::index_sequence<Sizes..., 3>, Types..., std::piecewise_construct_t, + KeyValue<K, V, E>, std::index_sequence<Sizes..., 3>, Types..., std::piecewise_construct_t, std::tuple<K&&>, std::tuple<Args&&...>> { return {std::tuple_cat( std::move(tuple), @@ -94,9 +95,9 @@ template <typename T, typename... Args> return InitializerList<T>{}(std::forward<Args>(args)...); } -template <typename K, typename V, typename... Args> +template <typename K, typename V, typename E = std::equal_to<K>, typename... Args> [[nodiscard]] constexpr auto map(Args&&... args) { - return list<KeyValue<K, V>>(std::forward<Args>(args)...); + return list<KeyValue<K, V, E>>(std::forward<Args>(args)...); } template <typename K, typename V> diff --git a/include/ftl/small_map.h b/include/ftl/small_map.h index 84c15ebdca..2effaa437c 100644 --- a/include/ftl/small_map.h +++ b/include/ftl/small_map.h @@ -19,6 +19,7 @@ #include <ftl/initializer_list.h> #include <ftl/small_vector.h> +#include <algorithm> #include <functional> #include <optional> #include <type_traits> @@ -28,7 +29,10 @@ namespace android::ftl { // Associative container with unique, unordered keys. Unlike std::unordered_map, key-value pairs are // stored in contiguous storage for cache efficiency. The map is allocated statically until its size -// exceeds N, at which point mappings are relocated to dynamic memory. +// exceeds N, at which point mappings are relocated to dynamic memory. The try_emplace operation has +// a non-standard analogue try_replace that destructively emplaces. The API also defines an in-place +// counterpart to insert_or_assign: emplace_or_replace. Lookup is done not via a subscript operator, +// but immutable getters that can optionally transform the value. // // SmallMap<K, V, 0> unconditionally allocates on the heap. // @@ -43,18 +47,21 @@ namespace android::ftl { // assert(!map.dynamic()); // // assert(map.contains(123)); -// assert(map.find(42, [](const std::string& s) { return s.size(); }) == 3u); +// assert(map.get(42, [](const std::string& s) { return s.size(); }) == 3u); // -// const auto opt = map.find(-1); +// const auto opt = map.get(-1); // assert(opt); // // std::string& ref = *opt; // assert(ref.empty()); // ref = "xyz"; // -// assert(map == SmallMap(ftl::init::map(-1, "xyz")(42, "???")(123, "abc"))); +// map.emplace_or_replace(0, "vanilla", 2u, 3u); +// assert(map.dynamic()); // -template <typename K, typename V, std::size_t N> +// assert(map == SmallMap(ftl::init::map(-1, "xyz")(0, "nil")(42, "???")(123, "abc"))); +// +template <typename K, typename V, std::size_t N, typename KeyEqual = std::equal_to<K>> class SmallMap final { using Map = SmallVector<std::pair<const K, V>, N>; @@ -80,12 +87,7 @@ class SmallMap final { // The syntax for listing pairs is as follows: // // ftl::SmallMap map = ftl::init::map<int, std::string>(123, "abc")(-1)(42, 3u, '?'); - // // static_assert(std::is_same_v<decltype(map), ftl::SmallMap<int, std::string, 3>>); - // assert(map.size() == 3u); - // assert(map.contains(-1) && map.find(-1)->get().empty()); - // assert(map.contains(42) && map.find(42)->get() == "???"); - // assert(map.contains(123) && map.find(123)->get() == "abc"); // // The types of the key and value are deduced if the first pair contains exactly two arguments: // @@ -95,7 +97,7 @@ class SmallMap final { template <typename U, std::size_t... Sizes, typename... Types> SmallMap(InitializerList<U, std::index_sequence<Sizes...>, Types...>&& list) : map_(std::move(list)) { - // TODO: Enforce unique keys. + deduplicate(); } size_type max_size() const { return map_.max_size(); } @@ -115,27 +117,27 @@ class SmallMap final { // Returns whether a mapping exists for the given key. bool contains(const key_type& key) const { - return find(key, [](const mapped_type&) {}); + return get(key, [](const mapped_type&) {}); } // Returns a reference to the value for the given key, or std::nullopt if the key was not found. // // ftl::SmallMap map = ftl::init::map('a', 'A')('b', 'B')('c', 'C'); // - // const auto opt = map.find('c'); + // const auto opt = map.get('c'); // assert(opt == 'C'); // // char d = 'd'; - // const auto ref = map.find('d').value_or(std::ref(d)); + // const auto ref = map.get('d').value_or(std::ref(d)); // ref.get() = 'D'; // assert(d == 'D'); // - auto find(const key_type& key) const -> std::optional<std::reference_wrapper<const mapped_type>> { - return find(key, [](const mapped_type& v) { return std::cref(v); }); + auto get(const key_type& key) const -> std::optional<std::reference_wrapper<const mapped_type>> { + return get(key, [](const mapped_type& v) { return std::cref(v); }); } - auto find(const key_type& key) -> std::optional<std::reference_wrapper<mapped_type>> { - return find(key, [](mapped_type& v) { return std::ref(v); }); + auto get(const key_type& key) -> std::optional<std::reference_wrapper<mapped_type>> { + return get(key, [](mapped_type& v) { return std::ref(v); }); } // Returns the result R of a unary operation F on (a constant or mutable reference to) the value @@ -144,14 +146,14 @@ class SmallMap final { // // ftl::SmallMap map = ftl::init::map('a', 'x')('b', 'y')('c', 'z'); // - // assert(map.find('c', [](char c) { return std::toupper(c); }) == 'Z'); - // assert(map.find('c', [](char& c) { c = std::toupper(c); })); + // assert(map.get('c', [](char c) { return std::toupper(c); }) == 'Z'); + // assert(map.get('c', [](char& c) { c = std::toupper(c); })); // template <typename F, typename R = std::invoke_result_t<F, const mapped_type&>> - auto find(const key_type& key, F f) const + auto get(const key_type& key, F f) const -> std::conditional_t<std::is_void_v<R>, bool, std::optional<R>> { for (auto& [k, v] : *this) { - if (k == key) { + if (KeyEqual{}(k, key)) { if constexpr (std::is_void_v<R>) { f(v); return true; @@ -165,28 +167,119 @@ class SmallMap final { } template <typename F> - auto find(const key_type& key, F f) { - return std::as_const(*this).find( + auto get(const key_type& key, F f) { + return std::as_const(*this).get( key, [&f](const mapped_type& v) { return f(const_cast<mapped_type&>(v)); }); } + // Returns an iterator to an existing mapping for the given key, or the end() iterator otherwise. + const_iterator find(const key_type& key) const { return const_cast<SmallMap&>(*this).find(key); } + iterator find(const key_type& key) { return find(key, begin()); } + + // Inserts a mapping unless it exists. Returns an iterator to the inserted or existing mapping, + // and whether the mapping was inserted. + // + // On emplace, if the map reaches its static or dynamic capacity, then all iterators are + // invalidated. Otherwise, only the end() iterator is invalidated. + // + template <typename... Args> + std::pair<iterator, bool> try_emplace(const key_type& key, Args&&... args) { + if (const auto it = find(key); it != end()) { + return {it, false}; + } + + auto& ref = map_.emplace_back(std::piecewise_construct, std::forward_as_tuple(key), + std::forward_as_tuple(std::forward<Args>(args)...)); + return {&ref, true}; + } + + // Replaces a mapping if it exists, and returns an iterator to it. Returns the end() iterator + // otherwise. + // + // The value is replaced via move constructor, so type V does not need to define copy/move + // assignment, e.g. its data members may be const. + // + // The arguments may directly or indirectly refer to the mapping being replaced. + // + // Iterators to the replaced mapping point to its replacement, and others remain valid. + // + template <typename... Args> + iterator try_replace(const key_type& key, Args&&... args) { + const auto it = find(key); + if (it == end()) return it; + map_.replace(it, std::piecewise_construct, std::forward_as_tuple(key), + std::forward_as_tuple(std::forward<Args>(args)...)); + return it; + } + + // In-place counterpart of std::unordered_map's insert_or_assign. Returns true on emplace, or + // false on replace. + // + // The value is emplaced and replaced via move constructor, so type V does not need to define + // copy/move assignment, e.g. its data members may be const. + // + // On emplace, if the map reaches its static or dynamic capacity, then all iterators are + // invalidated. Otherwise, only the end() iterator is invalidated. On replace, iterators + // to the replaced mapping point to its replacement, and others remain valid. + // + template <typename... Args> + std::pair<iterator, bool> emplace_or_replace(const key_type& key, Args&&... args) { + const auto [it, ok] = try_emplace(key, std::forward<Args>(args)...); + if (ok) return {it, ok}; + map_.replace(it, std::piecewise_construct, std::forward_as_tuple(key), + std::forward_as_tuple(std::forward<Args>(args)...)); + return {it, ok}; + } + + // Removes a mapping if it exists, and returns whether it did. + // + // The last() and end() iterators, as well as those to the erased mapping, are invalidated. + // + bool erase(const key_type& key) { return erase(key, begin()); } + + // Removes all mappings. + // + // All iterators are invalidated. + // + void clear() { map_.clear(); } + private: + iterator find(const key_type& key, iterator first) { + return std::find_if(first, end(), + [&key](const auto& pair) { return KeyEqual{}(pair.first, key); }); + } + + bool erase(const key_type& key, iterator first) { + const auto it = find(key, first); + if (it == end()) return false; + map_.unstable_erase(it); + return true; + } + + void deduplicate() { + for (auto it = begin(); it != end();) { + if (const auto key = it->first; ++it != end()) { + while (erase(key, it)); + } + } + } + Map map_; }; // Deduction guide for in-place constructor. -template <typename K, typename V, std::size_t... Sizes, typename... Types> -SmallMap(InitializerList<KeyValue<K, V>, std::index_sequence<Sizes...>, Types...>&&) - -> SmallMap<K, V, sizeof...(Sizes)>; +template <typename K, typename V, typename E, std::size_t... Sizes, typename... Types> +SmallMap(InitializerList<KeyValue<K, V, E>, std::index_sequence<Sizes...>, Types...>&&) + -> SmallMap<K, V, sizeof...(Sizes), E>; // Returns whether the key-value pairs of two maps are equal. -template <typename K, typename V, std::size_t N, typename Q, typename W, std::size_t M> -bool operator==(const SmallMap<K, V, N>& lhs, const SmallMap<Q, W, M>& rhs) { +template <typename K, typename V, std::size_t N, typename Q, typename W, std::size_t M, typename E> +bool operator==(const SmallMap<K, V, N, E>& lhs, const SmallMap<Q, W, M, E>& rhs) { if (lhs.size() != rhs.size()) return false; for (const auto& [k, v] : lhs) { const auto& lv = v; - if (!rhs.find(k, [&lv](const auto& rv) { return lv == rv; }).value_or(false)) { + if (!rhs.get(k, [&lv](const auto& rv) { return lv == rv; }).value_or(false)) { return false; } } @@ -195,8 +288,8 @@ bool operator==(const SmallMap<K, V, N>& lhs, const SmallMap<Q, W, M>& rhs) { } // TODO: Remove in C++20. -template <typename K, typename V, std::size_t N, typename Q, typename W, std::size_t M> -inline bool operator!=(const SmallMap<K, V, N>& lhs, const SmallMap<Q, W, M>& rhs) { +template <typename K, typename V, std::size_t N, typename Q, typename W, std::size_t M, typename E> +inline bool operator!=(const SmallMap<K, V, N, E>& lhs, const SmallMap<Q, W, M, E>& rhs) { return !(lhs == rhs); } diff --git a/include/ftl/small_vector.h b/include/ftl/small_vector.h index cb0ae359eb..03587e35ac 100644 --- a/include/ftl/small_vector.h +++ b/include/ftl/small_vector.h @@ -16,7 +16,7 @@ #pragma once -#include <ftl/array_traits.h> +#include <ftl/details/array_traits.h> #include <ftl/static_vector.h> #include <algorithm> @@ -73,7 +73,7 @@ struct is_small_vector; // assert(strings[2] == "???"); // template <typename T, std::size_t N> -class SmallVector final : ArrayTraits<T>, ArrayComparators<SmallVector> { +class SmallVector final : details::ArrayTraits<T>, details::ArrayComparators<SmallVector> { using Static = StaticVector<T, N>; using Dynamic = SmallVector<T, 0>; @@ -151,8 +151,6 @@ class SmallVector final : ArrayTraits<T>, ArrayComparators<SmallVector> { DISPATCH(reference, back, noexcept) DISPATCH(const_reference, back, const) -#undef DISPATCH - reference operator[](size_type i) { return dynamic() ? std::get<Dynamic>(vector_)[i] : std::get<Static>(vector_)[i]; } @@ -214,13 +212,15 @@ class SmallVector final : ArrayTraits<T>, ArrayComparators<SmallVector> { // // The last() and end() iterators are invalidated. // - void pop_back() { - if (dynamic()) { - std::get<Dynamic>(vector_).pop_back(); - } else { - std::get<Static>(vector_).pop_back(); - } - } + DISPATCH(void, pop_back, noexcept) + + // Removes all elements. + // + // All iterators are invalidated. + // + DISPATCH(void, clear, noexcept) + +#undef DISPATCH // Erases an element, but does not preserve order. Rather than shifting subsequent elements, // this moves the last element to the slot of the erased element. @@ -266,12 +266,12 @@ class SmallVector final : ArrayTraits<T>, ArrayComparators<SmallVector> { // Partial specialization without static storage. template <typename T> -class SmallVector<T, 0> final : ArrayTraits<T>, - ArrayIterators<SmallVector<T, 0>, T>, +class SmallVector<T, 0> final : details::ArrayTraits<T>, + details::ArrayIterators<SmallVector<T, 0>, T>, std::vector<T> { - using ArrayTraits<T>::construct_at; + using details::ArrayTraits<T>::construct_at; - using Iter = ArrayIterators<SmallVector, T>; + using Iter = details::ArrayIterators<SmallVector, T>; using Impl = std::vector<T>; friend Iter; @@ -345,10 +345,11 @@ class SmallVector<T, 0> final : ArrayTraits<T>, return true; } + using Impl::clear; using Impl::pop_back; void unstable_erase(iterator it) { - if (it != last()) std::iter_swap(it, last()); + if (it != last()) replace(it, std::move(back())); pop_back(); } diff --git a/include/ftl/static_vector.h b/include/ftl/static_vector.h index 96a1ae853d..b7f8c29dec 100644 --- a/include/ftl/static_vector.h +++ b/include/ftl/static_vector.h @@ -16,7 +16,7 @@ #pragma once -#include <ftl/array_traits.h> +#include <ftl/details/array_traits.h> #include <ftl/initializer_list.h> #include <algorithm> @@ -73,14 +73,14 @@ constexpr struct IteratorRangeTag { // assert(strings[2] == "???"); // template <typename T, std::size_t N> -class StaticVector final : ArrayTraits<T>, - ArrayIterators<StaticVector<T, N>, T>, - ArrayComparators<StaticVector> { +class StaticVector final : details::ArrayTraits<T>, + details::ArrayIterators<StaticVector<T, N>, T>, + details::ArrayComparators<StaticVector> { static_assert(N > 0); - using ArrayTraits<T>::construct_at; + using details::ArrayTraits<T>::construct_at; - using Iter = ArrayIterators<StaticVector, T>; + using Iter = details::ArrayIterators<StaticVector, T>; friend Iter; // There is ambiguity when constructing from two iterator-like elements like pointers: @@ -189,8 +189,7 @@ class StaticVector final : ArrayTraits<T>, } StaticVector& operator=(StaticVector&& other) { - std::destroy(begin(), end()); - size_ = 0; + clear(); swap<true>(other); return *this; } @@ -280,6 +279,15 @@ class StaticVector final : ArrayTraits<T>, // void pop_back() { unstable_erase(last()); } + // Removes all elements. + // + // All iterators are invalidated. + // + void clear() { + std::destroy(begin(), end()); + size_ = 0; + } + // Erases an element, but does not preserve order. Rather than shifting subsequent elements, // this moves the last element to the slot of the erased element. // diff --git a/include/ftl/string.h b/include/ftl/string.h new file mode 100644 index 0000000000..2d96b06a2f --- /dev/null +++ b/include/ftl/string.h @@ -0,0 +1,101 @@ +/* + * Copyright 2021 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. + */ + +#pragma once + +#include <cassert> +#include <charconv> +#include <limits> +#include <string> +#include <string_view> +#include <type_traits> + +namespace android::ftl { + +enum class Radix { kBin = 2, kDec = 10, kHex = 16 }; + +template <typename T> +struct to_chars_length { + static_assert(std::is_integral_v<T>); + // Maximum binary digits, plus minus sign and radix prefix. + static constexpr std::size_t value = std::numeric_limits<std::make_unsigned_t<T>>::digits + 3; +}; + +template <typename T> +constexpr std::size_t to_chars_length_v = to_chars_length<T>::value; + +template <typename T = std::int64_t> +using to_chars_buffer_t = char[to_chars_length_v<T>]; + +// Lightweight (not allocating nor sprintf-based) alternative to std::to_string for integers, with +// optional radix. See also ftl::to_string below. +// +// ftl::to_chars_buffer_t<> buffer; +// +// assert(ftl::to_chars(buffer, 123u) == "123"); +// assert(ftl::to_chars(buffer, -42, ftl::Radix::kBin) == "-0b101010"); +// assert(ftl::to_chars(buffer, 0xcafe, ftl::Radix::kHex) == "0xcafe"); +// assert(ftl::to_chars(buffer, '*', ftl::Radix::kHex) == "0x2a"); +// +template <typename T, std::size_t N> +std::string_view to_chars(char (&buffer)[N], T v, Radix radix = Radix::kDec) { + static_assert(N >= to_chars_length_v<T>); + + auto begin = buffer + 2; + const auto [end, err] = std::to_chars(begin, buffer + N, v, static_cast<int>(radix)); + assert(err == std::errc()); + + if (radix == Radix::kDec) { + // TODO: Replace with {begin, end} in C++20. + return {begin, static_cast<std::size_t>(end - begin)}; + } + + const auto prefix = radix == Radix::kBin ? 'b' : 'x'; + if constexpr (std::is_unsigned_v<T>) { + buffer[0] = '0'; + buffer[1] = prefix; + } else { + if (*begin == '-') { + *buffer = '-'; + } else { + --begin; + } + + *begin-- = prefix; + *begin = '0'; + } + + // TODO: Replace with {buffer, end} in C++20. + return {buffer, static_cast<std::size_t>(end - buffer)}; +} + +// Lightweight (not sprintf-based) alternative to std::to_string for integers, with optional radix. +// +// assert(ftl::to_string(123u) == "123"); +// assert(ftl::to_string(-42, ftl::Radix::kBin) == "-0b101010"); +// assert(ftl::to_string(0xcafe, ftl::Radix::kHex) == "0xcafe"); +// assert(ftl::to_string('*', ftl::Radix::kHex) == "0x2a"); +// +template <typename T> +inline std::string to_string(T v, Radix radix = Radix::kDec) { + to_chars_buffer_t<T> buffer; + return std::string(to_chars(buffer, v, radix)); +} + +std::string to_string(bool) = delete; +std::string to_string(bool, Radix) = delete; + +} // namespace android::ftl diff --git a/include/input/DisplayViewport.h b/include/input/DisplayViewport.h index a6213f3ddd..9148fee532 100644 --- a/include/input/DisplayViewport.h +++ b/include/input/DisplayViewport.h @@ -18,7 +18,8 @@ #define _LIBINPUT_DISPLAY_VIEWPORT_H #include <android-base/stringprintf.h> -#include <ftl/NamedEnum.h> +#include <ftl/enum.h> +#include <ftl/string.h> #include <gui/constants.h> #include <input/Input.h> @@ -44,6 +45,8 @@ enum class ViewportType : int32_t { INTERNAL = 1, EXTERNAL = 2, VIRTUAL = 3, + + ftl_last = VIRTUAL }; /* @@ -132,9 +135,8 @@ struct DisplayViewport { "physicalFrame=[%d, %d, %d, %d], " "deviceSize=[%d, %d], " "isActive=[%d]", - NamedEnum::string(type).c_str(), displayId, uniqueId.c_str(), - physicalPort ? StringPrintf("%" PRIu8, *physicalPort).c_str() - : "<none>", + ftl::enum_string(type).c_str(), displayId, uniqueId.c_str(), + physicalPort ? ftl::to_string(*physicalPort).c_str() : "<none>", orientation, logicalLeft, logicalTop, logicalRight, logicalBottom, physicalLeft, physicalTop, physicalRight, physicalBottom, deviceWidth, deviceHeight, isActive); diff --git a/include/input/Input.h b/include/input/Input.h index 4adaa5b1c5..f4147a0409 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -31,10 +31,8 @@ #include <stdint.h> #include <ui/Transform.h> #include <utils/BitSet.h> -#include <utils/KeyedVector.h> #include <utils/RefBase.h> #include <utils/Timers.h> -#include <utils/Vector.h> #include <array> #include <limits> #include <queue> @@ -88,7 +86,7 @@ enum { */ AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE = 0x40, -#ifdef __linux__ +#if defined(__linux__) /** * This event was generated or modified by accessibility service. */ @@ -201,8 +199,17 @@ namespace android { class Parcel; #endif +/* + * Apply the given transform to the point without applying any translation/offset. + */ +vec2 transformWithoutTranslation(const ui::Transform& transform, const vec2& xy); + const char* inputEventTypeToString(int32_t type); +std::string inputEventSourceToString(int32_t source); + +bool isFromSource(uint32_t source, uint32_t test); + /* * Flags that flow alongside events in the input dispatch system to help with certain * policy decisions such as waking from device sleep. @@ -369,13 +376,10 @@ struct PointerCoords { float getAxisValue(int32_t axis) const; status_t setAxisValue(int32_t axis, float value); - void scale(float globalScale); - // Scale the pointer coordinates according to a global scale and a // window scale. The global scale will be applied to TOUCH/TOOL_MAJOR/MINOR // axes, however the window scaling will not. void scale(float globalScale, float windowXScale, float windowYScale); - void applyOffset(float xOffset, float yOffset); void transform(const ui::Transform& transform); @@ -526,13 +530,17 @@ public: inline int32_t getAction() const { return mAction; } - inline int32_t getActionMasked() const { return mAction & AMOTION_EVENT_ACTION_MASK; } + static int32_t getActionMasked(int32_t action) { return action & AMOTION_EVENT_ACTION_MASK; } - inline int32_t getActionIndex() const { - return (mAction & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) - >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; + inline int32_t getActionMasked() const { return getActionMasked(mAction); } + + static int32_t getActionIndex(int32_t action) { + return (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> + AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; } + inline int32_t getActionIndex() const { return getActionIndex(mAction); } + inline void setAction(int32_t action) { mAction = action; } inline int32_t getFlags() const { return mFlags; } @@ -561,7 +569,9 @@ public: inline float getYOffset() const { return mTransform.ty(); } - inline ui::Transform getTransform() const { return mTransform; } + inline const ui::Transform& getTransform() const { return mTransform; } + + int getSurfaceRotation() const; inline float getXPrecision() const { return mXPrecision; } @@ -577,9 +587,7 @@ public: void setCursorPosition(float x, float y); - uint32_t getDisplayOrientation() const { return mDisplayOrientation; } - - int2 getDisplaySize() const { return {mDisplayWidth, mDisplayHeight}; } + inline const ui::Transform& getRawTransform() const { return mRawTransform; } static inline bool isValidCursorPosition(float x, float y) { return !isnan(x) && !isnan(y); } @@ -755,8 +763,8 @@ public: int32_t flags, int32_t edgeFlags, int32_t metaState, int32_t buttonState, MotionClassification classification, const ui::Transform& transform, float xPrecision, float yPrecision, float rawXCursorPosition, - float rawYCursorPosition, uint32_t displayOrientation, int32_t displayWidth, - int32_t displayHeight, nsecs_t downTime, nsecs_t eventTime, size_t pointerCount, + float rawYCursorPosition, const ui::Transform& rawTransform, nsecs_t downTime, + nsecs_t eventTime, size_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords); void copyFrom(const MotionEvent* other, bool keepHistory); @@ -789,11 +797,11 @@ public: // Low-level accessors. inline const PointerProperties* getPointerProperties() const { - return mPointerProperties.array(); + return mPointerProperties.data(); } inline const nsecs_t* getSampleEventTimes() const { return mSampleEventTimes.data(); } inline const PointerCoords* getSamplePointerCoords() const { - return mSamplePointerCoords.array(); + return mSamplePointerCoords.data(); } static const char* getLabel(int32_t axis); @@ -801,6 +809,14 @@ public: static std::string actionToString(int32_t action); + // MotionEvent will transform various axes in different ways, based on the source. For + // example, the x and y axes will not have any offsets/translations applied if it comes from a + // relative mouse device (since SOURCE_RELATIVE_MOUSE is a non-pointer source). These methods + // are used to apply these transformations for different axes. + static vec2 calculateTransformedXY(uint32_t source, const ui::Transform&, const vec2& xy); + static float calculateTransformedAxisValue(int32_t axis, uint32_t source, const ui::Transform&, + const PointerCoords&); + protected: int32_t mAction; int32_t mActionButton; @@ -814,13 +830,11 @@ protected: float mYPrecision; float mRawXCursorPosition; float mRawYCursorPosition; - uint32_t mDisplayOrientation; - int32_t mDisplayWidth; - int32_t mDisplayHeight; + ui::Transform mRawTransform; nsecs_t mDownTime; - Vector<PointerProperties> mPointerProperties; + std::vector<PointerProperties> mPointerProperties; std::vector<nsecs_t> mSampleEventTimes; - Vector<PointerCoords> mSamplePointerCoords; + std::vector<PointerCoords> mSamplePointerCoords; }; /* @@ -834,15 +848,12 @@ public: inline bool getHasFocus() const { return mHasFocus; } - inline bool getInTouchMode() const { return mInTouchMode; } - - void initialize(int32_t id, bool hasFocus, bool inTouchMode); + void initialize(int32_t id, bool hasFocus); void initialize(const FocusEvent& from); protected: bool mHasFocus; - bool mInTouchMode; }; /* @@ -888,6 +899,25 @@ protected: float mX, mY; }; +/* + * Touch mode events. + */ +class TouchModeEvent : public InputEvent { +public: + virtual ~TouchModeEvent() {} + + virtual int32_t getType() const override { return AINPUT_EVENT_TYPE_TOUCH_MODE; } + + inline bool isInTouchMode() const { return mIsInTouchMode; } + + void initialize(int32_t id, bool isInTouchMode); + + void initialize(const TouchModeEvent& from); + +protected: + bool mIsInTouchMode; +}; + /** * Base class for verified events. * Do not create a VerifiedInputEvent explicitly. @@ -912,8 +942,8 @@ struct __attribute__((__packed__)) VerifiedInputEvent { */ struct __attribute__((__packed__)) VerifiedKeyEvent : public VerifiedInputEvent { int32_t action; - nsecs_t downTimeNanos; int32_t flags; + nsecs_t downTimeNanos; int32_t keyCode; int32_t scanCode; int32_t metaState; @@ -928,8 +958,8 @@ struct __attribute__((__packed__)) VerifiedMotionEvent : public VerifiedInputEve float rawX; float rawY; int32_t actionMasked; - nsecs_t downTimeNanos; int32_t flags; + nsecs_t downTimeNanos; int32_t metaState; int32_t buttonState; }; @@ -952,6 +982,7 @@ public: virtual FocusEvent* createFocusEvent() = 0; virtual CaptureEvent* createCaptureEvent() = 0; virtual DragEvent* createDragEvent() = 0; + virtual TouchModeEvent* createTouchModeEvent() = 0; }; /* @@ -968,6 +999,7 @@ public: virtual FocusEvent* createFocusEvent() override { return &mFocusEvent; } virtual CaptureEvent* createCaptureEvent() override { return &mCaptureEvent; } virtual DragEvent* createDragEvent() override { return &mDragEvent; } + virtual TouchModeEvent* createTouchModeEvent() override { return &mTouchModeEvent; } private: KeyEvent mKeyEvent; @@ -975,6 +1007,7 @@ private: FocusEvent mFocusEvent; CaptureEvent mCaptureEvent; DragEvent mDragEvent; + TouchModeEvent mTouchModeEvent; }; /* @@ -990,6 +1023,7 @@ public: virtual FocusEvent* createFocusEvent() override; virtual CaptureEvent* createCaptureEvent() override; virtual DragEvent* createDragEvent() override; + virtual TouchModeEvent* createTouchModeEvent() override; void recycle(InputEvent* event); @@ -1001,6 +1035,7 @@ private: std::queue<std::unique_ptr<FocusEvent>> mFocusEventPool; std::queue<std::unique_ptr<CaptureEvent>> mCaptureEventPool; std::queue<std::unique_ptr<DragEvent>> mDragEventPool; + std::queue<std::unique_ptr<TouchModeEvent>> mTouchModeEventPool; }; /* diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h index 7f0324a4a8..22aae196c6 100644 --- a/include/input/InputDevice.h +++ b/include/input/InputDevice.h @@ -84,6 +84,9 @@ enum class InputDeviceSensorType : int32_t { GAME_ROTATION_VECTOR = ASENSOR_TYPE_GAME_ROTATION_VECTOR, GYROSCOPE_UNCALIBRATED = ASENSOR_TYPE_GYROSCOPE_UNCALIBRATED, SIGNIFICANT_MOTION = ASENSOR_TYPE_SIGNIFICANT_MOTION, + + ftl_first = ACCELEROMETER, + ftl_last = SIGNIFICANT_MOTION }; enum class InputDeviceSensorAccuracy : int32_t { @@ -105,6 +108,8 @@ enum class InputDeviceLightType : int32_t { PLAYER_ID = 1, RGB = 2, MULTI_COLOR = 3, + + ftl_last = MULTI_COLOR }; struct InputDeviceSensorInfo { diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h index a790b5637f..edcb615491 100644 --- a/include/input/InputTransport.h +++ b/include/input/InputTransport.h @@ -72,6 +72,9 @@ struct InputMessage { CAPTURE, DRAG, TIMELINE, + TOUCH_MODE, + + ftl_last = TOUCH_MODE }; struct Header { @@ -111,7 +114,7 @@ struct InputMessage { struct Motion { int32_t eventId; - uint32_t empty1; + uint32_t pointerCount; nsecs_t eventTime __attribute__((aligned(8))); int32_t deviceId; int32_t source; @@ -126,20 +129,22 @@ struct InputMessage { uint8_t empty2[3]; // 3 bytes to fill gap created by classification int32_t edgeFlags; nsecs_t downTime __attribute__((aligned(8))); - float dsdx; - float dtdx; - float dtdy; - float dsdy; - float tx; - float ty; + float dsdx; // Begin window transform + float dtdx; // + float dtdy; // + float dsdy; // + float tx; // + float ty; // End window transform float xPrecision; float yPrecision; float xCursorPosition; float yCursorPosition; - uint32_t displayOrientation; - int32_t displayWidth; - int32_t displayHeight; - uint32_t pointerCount; + float dsdxRaw; // Begin raw transform + float dtdxRaw; // + float dtdyRaw; // + float dsdyRaw; // + float txRaw; // + float tyRaw; // End raw transform /** * The "pointers" field must be the last field of the struct InputMessage. * When we send the struct InputMessage across the socket, we are not @@ -173,10 +178,9 @@ struct InputMessage { struct Focus { int32_t eventId; - // The following 3 fields take up 4 bytes total + // The following 2 fields take up 4 bytes total bool hasFocus; - bool inTouchMode; - uint8_t empty[2]; + uint8_t empty[3]; inline size_t size() const { return sizeof(Focus); } } focus; @@ -206,6 +210,15 @@ struct InputMessage { inline size_t size() const { return sizeof(Timeline); } } timeline; + + struct TouchMode { + int32_t eventId; + // The following 2 fields take up 4 bytes total + bool isInTouchMode; + uint8_t empty[3]; + + inline size_t size() const { return sizeof(TouchMode); } + } touchMode; } __attribute__((aligned(8))) body; bool isValid(size_t actualSize) const; @@ -355,9 +368,8 @@ public: int32_t metaState, int32_t buttonState, MotionClassification classification, const ui::Transform& transform, float xPrecision, float yPrecision, float xCursorPosition, - float yCursorPosition, uint32_t displayOrientation, - int32_t displayWidth, int32_t displayHeight, nsecs_t downTime, - nsecs_t eventTime, uint32_t pointerCount, + float yCursorPosition, const ui::Transform& rawTransform, + nsecs_t downTime, nsecs_t eventTime, uint32_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords); @@ -368,7 +380,7 @@ public: * Returns DEAD_OBJECT if the channel's peer has been closed. * Other errors probably indicate that the channel is broken. */ - status_t publishFocusEvent(uint32_t seq, int32_t eventId, bool hasFocus, bool inTouchMode); + status_t publishFocusEvent(uint32_t seq, int32_t eventId, bool hasFocus); /* Publishes a capture event to the input channel. * @@ -388,6 +400,15 @@ public: */ status_t publishDragEvent(uint32_t seq, int32_t eventId, float x, float y, bool isExiting); + /* Publishes a touch mode event to the input channel. + * + * Returns OK on success. + * Returns WOULD_BLOCK if the channel is full. + * Returns DEAD_OBJECT if the channel's peer has been closed. + * Other errors probably indicate that the channel is broken. + */ + status_t publishTouchModeEvent(uint32_t seq, int32_t eventId, bool isInTouchMode); + struct Finished { uint32_t seq; bool handled; @@ -658,6 +679,7 @@ private: static void initializeFocusEvent(FocusEvent* event, const InputMessage* msg); static void initializeCaptureEvent(CaptureEvent* event, const InputMessage* msg); static void initializeDragEvent(DragEvent* event, const InputMessage* msg); + static void initializeTouchModeEvent(TouchModeEvent* event, const InputMessage* msg); static void addSample(MotionEvent* event, const InputMessage* msg); static bool canAddSample(const Batch& batch, const InputMessage* msg); static ssize_t findSampleNoLaterThan(const Batch& batch, nsecs_t time); diff --git a/include/powermanager/PowerHalWrapper.h b/include/powermanager/PowerHalWrapper.h index 2c6eacbfaa..dfb0ff59a0 100644 --- a/include/powermanager/PowerHalWrapper.h +++ b/include/powermanager/PowerHalWrapper.h @@ -201,10 +201,8 @@ private: std::array<std::atomic<HalSupport>, static_cast<int32_t>(hardware::power::Boost::DISPLAY_UPDATE_IMMINENT) + 1> mBoostSupportedArray GUARDED_BY(mBoostMutex) = {HalSupport::UNKNOWN}; - // Android framework only sends mode upto DISPLAY_INACTIVE. - // Need to increase the array if more mode supported. std::array<std::atomic<HalSupport>, - static_cast<int32_t>(hardware::power::Mode::DISPLAY_INACTIVE) + 1> + static_cast<int32_t>(*(android::enum_range<hardware::power::Mode>().end() - 1)) + 1> mModeSupportedArray GUARDED_BY(mModeMutex) = {HalSupport::UNKNOWN}; }; diff --git a/include/private/surface_control_private.h b/include/private/surface_control_private.h index 37a476e679..7e6c51587d 100644 --- a/include/private/surface_control_private.h +++ b/include/private/surface_control_private.h @@ -29,8 +29,8 @@ typedef struct ASurfaceControlStats ASurfaceControlStats; /** * Callback to be notified when surface stats for a specific surface control are available. */ -typedef void (*ASurfaceControl_SurfaceStatsListener)(void* context, - ASurfaceControl* control, ASurfaceControlStats* stats); +typedef void (*ASurfaceControl_SurfaceStatsListener)(void* context, int32_t id, + ASurfaceControlStats* stats); /** * Registers a callback to be invoked when surface stats from a specific surface are available. @@ -42,7 +42,7 @@ typedef void (*ASurfaceControl_SurfaceStatsListener)(void* context, * * \param func The callback to be invoked when surface stats are available. */ -void ASurfaceControl_registerSurfaceStatsListener(ASurfaceControl* control, void* context, +void ASurfaceControl_registerSurfaceStatsListener(ASurfaceControl* control, int32_t id, void* context, ASurfaceControl_SurfaceStatsListener func); /** |