1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mfbt/NullPtr.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,112 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +/* 1.11 + * Implements a workaround for compilers which do not support the C++11 nullptr 1.12 + * constant. 1.13 + */ 1.14 + 1.15 +#ifndef mozilla_NullPtr_h 1.16 +#define mozilla_NullPtr_h 1.17 + 1.18 +#if defined(__clang__) 1.19 +# if !__has_extension(cxx_nullptr) 1.20 +# error "clang version natively supporting nullptr is required." 1.21 +# endif 1.22 +# define MOZ_HAVE_CXX11_NULLPTR 1.23 +#elif defined(__GNUC__) 1.24 +# if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L 1.25 +# include "mozilla/Compiler.h" 1.26 +# if MOZ_GCC_VERSION_AT_LEAST(4, 6, 0) 1.27 +# define MOZ_HAVE_CXX11_NULLPTR 1.28 +# endif 1.29 +# endif 1.30 +#elif defined(_MSC_VER) 1.31 + // The minimum supported MSVC (10, _MSC_VER 1600) supports nullptr. 1.32 +# define MOZ_HAVE_CXX11_NULLPTR 1.33 +#endif 1.34 + 1.35 +namespace mozilla { 1.36 + 1.37 +/** 1.38 + * IsNullPointer<T>::value is true iff T is the type of C++11's nullptr. If 1.39 + * nullptr is emulated, IsNullPointer<T>::value is false for all T. 1.40 + * 1.41 + * IsNullPointer is useful to give an argument the true decltype(nullptr) type. 1.42 + * decltype(nullptr) doesn't work when nullptr is emulated. The simplest 1.43 + * workaround is to use template overloading and SFINAE to expose an overload 1.44 + * only if an argument's type is decltype(nullptr). Some examples (that assume 1.45 + * namespace mozilla has been opened, for simplicity): 1.46 + * 1.47 + * // foo(T*), foo(stuff that converts to T*), and foo(decltype(nullptr)) 1.48 + * // (only invoked if nullptr is true nullptr, otherwise foo(T*) is invoked) 1.49 + * // but nothing else 1.50 + * void foo(T*) { } 1.51 + * template<typename N> 1.52 + * void foo(N, 1.53 + * typename EnableIf<IsNullPointer<N>::value, int>::Type dummy = 0) 1.54 + * { } 1.55 + * 1.56 + * // foo(T*) *exactly* and foo(decltype(nullptr)), nothing else 1.57 + * void foo(T*) { } 1.58 + * template<typename U> 1.59 + * void foo(U, 1.60 + * typename EnableIf<!IsNullPointer<U>::value, int>::Type dummy = 0) 1.61 + * MOZ_DELETE; 1.62 + * 1.63 + * The exact details of how set up the SFINAE bits vary on a case-by-case basis. 1.64 + * If you need help with this (and unless you've internalized way more sadmaking 1.65 + * nullptr-emulation knowledge than you should have, you do), feel free to poke 1.66 + * the person with blame on this comment with questions. :-) 1.67 + * 1.68 + * Ideally this would be in TypeTraits.h, but C++11 omitted std::is_null_pointer 1.69 + * (fixed in C++1y), so in the interests of easing a switch to <type_traits>, 1.70 + * this trait lives elsewhere. 1.71 + */ 1.72 +template<typename T> 1.73 +struct IsNullPointer { static const bool value = false; }; 1.74 + 1.75 +} // namespace mozilla 1.76 + 1.77 +/** 1.78 + * mozilla::NullptrT is a type that's sort of like decltype(nullptr). But it 1.79 + * can't be identical, because emulated nullptr doesn't have a distinct type. 1.80 + * Only with gcc 4.4/4.5, emulated nullptr is __null, and decltype(__null) is 1.81 + * int or long. But passing __null to an int/long parameter triggers 1.82 + * -Werror=conversion-null errors with gcc 4.5, or (depending on subsequent use 1.83 + * inside the overloaded function) can trigger pointer-to-integer comparison 1.84 + * compiler errors. So fairly often, actually, NullptrT is *not* what you want. 1.85 + * 1.86 + * Instead, often you should use template-based overloading in concert with 1.87 + * SFINAE to add a nullptr overload -- see the comments by IsNullPointer. 1.88 + * 1.89 + * So when *should* you use NullptrT? Thus far, the only truly good use seems 1.90 + * to be as an argument type for operator overloads (because C++ doesn't allow 1.91 + * operator= to have more than one argument, operator== to have more than two, 1.92 + * &c.). But even in such cases, it really only works if there are no other 1.93 + * overloads of the operator that accept a pointer type. If you want both T* 1.94 + * and nullptr_t overloads, you'll have to wait til we drop gcc 4.4/4.5 support. 1.95 + * (Currently b2g is the only impediment to this.) 1.96 + */ 1.97 +#ifdef MOZ_HAVE_CXX11_NULLPTR 1.98 + // decltype does the right thing for actual nullptr. 1.99 + namespace mozilla { 1.100 + typedef decltype(nullptr) NullptrT; 1.101 + template<> 1.102 + struct IsNullPointer<decltype(nullptr)> { static const bool value = true; }; 1.103 + } 1.104 +# undef MOZ_HAVE_CXX11_NULLPTR 1.105 +#elif MOZ_IS_GCC 1.106 +# define nullptr __null 1.107 + // void* sweeps up more than just nullptr, but compilers supporting true 1.108 + // nullptr are the majority now, so they should detect mistakes. If you're 1.109 + // feeling paranoid, check/assert that your NullptrT equals nullptr. 1.110 + namespace mozilla { typedef void* NullptrT; } 1.111 +#else 1.112 +# error "No compiler support for nullptr or its emulation." 1.113 +#endif 1.114 + 1.115 +#endif /* mozilla_NullPtr_h */