/* * Copyright 2019 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 #include #include #include #include namespace android { namespace ui { // Forward declare a few things. struct Size; bool operator==(const Size& lhs, const Size& rhs); /** * A simple value type representing a two-dimensional size */ struct Size { int32_t width; int32_t height; // Special values static const Size INVALID; static const Size EMPTY; // ------------------------------------------------------------------------ // Construction // ------------------------------------------------------------------------ Size() : Size(INVALID) {} template Size(T&& w, T&& h) : width(Size::clamp(std::forward(w))), height(Size::clamp(std::forward(h))) {} // ------------------------------------------------------------------------ // Accessors // ------------------------------------------------------------------------ int32_t getWidth() const { return width; } int32_t getHeight() const { return height; } template void setWidth(T&& v) { width = Size::clamp(std::forward(v)); } template void setHeight(T&& v) { height = Size::clamp(std::forward(v)); } // ------------------------------------------------------------------------ // Assignment // ------------------------------------------------------------------------ void set(const Size& size) { *this = size; } template void set(T&& w, T&& h) { set(Size(std::forward(w), std::forward(h))); } // Sets the value to INVALID void makeInvalid() { set(INVALID); } // Sets the value to EMPTY void clear() { set(EMPTY); } // ------------------------------------------------------------------------ // Semantic checks // ------------------------------------------------------------------------ // Valid means non-negative width and height bool isValid() const { return width >= 0 && height >= 0; } // Empty means zero width and height bool isEmpty() const { return *this == EMPTY; } // ------------------------------------------------------------------------ // Clamp Helpers // ------------------------------------------------------------------------ // Note: We use only features available in C++11 here for compatibility with // external targets which include this file directly or indirectly and which // themselves use C++11. // C++11 compatible replacement for std::remove_cv_reference_t [C++20] template using remove_cv_reference_t = typename std::remove_cv::type>::type; // Takes a value of type FromType, and ensures it can be represented as a value of type ToType, // clamping the input value to the output range if necessary. template static Size::remove_cv_reference_t clamp( typename std::enable_if< std::numeric_limits>::is_bounded && std::numeric_limits>::is_bounded, FromType&&>::type v) { static constexpr auto toHighest = std::numeric_limits>::max(); static constexpr auto toLowest = std::numeric_limits>::lowest(); static constexpr auto fromHighest = std::numeric_limits>::max(); static constexpr auto fromLowest = std::numeric_limits>::lowest(); // A clamp is needed if the range of FromType is not a subset of the range of ToType static constexpr bool isClampNeeded = (toLowest > fromLowest) || (toHighest < fromHighest); // If a clamp is not needed, the conversion is just a trivial cast. if (!isClampNeeded) { return static_cast(v); } // Otherwise we leverage implicit conversion to safely compare values of // different types, to ensure we return a value clamped to the range of // ToType. return v < toLowest ? toLowest : (v > toHighest ? toHighest : static_cast(v)); } }; // ------------------------------------------------------------------------ // Comparisons // ------------------------------------------------------------------------ inline bool operator==(const Size& lhs, const Size& rhs) { return lhs.width == rhs.width && lhs.height == rhs.height; } inline bool operator!=(const Size& lhs, const Size& rhs) { return !operator==(lhs, rhs); } inline bool operator<(const Size& lhs, const Size& rhs) { // Orders by increasing width, then height. if (lhs.width != rhs.width) return lhs.width < rhs.width; return lhs.height < rhs.height; } } // namespace ui } // namespace android