author | Jeff Walden <jwalden@mit.edu> |
Tue, 19 Jun 2012 13:55:23 -0700 | |
changeset 102311 | fe817bf85f36386d626ed35383ffb9dae2f4ddc5 |
parent 102310 | 54a17b76f48868f24dfa261309289af896eca39d |
child 102312 | b0fd1627db78134185402fc1ab59112cc5ffb697 |
push id | 1316 |
push user | akeybl@mozilla.com |
push date | Mon, 27 Aug 2012 22:37:00 +0000 |
treeherder | mozilla-beta@db4b09302ee2 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | luke |
bugs | 766347 |
milestone | 16.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/mfbt/TypeTraits.h +++ b/mfbt/TypeTraits.h @@ -22,18 +22,58 @@ namespace mozilla { * mozilla::IsBaseOf<A, C>::value is false; */ template<class Base, class Derived> class IsBaseOf { private: static char test(Base* b); static int test(...); + public: - static const bool value = (sizeof(test(static_cast<Derived*>(0))) == sizeof(char)); + static const bool value = + sizeof(test(static_cast<Derived*>(0))) == sizeof(char); +}; + +/* + * IsConvertible determines whether a value of type From will implicitly convert + * to a value of type To. For example: + * + * struct A {}; + * struct B : public A {}; + * struct C {}; + * + * mozilla::IsConvertible<A, A>::value is true; + * mozilla::IsConvertible<A*, A*>::value is true; + * mozilla::IsConvertible<B, A>::value is true; + * mozilla::IsConvertible<B*, A*>::value is true; + * mozilla::IsConvertible<C, A>::value is false; + * mozilla::IsConvertible<A, C>::value is false; + * mozilla::IsConvertible<A*, C*>::value is false; + * mozilla::IsConvertible<C*, A*>::value is false. + * + * For obscure reasons, you can't use IsConvertible when the types being tested + * are related through private inheritance, and you'll get a compile error if + * you try. Just don't do it! + */ +template<typename From, typename To> +struct IsConvertible +{ + private: + static From create(); + + template<typename From1, typename To1> + static char test(To to); + + template<typename From1, typename To1> + static int test(...); + + public: + static const bool value = + sizeof(test<From, To>(create())) == sizeof(char); }; /* * Conditional selects a class between two, depending on a given boolean value. * * mozilla::Conditional<true, A, B>::Type is A; * mozilla::Conditional<false, A, B>::Type is B; */
--- a/mfbt/tests/Makefile.in +++ b/mfbt/tests/Makefile.in @@ -8,16 +8,17 @@ srcdir = @srcdir@ VPATH = @srcdir@ include $(DEPTH)/config/autoconf.mk STL_FLAGS = CPP_UNIT_TESTS = \ TestCheckedInt.cpp \ + TestTypeTraits.cpp \ $(NULL) # in order to prevent rules.mk from trying to link to libraries that are # not available to MFBT, we have to reset these MOZ_GLUE*_LDFLAGS before including it # and LIBS_ after including it. For WRAP_LDFLAGS, it shouldn't matter. # See later comments in bug 732875. MOZ_GLUE_PROGRAM_LDFLAGS=
new file mode 100644 --- /dev/null +++ b/mfbt/tests/TestTypeTraits.cpp @@ -0,0 +1,55 @@ +/* -*- 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/Assertions.h" +#include "mozilla/TypeTraits.h" + +using mozilla::IsConvertible; + +class A { }; +class B : public A { }; +class C : private A { }; +class D { }; + +static void +TestIsConvertible() +{ + // Pointer type convertibility + MOZ_ASSERT((IsConvertible<A*, A*>::value), + "A* should convert to A*"); + MOZ_ASSERT((IsConvertible<B*, A*>::value), + "B* should convert to A*"); + MOZ_ASSERT((!IsConvertible<A*, B*>::value), + "A* shouldn't convert to B*"); + MOZ_ASSERT((!IsConvertible<A*, C*>::value), + "A* shouldn't convert to C*"); + MOZ_ASSERT((!IsConvertible<A*, D*>::value), + "A* shouldn't convert to unrelated D*"); + MOZ_ASSERT((!IsConvertible<D*, A*>::value), + "D* shouldn't convert to unrelated A*"); + + // Instance type convertibility + MOZ_ASSERT((IsConvertible<A, A>::value), + "A is A"); + MOZ_ASSERT((IsConvertible<B, A>::value), + "B converts to A"); + MOZ_ASSERT((!IsConvertible<D, A>::value), + "D and A are unrelated"); + MOZ_ASSERT((!IsConvertible<A, D>::value), + "A and D are unrelated"); + + // These cases seem to require C++11 support to properly implement them, so + // for now just disable them. + //MOZ_ASSERT((!IsConvertible<C*, A*>::value), + // "C* shouldn't convert to A* (private inheritance)"); + //MOZ_ASSERT((!IsConvertible<C, A>::value), + // "C doesn't convert to A (private inheritance)"); +} + +int +main() +{ + TestIsConvertible(); +}