Skip to content

Commit

Permalink
Merge #1858
Browse files Browse the repository at this point in the history
1858: Floating point geometry r=AlanGriffiths a=wmww

Will address #1829 when complete. Adds a new `geometry::generic::Wrapper` class and changes the ABI-stable `IntWrapper` to inherit from it.

Only minor issue is that to be generic, operations need to return `generic::Wrapper<Tag, int>` instead of `IntWrapper<Tag>`. The two can be implicitly converted between, but this can cause a problem in some cases. For example, if `std::max()` is called on an `IntWrapper` and a `generic::Wrapper`, it needs an explicit type to cast to.

When we break ABI, I would like to drop `IntWrapper` and make `Width`, `Height`, `X`, etc typedefs of the `generic::Type<int>`. This would fix those problems.

Co-authored-by: William Wold <wm@wmww.sh>
  • Loading branch information
bors[bot] and wmww committed Mar 18, 2021
2 parents 79609db + 2b9accb commit bb83ae5
Show file tree
Hide file tree
Showing 22 changed files with 1,204 additions and 559 deletions.
173 changes: 14 additions & 159 deletions include/core/mir/geometry/dimensions.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,190 +19,45 @@
#ifndef MIR_GEOMETRY_DIMENSIONS_H_
#define MIR_GEOMETRY_DIMENSIONS_H_

#include "dimensions_generic.h"

#include <cstdint>
#include <iosfwd>

namespace mir
{

/// Basic geometry types. Types for dimensions, displacements, etc.
/// and the operations that they support.
namespace geometry
{

namespace detail
{
template<typename Tag>
class IntWrapper
class IntWrapper : public generic::Value<int>::Wrapper<Tag>
{
public:
typedef int ValueType;
template<typename OtherTag>
using Corresponding = IntWrapper<OtherTag>;

constexpr IntWrapper() : value(0) {}
constexpr IntWrapper(IntWrapper const& that) = default;
IntWrapper& operator=(IntWrapper const& that) = default;
using generic::Value<int>::Wrapper<Tag>::Wrapper;

template<typename AnyInteger>
explicit constexpr IntWrapper(AnyInteger value) : value(static_cast<ValueType>(value)) {}
constexpr IntWrapper() {}

constexpr uint32_t as_uint32_t() const // TODO: Deprecate this later
{
return (uint32_t)value;
}

constexpr int as_int() const
{
return value;
return (uint32_t)this->value;
}

private:
ValueType value;
};

template<typename Tag>
std::ostream& operator<<(std::ostream& out, IntWrapper<Tag> const& value)
{
out << value.as_int();
return out;
}

template<typename Tag>
inline constexpr bool operator == (IntWrapper<Tag> const& lhs, IntWrapper<Tag> const& rhs)
{
return lhs.as_int() == rhs.as_int();
}

template<typename Tag>
inline constexpr bool operator != (IntWrapper<Tag> const& lhs, IntWrapper<Tag> const& rhs)
{
return lhs.as_int() != rhs.as_int();
}

template<typename Tag>
inline constexpr bool operator <= (IntWrapper<Tag> const& lhs, IntWrapper<Tag> const& rhs)
{
return lhs.as_int() <= rhs.as_int();
}

template<typename Tag>
inline constexpr bool operator >= (IntWrapper<Tag> const& lhs, IntWrapper<Tag> const& rhs)
{
return lhs.as_int() >= rhs.as_int();
}

template<typename Tag>
inline constexpr bool operator < (IntWrapper<Tag> const& lhs, IntWrapper<Tag> const& rhs)
{
return lhs.as_int() < rhs.as_int();
}

template<typename Tag>
inline constexpr bool operator > (IntWrapper<Tag> const& lhs, IntWrapper<Tag> const& rhs)
{
return lhs.as_int() > rhs.as_int();
}
} // namespace detail

typedef detail::IntWrapper<struct WidthTag> Width;
typedef detail::IntWrapper<struct HeightTag> Height;
typedef detail::IntWrapper<WidthTag> Width;
typedef detail::IntWrapper<HeightTag> Height;
// Just to be clear, mir::geometry::Stride is the stride of the buffer in bytes
typedef detail::IntWrapper<struct StrideTag> Stride;

typedef detail::IntWrapper<struct XTag> X;
typedef detail::IntWrapper<struct YTag> Y;
typedef detail::IntWrapper<struct DeltaXTag> DeltaX;
typedef detail::IntWrapper<struct DeltaYTag> 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<typename Scalar>
inline constexpr Width operator*(Scalar scale, Width const& w) { return Width{scale*w.as_int()}; }
template<typename Scalar>
inline constexpr Height operator*(Scalar scale, Height const& h) { return Height{scale*h.as_int()}; }
template<typename Scalar>
inline constexpr DeltaX operator*(Scalar scale, DeltaX const& dx) { return DeltaX{scale*dx.as_int()}; }
template<typename Scalar>
inline constexpr DeltaY operator*(Scalar scale, DeltaY const& dy) { return DeltaY{scale*dy.as_int()}; }
template<typename Scalar>
inline constexpr Width operator*(Width const& w, Scalar scale) { return scale*w; }
template<typename Scalar>
inline constexpr Height operator*(Height const& h, Scalar scale) { return scale*h; }
template<typename Scalar>
inline constexpr DeltaX operator*(DeltaX const& dx, Scalar scale) { return scale*dx; }
template<typename Scalar>
inline constexpr DeltaY operator*(DeltaY const& dy, Scalar scale) { return scale*dy; }

// Dividing by a scaler value is fine
template<typename Scalar>
inline constexpr Width operator/(Width const& w, Scalar scale) { return Width{w.as_int() / scale}; }
template<typename Scalar>
inline constexpr Height operator/(Height const& h, Scalar scale) { return Height{h.as_int() / scale}; }
template<typename Scalar>
inline constexpr DeltaX operator/(DeltaX const& dx, Scalar scale) { return DeltaX{dx.as_int() / scale}; }
template<typename Scalar>
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<typename Target, typename Source>
inline constexpr Target dim_cast(Source s) { return Target(s.as_int()); }
typedef detail::IntWrapper<XTag> X;
typedef detail::IntWrapper<YTag> Y;
typedef detail::IntWrapper<DeltaXTag> DeltaX;
typedef detail::IntWrapper<DeltaYTag> DeltaY;
}
}

Expand Down
37 changes: 37 additions & 0 deletions include/core/mir/geometry/dimensions_f.h
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.
*
* Authored by: William Wold <william.wold@canonical.com>
*/

#ifndef MIR_GEOMETRY_DIMENSIONS_F_H_
#define MIR_GEOMETRY_DIMENSIONS_F_H_

#include "dimensions_generic.h"

namespace mir
{
namespace geometry
{
using WidthF = generic::Width<float>;
using HeightF = generic::Height<float>;
using XF = generic::X<float>;
using YF = generic::Y<float>;
using DeltaXF = generic::DeltaX<float>;
using DeltaYF = generic::DeltaY<float>;
}
}

#endif // MIR_GEOMETRY_DIMENSIONS_F_H_

0 comments on commit bb83ae5

Please sign in to comment.