Mir
dimensions.h
Go to the documentation of this file.
1/*
2 * Copyright © Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 2 or 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef MIR_GEOMETRY_DIMENSIONS_H_
18#define MIR_GEOMETRY_DIMENSIONS_H_
19
20#include "forward.h"
21
22#include <iosfwd>
23#include <type_traits>
24#include <cstdint>
25
26namespace mir
27{
28namespace geometry
29{
30namespace generic
31{
32template<typename T, typename Tag>
33/// Wraps a geometry value and prevents it from being accidentally used for invalid operations (such as setting a
34/// width to a height or adding two x positions together). Of course, explicit casts are possible to get around
35/// these restrictions (see the as_*() functions).
36struct Value
37{
38 using ValueType = T;
39 using TagType = Tag;
40
41 template <typename Q = T>
42 constexpr typename std::enable_if<std::is_integral<Q>::value, int>::type as_int() const
43 {
44 return this->value;
45 }
46
47 template <typename Q = T>
48 constexpr typename std::enable_if<std::is_integral<Q>::value, uint32_t>::type as_uint32_t() const
49 {
50 return this->value;
51 }
52
53 constexpr T as_value() const noexcept
54 {
55 return value;
56 }
57
58 constexpr Value() noexcept : value{} {}
59
60 Value& operator=(Value const& that) noexcept
61 {
62 value = that.value;
63 return *this;
64 }
65
66 constexpr Value(Value const& that) noexcept
67 : value{that.value}
68 {
69 }
70
71 template<typename U>
72 explicit constexpr Value(Value<U, Tag> const& value) noexcept
73 : value{static_cast<T>(value.as_value())}
74 {
75 }
76
77 template<typename U, typename std::enable_if<std::is_scalar<U>::value, bool>::type = true>
78 explicit constexpr Value(U const& value) noexcept
79 : value{static_cast<T>(value)}
80 {
81 }
82
83 inline constexpr auto operator == (Value<T, Tag> const& rhs) const -> bool
84 {
85 return value == rhs.as_value();
86 }
87
88 inline constexpr auto operator != (Value<T, Tag> const& rhs) const -> bool
89 {
90 return value != rhs.as_value();
91 }
92
93 inline constexpr auto operator <= (Value<T, Tag> const& rhs) const -> bool
94 {
95 return value <= rhs.as_value();
96 }
97
98 inline constexpr auto operator >= (Value<T, Tag> const& rhs) const -> bool
99 {
100 return value >= rhs.as_value();
101 }
102
103 inline constexpr auto operator < (Value<T, Tag> const& rhs) const -> bool
104 {
105 return value < rhs.as_value();
106 }
107
108 inline constexpr auto operator > (Value<T, Tag> const& rhs) const -> bool
109 {
110 return value > rhs.as_value();
111 }
112
113protected:
115};
116
117template<typename T, typename Tag>
118std::ostream& operator<<(std::ostream& out, Value<T, Tag> const& value)
119{
120 out << value.as_value();
121 return out;
122}
123
124// Adding deltas is fine
125template<typename T>
126inline constexpr DeltaX<T> operator+(DeltaX<T> lhs, DeltaX<T> rhs){ return DeltaX<T>(lhs.as_value() + rhs.as_value()); }
127template<typename T>
128inline constexpr DeltaY<T> operator+(DeltaY<T> lhs, DeltaY<T> rhs) { return DeltaY<T>(lhs.as_value() + rhs.as_value()); }
129template<typename T>
130inline constexpr DeltaX<T> operator-(DeltaX<T> lhs, DeltaX<T> rhs) { return DeltaX<T>(lhs.as_value() - rhs.as_value()); }
131template<typename T>
132inline constexpr DeltaY<T> operator-(DeltaY<T> lhs, DeltaY<T> rhs) { return DeltaY<T>(lhs.as_value() - rhs.as_value()); }
133template<typename T>
134inline constexpr DeltaX<T> operator-(DeltaX<T> rhs) { return DeltaX<T>(-rhs.as_value()); }
135template<typename T>
136inline constexpr DeltaY<T> operator-(DeltaY<T> rhs) { return DeltaY<T>(-rhs.as_value()); }
137template<typename T>
138inline DeltaX<T>& operator+=(DeltaX<T>& lhs, DeltaX<T> rhs) { return lhs = lhs + rhs; }
139template<typename T>
140inline DeltaY<T>& operator+=(DeltaY<T>& lhs, DeltaY<T> rhs) { return lhs = lhs + rhs; }
141template<typename T>
142inline DeltaX<T>& operator-=(DeltaX<T>& lhs, DeltaX<T> rhs) { return lhs = lhs - rhs; }
143template<typename T>
144inline DeltaY<T>& operator-=(DeltaY<T>& lhs, DeltaY<T> rhs) { return lhs = lhs - rhs; }
145
146// Adding deltas to co-ordinates is fine
147template<typename T>
148inline constexpr X<T> operator+(X<T> lhs, DeltaX<T> rhs) { return X<T>(lhs.as_value() + rhs.as_value()); }
149template<typename T>
150inline constexpr Y<T> operator+(Y<T> lhs, DeltaY<T> rhs) { return Y<T>(lhs.as_value() + rhs.as_value()); }
151template<typename T>
152inline constexpr X<T> operator-(X<T> lhs, DeltaX<T> rhs) { return X<T>(lhs.as_value() - rhs.as_value()); }
153template<typename T>
154inline constexpr Y<T> operator-(Y<T> lhs, DeltaY<T> rhs) { return Y<T>(lhs.as_value() - rhs.as_value()); }
155template