mfbt/NullPtr.h

changeset 0
6474c204b198
     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 */

mercurial