mfbt/TypedEnumBits.h
author Morten Stenshorne <mstensho@chromium.org>
Tue, 09 Oct 2018 04:14:13 +0000
changeset 495959 13844f50ee32e17f513b7c1013c2348200e21b8c
parent 367428 0dfe466e790f39710ce553a9a858f92da6a095a6
child 505383 6f3709b3878117466168c40affa7bca0b60cf75b
permissions -rw-r--r--
Bug 1496274 [wpt PR 13345] - [LayoutNG] Correct clip-path reference box calculation., a=testonly Automatic update from web-platform-tests[LayoutNG] Correct clip-path reference box calculation. We used coordinates relatively to the line box, while we were expected by the caller to be relative to the containing block. Flipping for writing mode was bogus for NG (but needed by legacy), since NG uses truly physical coordinates. Hardened tests to contain a leading line and padding, and leading content on the first line of the clipped child. Bug: 641907 Change-Id: I2b1b9ff4ea92a6405fcdffcf139842458b46442f Cq-Include-Trybots: luci.chromium.try​:linux_layout_tests_layout_ng Reviewed-on: https://chromium-review.googlesource.com/c/1257913 Reviewed-by: Koji Ishii <kojii@chromium.org> Reviewed-by: Fredrik Söderquist <fs@opera.com> Commit-Queue: Morten Stenshorne <mstensho@chromium.org> Cr-Commit-Position: refs/heads/master@{#596554} -- wpt-commits: e9a0828c85819340f721f121aac19ab8eefa3439 wpt-pr: 13345

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/*
 * MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS allows using a typed enum as bit flags.
 */

#ifndef mozilla_TypedEnumBits_h
#define mozilla_TypedEnumBits_h

#include "mozilla/Attributes.h"
#include "mozilla/IntegerTypeTraits.h"

namespace mozilla {

/*
 * The problem that CastableTypedEnumResult aims to solve is that
 * typed enums are not convertible to bool, and there is no way to make them
 * be, yet user code wants to be able to write
 *
 *   if (myFlags & Flags::SOME_PARTICULAR_FLAG)              (1)
 *
 * There are different approaches to solving this. Most of them require
 * adapting user code. For example, we could implement operator! and have
 * the user write
 *
 *   if (!!(myFlags & Flags::SOME_PARTICULAR_FLAG))          (2)
 *
 * Or we could supply a IsNonZero() or Any() function returning whether
 * an enum value is nonzero, and have the user write
 *
 *   if (Any(Flags & Flags::SOME_PARTICULAR_FLAG))           (3)
 *
 * But instead, we choose to preserve the original user syntax (1) as it
 * is inherently more readable, and to ease porting existing code to typed
 * enums. We achieve this by having operator& and other binary bitwise
 * operators have as return type a class, CastableTypedEnumResult,
 * that wraps a typed enum but adds bool convertibility.
 */
template<typename E>
class CastableTypedEnumResult
{
private:
  const E mValue;

public:
  explicit constexpr CastableTypedEnumResult(E aValue)
    : mValue(aValue)
  {}

  constexpr operator E() const { return mValue; }

  template<typename DestinationType>
  explicit constexpr
  operator DestinationType() const { return DestinationType(mValue); }

  constexpr bool operator !() const { return !bool(mValue); }
};

#define MOZ_CASTABLETYPEDENUMRESULT_BINOP(Op, OtherType, ReturnType) \
template<typename E> \
constexpr ReturnType \
operator Op(const OtherType& aE, const CastableTypedEnumResult<E>& aR) \
{ \
  return ReturnType(aE Op OtherType(aR)); \
} \
template<typename E> \
constexpr ReturnType \
operator Op(const CastableTypedEnumResult<E>& aR, const OtherType& aE) \
{ \
  return ReturnType(OtherType(aR) Op aE); \
} \
template<typename E> \
constexpr ReturnType \
operator Op(const CastableTypedEnumResult<E>& aR1, \
            const CastableTypedEnumResult<E>& aR2) \
{ \
  return ReturnType(OtherType(aR1) Op OtherType(aR2)); \
}

MOZ_CASTABLETYPEDENUMRESULT_BINOP(|, E, CastableTypedEnumResult<E>)
MOZ_CASTABLETYPEDENUMRESULT_BINOP(&, E, CastableTypedEnumResult<E>)
MOZ_CASTABLETYPEDENUMRESULT_BINOP(^, E, CastableTypedEnumResult<E>)
MOZ_CASTABLETYPEDENUMRESULT_BINOP(==, E, bool)
MOZ_CASTABLETYPEDENUMRESULT_BINOP(!=, E, bool)

template <typename E>
constexpr CastableTypedEnumResult<E>
operator ~(const CastableTypedEnumResult<E>& aR)
{
  return CastableTypedEnumResult<E>(~(E(aR)));
}

#define MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(Op) \
template<typename E> \
E& \
operator Op(E& aR1, \
            const CastableTypedEnumResult<E>& aR2) \
{ \
  return aR1 Op E(aR2); \
}

MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(&=)
MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(|=)
MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(^=)

#undef MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP

#undef MOZ_CASTABLETYPEDENUMRESULT_BINOP

namespace detail {
template<typename E>
struct UnsignedIntegerTypeForEnum
  : UnsignedStdintTypeForSize<sizeof(E)>
{};
} // namespace detail

} // namespace mozilla

#define MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, Op) \
   inline constexpr mozilla::CastableTypedEnumResult<Name> \
   operator Op(Name a, Name b) \
   { \
     typedef mozilla::CastableTypedEnumResult<Name> Result; \
     typedef mozilla::detail::UnsignedIntegerTypeForEnum<Name>::Type U; \
     return Result(Name(U(a) Op U(b))); \
   } \
 \
   inline Name& \
   operator Op##=(Name& a, Name b) \
   { \
     return a = a Op b; \
   }

/**
 * MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS generates standard bitwise operators
 * for the given enum type. Use this to enable using an enum type as bit-field.
 */
#define MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Name) \
   MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, |) \
   MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, &) \
   MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, ^) \
   inline constexpr mozilla::CastableTypedEnumResult<Name> \
   operator~(Name a) \
   { \
     typedef mozilla::CastableTypedEnumResult<Name> Result; \
     typedef mozilla::detail::UnsignedIntegerTypeForEnum<Name>::Type U; \
     return Result(Name(~(U(a)))); \
   }

#endif // mozilla_TypedEnumBits_h