• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <algorithm>
20 #include <cstdint>
21 #include <limits>
22 #include <type_traits>
23 #include <utility>
24 
25 namespace android {
26 namespace ui {
27 
28 // Forward declare a few things.
29 struct Size;
30 bool operator==(const Size& lhs, const Size& rhs);
31 
32 /**
33  * A simple value type representing a two-dimensional size
34  */
35 struct Size {
36     int32_t width;
37     int32_t height;
38 
39     // Special values
40     static const Size INVALID;
41     static const Size EMPTY;
42 
43     // ------------------------------------------------------------------------
44     // Construction
45     // ------------------------------------------------------------------------
46 
SizeSize47     Size() : Size(INVALID) {}
48     template <typename T>
SizeSize49     Size(T&& w, T&& h)
50           : width(Size::clamp<int32_t, T>(std::forward<T>(w))),
51             height(Size::clamp<int32_t, T>(std::forward<T>(h))) {}
52 
53     // ------------------------------------------------------------------------
54     // Accessors
55     // ------------------------------------------------------------------------
56 
getWidthSize57     int32_t getWidth() const { return width; }
getHeightSize58     int32_t getHeight() const { return height; }
59 
60     template <typename T>
setWidthSize61     void setWidth(T&& v) {
62         width = Size::clamp<int32_t, T>(std::forward<T>(v));
63     }
64     template <typename T>
setHeightSize65     void setHeight(T&& v) {
66         height = Size::clamp<int32_t, T>(std::forward<T>(v));
67     }
68 
69     // ------------------------------------------------------------------------
70     // Assignment
71     // ------------------------------------------------------------------------
72 
setSize73     void set(const Size& size) { *this = size; }
74     template <typename T>
setSize75     void set(T&& w, T&& h) {
76         set(Size(std::forward<T>(w), std::forward<T>(h)));
77     }
78 
79     // Sets the value to INVALID
makeInvalidSize80     void makeInvalid() { set(INVALID); }
81 
82     // Sets the value to EMPTY
clearSize83     void clear() { set(EMPTY); }
84 
85     // ------------------------------------------------------------------------
86     // Semantic checks
87     // ------------------------------------------------------------------------
88 
89     // Valid means non-negative width and height
isValidSize90     bool isValid() const { return width >= 0 && height >= 0; }
91 
92     // Empty means zero width and height
isEmptySize93     bool isEmpty() const { return *this == EMPTY; }
94 
95     // ------------------------------------------------------------------------
96     // Clamp Helpers
97     // ------------------------------------------------------------------------
98 
99     // Note: We use only features available in C++11 here for compatibility with
100     // external targets which include this file directly or indirectly and which
101     // themselves use C++11.
102 
103     // C++11 compatible replacement for std::remove_cv_reference_t [C++20]
104     template <typename T>
105     using remove_cv_reference_t =
106             typename std::remove_cv<typename std::remove_reference<T>::type>::type;
107 
108     // Takes a value of type FromType, and ensures it can be represented as a value of type ToType,
109     // clamping the input value to the output range if necessary.
110     template <typename ToType, typename FromType>
clampSize111     static Size::remove_cv_reference_t<ToType> clamp(
112             typename std::enable_if<
113                     std::numeric_limits<Size::remove_cv_reference_t<ToType>>::is_bounded &&
114                             std::numeric_limits<Size::remove_cv_reference_t<FromType>>::is_bounded,
115                     FromType&&>::type v) {
116         static constexpr auto toHighest = std::numeric_limits<remove_cv_reference_t<ToType>>::max();
117         static constexpr auto toLowest =
118                 std::numeric_limits<remove_cv_reference_t<ToType>>::lowest();
119         static constexpr auto fromHighest =
120                 std::numeric_limits<remove_cv_reference_t<FromType>>::max();
121         static constexpr auto fromLowest =
122                 std::numeric_limits<remove_cv_reference_t<FromType>>::lowest();
123 
124         // A clamp is needed if the range of FromType is not a subset of the range of ToType
125         static constexpr bool isClampNeeded = (toLowest > fromLowest) || (toHighest < fromHighest);
126 
127         // If a clamp is not needed, the conversion is just a trivial cast.
128         if (!isClampNeeded) {
129             return static_cast<ToType>(v);
130         }
131 
132         // Otherwise we leverage implicit conversion to safely compare values of
133         // different types, to ensure we return a value clamped to the range of
134         // ToType.
135         return v < toLowest ? toLowest : (v > toHighest ? toHighest : static_cast<ToType>(v));
136     }
137 };
138 
139 // ------------------------------------------------------------------------
140 // Comparisons
141 // ------------------------------------------------------------------------
142 
143 inline bool operator==(const Size& lhs, const Size& rhs) {
144     return lhs.width == rhs.width && lhs.height == rhs.height;
145 }
146 
147 inline bool operator!=(const Size& lhs, const Size& rhs) {
148     return !operator==(lhs, rhs);
149 }
150 
151 inline bool operator<(const Size& lhs, const Size& rhs) {
152     // Orders by increasing width, then height.
153     if (lhs.width != rhs.width) return lhs.width < rhs.width;
154     return lhs.height < rhs.height;
155 }
156 
157 } // namespace ui
158 } // namespace android
159