From 843b0362bc701a92cfe148dc522f6ae99200e155 Mon Sep 17 00:00:00 2001 From: William Wold Date: Thu, 10 Dec 2020 13:26:04 -0800 Subject: [PATCH 01/18] Make geometry types explicit for std::min/max() --- examples/example-server-lib/decoration_provider.cpp | 4 ++-- examples/example-server-lib/floating_window_manager.cpp | 4 ++-- src/server/scene/basic_surface.cpp | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/example-server-lib/decoration_provider.cpp b/examples/example-server-lib/decoration_provider.cpp index de70d8554d4..76a61b61f89 100644 --- a/examples/example-server-lib/decoration_provider.cpp +++ b/examples/example-server-lib/decoration_provider.cpp @@ -247,8 +247,8 @@ void Printer::printhelp(BackgroundInfo const& region) std::max(X{}, region_top_left_in_glyph_space.x), std::max(Y{}, region_top_left_in_glyph_space.y)}; auto const clipped_glyph_lower_right = Point{ - std::min(X{} + as_displacement(glyph_size).dx, region_lower_right_in_glyph_space.x), - std::min(Y{} + as_displacement(glyph_size).dy, region_lower_right_in_glyph_space.y)}; + std::min(as_x(as_displacement(glyph_size).dx), region_lower_right_in_glyph_space.x), + std::min(as_y(as_displacement(glyph_size).dy), region_lower_right_in_glyph_space.y)}; unsigned char* const glyph_buffer = glyph->bitmap.buffer; auto glyph_pixel = Point{}; diff --git a/examples/example-server-lib/floating_window_manager.cpp b/examples/example-server-lib/floating_window_manager.cpp index 77f7d01e991..47f9822c517 100644 --- a/examples/example-server-lib/floating_window_manager.cpp +++ b/examples/example-server-lib/floating_window_manager.cpp @@ -203,8 +203,8 @@ bool FloatingWindowManagerPolicy::handle_touch_event(MirTouchEvent const* event) auto const delta_width = DeltaX{touch_pinch_width - old_touch_pinch_width}; auto const delta_height = DeltaY{touch_pinch_height - old_touch_pinch_height}; - auto new_width = std::max(old_size.width + delta_width, Width{5}); - auto new_height = std::max(old_size.height + delta_height, Height{5}); + auto new_width = std::max(old_size.width + delta_width, Width{5}); + auto new_height = std::max(old_size.height + delta_height, Height{5}); Displacement movement{ DeltaX{touch_pinch_left - old_touch_pinch_left}, DeltaY{touch_pinch_top - old_touch_pinch_top}}; diff --git a/src/server/scene/basic_surface.cpp b/src/server/scene/basic_surface.cpp index 212932c2b30..c1cb9272596 100644 --- a/src/server/scene/basic_surface.cpp +++ b/src/server/scene/basic_surface.cpp @@ -1080,8 +1080,8 @@ void mir::scene::BasicSurface::set_window_margins( auto mir::scene::BasicSurface::content_size(ProofOfMutexLock const&) const -> geometry::Size { return geom::Size{ - std::max(surface_rect.size.width - margins.left - margins.right, geom::Width{1}), - std::max(surface_rect.size.height - margins.top - margins.bottom, geom::Height{1})}; + std::max(surface_rect.size.width - margins.left - margins.right, geom::Width{1}), + std::max(surface_rect.size.height - margins.top - margins.bottom, geom::Height{1})}; } auto mir::scene::BasicSurface::content_top_left(ProofOfMutexLock const&) const -> geometry::Point From f49e561e6970aea2d31160a9ffde95a9ec3e0075 Mon Sep 17 00:00:00 2001 From: William Wold Date: Wed, 9 Dec 2020 16:44:59 -0800 Subject: [PATCH 02/18] Add generic geometry wrapper type --- include/core/mir/geometry/dimensions.h | 178 ++---------- .../core/mir/geometry/dimensions_generic.h | 275 ++++++++++++++++++ src/core/CMakeLists.txt | 1 + tests/unit-tests/geometry/CMakeLists.txt | 1 + .../geometry/test-dimensions-generic.cpp | 138 +++++++++ 5 files changed, 436 insertions(+), 157 deletions(-) create mode 100644 include/core/mir/geometry/dimensions_generic.h create mode 100644 tests/unit-tests/geometry/test-dimensions-generic.cpp diff --git a/include/core/mir/geometry/dimensions.h b/include/core/mir/geometry/dimensions.h index b4c696db70e..91eca117d76 100644 --- a/include/core/mir/geometry/dimensions.h +++ b/include/core/mir/geometry/dimensions.h @@ -19,8 +19,9 @@ #ifndef MIR_GEOMETRY_DIMENSIONS_H_ #define MIR_GEOMETRY_DIMENSIONS_H_ +#include "dimensions_generic.h" + #include -#include namespace mir { @@ -29,180 +30,43 @@ namespace mir /// and the operations that they support. namespace geometry { - namespace detail { +// TODO: On next ABI break, switch to just using Wrapper template -class IntWrapper +class IntWrapper : public generic::detail::Wrapper { public: - typedef int ValueType; - - constexpr IntWrapper() : value(0) {} - constexpr IntWrapper(IntWrapper const& that) = default; - IntWrapper& operator=(IntWrapper const& that) = default; + constexpr IntWrapper() {} - template - explicit constexpr IntWrapper(AnyInteger value) : value(static_cast(value)) {} - - constexpr uint32_t as_uint32_t() const // TODO: Deprecate this later + template + constexpr IntWrapper(generic::detail::Wrapper const& value) + : generic::detail::Wrapper{value} { - return (uint32_t)value; } - constexpr int as_int() const + template + explicit constexpr IntWrapper(U const& value) + : generic::detail::Wrapper{value} { - return value; } -private: - ValueType value; + constexpr uint32_t as_uint32_t() const // TODO: Deprecate this later + { + return (uint32_t)this->value; + } }; - -template -std::ostream& operator<<(std::ostream& out, IntWrapper const& value) -{ - out << value.as_int(); - return out; -} - -template -inline constexpr bool operator == (IntWrapper const& lhs, IntWrapper const& rhs) -{ - return lhs.as_int() == rhs.as_int(); -} - -template -inline constexpr bool operator != (IntWrapper const& lhs, IntWrapper const& rhs) -{ - return lhs.as_int() != rhs.as_int(); -} - -template -inline constexpr bool operator <= (IntWrapper const& lhs, IntWrapper const& rhs) -{ - return lhs.as_int() <= rhs.as_int(); -} - -template -inline constexpr bool operator >= (IntWrapper const& lhs, IntWrapper const& rhs) -{ - return lhs.as_int() >= rhs.as_int(); -} - -template -inline constexpr bool operator < (IntWrapper const& lhs, IntWrapper const& rhs) -{ - return lhs.as_int() < rhs.as_int(); -} - -template -inline constexpr bool operator > (IntWrapper const& lhs, IntWrapper const& rhs) -{ - return lhs.as_int() > rhs.as_int(); -} } // namespace detail -typedef detail::IntWrapper Width; -typedef detail::IntWrapper Height; +typedef detail::IntWrapper Width; +typedef detail::IntWrapper Height; // Just to be clear, mir::geometry::Stride is the stride of the buffer in bytes typedef detail::IntWrapper Stride; -typedef detail::IntWrapper X; -typedef detail::IntWrapper Y; -typedef detail::IntWrapper DeltaX; -typedef detail::IntWrapper DeltaY; - -// Adding deltas is fine -inline constexpr DeltaX operator+(DeltaX lhs, DeltaX rhs) { return DeltaX(lhs.as_int() + rhs.as_int()); } -inline constexpr DeltaY operator+(DeltaY lhs, DeltaY rhs) { return DeltaY(lhs.as_int() + rhs.as_int()); } -inline constexpr DeltaX operator-(DeltaX lhs, DeltaX rhs) { return DeltaX(lhs.as_int() - rhs.as_int()); } -inline constexpr DeltaY operator-(DeltaY lhs, DeltaY rhs) { return DeltaY(lhs.as_int() - rhs.as_int()); } -inline constexpr DeltaX operator-(DeltaX rhs) { return DeltaX(-rhs.as_int()); } -inline constexpr DeltaY operator-(DeltaY rhs) { return DeltaY(-rhs.as_int()); } -inline DeltaX& operator+=(DeltaX& lhs, DeltaX rhs) { return lhs = lhs + rhs; } -inline DeltaY& operator+=(DeltaY& lhs, DeltaY rhs) { return lhs = lhs + rhs; } -inline DeltaX& operator-=(DeltaX& lhs, DeltaX rhs) { return lhs = lhs - rhs; } -inline DeltaY& operator-=(DeltaY& lhs, DeltaY rhs) { return lhs = lhs - rhs; } - -// Adding deltas to co-ordinates is fine -inline constexpr X operator+(X lhs, DeltaX rhs) { return X(lhs.as_int() + rhs.as_int()); } -inline constexpr Y operator+(Y lhs, DeltaY rhs) { return Y(lhs.as_int() + rhs.as_int()); } -inline constexpr X operator-(X lhs, DeltaX rhs) { return X(lhs.as_int() - rhs.as_int()); } -inline constexpr Y operator-(Y lhs, DeltaY rhs) { return Y(lhs.as_int() - rhs.as_int()); } -inline X& operator+=(X& lhs, DeltaX rhs) { return lhs = lhs + rhs; } -inline Y& operator+=(Y& lhs, DeltaY rhs) { return lhs = lhs + rhs; } -inline X& operator-=(X& lhs, DeltaX rhs) { return lhs = lhs - rhs; } -inline Y& operator-=(Y& lhs, DeltaY rhs) { return lhs = lhs - rhs; } - -// Adding deltas to Width and Height is fine -inline constexpr Width operator+(Width lhs, DeltaX rhs) { return Width(lhs.as_int() + rhs.as_int()); } -inline constexpr Height operator+(Height lhs, DeltaY rhs) { return Height(lhs.as_int() + rhs.as_int()); } -inline constexpr Width operator-(Width lhs, DeltaX rhs) { return Width(lhs.as_int() - rhs.as_int()); } -inline constexpr Height operator-(Height lhs, DeltaY rhs) { return Height(lhs.as_int() - rhs.as_int()); } -inline Width& operator+=(Width& lhs, DeltaX rhs) { return lhs = lhs + rhs; } -inline Height& operator+=(Height& lhs, DeltaY rhs) { return lhs = lhs + rhs; } -inline Width& operator-=(Width& lhs, DeltaX rhs) { return lhs = lhs - rhs; } -inline Height& operator-=(Height& lhs, DeltaY rhs) { return lhs = lhs - rhs; } - -// Adding Widths and Heights is fine -inline constexpr Width operator+(Width lhs, Width rhs) { return Width(lhs.as_int() + rhs.as_int()); } -inline constexpr Height operator+(Height lhs, Height rhs) { return Height(lhs.as_int() + rhs.as_int()); } -inline Width& operator+=(Width& lhs, Width rhs) { return lhs = lhs + rhs; } -inline Height& operator+=(Height& lhs, Height rhs) { return lhs = lhs + rhs; } - -// Subtracting coordinates is fine -inline constexpr DeltaX operator-(X lhs, X rhs) { return DeltaX(lhs.as_int() - rhs.as_int()); } -inline constexpr DeltaY operator-(Y lhs, Y rhs) { return DeltaY(lhs.as_int() - rhs.as_int()); } - -//Subtracting Width and Height is fine -inline constexpr DeltaX operator-(Width lhs, Width rhs) { return DeltaX(lhs.as_int() - rhs.as_int()); } -inline constexpr DeltaY operator-(Height lhs, Height rhs) { return DeltaY(lhs.as_int() - rhs.as_int()); } - -// Multiplying by a scalar value is fine -template -inline constexpr Width operator*(Scalar scale, Width const& w) { return Width{scale*w.as_int()}; } -template -inline constexpr Height operator*(Scalar scale, Height const& h) { return Height{scale*h.as_int()}; } -template -inline constexpr DeltaX operator*(Scalar scale, DeltaX const& dx) { return DeltaX{scale*dx.as_int()}; } -template -inline constexpr DeltaY operator*(Scalar scale, DeltaY const& dy) { return DeltaY{scale*dy.as_int()}; } -template -inline constexpr Width operator*(Width const& w, Scalar scale) { return scale*w; } -template -inline constexpr Height operator*(Height const& h, Scalar scale) { return scale*h; } -template -inline constexpr DeltaX operator*(DeltaX const& dx, Scalar scale) { return scale*dx; } -template -inline constexpr DeltaY operator*(DeltaY const& dy, Scalar scale) { return scale*dy; } - -// Dividing by a scaler value is fine -template -inline constexpr Width operator/(Width const& w, Scalar scale) { return Width{w.as_int() / scale}; } -template -inline constexpr Height operator/(Height const& h, Scalar scale) { return Height{h.as_int() / scale}; } -template -inline constexpr DeltaX operator/(DeltaX const& dx, Scalar scale) { return DeltaX{dx.as_int() / scale}; } -template -inline constexpr DeltaY operator/(DeltaY const& dy, Scalar scale) { return DeltaY{dy.as_int() / scale}; } - -// Converting between types is fine, as long as they are along the same axis -inline constexpr Width as_width(DeltaX const& dx) { return Width{dx.as_int()}; } -inline constexpr Height as_height(DeltaY const& dy) { return Height{dy.as_int()}; } -inline constexpr X as_x(DeltaX const& dx) { return X{dx.as_int()}; } -inline constexpr Y as_y(DeltaY const& dy) { return Y{dy.as_int()}; } -inline constexpr DeltaX as_delta(X const& x) { return DeltaX{x.as_int()}; } -inline constexpr DeltaY as_delta(Y const& y) { return DeltaY{y.as_int()}; } -inline constexpr X as_x(Width const& w) { return X{w.as_int()}; } -inline constexpr Y as_y(Height const& h) { return Y{h.as_int()}; } -inline constexpr Width as_width(X const& x) { return Width{x.as_int()}; } -inline constexpr Height as_height(Y const& y) { return Height{y.as_int()}; } -inline constexpr DeltaX as_delta(Width const& w) { return DeltaX{w.as_int()}; } -inline constexpr DeltaY as_delta(Height const& h) { return DeltaY{h.as_int()}; } - -template -inline constexpr Target dim_cast(Source s) { return Target(s.as_int()); } +typedef detail::IntWrapper X; +typedef detail::IntWrapper Y; +typedef detail::IntWrapper DeltaX; +typedef detail::IntWrapper DeltaY; } } diff --git a/include/core/mir/geometry/dimensions_generic.h b/include/core/mir/geometry/dimensions_generic.h new file mode 100644 index 00000000000..0e7ead8f3ed --- /dev/null +++ b/include/core/mir/geometry/dimensions_generic.h @@ -0,0 +1,275 @@ +/* + * Copyright © 2020 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License version 2 or 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Authored by: William Wold + */ + +#ifndef MIR_GEOMETRY_DIMENSIONS_GENERIC_H_ +#define MIR_GEOMETRY_DIMENSIONS_GENERIC_H_ + +#include +#include + +namespace mir +{ +/// Basic geometry types. Types for dimensions, displacements, etc. +/// and the operations that they support. +namespace geometry +{ + +struct WidthTag; +struct HeightTag; +struct XTag; +struct YTag; +struct DeltaXTag; +struct DeltaYTag; + +namespace generic +{ +namespace detail +{ +template +class Wrapper +{ +public: + typedef T ValueType; + + constexpr Wrapper() : value{} {} + + template + Wrapper& operator=(Wrapper const& that) + { + value = static_cast(that.value); + } + + template + constexpr Wrapper(Wrapper const& value) + : value{static_cast(value.as_value())} + { + } + + template + explicit constexpr Wrapper(U const& value) + : value{static_cast(value)} + { + } + + template + constexpr typename std::enable_if::value, int>::type as_int() const + { + return this->value; + } + + constexpr T as_value() const + { + return value; + } + +protected: + T value; +}; + +template +std::ostream& operator<<(std::ostream& out, Wrapper const& value) +{ + out << value.as_value(); + return out; +} + +template +inline constexpr bool operator == (Wrapper const& lhs, Wrapper const& rhs) +{ + return lhs.as_value() == rhs.as_value(); +} + +template +inline constexpr bool operator != (Wrapper const& lhs, Wrapper const& rhs) +{ + return lhs.as_value() != rhs.as_value(); +} + +template +inline constexpr bool operator <= (Wrapper const& lhs, Wrapper const& rhs) +{ + return lhs.as_value() <= rhs.as_value(); +} + +template +inline constexpr bool operator >= (Wrapper const& lhs, Wrapper const& rhs) +{ + return lhs.as_value() >= rhs.as_value(); +} + +template +inline constexpr bool operator < (Wrapper const& lhs, Wrapper const& rhs) +{ + return lhs.as_value() < rhs.as_value(); +} + +template +inline constexpr bool operator > (Wrapper const& lhs, Wrapper const& rhs) +{ + return lhs.as_value() > rhs.as_value(); +} +} // namespace detail + +template using Width = detail::Wrapper; +template using Height = detail::Wrapper; +template using X = detail::Wrapper; +template using Y = detail::Wrapper; +template using DeltaX = detail::Wrapper; +template using DeltaY = detail::Wrapper; +} // namespace generic + +// Adding deltas is fine +template +inline constexpr generic::DeltaX operator+(generic::DeltaX lhs, generic::DeltaX rhs){ return generic::DeltaX(lhs.as_value() + rhs.as_value()); } +template +inline constexpr generic::DeltaY operator+(generic::DeltaY lhs, generic::DeltaY rhs) { return generic::DeltaY(lhs.as_value() + rhs.as_value()); } +template +inline constexpr generic::DeltaX operator-(generic::DeltaX lhs, generic::DeltaX rhs) { return generic::DeltaX(lhs.as_value() - rhs.as_value()); } +template +inline constexpr generic::DeltaY operator-(generic::DeltaY lhs, generic::DeltaY rhs) { return generic::DeltaY(lhs.as_value() - rhs.as_value()); } +template +inline constexpr generic::DeltaX operator-(generic::DeltaX rhs) { return generic::DeltaX(-rhs.as_value()); } +template +inline constexpr generic::DeltaY operator-(generic::DeltaY rhs) { return generic::DeltaY(-rhs.as_value()); } +template +inline generic::DeltaX& operator+=(generic::DeltaX& lhs, generic::DeltaX rhs) { return lhs = lhs + rhs; } +template +inline generic::DeltaY& operator+=(generic::DeltaY& lhs, generic::DeltaY rhs) { return lhs = lhs + rhs; } +template +inline generic::DeltaX& operator-=(generic::DeltaX& lhs, generic::DeltaX rhs) { return lhs = lhs - rhs; } +template +inline generic::DeltaY& operator-=(generic::DeltaY& lhs, generic::DeltaY rhs) { return lhs = lhs - rhs; } + +// Adding deltas to co-ordinates is fine +template +inline constexpr generic::X operator+(generic::X lhs, generic::DeltaX rhs) { return generic::X(lhs.as_value() + rhs.as_value()); } +template +inline constexpr generic::Y operator+(generic::Y lhs, generic::DeltaY rhs) { return generic::Y(lhs.as_value() + rhs.as_value()); } +template +inline constexpr generic::X operator-(generic::X lhs, generic::DeltaX rhs) { return generic::X(lhs.as_value() - rhs.as_value()); } +template +inline constexpr generic::Y operator-(generic::Y lhs, generic::DeltaY rhs) { return generic::Y(lhs.as_value() - rhs.as_value()); } +template +inline generic::X& operator+=(generic::X& lhs, generic::DeltaX rhs) { return lhs = lhs + rhs; } +template +inline generic::Y& operator+=(generic::Y& lhs, generic::DeltaY rhs) { return lhs = lhs + rhs; } +template +inline generic::X& operator-=(generic::X& lhs, generic::DeltaX rhs) { return lhs = lhs - rhs; } +template +inline generic::Y& operator-=(generic::Y& lhs, generic::DeltaY rhs) { return lhs = lhs - rhs; } + +// Adding deltas to generic::Width and generic::Height is fine +template +inline constexpr generic::Width operator+(generic::Width lhs, generic::DeltaX rhs) { return generic::Width(lhs.as_value() + rhs.as_value()); } +template +inline constexpr generic::Height operator+(generic::Height lhs, generic::DeltaY rhs) { return generic::Height(lhs.as_value() + rhs.as_value()); } +template +inline constexpr generic::Width operator-(generic::Width lhs, generic::DeltaX rhs) { return generic::Width(lhs.as_value() - rhs.as_value()); } +template +inline constexpr generic::Height operator-(generic::Height lhs, generic::DeltaY rhs) { return generic::Height(lhs.as_value() - rhs.as_value()); } +template +inline generic::Width& operator+=(generic::Width& lhs, generic::DeltaX rhs) { return lhs = lhs + rhs; } +template +inline generic::Height& operator+=(generic::Height& lhs, generic::DeltaY rhs) { return lhs = lhs + rhs; } +template +inline generic::Width& operator-=(generic::Width& lhs, generic::DeltaX rhs) { return lhs = lhs - rhs; } +template +inline generic::Height& operator-=(generic::Height& lhs, generic::DeltaY rhs) { return lhs = lhs - rhs; } + +// Adding Widths and Heights is fine +template +inline constexpr generic::Width operator+(generic::Width lhs, generic::Width rhs) { return generic::Width(lhs.as_value() + rhs.as_value()); } +template +inline constexpr generic::Height operator+(generic::Height lhs, generic::Height rhs) { return generic::Height(lhs.as_value() + rhs.as_value()); } +template +inline generic::Width& operator+=(generic::Width& lhs, generic::Width rhs) { return lhs = lhs + rhs; } +template +inline generic::Height& operator+=(generic::Height& lhs, generic::Height rhs) { return lhs = lhs + rhs; } + +// Subtracting coordinates is fine +template +inline constexpr generic::DeltaX operator-(generic::X lhs, generic::X rhs) { return generic::DeltaX(lhs.as_value() - rhs.as_value()); } +template +inline constexpr generic::DeltaY operator-(generic::Y lhs, generic::Y rhs) { return generic::DeltaY(lhs.as_value() - rhs.as_value()); } + +//Subtracting generic::Width and generic::Height is fine +template +inline constexpr generic::DeltaX operator-(generic::Width lhs, generic::Width rhs) { return generic::DeltaX(lhs.as_value() - rhs.as_value()); } +template +inline constexpr generic::DeltaY operator-(generic::Height lhs, generic::Height rhs) { return generic::DeltaY(lhs.as_value() - rhs.as_value()); } + +// Multiplying by a scalar value is fine +template +inline constexpr generic::Width operator*(Scalar scale, generic::Width const& w) { return generic::Width{scale*w.as_value()}; } +template +inline constexpr generic::Height operator*(Scalar scale, generic::Height const& h) { return generic::Height{scale*h.as_value()}; } +template +inline constexpr generic::DeltaX operator*(Scalar scale, generic::DeltaX const& dx) { return generic::DeltaX{scale*dx.as_value()}; } +template +inline constexpr generic::DeltaY operator*(Scalar scale, generic::DeltaY const& dy) { return generic::DeltaY{scale*dy.as_value()}; } +template +inline constexpr generic::Width operator*(generic::Width const& w, Scalar scale) { return scale*w; } +template +inline constexpr generic::Height operator*(generic::Height const& h, Scalar scale) { return scale*h; } +template +inline constexpr generic::DeltaX operator*(generic::DeltaX const& dx, Scalar scale) { return scale*dx; } +template +inline constexpr generic::DeltaY operator*(generic::DeltaY const& dy, Scalar scale) { return scale*dy; } + +// Dividing by a scaler value is fine +template +inline constexpr generic::Width operator/(generic::Width const& w, Scalar scale) { return generic::Width{w.as_value() / scale}; } +template +inline constexpr generic::Height operator/(generic::Height const& h, Scalar scale) { return generic::Height{h.as_value() / scale}; } +template +inline constexpr generic::DeltaX operator/(generic::DeltaX const& dx, Scalar scale) { return generic::DeltaX{dx.as_value() / scale}; } +template +inline constexpr generic::DeltaY operator/(generic::DeltaY const& dy, Scalar scale) { return generic::DeltaY{dy.as_value() / scale}; } + +// Converting between types is fine, as long as they are along the same axis +template +inline constexpr generic::Width as_width(generic::DeltaX const& dx) { return generic::Width{dx.as_value()}; } +template +inline constexpr generic::Height as_height(generic::DeltaY const& dy) { return generic::Height{dy.as_value()}; } +template +inline constexpr generic::X as_x(generic::DeltaX const& dx) { return generic::X{dx.as_value()}; } +template +inline constexpr generic::Y as_y(generic::DeltaY const& dy) { return generic::Y{dy.as_value()}; } +template +inline constexpr generic::DeltaX as_delta(generic::X const& x) { return generic::DeltaX{x.as_value()}; } +template +inline constexpr generic::DeltaY as_delta(generic::Y const& y) { return generic::DeltaY{y.as_value()}; } +template +inline constexpr generic::X as_x(generic::Width const& w) { return generic::X{w.as_value()}; } +template +inline constexpr generic::Y as_y(generic::Height const& h) { return generic::Y{h.as_value()}; } +template +inline constexpr generic::Width as_width(generic::X const& x) { return generic::Width{x.as_value()}; } +template +inline constexpr generic::Height as_height(generic::Y const& y) { return generic::Height{y.as_value()}; } +template +inline constexpr generic::DeltaX as_delta(generic::Width const& w) { return generic::DeltaX{w.as_value()}; } +template +inline constexpr generic::DeltaY as_delta(generic::Height const& h) { return generic::DeltaY{h.as_value()}; } + +template +inline constexpr Target dim_cast(Source s) { return Target(s.as_value()); } +} // namespace geometry +} // namespace mir + +#endif // MIR_GEOMETRY_DIMENSIONS_GENERIC_H_ diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index babf1821436..47c9ee90529 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -24,6 +24,7 @@ add_library(mircore SHARED ${PROJECT_SOURCE_DIR}/include/core/mir/geometry/size.h ${PROJECT_SOURCE_DIR}/include/core/mir/geometry/forward.h ${PROJECT_SOURCE_DIR}/include/core/mir/geometry/dimensions.h + ${PROJECT_SOURCE_DIR}/include/core/mir/geometry/dimensions_generic.h ${PROJECT_SOURCE_DIR}/include/core/mir/shm_file.h ${PROJECT_SOURCE_DIR}/include/core/mir/depth_layer.h ${PROJECT_SOURCE_DIR}/include/core/mir_toolkit/common.h diff --git a/tests/unit-tests/geometry/CMakeLists.txt b/tests/unit-tests/geometry/CMakeLists.txt index 6492f7953ff..980c2f0f023 100644 --- a/tests/unit-tests/geometry/CMakeLists.txt +++ b/tests/unit-tests/geometry/CMakeLists.txt @@ -6,6 +6,7 @@ list(APPEND UNIT_TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test-rectangle.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test-rectangles.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test-length.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/test-dimensions-generic.cpp ) set(UNIT_TEST_SOURCES ${UNIT_TEST_SOURCES} PARENT_SCOPE) diff --git a/tests/unit-tests/geometry/test-dimensions-generic.cpp b/tests/unit-tests/geometry/test-dimensions-generic.cpp new file mode 100644 index 00000000000..9d1ab835d9d --- /dev/null +++ b/tests/unit-tests/geometry/test-dimensions-generic.cpp @@ -0,0 +1,138 @@ +/* + * Copyright © 2012 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authored by: Alan Griffiths + */ + +#include "mir/geometry/dimensions_generic.h" + +#include "boost/throw_exception.hpp" +#include +#include + +using namespace mir::geometry::generic; + +TEST(geometry, generic_casting_between_same_tag) +{ + Width const width_i {42}; + Width const width_f = width_i; + + EXPECT_EQ(width_i, static_cast>(width_f)); +} + +TEST(geometry, generic_width) +{ + Width width0 {0}; + Width width42 {42}; + + EXPECT_EQ(uint32_t{0}, width0.as_value()); + EXPECT_EQ(uint32_t{42}, width42.as_value()); + + EXPECT_EQ(width0, width0); + EXPECT_NE(width0, width42); + EXPECT_EQ(width42, width42); + EXPECT_NE(width42, width0); +} + +TEST(geometry, generic_height) +{ + Height height0 {0}; + Height height42 {42}; + + EXPECT_EQ(uint32_t{0}, height0.as_value()); + EXPECT_EQ(uint32_t{42}, height42.as_value()); + + EXPECT_EQ(height0, height0); + EXPECT_NE(height0, height42); + EXPECT_EQ(height42, height42); + EXPECT_NE(height42, height0); +} + +TEST(geometry, generic_delta_arithmetic) +{ + DeltaX dx1{1}; + + DeltaX x2 = DeltaX(1) + dx1; + EXPECT_EQ(DeltaX(2), x2); + EXPECT_EQ(DeltaX(1), x2-dx1); +} + +TEST(geometry, generic_coordinates) +{ + X x1{1}; + X x2{2}; + DeltaX dx1{1}; + + EXPECT_EQ(X(2), x1 + dx1); + EXPECT_EQ(X(1), x2 - dx1); + + Y y24{24}; + Y y42{42}; + DeltaY dx18{18}; + + EXPECT_EQ(dx18, y42 - y24); +} + +TEST(geometry, generic_conversions) +{ + Width w1{1}; + DeltaX dx1{1}; + + EXPECT_EQ(w1, mir::geometry::dim_cast>(dx1)); + EXPECT_EQ(dx1, mir::geometry::dim_cast>(w1)); + EXPECT_NE(dx1, mir::geometry::dim_cast>(X())); +} + +TEST(geometry, generic_signed_dimensions) +{ + X const x0{0}; + X const x2{2}; + X const xn5{-5}; + Y const y0{0}; + Y const y3{3}; + Y const yn6{-6}; + Y const yn7{-7}; + + // Compare against zero to catch regressions of signed->unsigned that + // wouldn't be caught using as_*int()... + EXPECT_GT(x0, xn5); + EXPECT_GT(y0, yn7); + + EXPECT_LT(xn5, x0); + EXPECT_LT(xn5, x2); + EXPECT_LT(yn7, yn6); + EXPECT_LT(yn7, y0); + EXPECT_LT(yn7, y3); + + EXPECT_LE(xn5, x0); + EXPECT_LE(xn5, x2); + EXPECT_LE(yn7, yn6); + EXPECT_LE(yn7, y0); + EXPECT_LE(yn7, y3); + EXPECT_LE(yn7, yn7); + + EXPECT_GT(x0, xn5); + EXPECT_GT(x2, xn5); + EXPECT_GT(yn6, yn7); + EXPECT_GT(y0, yn7); + EXPECT_GT(y3, yn7); + + EXPECT_GE(x0, xn5); + EXPECT_GE(x2, xn5); + EXPECT_GE(yn6, yn7); + EXPECT_GE(y0, yn7); + EXPECT_GE(y3, yn7); + EXPECT_GE(yn7, yn7); +} From 2a4e2151315d254059029883609315c1e879a2c1 Mon Sep 17 00:00:00 2001 From: William Wold Date: Thu, 10 Dec 2020 13:48:23 -0800 Subject: [PATCH 03/18] Add floating point dimensions --- include/core/mir/geometry/dimensions_f.h | 37 ++++++++++++++++++++++++ src/core/CMakeLists.txt | 1 + 2 files changed, 38 insertions(+) create mode 100644 include/core/mir/geometry/dimensions_f.h diff --git a/include/core/mir/geometry/dimensions_f.h b/include/core/mir/geometry/dimensions_f.h new file mode 100644 index 00000000000..a6d7ad97cd8 --- /dev/null +++ b/include/core/mir/geometry/dimensions_f.h @@ -0,0 +1,37 @@ +/* + * Copyright © 2020 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License version 2 or 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Authored by: William Wold + */ + +#ifndef MIR_GEOMETRY_DIMENSIONS_F_H_ +#define MIR_GEOMETRY_DIMENSIONS_F_H_ + +#include "dimensions_generic.h" + +namespace mir +{ +namespace geometry +{ +using WidthF = generic::Width; +using HeightF = generic::Height; +using XF = generic::X; +using YF = generic::Y; +using DeltaXF = generic::DeltaX; +using DeltaYF = generic::DeltaY; +} +} + +#endif // MIR_GEOMETRY_DIMENSIONS_F_H_ diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 47c9ee90529..de317dbdd0e 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -25,6 +25,7 @@ add_library(mircore SHARED ${PROJECT_SOURCE_DIR}/include/core/mir/geometry/forward.h ${PROJECT_SOURCE_DIR}/include/core/mir/geometry/dimensions.h ${PROJECT_SOURCE_DIR}/include/core/mir/geometry/dimensions_generic.h + ${PROJECT_SOURCE_DIR}/include/core/mir/geometry/dimensions_f.h ${PROJECT_SOURCE_DIR}/include/core/mir/shm_file.h ${PROJECT_SOURCE_DIR}/include/core/mir/depth_layer.h ${PROJECT_SOURCE_DIR}/include/core/mir_toolkit/common.h From aed8d36e9dca49537801edf646e8d16443d15a3f Mon Sep 17 00:00:00 2001 From: William Wold Date: Mon, 18 Jan 2021 17:22:05 -0800 Subject: [PATCH 04/18] Return correct wrapper types from geometry operations --- include/core/mir/geometry/dimensions.h | 5 +- include/core/mir/geometry/dimensions_f.h | 42 ++- .../core/mir/geometry/dimensions_generic.h | 263 +++++++++--------- tests/unit-tests/geometry/CMakeLists.txt | 1 - .../geometry/test-dimensions-generic.cpp | 138 --------- 5 files changed, 172 insertions(+), 277 deletions(-) delete mode 100644 tests/unit-tests/geometry/test-dimensions-generic.cpp diff --git a/include/core/mir/geometry/dimensions.h b/include/core/mir/geometry/dimensions.h index 91eca117d76..7b6e3302950 100644 --- a/include/core/mir/geometry/dimensions.h +++ b/include/core/mir/geometry/dimensions.h @@ -25,18 +25,19 @@ namespace mir { - /// Basic geometry types. Types for dimensions, displacements, etc. /// and the operations that they support. namespace geometry { namespace detail { -// TODO: On next ABI break, switch to just using Wrapper template class IntWrapper : public generic::detail::Wrapper { public: + template + using WrapperType = IntWrapper; + constexpr IntWrapper() {} template diff --git a/include/core/mir/geometry/dimensions_f.h b/include/core/mir/geometry/dimensions_f.h index a6d7ad97cd8..71e4f2a0ffe 100644 --- a/include/core/mir/geometry/dimensions_f.h +++ b/include/core/mir/geometry/dimensions_f.h @@ -25,12 +25,42 @@ namespace mir { namespace geometry { -using WidthF = generic::Width; -using HeightF = generic::Height; -using XF = generic::X; -using YF = generic::Y; -using DeltaXF = generic::DeltaX; -using DeltaYF = generic::DeltaY; +namespace detail +{ +template +class FloatWrapper : public generic::detail::Wrapper +{ +public: + template + using WrapperType = FloatWrapper; + + constexpr FloatWrapper() {} + + template + constexpr FloatWrapper(generic::detail::Wrapper const& value) + : generic::detail::Wrapper{value} + { + } + + template + explicit constexpr FloatWrapper(U const& value) + : generic::detail::Wrapper{value} + { + } + + constexpr auto as_float() const -> float + { + return this->value; + } +}; +} // namespace detail + +typedef detail::FloatWrapper FWidth; +typedef detail::FloatWrapper FHeight; +typedef detail::FloatWrapper FX; +typedef detail::FloatWrapper FY; +typedef detail::FloatWrapper FDeltaX; +typedef detail::FloatWrapper FDeltaY; } } diff --git a/include/core/mir/geometry/dimensions_generic.h b/include/core/mir/geometry/dimensions_generic.h index 0e7ead8f3ed..618fc8bf1c1 100644 --- a/include/core/mir/geometry/dimensions_generic.h +++ b/include/core/mir/geometry/dimensions_generic.h @@ -44,8 +44,23 @@ template class Wrapper { public: - typedef T ValueType; + using ValueType = T; + using TagType = Tag; + template + using WrapperType = Wrapper; + template + constexpr typename std::enable_if::value, int>::type as_int() const + { + return this->value; + } + + constexpr T as_value() const + { + return value; + } + +protected: constexpr Wrapper() : value{} {} template @@ -66,18 +81,6 @@ class Wrapper { } - template - constexpr typename std::enable_if::value, int>::type as_int() const - { - return this->value; - } - - constexpr T as_value() const - { - return value; - } - -protected: T value; }; @@ -134,138 +137,138 @@ template using DeltaY = detail::Wrapper; } // namespace generic // Adding deltas is fine -template -inline constexpr generic::DeltaX operator+(generic::DeltaX lhs, generic::DeltaX rhs){ return generic::DeltaX(lhs.as_value() + rhs.as_value()); } -template -inline constexpr generic::DeltaY operator+(generic::DeltaY lhs, generic::DeltaY rhs) { return generic::DeltaY(lhs.as_value() + rhs.as_value()); } -template -inline constexpr generic::DeltaX operator-(generic::DeltaX lhs, generic::DeltaX rhs) { return generic::DeltaX(lhs.as_value() - rhs.as_value()); } -template -inline constexpr generic::DeltaY operator-(generic::DeltaY lhs, generic::DeltaY rhs) { return generic::DeltaY(lhs.as_value() - rhs.as_value()); } -template -inline constexpr generic::DeltaX operator-(generic::DeltaX rhs) { return generic::DeltaX(-rhs.as_value()); } -template -inline constexpr generic::DeltaY operator-(generic::DeltaY rhs) { return generic::DeltaY(-rhs.as_value()); } -template -inline generic::DeltaX& operator+=(generic::DeltaX& lhs, generic::DeltaX rhs) { return lhs = lhs + rhs; } -template -inline generic::DeltaY& operator+=(generic::DeltaY& lhs, generic::DeltaY rhs) { return lhs = lhs + rhs; } -template -inline generic::DeltaX& operator-=(generic::DeltaX& lhs, generic::DeltaX rhs) { return lhs = lhs - rhs; } -template -inline generic::DeltaY& operator-=(generic::DeltaY& lhs, generic::DeltaY rhs) { return lhs = lhs - rhs; } +template typename T> +inline constexpr T operator+(T lhs, T rhs){ return T(lhs.as_value() + rhs.as_value()); } +template typename T> +inline constexpr T operator+(T lhs, T rhs) { return T(lhs.as_value() + rhs.as_value()); } +template typename T> +inline constexpr T operator-(T lhs, T rhs) { return T(lhs.as_value() - rhs.as_value()); } +template typename T> +inline constexpr T operator-(T lhs, T rhs) { return T(lhs.as_value() - rhs.as_value()); } +template typename T> +inline constexpr T operator-(T rhs) { return T(-rhs.as_value()); } +template typename T> +inline constexpr T operator-(T rhs) { return T(-rhs.as_value()); } +template typename T> +inline T& operator+=(T& lhs, T rhs) { return lhs = lhs + rhs; } +template typename T> +inline T& operator+=(T& lhs, T rhs) { return lhs = lhs + rhs; } +template typename T> +inline T& operator-=(T& lhs, T rhs) { return lhs = lhs - rhs; } +template typename T> +inline T& operator-=(T& lhs, T rhs) { return lhs = lhs - rhs; } // Adding deltas to co-ordinates is fine -template -inline constexpr generic::X operator+(generic::X lhs, generic::DeltaX rhs) { return generic::X(lhs.as_value() + rhs.as_value()); } -template -inline constexpr generic::Y operator+(generic::Y lhs, generic::DeltaY rhs) { return generic::Y(lhs.as_value() + rhs.as_value()); } -template -inline constexpr generic::X operator-(generic::X lhs, generic::DeltaX rhs) { return generic::X(lhs.as_value() - rhs.as_value()); } -template -inline constexpr generic::Y operator-(generic::Y lhs, generic::DeltaY rhs) { return generic::Y(lhs.as_value() - rhs.as_value()); } -template -inline generic::X& operator+=(generic::X& lhs, generic::DeltaX rhs) { return lhs = lhs + rhs; } -template -inline generic::Y& operator+=(generic::Y& lhs, generic::DeltaY rhs) { return lhs = lhs + rhs; } -template -inline generic::X& operator-=(generic::X& lhs, generic::DeltaX rhs) { return lhs = lhs - rhs; } -template -inline generic::Y& operator-=(generic::Y& lhs, generic::DeltaY rhs) { return lhs = lhs - rhs; } +template typename T> +inline constexpr T operator+(T lhs, T rhs) { return T(lhs.as_value() + rhs.as_value()); } +template typename T> +inline constexpr T operator+(T lhs, T rhs) { return T(lhs.as_value() + rhs.as_value()); } +template typename T> +inline constexpr T operator-(T lhs, T rhs) { return T(lhs.as_value() - rhs.as_value()); } +template typename T> +inline constexpr T operator-(T lhs, T rhs) { return T(lhs.as_value() - rhs.as_value()); } +template typename T> +inline T& operator+=(T& lhs, T rhs) { return lhs = lhs + rhs; } +template typename T> +inline T& operator+=(T& lhs, T rhs) { return lhs = lhs + rhs; } +template typename T> +inline T& operator-=(T& lhs, T rhs) { return lhs = lhs - rhs; } +template typename T> +inline T& operator-=(T& lhs, T rhs) { return lhs = lhs - rhs; } // Adding deltas to generic::Width and generic::Height is fine -template -inline constexpr generic::Width operator+(generic::Width lhs, generic::DeltaX rhs) { return generic::Width(lhs.as_value() + rhs.as_value()); } -template -inline constexpr generic::Height operator+(generic::Height lhs, generic::DeltaY rhs) { return generic::Height(lhs.as_value() + rhs.as_value()); } -template -inline constexpr generic::Width operator-(generic::Width lhs, generic::DeltaX rhs) { return generic::Width(lhs.as_value() - rhs.as_value()); } -template -inline constexpr generic::Height operator-(generic::Height lhs, generic::DeltaY rhs) { return generic::Height(lhs.as_value() - rhs.as_value()); } -template -inline generic::Width& operator+=(generic::Width& lhs, generic::DeltaX rhs) { return lhs = lhs + rhs; } -template -inline generic::Height& operator+=(generic::Height& lhs, generic::DeltaY rhs) { return lhs = lhs + rhs; } -template -inline generic::Width& operator-=(generic::Width& lhs, generic::DeltaX rhs) { return lhs = lhs - rhs; } -template -inline generic::Height& operator-=(generic::Height& lhs, generic::DeltaY rhs) { return lhs = lhs - rhs; } +template typename T> +inline constexpr T operator+(T lhs, T rhs) { return T(lhs.as_value() + rhs.as_value()); } +template typename T> +inline constexpr T operator+(T lhs, T rhs) { return T(lhs.as_value() + rhs.as_value()); } +template typename T> +inline constexpr T operator-(T lhs, T rhs) { return T(lhs.as_value() - rhs.as_value()); } +template typename T> +inline constexpr T operator-(T lhs, T rhs) { return T(lhs.as_value() - rhs.as_value()); } +template typename T> +inline T& operator+=(T& lhs, T rhs) { return lhs = lhs + rhs; } +template typename T> +inline T& operator+=(T& lhs, T rhs) { return lhs = lhs + rhs; } +template typename T> +inline T& operator-=(T& lhs, T rhs) { return lhs = lhs - rhs; } +template typename T> +inline T& operator-=(T& lhs, T rhs) { return lhs = lhs - rhs; } // Adding Widths and Heights is fine -template -inline constexpr generic::Width operator+(generic::Width lhs, generic::Width rhs) { return generic::Width(lhs.as_value() + rhs.as_value()); } -template -inline constexpr generic::Height operator+(generic::Height lhs, generic::Height rhs) { return generic::Height(lhs.as_value() + rhs.as_value()); } -template -inline generic::Width& operator+=(generic::Width& lhs, generic::Width rhs) { return lhs = lhs + rhs; } -template -inline generic::Height& operator+=(generic::Height& lhs, generic::Height rhs) { return lhs = lhs + rhs; } +template typename T> +inline constexpr T operator+(T lhs, T rhs) { return T(lhs.as_value() + rhs.as_value()); } +template typename T> +inline constexpr T operator+(T lhs, T rhs) { return T(lhs.as_value() + rhs.as_value()); } +template typename T> +inline T& operator+=(T& lhs, T rhs) { return lhs = lhs + rhs; } +template typename T> +inline T& operator+=(T& lhs, T rhs) { return lhs = lhs + rhs; } // Subtracting coordinates is fine -template -inline constexpr generic::DeltaX operator-(generic::X lhs, generic::X rhs) { return generic::DeltaX(lhs.as_value() - rhs.as_value()); } -template -inline constexpr generic::DeltaY operator-(generic::Y lhs, generic::Y rhs) { return generic::DeltaY(lhs.as_value() - rhs.as_value()); } +template typename T> +inline constexpr T operator-(T lhs, T rhs) { return T(lhs.as_value() - rhs.as_value()); } +template typename T> +inline constexpr T operator-(T lhs, T rhs) { return T(lhs.as_value() - rhs.as_value()); } -//Subtracting generic::Width and generic::Height is fine -template -inline constexpr generic::DeltaX operator-(generic::Width lhs, generic::Width rhs) { return generic::DeltaX(lhs.as_value() - rhs.as_value()); } -template -inline constexpr generic::DeltaY operator-(generic::Height lhs, generic::Height rhs) { return generic::DeltaY(lhs.as_value() - rhs.as_value()); } +//Subtracting T and T is fine +template typename T> +inline constexpr T operator-(T lhs, T rhs) { return T(lhs.as_value() - rhs.as_value()); } +template typename T> +inline constexpr T operator-(T lhs, T rhs) { return T(lhs.as_value() - rhs.as_value()); } // Multiplying by a scalar value is fine -template -inline constexpr generic::Width operator*(Scalar scale, generic::Width const& w) { return generic::Width{scale*w.as_value()}; } -template -inline constexpr generic::Height operator*(Scalar scale, generic::Height const& h) { return generic::Height{scale*h.as_value()}; } -template -inline constexpr generic::DeltaX operator*(Scalar scale, generic::DeltaX const& dx) { return generic::DeltaX{scale*dx.as_value()}; } -template -inline constexpr generic::DeltaY operator*(Scalar scale, generic::DeltaY const& dy) { return generic::DeltaY{scale*dy.as_value()}; } -template -inline constexpr generic::Width operator*(generic::Width const& w, Scalar scale) { return scale*w; } -template -inline constexpr generic::Height operator*(generic::Height const& h, Scalar scale) { return scale*h; } -template -inline constexpr generic::DeltaX operator*(generic::DeltaX const& dx, Scalar scale) { return scale*dx; } -template -inline constexpr generic::DeltaY operator*(generic::DeltaY const& dy, Scalar scale) { return scale*dy; } +template typename T, typename Scalar> +inline constexpr T operator*(Scalar scale, T const& w) { return T{scale*w.as_value()}; } +template typename T, typename Scalar> +inline constexpr T operator*(Scalar scale, T const& h) { return T{scale*h.as_value()}; } +template typename T, typename Scalar> +inline constexpr T operator*(Scalar scale, T const& dx) { return T{scale*dx.as_value()}; } +template typename T, typename Scalar> +inline constexpr T operator*(Scalar scale, T const& dy) { return T{scale*dy.as_value()}; } +template typename T, typename Scalar> +inline constexpr T operator*(T const& w, Scalar scale) { return scale*w; } +template typename T, typename Scalar> +inline constexpr T operator*(T const& h, Scalar scale) { return scale*h; } +template typename T, typename Scalar> +inline constexpr T operator*(T const& dx, Scalar scale) { return scale*dx; } +template typename T, typename Scalar> +inline constexpr T operator*(T const& dy, Scalar scale) { return scale*dy; } // Dividing by a scaler value is fine -template -inline constexpr generic::Width operator/(generic::Width const& w, Scalar scale) { return generic::Width{w.as_value() / scale}; } -template -inline constexpr generic::Height operator/(generic::Height const& h, Scalar scale) { return generic::Height{h.as_value() / scale}; } -template -inline constexpr generic::DeltaX operator/(generic::DeltaX const& dx, Scalar scale) { return generic::DeltaX{dx.as_value() / scale}; } -template -inline constexpr generic::DeltaY operator/(generic::DeltaY const& dy, Scalar scale) { return generic::DeltaY{dy.as_value() / scale}; } +template typename T, typename Scalar> +inline constexpr T operator/(T const& w, Scalar scale) { return T{w.as_value() / scale}; } +template typename T, typename Scalar> +inline constexpr T operator/(T const& h, Scalar scale) { return T{h.as_value() / scale}; } +template typename T, typename Scalar> +inline constexpr T operator/(T const& dx, Scalar scale) { return T{dx.as_value() / scale}; } +template typename T, typename Scalar> +inline constexpr T operator/(T const& dy, Scalar scale) { return T{dy.as_value() / scale}; } // Converting between types is fine, as long as they are along the same axis -template -inline constexpr generic::Width as_width(generic::DeltaX const& dx) { return generic::Width{dx.as_value()}; } -template -inline constexpr generic::Height as_height(generic::DeltaY const& dy) { return generic::Height{dy.as_value()}; } -template -inline constexpr generic::X as_x(generic::DeltaX const& dx) { return generic::X{dx.as_value()}; } -template -inline constexpr generic::Y as_y(generic::DeltaY const& dy) { return generic::Y{dy.as_value()}; } -template -inline constexpr generic::DeltaX as_delta(generic::X const& x) { return generic::DeltaX{x.as_value()}; } -template -inline constexpr generic::DeltaY as_delta(generic::Y const& y) { return generic::DeltaY{y.as_value()}; } -template -inline constexpr generic::X as_x(generic::Width const& w) { return generic::X{w.as_value()}; } -template -inline constexpr generic::Y as_y(generic::Height const& h) { return generic::Y{h.as_value()}; } -template -inline constexpr generic::Width as_width(generic::X const& x) { return generic::Width{x.as_value()}; } -template -inline constexpr generic::Height as_height(generic::Y const& y) { return generic::Height{y.as_value()}; } -template -inline constexpr generic::DeltaX as_delta(generic::Width const& w) { return generic::DeltaX{w.as_value()}; } -template -inline constexpr generic::DeltaY as_delta(generic::Height const& h) { return generic::DeltaY{h.as_value()}; } +template typename T> +inline constexpr T as_width(T const& dx) { return T{dx.as_value()}; } +template typename T> +inline constexpr T as_height(T const& dy) { return T{dy.as_value()}; } +template typename T> +inline constexpr T as_x(T const& dx) { return T{dx.as_value()}; } +template typename T> +inline constexpr T as_y(T const& dy) { return T{dy.as_value()}; } +template typename T> +inline constexpr T as_delta(T const& x) { return T{x.as_value()}; } +template typename T> +inline constexpr T as_delta(T const& y) { return T{y.as_value()}; } +template typename T> +inline constexpr T as_x(T const& w) { return T{w.as_value()}; } +template typename T> +inline constexpr T as_y(T const& h) { return T{h.as_value()}; } +template typename T> +inline constexpr T as_width(T const& x) { return T{x.as_value()}; } +template typename T> +inline constexpr T as_height(T const& y) { return T{y.as_value()}; } +template typename T> +inline constexpr T as_delta(T const& w) { return T{w.as_value()}; } +template typename T> +inline constexpr T as_delta(T const& h) { return T{h.as_value()}; } template inline constexpr Target dim_cast(Source s) { return Target(s.as_value()); } diff --git a/tests/unit-tests/geometry/CMakeLists.txt b/tests/unit-tests/geometry/CMakeLists.txt index 980c2f0f023..6492f7953ff 100644 --- a/tests/unit-tests/geometry/CMakeLists.txt +++ b/tests/unit-tests/geometry/CMakeLists.txt @@ -6,7 +6,6 @@ list(APPEND UNIT_TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test-rectangle.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test-rectangles.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test-length.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/test-dimensions-generic.cpp ) set(UNIT_TEST_SOURCES ${UNIT_TEST_SOURCES} PARENT_SCOPE) diff --git a/tests/unit-tests/geometry/test-dimensions-generic.cpp b/tests/unit-tests/geometry/test-dimensions-generic.cpp deleted file mode 100644 index 9d1ab835d9d..00000000000 --- a/tests/unit-tests/geometry/test-dimensions-generic.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright © 2012 Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 or 3 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Authored by: Alan Griffiths - */ - -#include "mir/geometry/dimensions_generic.h" - -#include "boost/throw_exception.hpp" -#include -#include - -using namespace mir::geometry::generic; - -TEST(geometry, generic_casting_between_same_tag) -{ - Width const width_i {42}; - Width const width_f = width_i; - - EXPECT_EQ(width_i, static_cast>(width_f)); -} - -TEST(geometry, generic_width) -{ - Width width0 {0}; - Width width42 {42}; - - EXPECT_EQ(uint32_t{0}, width0.as_value()); - EXPECT_EQ(uint32_t{42}, width42.as_value()); - - EXPECT_EQ(width0, width0); - EXPECT_NE(width0, width42); - EXPECT_EQ(width42, width42); - EXPECT_NE(width42, width0); -} - -TEST(geometry, generic_height) -{ - Height height0 {0}; - Height height42 {42}; - - EXPECT_EQ(uint32_t{0}, height0.as_value()); - EXPECT_EQ(uint32_t{42}, height42.as_value()); - - EXPECT_EQ(height0, height0); - EXPECT_NE(height0, height42); - EXPECT_EQ(height42, height42); - EXPECT_NE(height42, height0); -} - -TEST(geometry, generic_delta_arithmetic) -{ - DeltaX dx1{1}; - - DeltaX x2 = DeltaX(1) + dx1; - EXPECT_EQ(DeltaX(2), x2); - EXPECT_EQ(DeltaX(1), x2-dx1); -} - -TEST(geometry, generic_coordinates) -{ - X x1{1}; - X x2{2}; - DeltaX dx1{1}; - - EXPECT_EQ(X(2), x1 + dx1); - EXPECT_EQ(X(1), x2 - dx1); - - Y y24{24}; - Y y42{42}; - DeltaY dx18{18}; - - EXPECT_EQ(dx18, y42 - y24); -} - -TEST(geometry, generic_conversions) -{ - Width w1{1}; - DeltaX dx1{1}; - - EXPECT_EQ(w1, mir::geometry::dim_cast>(dx1)); - EXPECT_EQ(dx1, mir::geometry::dim_cast>(w1)); - EXPECT_NE(dx1, mir::geometry::dim_cast>(X())); -} - -TEST(geometry, generic_signed_dimensions) -{ - X const x0{0}; - X const x2{2}; - X const xn5{-5}; - Y const y0{0}; - Y const y3{3}; - Y const yn6{-6}; - Y const yn7{-7}; - - // Compare against zero to catch regressions of signed->unsigned that - // wouldn't be caught using as_*int()... - EXPECT_GT(x0, xn5); - EXPECT_GT(y0, yn7); - - EXPECT_LT(xn5, x0); - EXPECT_LT(xn5, x2); - EXPECT_LT(yn7, yn6); - EXPECT_LT(yn7, y0); - EXPECT_LT(yn7, y3); - - EXPECT_LE(xn5, x0); - EXPECT_LE(xn5, x2); - EXPECT_LE(yn7, yn6); - EXPECT_LE(yn7, y0); - EXPECT_LE(yn7, y3); - EXPECT_LE(yn7, yn7); - - EXPECT_GT(x0, xn5); - EXPECT_GT(x2, xn5); - EXPECT_GT(yn6, yn7); - EXPECT_GT(y0, yn7); - EXPECT_GT(y3, yn7); - - EXPECT_GE(x0, xn5); - EXPECT_GE(x2, xn5); - EXPECT_GE(yn6, yn7); - EXPECT_GE(y0, yn7); - EXPECT_GE(y3, yn7); - EXPECT_GE(yn7, yn7); -} From d8de5d85a0664df4e6eb4d7efa185a3ea17d3bcb Mon Sep 17 00:00:00 2001 From: William Wold Date: Mon, 18 Jan 2021 17:25:06 -0800 Subject: [PATCH 05/18] Revert "Make geometry types explicit for std::min/max()" This reverts commit 843b0362bc701a92cfe148dc522f6ae99200e155. --- examples/example-server-lib/decoration_provider.cpp | 4 ++-- examples/example-server-lib/floating_window_manager.cpp | 4 ++-- src/server/scene/basic_surface.cpp | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/example-server-lib/decoration_provider.cpp b/examples/example-server-lib/decoration_provider.cpp index 76a61b61f89..de70d8554d4 100644 --- a/examples/example-server-lib/decoration_provider.cpp +++ b/examples/example-server-lib/decoration_provider.cpp @@ -247,8 +247,8 @@ void Printer::printhelp(BackgroundInfo const& region) std::max(X{}, region_top_left_in_glyph_space.x), std::max(Y{}, region_top_left_in_glyph_space.y)}; auto const clipped_glyph_lower_right = Point{ - std::min(as_x(as_displacement(glyph_size).dx), region_lower_right_in_glyph_space.x), - std::min(as_y(as_displacement(glyph_size).dy), region_lower_right_in_glyph_space.y)}; + std::min(X{} + as_displacement(glyph_size).dx, region_lower_right_in_glyph_space.x), + std::min(Y{} + as_displacement(glyph_size).dy, region_lower_right_in_glyph_space.y)}; unsigned char* const glyph_buffer = glyph->bitmap.buffer; auto glyph_pixel = Point{}; diff --git a/examples/example-server-lib/floating_window_manager.cpp b/examples/example-server-lib/floating_window_manager.cpp index 47f9822c517..77f7d01e991 100644 --- a/examples/example-server-lib/floating_window_manager.cpp +++ b/examples/example-server-lib/floating_window_manager.cpp @@ -203,8 +203,8 @@ bool FloatingWindowManagerPolicy::handle_touch_event(MirTouchEvent const* event) auto const delta_width = DeltaX{touch_pinch_width - old_touch_pinch_width}; auto const delta_height = DeltaY{touch_pinch_height - old_touch_pinch_height}; - auto new_width = std::max(old_size.width + delta_width, Width{5}); - auto new_height = std::max(old_size.height + delta_height, Height{5}); + auto new_width = std::max(old_size.width + delta_width, Width{5}); + auto new_height = std::max(old_size.height + delta_height, Height{5}); Displacement movement{ DeltaX{touch_pinch_left - old_touch_pinch_left}, DeltaY{touch_pinch_top - old_touch_pinch_top}}; diff --git a/src/server/scene/basic_surface.cpp b/src/server/scene/basic_surface.cpp index c1cb9272596..212932c2b30 100644 --- a/src/server/scene/basic_surface.cpp +++ b/src/server/scene/basic_surface.cpp @@ -1080,8 +1080,8 @@ void mir::scene::BasicSurface::set_window_margins( auto mir::scene::BasicSurface::content_size(ProofOfMutexLock const&) const -> geometry::Size { return geom::Size{ - std::max(surface_rect.size.width - margins.left - margins.right, geom::Width{1}), - std::max(surface_rect.size.height - margins.top - margins.bottom, geom::Height{1})}; + std::max(surface_rect.size.width - margins.left - margins.right, geom::Width{1}), + std::max(surface_rect.size.height - margins.top - margins.bottom, geom::Height{1})}; } auto mir::scene::BasicSurface::content_top_left(ProofOfMutexLock const&) const -> geometry::Point From 5518030bfeb819bc4735bee8ce6ef368fc4ef34f Mon Sep 17 00:00:00 2001 From: William Wold Date: Mon, 18 Jan 2021 19:17:57 -0800 Subject: [PATCH 06/18] Add generic point --- include/core/mir/geometry/point.h | 37 ++------- include/core/mir/geometry/point_generic.h | 94 +++++++++++++++++++++++ src/core/geometry/ostream.cpp | 6 -- 3 files changed, 100 insertions(+), 37 deletions(-) create mode 100644 include/core/mir/geometry/point_generic.h diff --git a/include/core/mir/geometry/point.h b/include/core/mir/geometry/point.h index 943f8e88934..9cf57de8244 100644 --- a/include/core/mir/geometry/point.h +++ b/include/core/mir/geometry/point.h @@ -20,50 +20,25 @@ #define MIR_GEOMETRY_POINT_H_ #include "dimensions.h" +#include "point_generic.h" #include namespace mir { namespace geometry { - -struct Point +struct Point : generic::Point { + template + using WrapperType = detail::IntWrapper; + constexpr Point() = default; constexpr Point(Point const&) = default; Point& operator=(Point const&) = default; template - constexpr Point(XType&& x, YType&& y) : x(x), y(y) {} - - X x; - Y y; + constexpr Point(XType&& x, YType&& y) : generic::Point{x, y} {} }; - -inline constexpr bool operator == (Point const& lhs, Point const& rhs) -{ - return lhs.x == rhs.x && lhs.y == rhs.y; } - -inline constexpr bool operator != (Point const& lhs, Point const& rhs) -{ - return lhs.x != rhs.x || lhs.y != rhs.y; } - -inline constexpr Point operator+(Point lhs, DeltaX rhs) { return{lhs.x + rhs, lhs.y}; } -inline constexpr Point operator+(Point lhs, DeltaY rhs) { return{lhs.x, lhs.y + rhs}; } - -inline constexpr Point operator-(Point lhs, DeltaX rhs) { return{lhs.x - rhs, lhs.y}; } -inline constexpr Point operator-(Point lhs, DeltaY rhs) { return{lhs.x, lhs.y - rhs}; } - -inline Point& operator+=(Point& lhs, DeltaX rhs) { lhs.x += rhs; return lhs; } -inline Point& operator+=(Point& lhs, DeltaY rhs) { lhs.y += rhs; return lhs; } - -inline Point& operator-=(Point& lhs, DeltaX rhs) { lhs.x -= rhs; return lhs; } -inline Point& operator-=(Point& lhs, DeltaY rhs) { lhs.y -= rhs; return lhs; } - -std::ostream& operator<<(std::ostream& out, Point const& value); -} -} - #endif /* MIR_GEOMETRY_POINT_H_ */ diff --git a/include/core/mir/geometry/point_generic.h b/include/core/mir/geometry/point_generic.h new file mode 100644 index 00000000000..83a81749498 --- /dev/null +++ b/include/core/mir/geometry/point_generic.h @@ -0,0 +1,94 @@ +/* + * Copyright © 2020 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License version 2 or 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Authored by: William Wold + */ + +#ifndef MIR_GEOMETRY_POINT_GENERIC_H_ +#define MIR_GEOMETRY_POINT_GENERIC_H_ + +#include "dimensions_generic.h" + +namespace mir +{ +namespace geometry +{ +namespace generic +{ +struct PointBase +{ +}; + +template typename T> +struct Point : PointBase +{ + template + using WrapperType = T; + + constexpr Point() = default; + constexpr Point(Point const&) = default; + Point& operator=(Point const&) = default; + + template + constexpr Point(XType&& x, YType&& y) : x(x), y(y) {} + + T x; + T y; +}; + +template::value, bool>::type = true> +inline constexpr bool operator == (P const& lhs, P const& rhs) +{ + return lhs.x == rhs.x && lhs.y == rhs.y; +} + +template::value, bool>::type = true> +inline constexpr bool operator != (P const& lhs, P const& rhs) +{ + return lhs.x != rhs.x || lhs.y != rhs.y; +} + +template::value, bool>::type = true> +inline constexpr P operator+(P lhs, typename P::template WrapperType rhs) { return{lhs.x + rhs, lhs.y}; } +template::value, bool>::type = true> +inline constexpr P operator+(P lhs, typename P::template WrapperType rhs) { return{lhs.x, lhs.y + rhs}; } + +template::value, bool>::type = true> +inline constexpr P operator-(P lhs, typename P::template WrapperType rhs) { return{lhs.x - rhs, lhs.y}; } +template::value, bool>::type = true> +inline constexpr P operator-(P lhs, typename P::template WrapperType rhs) { return{lhs.x, lhs.y - rhs}; } + +template::value, bool>::type = true> +inline P& operator+=(P& lhs, typename P::template WrapperType rhs) { lhs.x += rhs; return lhs; } +template::value, bool>::type = true> +inline P& operator+=(P& lhs, typename P::template WrapperType rhs) { lhs.y += rhs; return lhs; } + +template::value, bool>::type = true> +inline P& operator-=(P& lhs, typename P::template WrapperType rhs) { lhs.x -= rhs; return lhs; } +template::value, bool>::type = true> +inline P& operator-=(P& lhs, typename P::template WrapperType rhs) { lhs.y -= rhs; return lhs; } + +template::value, bool>::type = true> +std::ostream& operator<<(std::ostream& out, P const& value) +{ + out << value.x << ", " << value.y; + return out; +} + +} +} +} + +#endif // MIR_GEOMETRY_POINT_GENERIC_H_ diff --git a/src/core/geometry/ostream.cpp b/src/core/geometry/ostream.cpp index f803c93bb87..4753ec95e4a 100644 --- a/src/core/geometry/ostream.cpp +++ b/src/core/geometry/ostream.cpp @@ -31,12 +31,6 @@ std::ostream& geom::operator<<(std::ostream& out, Displacement const& value) return out; } -std::ostream& geom::operator<<(std::ostream& out, Point const& value) -{ - out << '(' << value.x << ", " << value.y << ')'; - return out; -} - std::ostream& geom::operator<<(std::ostream& out, Size const& value) { out << '(' << value.width << ", " << value.height << ')'; From 854a7a4f87c9a548ea65afdffa3ce506b2f96245 Mon Sep 17 00:00:00 2001 From: William Wold Date: Mon, 18 Jan 2021 19:20:20 -0800 Subject: [PATCH 07/18] Add FPoint --- include/core/mir/geometry/point_f.h | 44 +++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 include/core/mir/geometry/point_f.h diff --git a/include/core/mir/geometry/point_f.h b/include/core/mir/geometry/point_f.h new file mode 100644 index 00000000000..74a1bc6339d --- /dev/null +++ b/include/core/mir/geometry/point_f.h @@ -0,0 +1,44 @@ +/* + * Copyright © 2021 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License version 2 or 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Authored by: William Wold + +namespace mir +{ +namespace geometry +{ +struct FPoint : generic::Point +{ + template + using WrapperType = detail::FloatWrapper; + + constexpr FPoint() = default; + constexpr FPoint(FPoint const&) = default; + FPoint& operator=(FPoint const&) = default; + + template + constexpr FPoint(XType&& x, YType&& y) : generic::Point{x, y} {} +}; +} +} +#endif // MIR_GEOMETRY_POINT_F_H_ From 963c86817781c6c57e6a9b0450f898532bff7d45 Mon Sep 17 00:00:00 2001 From: William Wold Date: Wed, 20 Jan 2021 11:45:11 -0800 Subject: [PATCH 08/18] Give tag types real declarations --- include/core/mir/geometry/dimensions_generic.h | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/include/core/mir/geometry/dimensions_generic.h b/include/core/mir/geometry/dimensions_generic.h index 618fc8bf1c1..1114150600d 100644 --- a/include/core/mir/geometry/dimensions_generic.h +++ b/include/core/mir/geometry/dimensions_generic.h @@ -29,12 +29,17 @@ namespace mir namespace geometry { -struct WidthTag; -struct HeightTag; -struct XTag; -struct YTag; -struct DeltaXTag; -struct DeltaYTag; +/// These tag types determine what type of dimension a value holds and what operations are possible with it. They are +/// only used as template paramaters, are never instantiated and should only require forward declarations, but some +/// compiler versions seem to fail if they aren't given real declarations. +/// @{ +struct WidthTag{}; +struct HeightTag{}; +struct XTag{}; +struct YTag{}; +struct DeltaXTag{}; +struct DeltaYTag{}; +/// @} namespace generic { From 06b6d3138b63d60b4734c5f7fd1d50ed12cdef64 Mon Sep 17 00:00:00 2001 From: William Wold Date: Wed, 20 Jan 2021 11:54:46 -0800 Subject: [PATCH 09/18] Move F prefix to postfix --- include/core/mir/geometry/dimensions_f.h | 12 ++++++------ include/core/mir/geometry/point_f.h | 10 +++++----- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/core/mir/geometry/dimensions_f.h b/include/core/mir/geometry/dimensions_f.h index 71e4f2a0ffe..1291168d449 100644 --- a/include/core/mir/geometry/dimensions_f.h +++ b/include/core/mir/geometry/dimensions_f.h @@ -55,12 +55,12 @@ class FloatWrapper : public generic::detail::Wrapper }; } // namespace detail -typedef detail::FloatWrapper FWidth; -typedef detail::FloatWrapper FHeight; -typedef detail::FloatWrapper FX; -typedef detail::FloatWrapper FY; -typedef detail::FloatWrapper FDeltaX; -typedef detail::FloatWrapper FDeltaY; +typedef detail::FloatWrapper WidthF; +typedef detail::FloatWrapper HeightF; +typedef detail::FloatWrapper XF; +typedef detail::FloatWrapper YF; +typedef detail::FloatWrapper DeltaXF; +typedef detail::FloatWrapper DeltaYF; } } diff --git a/include/core/mir/geometry/point_f.h b/include/core/mir/geometry/point_f.h index 74a1bc6339d..717e92d430e 100644 --- a/include/core/mir/geometry/point_f.h +++ b/include/core/mir/geometry/point_f.h @@ -27,17 +27,17 @@ namespace mir { namespace geometry { -struct FPoint : generic::Point +struct PointF : generic::Point { template using WrapperType = detail::FloatWrapper; - constexpr FPoint() = default; - constexpr FPoint(FPoint const&) = default; - FPoint& operator=(FPoint const&) = default; + constexpr PointF() = default; + constexpr PointF(PointF const&) = default; + PointF& operator=(PointF const&) = default; template - constexpr FPoint(XType&& x, YType&& y) : generic::Point{x, y} {} + constexpr PointF(XType&& x, YType&& y) : generic::Point{x, y} {} }; } } From 0526fe06aef8e482508744858c270cc8802f53fa Mon Sep 17 00:00:00 2001 From: William Wold Date: Wed, 20 Jan 2021 13:58:01 -0800 Subject: [PATCH 10/18] Allow generic types to be used directly --- include/core/mir/geometry/dimensions.h | 8 +- include/core/mir/geometry/dimensions_f.h | 42 +---- .../core/mir/geometry/dimensions_generic.h | 157 +++++++++--------- include/core/mir/geometry/point_f.h | 13 +- tests/unit-tests/geometry/CMakeLists.txt | 1 + .../geometry/test-dimensions-generic.cpp | 139 ++++++++++++++++ 6 files changed, 229 insertions(+), 131 deletions(-) create mode 100644 tests/unit-tests/geometry/test-dimensions-generic.cpp diff --git a/include/core/mir/geometry/dimensions.h b/include/core/mir/geometry/dimensions.h index 7b6e3302950..f12c2d91ac1 100644 --- a/include/core/mir/geometry/dimensions.h +++ b/include/core/mir/geometry/dimensions.h @@ -32,7 +32,7 @@ namespace geometry namespace detail { template -class IntWrapper : public generic::detail::Wrapper +class IntWrapper : public generic::Value::Wrapper { public: template @@ -41,14 +41,14 @@ class IntWrapper : public generic::detail::Wrapper constexpr IntWrapper() {} template - constexpr IntWrapper(generic::detail::Wrapper const& value) - : generic::detail::Wrapper{value} + constexpr IntWrapper(typename generic::Value::template Wrapper const& value) + : generic::Value::Wrapper{value} { } template explicit constexpr IntWrapper(U const& value) - : generic::detail::Wrapper{value} + : generic::Value::Wrapper{value} { } diff --git a/include/core/mir/geometry/dimensions_f.h b/include/core/mir/geometry/dimensions_f.h index 1291168d449..a6d7ad97cd8 100644 --- a/include/core/mir/geometry/dimensions_f.h +++ b/include/core/mir/geometry/dimensions_f.h @@ -25,42 +25,12 @@ namespace mir { namespace geometry { -namespace detail -{ -template -class FloatWrapper : public generic::detail::Wrapper -{ -public: - template - using WrapperType = FloatWrapper; - - constexpr FloatWrapper() {} - - template - constexpr FloatWrapper(generic::detail::Wrapper const& value) - : generic::detail::Wrapper{value} - { - } - - template - explicit constexpr FloatWrapper(U const& value) - : generic::detail::Wrapper{value} - { - } - - constexpr auto as_float() const -> float - { - return this->value; - } -}; -} // namespace detail - -typedef detail::FloatWrapper WidthF; -typedef detail::FloatWrapper HeightF; -typedef detail::FloatWrapper XF; -typedef detail::FloatWrapper YF; -typedef detail::FloatWrapper DeltaXF; -typedef detail::FloatWrapper DeltaYF; +using WidthF = generic::Width; +using HeightF = generic::Height; +using XF = generic::X; +using YF = generic::Y; +using DeltaXF = generic::DeltaX; +using DeltaYF = generic::DeltaY; } } diff --git a/include/core/mir/geometry/dimensions_generic.h b/include/core/mir/geometry/dimensions_generic.h index 1114150600d..fcbbbaffef9 100644 --- a/include/core/mir/geometry/dimensions_generic.h +++ b/include/core/mir/geometry/dimensions_generic.h @@ -43,102 +43,101 @@ struct DeltaYTag{}; namespace generic { -namespace detail +template +struct Value { -template -class Wrapper -{ -public: - using ValueType = T; - using TagType = Tag; - template - using WrapperType = Wrapper; - - template - constexpr typename std::enable_if::value, int>::type as_int() const + template + class Wrapper { - return this->value; - } + public: + using ValueType = T; + using TagType = Tag; + template + using WrapperType = Wrapper; + using IsGemetryWrapper = void; ///< Used to check if this is a geometry wrapper type - constexpr T as_value() const - { - return value; - } + template + constexpr typename std::enable_if::value, int>::type as_int() const + { + return this->value; + } -protected: - constexpr Wrapper() : value{} {} + constexpr T as_value() const + { + return value; + } - template - Wrapper& operator=(Wrapper const& that) - { - value = static_cast(that.value); - } + constexpr Wrapper() : value{} {} - template - constexpr Wrapper(Wrapper const& value) - : value{static_cast(value.as_value())} - { - } + template::value, bool>::type = true> + Wrapper& operator=(W const& that) + { + value = static_cast(that.value); + } - template - explicit constexpr Wrapper(U const& value) - : value{static_cast(value)} - { - } + template::value, bool>::type = true> + explicit constexpr Wrapper(W const& value) + : value{static_cast(value.as_value())} + { + } - T value; -}; + template::value, bool>::type = true> + explicit constexpr Wrapper(U const& value) + : value{static_cast(value)} + { + } -template -std::ostream& operator<<(std::ostream& out, Wrapper const& value) -{ - out << value.as_value(); - return out; -} + inline constexpr auto operator == (Wrapper const& rhs) const -> bool + { + return value == rhs.as_value(); + } -template -inline constexpr bool operator == (Wrapper const& lhs, Wrapper const& rhs) -{ - return lhs.as_value() == rhs.as_value(); -} + inline constexpr auto operator != (Wrapper const& rhs) const -> bool + { + return value != rhs.as_value(); + } -template -inline constexpr bool operator != (Wrapper const& lhs, Wrapper const& rhs) -{ - return lhs.as_value() != rhs.as_value(); -} + inline constexpr auto operator <= (Wrapper const& rhs) const -> bool + { + return value <= rhs.as_value(); + } -template -inline constexpr bool operator <= (Wrapper const& lhs, Wrapper const& rhs) -{ - return lhs.as_value() <= rhs.as_value(); -} + inline constexpr auto operator >= (Wrapper const& rhs) const -> bool + { + return value >= rhs.as_value(); + } -template -inline constexpr bool operator >= (Wrapper const& lhs, Wrapper const& rhs) -{ - return lhs.as_value() >= rhs.as_value(); -} + inline constexpr auto operator < (Wrapper const& rhs) const -> bool + { + return value < rhs.as_value(); + } -template -inline constexpr bool operator < (Wrapper const& lhs, Wrapper const& rhs) -{ - return lhs.as_value() < rhs.as_value(); -} + inline constexpr auto operator > (Wrapper const& rhs) const -> bool + { + return value > rhs.as_value(); + } -template -inline constexpr bool operator > (Wrapper const& lhs, Wrapper const& rhs) + protected: + T value; + }; + +private: + Value(); +}; + +template::value, bool>::type = true> +std::ostream& operator<<(std::ostream& out, W const& value) { - return lhs.as_value() > rhs.as_value(); + out << value.as_value(); + return out; } -} // namespace detail - -template using Width = detail::Wrapper; -template using Height = detail::Wrapper; -template using X = detail::Wrapper; -template using Y = detail::Wrapper; -template using DeltaX = detail::Wrapper; -template using DeltaY = detail::Wrapper; + +template using Width = typename Value::template Wrapper; +template using Height = typename Value::template Wrapper; +template using X = typename Value::template Wrapper; +template using Y = typename Value::template Wrapper; +template using DeltaX = typename Value::template Wrapper; +template using DeltaY = typename Value::template Wrapper; } // namespace generic // Adding deltas is fine diff --git a/include/core/mir/geometry/point_f.h b/include/core/mir/geometry/point_f.h index 717e92d430e..a6cdea6c024 100644 --- a/include/core/mir/geometry/point_f.h +++ b/include/core/mir/geometry/point_f.h @@ -27,18 +27,7 @@ namespace mir { namespace geometry { -struct PointF : generic::Point -{ - template - using WrapperType = detail::FloatWrapper; - - constexpr PointF() = default; - constexpr PointF(PointF const&) = default; - PointF& operator=(PointF const&) = default; - - template - constexpr PointF(XType&& x, YType&& y) : generic::Point{x, y} {} -}; +using PointF = generic::Point::Wrapper>; } } #endif // MIR_GEOMETRY_POINT_F_H_ diff --git a/tests/unit-tests/geometry/CMakeLists.txt b/tests/unit-tests/geometry/CMakeLists.txt index 6492f7953ff..8470b0b20b5 100644 --- a/tests/unit-tests/geometry/CMakeLists.txt +++ b/tests/unit-tests/geometry/CMakeLists.txt @@ -1,5 +1,6 @@ list(APPEND UNIT_TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test-dimensions.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/test-dimensions-generic.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test-size.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test-point.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test-displacement.cpp diff --git a/tests/unit-tests/geometry/test-dimensions-generic.cpp b/tests/unit-tests/geometry/test-dimensions-generic.cpp new file mode 100644 index 00000000000..8d5c44b4089 --- /dev/null +++ b/tests/unit-tests/geometry/test-dimensions-generic.cpp @@ -0,0 +1,139 @@ +/* + * Copyright © 2021 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authored by: William Wold + */ + +#include "mir/geometry/dimensions_generic.h" + +#include "boost/throw_exception.hpp" +#include +#include + +using namespace mir::geometry::generic; +using namespace mir::geometry; + +TEST(geometry, generic_casting_between_same_tag) +{ + Width const width_i {42}; + Width const width_f{width_i}; + + EXPECT_EQ(width_i, static_cast>(width_f)); +} + +TEST(geometry, generic_width) +{ + Width width0 {0}; + Width width42 {42}; + + EXPECT_EQ(uint32_t{0}, width0.as_value()); + EXPECT_EQ(uint32_t{42}, width42.as_value()); + + EXPECT_EQ(width0, width0); + EXPECT_NE(width0, width42); + EXPECT_EQ(width42, width42); + EXPECT_NE(width42, width0); +} + +TEST(geometry, generic_height) +{ + Height height0 {0}; + Height height42 {42}; + + EXPECT_EQ(uint32_t{0}, height0.as_value()); + EXPECT_EQ(uint32_t{42}, height42.as_value()); + + EXPECT_EQ(height0, height0); + EXPECT_NE(height0, height42); + EXPECT_EQ(height42, height42); + EXPECT_NE(height42, height0); +} + +TEST(geometry, generic_delta_arithmetic) +{ + DeltaX dx1{1}; + + DeltaX x2 = DeltaX(1) + dx1; + EXPECT_EQ(DeltaX(2), x2); + EXPECT_EQ(DeltaX(1), x2-dx1); +} + +TEST(geometry, generic_coordinates) +{ + X x1{1}; + X x2{2}; + DeltaX dx1{1}; + + EXPECT_EQ(X(2), x1 + dx1); + EXPECT_EQ(X(1), x2 - dx1); + + Y y24{24}; + Y y42{42}; + DeltaY dx18{18}; + + EXPECT_EQ(dx18, y42 - y24); +} + +TEST(geometry, generic_conversions) +{ + Width w1{1}; + DeltaX dx1{1}; + + EXPECT_EQ(w1, mir::geometry::dim_cast>(dx1)); + EXPECT_EQ(dx1, mir::geometry::dim_cast>(w1)); + EXPECT_NE(dx1, mir::geometry::dim_cast>(X())); +} + +TEST(geometry, generic_signed_dimensions) +{ + X const x0{0}; + X const x2{2}; + X const xn5{-5}; + Y const y0{0}; + Y const y3{3}; + Y const yn6{-6}; + Y const yn7{-7}; + + // Compare against zero to catch regressions of signed->unsigned that + // wouldn't be caught using as_*int()... + EXPECT_GT(x0, xn5); + EXPECT_GT(y0, yn7); + + EXPECT_LT(xn5, x0); + EXPECT_LT(xn5, x2); + EXPECT_LT(yn7, yn6); + EXPECT_LT(yn7, y0); + EXPECT_LT(yn7, y3); + + EXPECT_LE(xn5, x0); + EXPECT_LE(xn5, x2); + EXPECT_LE(yn7, yn6); + EXPECT_LE(yn7, y0); + EXPECT_LE(yn7, y3); + EXPECT_LE(yn7, yn7); + + EXPECT_GT(x0, xn5); + EXPECT_GT(x2, xn5); + EXPECT_GT(yn6, yn7); + EXPECT_GT(y0, yn7); + EXPECT_GT(y3, yn7); + + EXPECT_GE(x0, xn5); + EXPECT_GE(x2, xn5); + EXPECT_GE(yn6, yn7); + EXPECT_GE(y0, yn7); + EXPECT_GE(y3, yn7); + EXPECT_GE(yn7, yn7); +} From d18da3b8b458a14fa6bc18f5ef08f8ab45092d56 Mon Sep 17 00:00:00 2001 From: William Wold Date: Wed, 20 Jan 2021 14:04:55 -0800 Subject: [PATCH 11/18] Use base structs in detail namespace to determine types --- .../core/mir/geometry/dimensions_generic.h | 14 ++++++-- include/core/mir/geometry/point_generic.h | 32 +++++++++---------- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/include/core/mir/geometry/dimensions_generic.h b/include/core/mir/geometry/dimensions_generic.h index fcbbbaffef9..693c81ba7e5 100644 --- a/include/core/mir/geometry/dimensions_generic.h +++ b/include/core/mir/geometry/dimensions_generic.h @@ -41,15 +41,23 @@ struct DeltaXTag{}; struct DeltaYTag{}; /// @} +namespace detail +{ +struct ValueWrapperBase{}; // Used for determining if a type is a wrapper +} + namespace generic { template struct Value { + /// Wraps a geometry value and prevents it from being accidentally used for invalid operations (such as setting a + /// width to a height or adding two x positions together). Of course, explicit casts are possible to get around + /// these restrictions (see the as_*() functions). int values (which are most values) should use the + /// derived IntWrapper class, and other types should use this directly. template - class Wrapper + struct Wrapper: detail::ValueWrapperBase { - public: using ValueType = T; using TagType = Tag; template @@ -125,7 +133,7 @@ struct Value Value(); }; -template::value, bool>::type = true> +template::value, bool>::type = true> std::ostream& operator<<(std::ostream& out, W const& value) { out << value.as_value(); diff --git a/include/core/mir/geometry/point_generic.h b/include/core/mir/geometry/point_generic.h index 83a81749498..3a6e32a56cb 100644 --- a/include/core/mir/geometry/point_generic.h +++ b/include/core/mir/geometry/point_generic.h @@ -25,14 +25,14 @@ namespace mir { namespace geometry { -namespace generic +namespace detail { -struct PointBase +struct PointBase{}; ///< Used for determining if a type is a point +} +namespace generic { -}; - template typename T> -struct Point : PointBase +struct Point : detail::PointBase { template using WrapperType = T; @@ -48,39 +48,39 @@ struct Point : PointBase T y; }; -template::value, bool>::type = true> +template::value, bool>::type = true> inline constexpr bool operator == (P const& lhs, P const& rhs) { return lhs.x == rhs.x && lhs.y == rhs.y; } -template::value, bool>::type = true> +template::value, bool>::type = true> inline constexpr bool operator != (P const& lhs, P const& rhs) { return lhs.x != rhs.x || lhs.y != rhs.y; } -template::value, bool>::type = true> +template::value, bool>::type = true> inline constexpr P operator+(P lhs, typename P::template WrapperType rhs) { return{lhs.x + rhs, lhs.y}; } -template::value, bool>::type = true> +template::value, bool>::type = true> inline constexpr P operator+(P lhs, typename P::template WrapperType rhs) { return{lhs.x, lhs.y + rhs}; } -template::value, bool>::type = true> +template::value, bool>::type = true> inline constexpr P operator-(P lhs, typename P::template WrapperType rhs) { return{lhs.x - rhs, lhs.y}; } -template::value, bool>::type = true> +template::value, bool>::type = true> inline constexpr P operator-(P lhs, typename P::template WrapperType rhs) { return{lhs.x, lhs.y - rhs}; } -template::value, bool>::type = true> +template::value, bool>::type = true> inline P& operator+=(P& lhs, typename P::template WrapperType rhs) { lhs.x += rhs; return lhs; } -template::value, bool>::type = true> +template::value, bool>::type = true> inline P& operator+=(P& lhs, typename P::template WrapperType rhs) { lhs.y += rhs; return lhs; } -template::value, bool>::type = true> +template::value, bool>::type = true> inline P& operator-=(P& lhs, typename P::template WrapperType rhs) { lhs.x -= rhs; return lhs; } -template::value, bool>::type = true> +template::value, bool>::type = true> inline P& operator-=(P& lhs, typename P::template WrapperType rhs) { lhs.y -= rhs; return lhs; } -template::value, bool>::type = true> +template::value, bool>::type = true> std::ostream& operator<<(std::ostream& out, P const& value) { out << value.x << ", " << value.y; From c51d57abc91a5b1b38af3347a728014dad9aea11 Mon Sep 17 00:00:00 2001 From: William Wold Date: Mon, 1 Feb 2021 12:40:58 -0800 Subject: [PATCH 12/18] Simplify constructors --- include/core/mir/geometry/dimensions.h | 14 ++------------ include/core/mir/geometry/point.h | 5 ++--- 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/include/core/mir/geometry/dimensions.h b/include/core/mir/geometry/dimensions.h index f12c2d91ac1..851ea51eb59 100644 --- a/include/core/mir/geometry/dimensions.h +++ b/include/core/mir/geometry/dimensions.h @@ -38,19 +38,9 @@ class IntWrapper : public generic::Value::Wrapper template using WrapperType = IntWrapper; - constexpr IntWrapper() {} - - template - constexpr IntWrapper(typename generic::Value::template Wrapper const& value) - : generic::Value::Wrapper{value} - { - } + using generic::Value::Wrapper::Wrapper; - template - explicit constexpr IntWrapper(U const& value) - : generic::Value::Wrapper{value} - { - } + constexpr IntWrapper() {} constexpr uint32_t as_uint32_t() const // TODO: Deprecate this later { diff --git a/include/core/mir/geometry/point.h b/include/core/mir/geometry/point.h index 9cf57de8244..547f6b50300 100644 --- a/include/core/mir/geometry/point.h +++ b/include/core/mir/geometry/point.h @@ -32,12 +32,11 @@ struct Point : generic::Point template using WrapperType = detail::IntWrapper; + using generic::Point::Point; + constexpr Point() = default; constexpr Point(Point const&) = default; Point& operator=(Point const&) = default; - - template - constexpr Point(XType&& x, YType&& y) : generic::Point{x, y} {} }; } } From 7ee986fe53ff9e3c6e695c61db0baa62fbdc185f Mon Sep 17 00:00:00 2001 From: William Wold Date: Mon, 1 Feb 2021 13:33:30 -0800 Subject: [PATCH 13/18] Add generic size --- include/core/mir/geometry/point.h | 10 +- include/core/mir/geometry/point_generic.h | 7 +- include/core/mir/geometry/size.h | 57 +---------- include/core/mir/geometry/size_generic.h | 109 ++++++++++++++++++++++ src/core/geometry/ostream.cpp | 6 -- 5 files changed, 122 insertions(+), 67 deletions(-) create mode 100644 include/core/mir/geometry/size_generic.h diff --git a/include/core/mir/geometry/point.h b/include/core/mir/geometry/point.h index 547f6b50300..4677a1b29aa 100644 --- a/include/core/mir/geometry/point.h +++ b/include/core/mir/geometry/point.h @@ -21,22 +21,16 @@ #include "dimensions.h" #include "point_generic.h" -#include namespace mir { namespace geometry { +struct Size; struct Point : generic::Point { - template - using WrapperType = detail::IntWrapper; - + using SizeType = Size; using generic::Point::Point; - - constexpr Point() = default; - constexpr Point(Point const&) = default; - Point& operator=(Point const&) = default; }; } } diff --git a/include/core/mir/geometry/point_generic.h b/include/core/mir/geometry/point_generic.h index 3a6e32a56cb..29b1d3ff54b 100644 --- a/include/core/mir/geometry/point_generic.h +++ b/include/core/mir/geometry/point_generic.h @@ -19,7 +19,7 @@ #ifndef MIR_GEOMETRY_POINT_GENERIC_H_ #define MIR_GEOMETRY_POINT_GENERIC_H_ -#include "dimensions_generic.h" +#include namespace mir { @@ -31,12 +31,17 @@ struct PointBase{}; ///< Used for determining if a type is a point } namespace generic { +template typename T> +struct Size; + template typename T> struct Point : detail::PointBase { template using WrapperType = T; + using SizeType = Size; + constexpr Point() = default; constexpr Point(Point const&) = default; Point& operator=(Point const&) = default; diff --git a/include/core/mir/geometry/size.h b/include/core/mir/geometry/size.h index 6bd077ce9df..cce8f541e0d 100644 --- a/include/core/mir/geometry/size.h +++ b/include/core/mir/geometry/size.h @@ -20,66 +20,19 @@ #define MIR_GEOMETRY_SIZE_H_ #include "mir/geometry/dimensions.h" +#include "size_generic.h" #include "point.h" -#include namespace mir { namespace geometry { - -struct Size +struct Point; +struct Size : generic::Size { - constexpr Size() noexcept {} - constexpr Size(Size const&) noexcept = default; - Size& operator=(Size const&) noexcept = default; - - template - constexpr Size(WidthType&& width, HeightType&& height) noexcept : width(width), height(height) {} - - Width width; - Height height; + using PointType = Point; + using generic::Size::Size; }; - -inline constexpr bool operator == (Size const& lhs, Size const& rhs) -{ - return lhs.width == rhs.width && lhs.height == rhs.height; -} - -inline constexpr bool operator != (Size const& lhs, Size const& rhs) -{ - return lhs.width != rhs.width || lhs.height != rhs.height; -} - -std::ostream& operator<<(std::ostream& out, Size const& value); - -template -inline constexpr Size operator*(Scalar scale, Size const& size) -{ - return Size{scale*size.width, scale*size.height}; -} - -template -inline constexpr Size operator*(Size const& size, Scalar scale) -{ - return scale*size; -} - -template -inline constexpr Size operator/(Size const& size, Scalar scale) -{ - return Size{size.width / scale, size.height / scale}; -} - -inline constexpr Size as_size(Point const& point) -{ - return Size{point.x.as_int(), point.y.as_int()}; -} - -inline constexpr Point as_point(Size const& size) -{ - return Point{size.width.as_int(), size.height.as_int()}; -} } } diff --git a/include/core/mir/geometry/size_generic.h b/include/core/mir/geometry/size_generic.h new file mode 100644 index 00000000000..2710f133051 --- /dev/null +++ b/include/core/mir/geometry/size_generic.h @@ -0,0 +1,109 @@ +/* + * Copyright © 2021 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License version 2 or 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Authored by: William Wold + */ + +#ifndef MIR_GEOMETRY_SIZE_GENERIC_H_ +#define MIR_GEOMETRY_SIZE_GENERIC_H_ + +#include + +namespace mir +{ +namespace geometry +{ +namespace detail +{ +struct PointBase; +struct SizeBase{}; ///< Used for determining if a type is a size +} +namespace generic +{ +template typename T> +struct Point; + +template typename T> +struct Size : detail::SizeBase +{ + template + using WrapperType = T; + + using PointType = Point; + + constexpr Size() noexcept {} + constexpr Size(Size const&) noexcept = default; + Size& operator=(Size const&) noexcept = default; + + template + constexpr Size(WidthType&& width, HeightType&& height) noexcept : width(width), height(height) {} + + T width; + T height; +}; + +template::value, bool>::type = true> +inline constexpr bool operator == (S const& lhs, S const& rhs) +{ + return lhs.width == rhs.width && lhs.height == rhs.height; +} + +template::value, bool>::type = true> +inline constexpr bool operator != (S const& lhs, S const& rhs) +{ + return lhs.width != rhs.width || lhs.height != rhs.height; +} + +template::value, bool>::type = true> +std::ostream& operator<<(std::ostream& out, S const& value) +{ + out << '(' << value.width << ", " << value.height << ')'; + return out; +} + +template::value, bool>::type = true> +inline constexpr S operator*(Scalar scale, S const& size) +{ + return S{scale*size.width, scale*size.height}; +} + +template::value, bool>::type = true> +inline constexpr S operator*(S const& size, Scalar scale) +{ + return scale*size; +} + +template::value, bool>::type = true> +inline constexpr S operator/(S const& size, Scalar scale) +{ + return S{size.width / scale, size.height / scale}; +} + +template::value, bool>::type = true> +inline constexpr typename P::SizeType as_size(P const& point) +{ + return typename P::SizeType{point.x.as_int(), point.y.as_int()}; +} + +template::value, bool>::type = true> +inline constexpr typename S::PointType as_point(S const& size) +{ + return typename S::PointType{size.width.as_int(), size.height.as_int()}; +} +} +} +} + +#endif // MIR_GEOMETRY_SIZE_GENERIC_H_ diff --git a/src/core/geometry/ostream.cpp b/src/core/geometry/ostream.cpp index 4753ec95e4a..68880e1d21b 100644 --- a/src/core/geometry/ostream.cpp +++ b/src/core/geometry/ostream.cpp @@ -31,12 +31,6 @@ std::ostream& geom::operator<<(std::ostream& out, Displacement const& value) return out; } -std::ostream& geom::operator<<(std::ostream& out, Size const& value) -{ - out << '(' << value.width << ", " << value.height << ')'; - return out; -} - std::ostream& geom::operator<<(std::ostream& out, Rectangle const& value) { out << '(' << value.top_left << ", " << value.size << ')'; From 83be45c60df388585c91eb471ee4826169d1a648 Mon Sep 17 00:00:00 2001 From: William Wold Date: Mon, 1 Feb 2021 14:14:00 -0800 Subject: [PATCH 14/18] Add generic displacement --- include/core/mir/geometry/displacement.h | 117 +---------- .../core/mir/geometry/displacement_generic.h | 181 ++++++++++++++++++ include/core/mir/geometry/point.h | 4 +- include/core/mir/geometry/point_generic.h | 4 + include/core/mir/geometry/size.h | 5 +- include/core/mir/geometry/size_generic.h | 4 + src/core/geometry/ostream.cpp | 6 - 7 files changed, 203 insertions(+), 118 deletions(-) create mode 100644 include/core/mir/geometry/displacement_generic.h diff --git a/include/core/mir/geometry/displacement.h b/include/core/mir/geometry/displacement.h index e11303568f1..a4adf92d775 100644 --- a/include/core/mir/geometry/displacement.h +++ b/include/core/mir/geometry/displacement.h @@ -19,129 +19,28 @@ #ifndef MIR_GEOMETRY_DISPLACEMENT_H_ #define MIR_GEOMETRY_DISPLACEMENT_H_ -#include "mir/geometry/dimensions.h" -#include "mir/geometry/point.h" -#include "mir/geometry/size.h" - -#include +#include "displacement_generic.h" +#include "dimensions.h" +#include "point.h" +#include "size.h" namespace mir { namespace geometry { - -struct Displacement +struct Displacement : generic::Displacement { - constexpr Displacement() {} - constexpr Displacement(Displacement const&) = default; - Displacement& operator=(Displacement const&) = default; + using PointType = Point; + using SizeType = Size; - template - constexpr Displacement(DeltaXType&& dx, DeltaYType&& dy) : dx{dx}, dy{dy} {} + using generic::Displacement::Displacement; long long length_squared() const { long long x = dx.as_int(), y = dy.as_int(); return x * x + y * y; } - - DeltaX dx; - DeltaY dy; }; - -inline constexpr bool operator==(Displacement const& lhs, Displacement const& rhs) -{ - return lhs.dx == rhs.dx && lhs.dy == rhs.dy; -} - -inline constexpr bool operator!=(Displacement const& lhs, Displacement const& rhs) -{ - return lhs.dx != rhs.dx || lhs.dy != rhs.dy; -} - -std::ostream& operator<<(std::ostream& out, Displacement const& value); - -inline constexpr Displacement operator+(Displacement const& lhs, Displacement const& rhs) -{ - return Displacement{lhs.dx + rhs.dx, lhs.dy + rhs.dy}; -} - -inline constexpr Displacement operator-(Displacement const& lhs, Displacement const& rhs) -{ - return Displacement{lhs.dx - rhs.dx, lhs.dy - rhs.dy}; -} - -inline constexpr Displacement operator-(Displacement const& rhs) -{ - return Displacement{-rhs.dx, -rhs.dy}; -} - -inline constexpr Point operator+(Point const& lhs, Displacement const& rhs) -{ - return Point{lhs.x + rhs.dx, lhs.y + rhs.dy}; -} - -inline constexpr Point operator+(Displacement const& lhs, Point const& rhs) -{ - return Point{rhs.x + lhs.dx, rhs.y + lhs.dy}; -} - -inline constexpr Point operator-(Point const& lhs, Displacement const& rhs) -{ - return Point{lhs.x - rhs.dx, lhs.y - rhs.dy}; -} - -inline constexpr Displacement operator-(Point const& lhs, Point const& rhs) -{ - return Displacement{lhs.x - rhs.x, lhs.y - rhs.y}; -} - -inline constexpr Point& operator+=(Point& lhs, Displacement const& rhs) -{ - return lhs = lhs + rhs; -} - -inline constexpr Point& operator-=(Point& lhs, Displacement const& rhs) -{ - return lhs = lhs - rhs; -} - -inline bool operator<(Displacement const& lhs, Displacement const& rhs) -{ - return lhs.length_squared() < rhs.length_squared(); -} - -template -inline constexpr Displacement operator*(Scalar scale, Displacement const& disp) -{ - return Displacement{scale*disp.dx, scale*disp.dy}; -} - -template -inline constexpr Displacement operator*(Displacement const& disp, Scalar scale) -{ - return scale*disp; -} - -inline constexpr Displacement as_displacement(Size const& size) -{ - return Displacement{size.width.as_int(), size.height.as_int()}; -} - -inline constexpr Size as_size(Displacement const& disp) -{ - return Size{disp.dx.as_int(), disp.dy.as_int()}; -} - -inline constexpr Displacement as_displacement(Point const& point) -{ - return Displacement{point.x.as_int(), point.y.as_int()}; -} - -inline constexpr Point as_point(Displacement const& disp) -{ - return Point{disp.dx.as_int(), disp.dy.as_int()}; -} } } diff --git a/include/core/mir/geometry/displacement_generic.h b/include/core/mir/geometry/displacement_generic.h new file mode 100644 index 00000000000..37ae6347652 --- /dev/null +++ b/include/core/mir/geometry/displacement_generic.h @@ -0,0 +1,181 @@ +/* + * Copyright © 2021 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License version 2 or 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Authored by: William Wold + */ + +#ifndef MIR_GEOMETRY_DISPLACEMENT_GENERIC_H_ +#define MIR_GEOMETRY_DISPLACEMENT_GENERIC_H_ + +#include "dimensions_generic.h" +#include + +namespace mir +{ +namespace geometry +{ +namespace detail +{ +struct PointBase; +struct SizeBase; +struct DisplacementBase{}; ///< Used for determining if a type is a displacement +} +namespace generic +{ +template typename T> +struct Point; + +template typename T> +struct Size; + +template typename T> +struct Displacement : detail::DisplacementBase +{ + template + using WrapperType = T; + + using PointType = Point; + using SizeType = Size; + + constexpr Displacement() {} + constexpr Displacement(Displacement const&) = default; + Displacement& operator=(Displacement const&) = default; + + template + constexpr Displacement(DeltaXType&& dx, DeltaYType&& dy) : dx{dx}, dy{dy} {} + + T dx; + T dy; +}; + +template::value, bool>::type = true> +inline constexpr bool operator==(D const& lhs, D const& rhs) +{ + return lhs.dx == rhs.dx && lhs.dy == rhs.dy; +} + +template::value, bool>::type = true> +inline constexpr bool operator!=(D const& lhs, D const& rhs) +{ + return lhs.dx != rhs.dx || lhs.dy != rhs.dy; +} + +template::value, bool>::type = true> +std::ostream& operator<<(std::ostream& out, D const& value) +{ + out << '(' << value.dx << ", " << value.dy << ')'; + return out; +} + +template::value, bool>::type = true> +inline constexpr D operator+(D const& lhs, D const& rhs) +{ + return D{lhs.dx + rhs.dx, lhs.dy + rhs.dy}; +} + +template::value, bool>::type = true> +inline constexpr D operator-(D const& lhs, D const& rhs) +{ + return D{lhs.dx - rhs.dx, lhs.dy - rhs.dy}; +} + +template::value, bool>::type = true> +inline constexpr D operator-(D const& rhs) +{ + return D{-rhs.dx, -rhs.dy}; +} + +template::value, bool>::type = true> +inline constexpr typename D::PointType operator+(typename D::PointType const& lhs, D const& rhs) +{ + return typename D::PointType{lhs.x + rhs.dx, lhs.y + rhs.dy}; +} + +template::value, bool>::type = true> +inline constexpr typename D::PointType operator+(D const& lhs, typename D::PointType const& rhs) +{ + return typename D::PointType{rhs.x + lhs.dx, rhs.y + lhs.dy}; +} + +template::value, bool>::type = true> +inline constexpr typename D::PointType operator-(typename D::PointType const& lhs, D const& rhs) +{ + return typename D::PointType{lhs.x - rhs.dx, lhs.y - rhs.dy}; +} + +template::value, bool>::type = true> +inline constexpr typename P::DisplacementType operator-(P const& lhs, P const& rhs) +{ + return typename P::DisplacementType{lhs.x - rhs.x, lhs.y - rhs.y}; +} + +template::value, bool>::type = true> +inline constexpr typename D::PointType& operator+=(typename D::PointType& lhs, D const& rhs) +{ + return lhs = lhs + rhs; +} + +template::value, bool>::type = true> +inline constexpr typename D::PointType& operator-=(typename D::PointType& lhs, D const& rhs) +{ + return lhs = lhs - rhs; +} + +template::value, bool>::type = true> +inline bool operator<(D const& lhs, D const& rhs) +{ + return lhs.length_squared() < rhs.length_squared(); +} + +template::value, bool>::type = true> +inline constexpr D operator*(Scalar scale, D const& disp) +{ + return D{scale*disp.dx, scale*disp.dy}; +} + +template::value, bool>::type = true> +inline constexpr D operator*(D const& disp, Scalar scale) +{ + return scale*disp; +} + +template::value, bool>::type = true> +inline constexpr typename S::DisplacementType as_displacement(S const& size) +{ + return typename S::DisplacementType{size.width.as_int(), size.height.as_int()}; +} + +template::value, bool>::type = true> +inline constexpr typename D::SizeType as_size(D const& disp) +{ + return typename D::SizeType{disp.dx.as_int(), disp.dy.as_int()}; +} + +template::value, bool>::type = true> +inline constexpr typename P::DisplacementType as_displacement(P const& point) +{ + return typename P::DisplacementType{point.x.as_int(), point.y.as_int()}; +} + +template::value, bool>::type = true> +inline constexpr typename D::PointType as_point(D const& disp) +{ + return typename D::PointType{disp.dx.as_int(), disp.dy.as_int()}; +} +} +} +} + +#endif // MIR_GEOMETRY_DISPLACEMENT_GENERIC_H_ diff --git a/include/core/mir/geometry/point.h b/include/core/mir/geometry/point.h index 4677a1b29aa..11744bdcc2b 100644 --- a/include/core/mir/geometry/point.h +++ b/include/core/mir/geometry/point.h @@ -19,17 +19,19 @@ #ifndef MIR_GEOMETRY_POINT_H_ #define MIR_GEOMETRY_POINT_H_ -#include "dimensions.h" #include "point_generic.h" +#include "dimensions.h" namespace mir { namespace geometry { struct Size; +struct Displacement; struct Point : generic::Point { using SizeType = Size; + using DisplacementType = Displacement; using generic::Point::Point; }; } diff --git a/include/core/mir/geometry/point_generic.h b/include/core/mir/geometry/point_generic.h index 29b1d3ff54b..006910bf28d 100644 --- a/include/core/mir/geometry/point_generic.h +++ b/include/core/mir/geometry/point_generic.h @@ -19,6 +19,7 @@ #ifndef MIR_GEOMETRY_POINT_GENERIC_H_ #define MIR_GEOMETRY_POINT_GENERIC_H_ +#include "dimensions_generic.h" #include namespace mir @@ -33,6 +34,8 @@ namespace generic { template typename T> struct Size; +template typename T> +struct Displacement; template typename T> struct Point : detail::PointBase @@ -41,6 +44,7 @@ struct Point : detail::PointBase using WrapperType = T; using SizeType = Size; + using DisplacementType = Displacement; constexpr Point() = default; constexpr Point(Point const&) = default; diff --git a/include/core/mir/geometry/size.h b/include/core/mir/geometry/size.h index cce8f541e0d..012d02a7a1f 100644 --- a/include/core/mir/geometry/size.h +++ b/include/core/mir/geometry/size.h @@ -19,18 +19,19 @@ #ifndef MIR_GEOMETRY_SIZE_H_ #define MIR_GEOMETRY_SIZE_H_ -#include "mir/geometry/dimensions.h" #include "size_generic.h" -#include "point.h" +#include "dimensions.h" namespace mir { namespace geometry { struct Point; +struct Displacement; struct Size : generic::Size { using PointType = Point; + using DisplacementType = Displacement; using generic::Size::Size; }; } diff --git a/include/core/mir/geometry/size_generic.h b/include/core/mir/geometry/size_generic.h index 2710f133051..961fb294635 100644 --- a/include/core/mir/geometry/size_generic.h +++ b/include/core/mir/geometry/size_generic.h @@ -19,6 +19,7 @@ #ifndef MIR_GEOMETRY_SIZE_GENERIC_H_ #define MIR_GEOMETRY_SIZE_GENERIC_H_ +#include "dimensions_generic.h" #include namespace mir @@ -34,6 +35,8 @@ namespace generic { template typename T> struct Point; +template typename T> +struct Displacement; template typename T> struct Size : detail::SizeBase @@ -42,6 +45,7 @@ struct Size : detail::SizeBase using WrapperType = T; using PointType = Point; + using DisplacementType = Displacement; constexpr Size() noexcept {} constexpr Size(Size const&) noexcept = default; diff --git a/src/core/geometry/ostream.cpp b/src/core/geometry/ostream.cpp index 68880e1d21b..6ff4801d0e3 100644 --- a/src/core/geometry/ostream.cpp +++ b/src/core/geometry/ostream.cpp @@ -25,12 +25,6 @@ namespace geom = mir::geometry; -std::ostream& geom::operator<<(std::ostream& out, Displacement const& value) -{ - out << '(' << value.dx << ", " << value.dy << ')'; - return out; -} - std::ostream& geom::operator<<(std::ostream& out, Rectangle const& value) { out << '(' << value.top_left << ", " << value.size << ')'; From 3a6a5eff599d2ea28262b8140ee38bd2b674bb4c Mon Sep 17 00:00:00 2001 From: William Wold Date: Mon, 1 Feb 2021 15:08:53 -0800 Subject: [PATCH 15/18] Add generic rectangle class --- .../core/mir/geometry/displacement_generic.h | 2 +- include/core/mir/geometry/point_f.h | 1 - include/core/mir/geometry/point_generic.h | 2 +- include/core/mir/geometry/rectangle.h | 57 +------ include/core/mir/geometry/rectangle_generic.h | 153 ++++++++++++++++++ include/core/mir/geometry/size_generic.h | 2 +- src/core/CMakeLists.txt | 2 - src/core/geometry/CMakeLists.txt | 2 - src/core/geometry/ostream.cpp | 41 ----- src/core/geometry/rectangle.cpp | 87 ---------- src/core/geometry/rectangles.cpp | 10 ++ 11 files changed, 173 insertions(+), 186 deletions(-) create mode 100644 include/core/mir/geometry/rectangle_generic.h delete mode 100644 src/core/geometry/ostream.cpp delete mode 100644 src/core/geometry/rectangle.cpp diff --git a/include/core/mir/geometry/displacement_generic.h b/include/core/mir/geometry/displacement_generic.h index 37ae6347652..e66635c231d 100644 --- a/include/core/mir/geometry/displacement_generic.h +++ b/include/core/mir/geometry/displacement_generic.h @@ -20,7 +20,7 @@ #define MIR_GEOMETRY_DISPLACEMENT_GENERIC_H_ #include "dimensions_generic.h" -#include +#include namespace mir { diff --git a/include/core/mir/geometry/point_f.h b/include/core/mir/geometry/point_f.h index a6cdea6c024..2036fd0130f 100644 --- a/include/core/mir/geometry/point_f.h +++ b/include/core/mir/geometry/point_f.h @@ -21,7 +21,6 @@ #include "dimensions_f.h" #include "point_generic.h" -#include namespace mir { diff --git a/include/core/mir/geometry/point_generic.h b/include/core/mir/geometry/point_generic.h index 006910bf28d..fc6546294ef 100644 --- a/include/core/mir/geometry/point_generic.h +++ b/include/core/mir/geometry/point_generic.h @@ -20,7 +20,7 @@ #define MIR_GEOMETRY_POINT_GENERIC_H_ #include "dimensions_generic.h" -#include +#include namespace mir { diff --git a/include/core/mir/geometry/rectangle.h b/include/core/mir/geometry/rectangle.h index 1ec9d2e232c..9bc69955b93 100644 --- a/include/core/mir/geometry/rectangle.h +++ b/include/core/mir/geometry/rectangle.h @@ -20,68 +20,25 @@ #ifndef MIR_GEOMETRY_RECTANGLE_H_ #define MIR_GEOMETRY_RECTANGLE_H_ -#include "mir/geometry/point.h" +#include "rectangle_generic.h" +#include "point.h" #include "size.h" - -#include +#include "displacement.h" namespace mir { namespace geometry { -struct Rectangle +struct Rectangle : generic::Rectangle { - constexpr Rectangle() = default; + using generic::Rectangle::Rectangle; - constexpr Rectangle(Point const& top_left, Size const& size) - : top_left{top_left}, size{size} + Rectangle intersection_with(Rectangle const& r) const { + return intersection_of(*this, r); } - - Point top_left; - Size size; - - /** - * The bottom right boundary point of the rectangle. - * - * Note that the returned point is *not* included in the rectangle - * area, that is, the rectangle is represented as [top_left,bottom_right). - */ - Point bottom_right() const; - Point top_right() const; - Point bottom_left() const; - bool contains(Point const& p) const; - - /** - * Test if the rectangle contains another. - * - * Note that an empty rectangle can still contain other empty rectangles, - * which are treated as points or lines of thickness zero. - */ - bool contains(Rectangle const& r) const; - - bool overlaps(Rectangle const& r) const; - - Rectangle intersection_with(Rectangle const& r) const; - - X left() const { return top_left.x; } - X right() const { return bottom_right().x; } - Y top() const { return top_left.y; } - Y bottom() const { return bottom_right().y; } }; - -inline constexpr bool operator == (Rectangle const& lhs, Rectangle const& rhs) -{ - return lhs.top_left == rhs.top_left && lhs.size == rhs.size; -} - -inline constexpr bool operator != (Rectangle const& lhs, Rectangle const& rhs) -{ - return lhs.top_left != rhs.top_left || lhs.size != rhs.size; -} - -std::ostream& operator<<(std::ostream& out, Rectangle const& value); } } diff --git a/include/core/mir/geometry/rectangle_generic.h b/include/core/mir/geometry/rectangle_generic.h new file mode 100644 index 00000000000..5fb1d6bfc60 --- /dev/null +++ b/include/core/mir/geometry/rectangle_generic.h @@ -0,0 +1,153 @@ +/* + * Copyright © 2021 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License version 2 or 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Authored by: William Wold + */ + +#ifndef MIR_GEOMETRY_RECTANGLE_GENERIC_H_ +#define MIR_GEOMETRY_RECTANGLE_GENERIC_H_ + +#include "point_generic.h" +#include "size_generic.h" +#include "displacement_generic.h" + +#include + +namespace mir +{ +namespace geometry +{ +namespace detail +{ +struct RectangleBase{}; ///< Used for determining if a type is a rectangle +} +namespace generic +{ +template +struct Rectangle : detail::RectangleBase +{ + constexpr Rectangle() = default; + + constexpr Rectangle(P const& top_left, S const& size) + : top_left{top_left}, size{size} + { + } + + /** + * The bottom right boundary point of the rectangle. + * + * Note that the returned point is *not* included in the rectangle + * area, that is, the rectangle is represented as [top_left,bottom_right). + */ + P bottom_right() const + { + return top_left + as_displacement(size); + } + + P top_right() const + { + return top_left + as_delta(size.width); + } + + P bottom_left() const + { + return top_left + as_delta(size.height); + } + + bool contains(P const& p) const + { + if (size.width == decltype(size.width){} || size.height == decltype(size.height){}) + return false; + + auto br = bottom_right(); + return p.x >= left() && p.x < br.x && + p.y >= top() && p.y < br.y; + } + + /** + * Test if the rectangle contains another. + * + * Note that an empty rectangle can still contain other empty rectangles, + * which are treated as points or lines of thickness zero. + */ + bool contains(Rectangle const& r) const + { + return r.left() >= left() && + r.left() + as_delta(r.size.width) <= left() + as_delta(size.width) && + r.top() >= top() && + r.top() + as_delta(r.size.height) <= top() + as_delta(size.height); + } + + bool overlaps(Rectangle const& r) const + { + bool disjoint = r.left() >= right() + || r.right() <= left() + || r.top() >= bottom() + || r.bottom() <= top() + || size.width == decltype(size.width){} + || size.height == decltype(size.height){} + || r.size.width == decltype(r.size.width){} + || r.size.height == decltype(r.size.height){}; + return !disjoint; + } + + typename P::template WrapperType left() const { return top_left.x; } + typename P::template WrapperType right() const { return bottom_right().x; } + typename P::template WrapperType top() const { return top_left.y; } + typename P::template WrapperType bottom() const { return bottom_right().y; } + + P top_left; + S size; +}; + +template::value, bool>::type = true> +R intersection_of(R const& a, R const& b) +{ + auto const max_left = std::max(a.left(), b.left()); + auto const min_right = std::min(a.right(), b.right()); + auto const max_top = std::max(a.top(), b.top()); + auto const min_bottom = std::min(a.bottom(), b.bottom()); + + if (max_left < min_right && max_top < min_bottom) + return {{max_left, max_top}, + {(min_right - max_left).as_int(), + (min_bottom - max_top).as_int()}}; + else + return {}; +} + +template +inline constexpr bool operator == (Rectangle const& lhs, Rectangle const& rhs) +{ + return lhs.top_left == rhs.top_left && lhs.size == rhs.size; +} + +template +inline constexpr bool operator != (Rectangle const& lhs, Rectangle const& rhs) +{ + return lhs.top_left != rhs.top_left || lhs.size != rhs.size; +} + +template +std::ostream& operator<<(std::ostream& out, Rectangle const& value) +{ + out << '(' << value.top_left << ", " << value.size << ')'; + return out; +} +} +} +} + +#endif // MIR_GEOMETRY_RECTANGLE_GENERIC_H_ diff --git a/include/core/mir/geometry/size_generic.h b/include/core/mir/geometry/size_generic.h index 961fb294635..7c3dd08bde1 100644 --- a/include/core/mir/geometry/size_generic.h +++ b/include/core/mir/geometry/size_generic.h @@ -20,7 +20,7 @@ #define MIR_GEOMETRY_SIZE_GENERIC_H_ #include "dimensions_generic.h" -#include +#include namespace mir { diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index de317dbdd0e..126908643d1 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -8,9 +8,7 @@ add_library(mircore SHARED fatal.cpp fd.cpp depth_layer.cpp - geometry/rectangle.cpp geometry/rectangles.cpp - geometry/ostream.cpp ${PROJECT_SOURCE_DIR}/include/core/mir/anonymous_shm_file.h ${PROJECT_SOURCE_DIR}/include/core/mir/int_wrapper.h ${PROJECT_SOURCE_DIR}/include/core/mir/optional_value.h diff --git a/src/core/geometry/CMakeLists.txt b/src/core/geometry/CMakeLists.txt index f56b791ad87..33c0f658c8c 100644 --- a/src/core/geometry/CMakeLists.txt +++ b/src/core/geometry/CMakeLists.txt @@ -15,9 +15,7 @@ # Authored by: Alexandros Frantzis add_library(mirsharedgeometry OBJECT - rectangle.cpp rectangles.cpp - ostream.cpp ) list(APPEND MIR_COMMON_SOURCES diff --git a/src/core/geometry/ostream.cpp b/src/core/geometry/ostream.cpp deleted file mode 100644 index 6ff4801d0e3..00000000000 --- a/src/core/geometry/ostream.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright © 2013 Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License version 2 or 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - * - * Authored by: Alan Griffiths - */ - -#include "mir/geometry/displacement.h" -#include "mir/geometry/size.h" -#include "mir/geometry/rectangle.h" -#include "mir/geometry/rectangles.h" - -#include - -namespace geom = mir::geometry; - -std::ostream& geom::operator<<(std::ostream& out, Rectangle const& value) -{ - out << '(' << value.top_left << ", " << value.size << ')'; - return out; -} - -std::ostream& geom::operator<<(std::ostream& out, Rectangles const& value) -{ - out << '['; - for (auto const& rect : value) - out << rect << ", "; - out << ']'; - return out; -} diff --git a/src/core/geometry/rectangle.cpp b/src/core/geometry/rectangle.cpp deleted file mode 100644 index 99c9b1b6791..00000000000 --- a/src/core/geometry/rectangle.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright © 2013 Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License version 2 or 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - * - * Authored by: Alexandros Frantzis - */ - -#include "mir/geometry/rectangle.h" -#include "mir/geometry/displacement.h" - -#include - -namespace geom = mir::geometry; - -geom::Point geom::Rectangle::bottom_right() const -{ - return top_left + as_displacement(size); -} - -geom::Point geom::Rectangle::top_right() const -{ - return top_left + DeltaX{size.width.as_int()}; -} - -geom::Point geom::Rectangle::bottom_left() const -{ - return top_left + DeltaY{size.height.as_int()}; -} - -bool geom::Rectangle::contains(Rectangle const& r) const -{ - return r.left() >= left() && - r.left().as_int() + r.size.width.as_int() <= - left().as_int() + size.width.as_int() && - r.top() >= top() && - r.top().as_int() + r.size.height.as_int() <= - top().as_int() + size.height.as_int(); -} - -bool geom::Rectangle::contains(Point const& p) const -{ - if (size.width == geom::Width{0} || size.height == geom::Height{0}) - return false; - - auto br = bottom_right(); - return p.x >= left() && p.x < br.x && - p.y >= top() && p.y < br.y; -} - -bool geom::Rectangle::overlaps(Rectangle const& r) const -{ - bool disjoint = r.left() >= right() - || r.right() <= left() - || r.top() >= bottom() - || r.bottom() <= top() - || size.width == geom::Width{0} - || size.height == geom::Height{0} - || r.size.width == geom::Width{0} - || r.size.height == geom::Height{0}; - return !disjoint; -} - -geom::Rectangle geom::Rectangle::intersection_with(Rectangle const& r) const -{ - auto const max_left = std::max(left(), r.left()); - auto const min_right = std::min(right(), r.right()); - auto const max_top = std::max(top(), r.top()); - auto const min_bottom = std::min(bottom(), r.bottom()); - - if (max_left < min_right && max_top < min_bottom) - return {{max_left, max_top}, - {(min_right - max_left).as_int(), - (min_bottom - max_top).as_int()}}; - else - return geom::Rectangle(); -} diff --git a/src/core/geometry/rectangles.cpp b/src/core/geometry/rectangles.cpp index 6bb81b7fcd1..be2009b8056 100644 --- a/src/core/geometry/rectangles.cpp +++ b/src/core/geometry/rectangles.cpp @@ -20,6 +20,7 @@ #include "mir/geometry/displacement.h" #include #include +#include namespace geom = mir::geometry; @@ -192,3 +193,12 @@ bool geom::Rectangles::operator!=(Rectangles const& rects) const { return !(*this == rects); } + +std::ostream& geom::operator<<(std::ostream& out, Rectangles const& value) +{ + out << '['; + for (auto const& rect : value) + out << rect << ", "; + out << ']'; + return out; +} From cf5e87408c91c1a7a0e1491944f5dc03ff3ac8ec Mon Sep 17 00:00:00 2001 From: William Wold Date: Mon, 1 Feb 2021 15:09:21 -0800 Subject: [PATCH 16/18] Add float versions of size, rectangle and displacement --- include/core/mir/geometry/displacement_f.h | 32 +++++++++++++++++++++ include/core/mir/geometry/rectangle_f.h | 33 ++++++++++++++++++++++ include/core/mir/geometry/size_f.h | 32 +++++++++++++++++++++ 3 files changed, 97 insertions(+) create mode 100644 include/core/mir/geometry/displacement_f.h create mode 100644 include/core/mir/geometry/rectangle_f.h create mode 100644 include/core/mir/geometry/size_f.h diff --git a/include/core/mir/geometry/displacement_f.h b/include/core/mir/geometry/displacement_f.h new file mode 100644 index 00000000000..2195705ab38 --- /dev/null +++ b/include/core/mir/geometry/displacement_f.h @@ -0,0 +1,32 @@ +/* + * Copyright © 2021 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License version 2 or 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Authored by: William Wold ::Wrapper>; +} +} +#endif // MIR_GEOMETRY_DISPLACEMENT_F_H_ diff --git a/include/core/mir/geometry/rectangle_f.h b/include/core/mir/geometry/rectangle_f.h new file mode 100644 index 00000000000..f7c925e71d9 --- /dev/null +++ b/include/core/mir/geometry/rectangle_f.h @@ -0,0 +1,33 @@ +/* + * Copyright © 2021 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License version 2 or 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Authored by: William Wold ; +} +} +#endif // MIR_GEOMETRY_RECTANGLE_F_H_ diff --git a/include/core/mir/geometry/size_f.h b/include/core/mir/geometry/size_f.h new file mode 100644 index 00000000000..5451bd770a9 --- /dev/null +++ b/include/core/mir/geometry/size_f.h @@ -0,0 +1,32 @@ +/* + * Copyright © 2021 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License version 2 or 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Authored by: William Wold ::Wrapper>; +} +} +#endif // MIR_GEOMETRY_SIZE_F_H_ From 06973eb9c3438c3e33f3a3922dc3a9caf753cd2c Mon Sep 17 00:00:00 2001 From: William Wold Date: Tue, 23 Feb 2021 12:50:37 -0800 Subject: [PATCH 17/18] Address review --- include/core/mir/geometry/dimensions.h | 2 +- include/core/mir/geometry/dimensions_generic.h | 3 +-- .../core/mir/geometry/displacement_generic.h | 2 +- include/core/mir/geometry/point_generic.h | 18 +++++++++--------- include/core/mir/geometry/rectangle_generic.h | 8 ++++---- include/core/mir/geometry/size_generic.h | 2 +- 6 files changed, 17 insertions(+), 18 deletions(-) diff --git a/include/core/mir/geometry/dimensions.h b/include/core/mir/geometry/dimensions.h index 851ea51eb59..ffe7d0cd36f 100644 --- a/include/core/mir/geometry/dimensions.h +++ b/include/core/mir/geometry/dimensions.h @@ -36,7 +36,7 @@ class IntWrapper : public generic::Value::Wrapper { public: template - using WrapperType = IntWrapper; + using Corresponding = IntWrapper; using generic::Value::Wrapper::Wrapper; diff --git a/include/core/mir/geometry/dimensions_generic.h b/include/core/mir/geometry/dimensions_generic.h index 693c81ba7e5..70bd6aad569 100644 --- a/include/core/mir/geometry/dimensions_generic.h +++ b/include/core/mir/geometry/dimensions_generic.h @@ -61,8 +61,7 @@ struct Value using ValueType = T; using TagType = Tag; template - using WrapperType = Wrapper; - using IsGemetryWrapper = void; ///< Used to check if this is a geometry wrapper type + using Corresponding = Wrapper; template constexpr typename std::enable_if::value, int>::type as_int() const diff --git a/include/core/mir/geometry/displacement_generic.h b/include/core/mir/geometry/displacement_generic.h index e66635c231d..5a5cd189187 100644 --- a/include/core/mir/geometry/displacement_generic.h +++ b/include/core/mir/geometry/displacement_generic.h @@ -44,7 +44,7 @@ template typename T> struct Displacement : detail::DisplacementBase { template - using WrapperType = T; + using Corresponding = T; using PointType = Point; using SizeType = Size; diff --git a/include/core/mir/geometry/point_generic.h b/include/core/mir/geometry/point_generic.h index fc6546294ef..5dd917f1fcc 100644 --- a/include/core/mir/geometry/point_generic.h +++ b/include/core/mir/geometry/point_generic.h @@ -41,7 +41,7 @@ template typename T> struct Point : detail::PointBase { template - using WrapperType = T; + using Corresponding = T; using SizeType = Size; using DisplacementType = Displacement; @@ -70,24 +70,24 @@ inline constexpr bool operator != (P const& lhs, P const& rhs) } template::value, bool>::type = true> -inline constexpr P operator+(P lhs, typename P::template WrapperType rhs) { return{lhs.x + rhs, lhs.y}; } +inline constexpr P operator+(P lhs, typename P::template Corresponding rhs) { return{lhs.x + rhs, lhs.y}; } template::value, bool>::type = true> -inline constexpr P operator+(P lhs, typename P::template WrapperType rhs) { return{lhs.x, lhs.y + rhs}; } +inline constexpr P operator+(P lhs, typename P::template Corresponding rhs) { return{lhs.x, lhs.y + rhs}; } template::value, bool>::type = true> -inline constexpr P operator-(P lhs, typename P::template WrapperType rhs) { return{lhs.x - rhs, lhs.y}; } +inline constexpr P operator-(P lhs, typename P::template Corresponding rhs) { return{lhs.x - rhs, lhs.y}; } template::value, bool>::type = true> -inline constexpr P operator-(P lhs, typename P::template WrapperType rhs) { return{lhs.x, lhs.y - rhs}; } +inline constexpr P operator-(P lhs, typename P::template Corresponding rhs) { return{lhs.x, lhs.y - rhs}; } template::value, bool>::type = true> -inline P& operator+=(P& lhs, typename P::template WrapperType rhs) { lhs.x += rhs; return lhs; } +inline P& operator+=(P& lhs, typename P::template Corresponding rhs) { lhs.x += rhs; return lhs; } template::value, bool>::type = true> -inline P& operator+=(P& lhs, typename P::template WrapperType rhs) { lhs.y += rhs; return lhs; } +inline P& operator+=(P& lhs, typename P::template Corresponding rhs) { lhs.y += rhs; return lhs; } template::value, bool>::type = true> -inline P& operator-=(P& lhs, typename P::template WrapperType rhs) { lhs.x -= rhs; return lhs; } +inline P& operator-=(P& lhs, typename P::template Corresponding rhs) { lhs.x -= rhs; return lhs; } template::value, bool>::type = true> -inline P& operator-=(P& lhs, typename P::template WrapperType rhs) { lhs.y -= rhs; return lhs; } +inline P& operator-=(P& lhs, typename P::template Corresponding rhs) { lhs.y -= rhs; return lhs; } template::value, bool>::type = true> std::ostream& operator<<(std::ostream& out, P const& value) diff --git a/include/core/mir/geometry/rectangle_generic.h b/include/core/mir/geometry/rectangle_generic.h index 5fb1d6bfc60..7300a05fcf3 100644 --- a/include/core/mir/geometry/rectangle_generic.h +++ b/include/core/mir/geometry/rectangle_generic.h @@ -103,10 +103,10 @@ struct Rectangle : detail::RectangleBase return !disjoint; } - typename P::template WrapperType left() const { return top_left.x; } - typename P::template WrapperType right() const { return bottom_right().x; } - typename P::template WrapperType top() const { return top_left.y; } - typename P::template WrapperType bottom() const { return bottom_right().y; } + typename P::template Corresponding left() const { return top_left.x; } + typename P::template Corresponding right() const { return bottom_right().x; } + typename P::template Corresponding top() const { return top_left.y; } + typename P::template Corresponding bottom() const { return bottom_right().y; } P top_left; S size; diff --git a/include/core/mir/geometry/size_generic.h b/include/core/mir/geometry/size_generic.h index 7c3dd08bde1..05c9ff560d3 100644 --- a/include/core/mir/geometry/size_generic.h +++ b/include/core/mir/geometry/size_generic.h @@ -42,7 +42,7 @@ template typename T> struct Size : detail::SizeBase { template - using WrapperType = T; + using Corresponding = T; using PointType = Point; using DisplacementType = Displacement; From 2b9accbe886079e883c745a632fb39b323fd482f Mon Sep 17 00:00:00 2001 From: William Wold Date: Thu, 25 Feb 2021 15:15:44 -0800 Subject: [PATCH 18/18] Add Corresponding<> --- include/core/mir/geometry/dimensions_generic.h | 3 +++ include/core/mir/geometry/point_generic.h | 16 ++++++++-------- include/core/mir/geometry/rectangle_generic.h | 8 ++++---- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/include/core/mir/geometry/dimensions_generic.h b/include/core/mir/geometry/dimensions_generic.h index 70bd6aad569..0f2a38d46e8 100644 --- a/include/core/mir/geometry/dimensions_generic.h +++ b/include/core/mir/geometry/dimensions_generic.h @@ -132,6 +132,9 @@ struct Value Value(); }; +template +using Corresponding = typename GeometricType::template Corresponding; + template::value, bool>::type = true> std::ostream& operator<<(std::ostream& out, W const& value) { diff --git a/include/core/mir/geometry/point_generic.h b/include/core/mir/geometry/point_generic.h index 5dd917f1fcc..ced3a6f73a0 100644 --- a/include/core/mir/geometry/point_generic.h +++ b/include/core/mir/geometry/point_generic.h @@ -70,24 +70,24 @@ inline constexpr bool operator != (P const& lhs, P const& rhs) } template::value, bool>::type = true> -inline constexpr P operator+(P lhs, typename P::template Corresponding rhs) { return{lhs.x + rhs, lhs.y}; } +inline constexpr P operator+(P lhs, Corresponding rhs) { return{lhs.x + rhs, lhs.y}; } template::value, bool>::type = true> -inline constexpr P operator+(P lhs, typename P::template Corresponding rhs) { return{lhs.x, lhs.y + rhs}; } +inline constexpr P operator+(P lhs, Corresponding rhs) { return{lhs.x, lhs.y + rhs}; } template::value, bool>::type = true> -inline constexpr P operator-(P lhs, typename P::template Corresponding rhs) { return{lhs.x - rhs, lhs.y}; } +inline constexpr P operator-(P lhs, Corresponding rhs) { return{lhs.x - rhs, lhs.y}; } template::value, bool>::type = true> -inline constexpr P operator-(P lhs, typename P::template Corresponding rhs) { return{lhs.x, lhs.y - rhs}; } +inline constexpr P operator-(P lhs, Corresponding rhs) { return{lhs.x, lhs.y - rhs}; } template::value, bool>::type = true> -inline P& operator+=(P& lhs, typename P::template Corresponding rhs) { lhs.x += rhs; return lhs; } +inline P& operator+=(P& lhs, Corresponding rhs) { lhs.x += rhs; return lhs; } template::value, bool>::type = true> -inline P& operator+=(P& lhs, typename P::template Corresponding rhs) { lhs.y += rhs; return lhs; } +inline P& operator+=(P& lhs, Corresponding rhs) { lhs.y += rhs; return lhs; } template::value, bool>::type = true> -inline P& operator-=(P& lhs, typename P::template Corresponding rhs) { lhs.x -= rhs; return lhs; } +inline P& operator-=(P& lhs, Corresponding rhs) { lhs.x -= rhs; return lhs; } template::value, bool>::type = true> -inline P& operator-=(P& lhs, typename P::template Corresponding rhs) { lhs.y -= rhs; return lhs; } +inline P& operator-=(P& lhs, Corresponding rhs) { lhs.y -= rhs; return lhs; } template::value, bool>::type = true> std::ostream& operator<<(std::ostream& out, P const& value) diff --git a/include/core/mir/geometry/rectangle_generic.h b/include/core/mir/geometry/rectangle_generic.h index 7300a05fcf3..07772d79493 100644 --- a/include/core/mir/geometry/rectangle_generic.h +++ b/include/core/mir/geometry/rectangle_generic.h @@ -103,10 +103,10 @@ struct Rectangle : detail::RectangleBase return !disjoint; } - typename P::template Corresponding left() const { return top_left.x; } - typename P::template Corresponding right() const { return bottom_right().x; } - typename P::template Corresponding top() const { return top_left.y; } - typename P::template Corresponding bottom() const { return bottom_right().y; } + Corresponding left() const { return top_left.x; } + Corresponding right() const { return bottom_right().x; } + Corresponding top() const { return top_left.y; } + Corresponding bottom() const { return bottom_right().y; } P top_left; S size;