Skip to content

Commit

Permalink
Bug 1297306 - part4:rename IsEnumFittingWithin with EnumTypeFitsWithi…
Browse files Browse the repository at this point in the history
…n and move it to mfbt/EnumTypeTraits.h. r=froydnj

With this change, we could share this EnumTypeTraits between files easily.

MozReview-Commit-ID: 9Q2augati7l
  • Loading branch information
chenpighead committed Sep 7, 2016
1 parent 2286173 commit e54a266
Show file tree
Hide file tree
Showing 8 changed files with 215 additions and 23 deletions.
2 changes: 1 addition & 1 deletion layout/style/StyleAnimationValue.h
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,7 @@ class StyleAnimationValue {
typename = typename std::enable_if<std::is_enum<T>::value>::type>
void SetIntValue(T aInt, Unit aUnit)
{
static_assert(mozilla::IsEnumFittingWithin<T, int32_t>::value,
static_assert(mozilla::EnumTypeFitsWithin<T, int32_t>::value,
"aValue must be an enum that fits within mValue.mInt");
SetIntValue(static_cast<int32_t>(aInt), aUnit);
}
Expand Down
25 changes: 4 additions & 21 deletions layout/style/nsCSSProps.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "nsCSSKeywords.h"
#include "mozilla/CSSEnabledState.h"
#include "mozilla/UseCounter.h"
#include "mozilla/EnumTypeTraits.h"

// Length of the "--" prefix on custom names (such as custom property names,
// and, in the future, custom media query names).
Expand Down Expand Up @@ -327,24 +328,6 @@ enum nsStyleAnimType {
eStyleAnimType_None
};

namespace mozilla {

// Type trait that determines whether the integral or enum type Type can fit
// within the integral type Storage without loss.
template<typename T, typename Storage>
struct IsEnumFittingWithin
: IntegralConstant<
bool,
std::is_integral<Storage>::value &&
std::numeric_limits<typename std::underlying_type<T>::type>::min() >=
std::numeric_limits<Storage>::min() &&
std::numeric_limits<typename std::underlying_type<T>::type>::max() <=
std::numeric_limits<Storage>::max()
>
{};

} // namespace mozilla

class nsCSSProps {
public:
typedef mozilla::CSSEnabledState EnabledState;
Expand All @@ -366,7 +349,7 @@ class nsCSSProps {
: mKeyword(aKeyword)
, mValue(static_cast<int16_t>(aValue))
{
static_assert(mozilla::IsEnumFittingWithin<T, int16_t>::value,
static_assert(mozilla::EnumTypeFitsWithin<T, int16_t>::value,
"aValue must be an enum that fits within mValue");
}

Expand Down Expand Up @@ -452,7 +435,7 @@ class nsCSSProps {
static nsCSSKeyword ValueToKeywordEnum(T aValue,
const KTableEntry aTable[])
{
static_assert(mozilla::IsEnumFittingWithin<T, int16_t>::value,
static_assert(mozilla::EnumTypeFitsWithin<T, int16_t>::value,
"aValue must be an enum that fits within KTableEntry::mValue");
return ValueToKeywordEnum(static_cast<int16_t>(aValue), aTable);
}
Expand All @@ -464,7 +447,7 @@ class nsCSSProps {
static const nsAFlatCString& ValueToKeyword(T aValue,
const KTableEntry aTable[])
{
static_assert(mozilla::IsEnumFittingWithin<T, int16_t>::value,
static_assert(mozilla::EnumTypeFitsWithin<T, int16_t>::value,
"aValue must be an enum that fits within KTableEntry::mValue");
return ValueToKeyword(static_cast<int16_t>(aValue), aTable);
}
Expand Down
2 changes: 1 addition & 1 deletion layout/style/nsCSSValue.h
Original file line number Diff line number Diff line change
Expand Up @@ -758,7 +758,7 @@ class nsCSSValue {
typename = typename std::enable_if<std::is_enum<T>::value>::type>
void SetIntValue(T aValue, nsCSSUnit aUnit)
{
static_assert(mozilla::IsEnumFittingWithin<T, int32_t>::value,
static_assert(mozilla::EnumTypeFitsWithin<T, int32_t>::value,
"aValue must be an enum that fits within mValue.mInt");
SetIntValue(static_cast<int32_t>(aValue), aUnit);
}
Expand Down
70 changes: 70 additions & 0 deletions mfbt/EnumTypeTraits.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */

/* Type traits for enums. */

#ifndef mozilla_EnumTypeTraits_h
#define mozilla_EnumTypeTraits_h

#include <type_traits>

namespace mozilla {

namespace detail {

template<size_t EnumSize, bool EnumSigned, size_t StorageSize, bool StorageSigned>
struct EnumFitsWithinHelper;

// Signed enum, signed storage.
template<size_t EnumSize, size_t StorageSize>
struct EnumFitsWithinHelper<EnumSize, true, StorageSize, true>
: public std::integral_constant<bool, (EnumSize <= StorageSize)>
{};

// Signed enum, unsigned storage.
template<size_t EnumSize, size_t StorageSize>
struct EnumFitsWithinHelper<EnumSize, true, StorageSize, false>
: public std::integral_constant<bool, false>
{};

// Unsigned enum, signed storage.
template<size_t EnumSize, size_t StorageSize>
struct EnumFitsWithinHelper<EnumSize, false, StorageSize, true>
: public std::integral_constant<bool, (EnumSize * 2 <= StorageSize)>
{};

// Unsigned enum, unsigned storage.
template<size_t EnumSize, size_t StorageSize>
struct EnumFitsWithinHelper<EnumSize, false, StorageSize, false>
: public std::integral_constant<bool, (EnumSize <= StorageSize)>
{};

} // namespace detail

/*
* Type trait that determines whether the enum type T can fit within the
* integral type Storage without data loss. This trait should be used with
* caution with an enum type whose underlying type has not been explicitly
* specified: for such enums, the C++ implementation is free to choose a type
* no smaller than int whose range encompasses all possible values of the enum.
* So for an enum with only small non-negative values, the underlying type may
* be either int or unsigned int, depending on the whims of the implementation.
*/
template<typename T, typename Storage>
struct EnumTypeFitsWithin
: public detail::EnumFitsWithinHelper<
sizeof(T),
std::is_signed<typename std::underlying_type<T>::type>::value,
sizeof(Storage),
std::is_signed<Storage>::value
>
{
static_assert(std::is_enum<T>::value, "must provide an enum type");
static_assert(std::is_integral<Storage>::value, "must provide an integral type");
};

} // namespace mozilla

#endif /* mozilla_EnumTypeTraits_h */
1 change: 1 addition & 0 deletions mfbt/moz.build
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ EXPORTS.mozilla = [
'EnumeratedArray.h',
'EnumeratedRange.h',
'EnumSet.h',
'EnumTypeTraits.h',
'FastBernoulliTrial.h',
'FloatingPoint.h',
'Function.h',
Expand Down
136 changes: 136 additions & 0 deletions mfbt/tests/TestEnumTypeTraits.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */

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

using namespace mozilla;

/* Feature check for EnumTypeFitsWithin. */

#define MAKE_FIXED_EMUM_FOR_TYPE(IntType) \
enum FixedEnumFor_##IntType : IntType { \
A_##IntType, \
B_##IntType, \
C_##IntType, \
};

template<typename EnumType, typename IntType>
static void
TestShouldFit()
{
static_assert(EnumTypeFitsWithin<EnumType, IntType>::value,
"Should fit within exact/promoted integral type");
}

template<typename EnumType, typename IntType>
static void
TestShouldNotFit()
{
static_assert(!EnumTypeFitsWithin<EnumType, IntType>::value,
"Should not fit within");
}

int
main()
{
// check for int8_t
MAKE_FIXED_EMUM_FOR_TYPE(int8_t);
TestShouldFit<FixedEnumFor_int8_t, int8_t>();
TestShouldFit<FixedEnumFor_int8_t, int16_t>();
TestShouldFit<FixedEnumFor_int8_t, int32_t>();
TestShouldFit<FixedEnumFor_int8_t, int64_t>();

TestShouldNotFit<FixedEnumFor_int8_t, uint8_t>();
TestShouldNotFit<FixedEnumFor_int8_t, uint16_t>();
TestShouldNotFit<FixedEnumFor_int8_t, uint32_t>();
TestShouldNotFit<FixedEnumFor_int8_t, uint64_t>();

// check for uint8_t
MAKE_FIXED_EMUM_FOR_TYPE(uint8_t);
TestShouldFit<FixedEnumFor_uint8_t, uint8_t>();
TestShouldFit<FixedEnumFor_uint8_t, uint16_t>();
TestShouldFit<FixedEnumFor_uint8_t, uint32_t>();
TestShouldFit<FixedEnumFor_uint8_t, uint64_t>();

TestShouldNotFit<FixedEnumFor_uint8_t, int8_t>();
TestShouldFit<FixedEnumFor_uint8_t, int16_t>();
TestShouldFit<FixedEnumFor_uint8_t, int32_t>();
TestShouldFit<FixedEnumFor_uint8_t, int64_t>();

// check for int16_t
MAKE_FIXED_EMUM_FOR_TYPE(int16_t);
TestShouldNotFit<FixedEnumFor_int16_t, int8_t>();
TestShouldFit<FixedEnumFor_int16_t, int16_t>();
TestShouldFit<FixedEnumFor_int16_t, int32_t>();
TestShouldFit<FixedEnumFor_int16_t, int64_t>();

TestShouldNotFit<FixedEnumFor_int16_t, uint8_t>();
TestShouldNotFit<FixedEnumFor_int16_t, uint16_t>();
TestShouldNotFit<FixedEnumFor_int16_t, uint32_t>();
TestShouldNotFit<FixedEnumFor_int16_t, uint64_t>();

// check for uint16_t
MAKE_FIXED_EMUM_FOR_TYPE(uint16_t);
TestShouldNotFit<FixedEnumFor_uint16_t, uint8_t>();
TestShouldFit<FixedEnumFor_uint16_t, uint16_t>();
TestShouldFit<FixedEnumFor_uint16_t, uint32_t>();
TestShouldFit<FixedEnumFor_uint16_t, uint64_t>();

TestShouldNotFit<FixedEnumFor_uint16_t, int8_t>();
TestShouldNotFit<FixedEnumFor_uint16_t, int16_t>();
TestShouldFit<FixedEnumFor_uint16_t, int32_t>();
TestShouldFit<FixedEnumFor_uint16_t, int64_t>();

// check for int32_t
MAKE_FIXED_EMUM_FOR_TYPE(int32_t);
TestShouldNotFit<FixedEnumFor_int32_t, int8_t>();
TestShouldNotFit<FixedEnumFor_int32_t, int16_t>();
TestShouldFit<FixedEnumFor_int32_t, int32_t>();
TestShouldFit<FixedEnumFor_int32_t, int64_t>();

TestShouldNotFit<FixedEnumFor_int32_t, uint8_t>();
TestShouldNotFit<FixedEnumFor_int32_t, uint16_t>();
TestShouldNotFit<FixedEnumFor_int32_t, uint32_t>();
TestShouldNotFit<FixedEnumFor_int32_t, uint64_t>();

// check for uint32_t
MAKE_FIXED_EMUM_FOR_TYPE(uint32_t);
TestShouldNotFit<FixedEnumFor_uint32_t, uint8_t>();
TestShouldNotFit<FixedEnumFor_uint32_t, uint16_t>();
TestShouldFit<FixedEnumFor_uint32_t, uint32_t>();
TestShouldFit<FixedEnumFor_uint32_t, uint64_t>();

TestShouldNotFit<FixedEnumFor_uint32_t, int8_t>();
TestShouldNotFit<FixedEnumFor_uint32_t, int16_t>();
TestShouldNotFit<FixedEnumFor_uint32_t, int32_t>();
TestShouldFit<FixedEnumFor_uint32_t, int64_t>();

// check for int64_t
MAKE_FIXED_EMUM_FOR_TYPE(int64_t);
TestShouldNotFit<FixedEnumFor_int64_t, int8_t>();
TestShouldNotFit<FixedEnumFor_int64_t, int16_t>();
TestShouldNotFit<FixedEnumFor_int64_t, int32_t>();
TestShouldFit<FixedEnumFor_int64_t, int64_t>();

TestShouldNotFit<FixedEnumFor_int64_t, uint8_t>();
TestShouldNotFit<FixedEnumFor_int64_t, uint16_t>();
TestShouldNotFit<FixedEnumFor_int64_t, uint32_t>();
TestShouldNotFit<FixedEnumFor_int64_t, uint64_t>();

// check for uint64_t
MAKE_FIXED_EMUM_FOR_TYPE(uint64_t);
TestShouldNotFit<FixedEnumFor_uint64_t, uint8_t>();
TestShouldNotFit<FixedEnumFor_uint64_t, uint16_t>();
TestShouldNotFit<FixedEnumFor_uint64_t, uint32_t>();
TestShouldFit<FixedEnumFor_uint64_t, uint64_t>();

TestShouldNotFit<FixedEnumFor_uint64_t, int8_t>();
TestShouldNotFit<FixedEnumFor_uint64_t, int16_t>();
TestShouldNotFit<FixedEnumFor_uint64_t, int32_t>();
TestShouldNotFit<FixedEnumFor_uint64_t, int64_t>();

return 0;
}
1 change: 1 addition & 0 deletions mfbt/tests/moz.build
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ CppUnitTests([
'TestCountZeroes',
'TestEndian',
'TestEnumSet',
'TestEnumTypeTraits',
'TestFastBernoulliTrial',
'TestFloatingPoint',
'TestFunction',
Expand Down
1 change: 1 addition & 0 deletions testing/cppunittest.ini
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ skip-if = os == 'b2g' || (os == 'android' && debug) # Bug 1054249
skip-if = os != 'win'
[TestEndian]
[TestEnumSet]
[TestEnumTypeTraits]
[TestFastBernoulliTrial]
[TestFile]
[TestFloatingPoint]
Expand Down

0 comments on commit e54a266

Please sign in to comment.