mfbt/Maybe.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/mfbt/Maybe.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,163 @@
     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 +/* A class for lazily constructing an object without sticking it on the heap. */
    1.11 +
    1.12 +#ifndef mozilla_Maybe_h
    1.13 +#define mozilla_Maybe_h
    1.14 +
    1.15 +#include "mozilla/Alignment.h"
    1.16 +#include "mozilla/Assertions.h"
    1.17 +
    1.18 +// For placement new
    1.19 +#include <new>
    1.20 +
    1.21 +namespace mozilla {
    1.22 +
    1.23 +/*
    1.24 + * Small utility for lazily constructing objects without using dynamic storage.
    1.25 + * When a Maybe<T> is constructed, it is |empty()|, i.e., no value of T has
    1.26 + * been constructed and no T destructor will be called when the Maybe<T> is
    1.27 + * destroyed. Upon calling |construct|, a T object will be constructed with the
    1.28 + * given arguments and that object will be destroyed when the owning Maybe<T>
    1.29 + * is destroyed.
    1.30 + *
    1.31 + * N.B. GCC seems to miss some optimizations with Maybe and may generate extra
    1.32 + * branches/loads/stores. Use with caution on hot paths.
    1.33 + */
    1.34 +template<class T>
    1.35 +class Maybe
    1.36 +{
    1.37 +    AlignedStorage2<T> storage;
    1.38 +    bool constructed;
    1.39 +
    1.40 +    T& asT() { return *storage.addr(); }
    1.41 +
    1.42 +  public:
    1.43 +    Maybe() { constructed = false; }
    1.44 +    ~Maybe() { if (constructed) asT().~T(); }
    1.45 +
    1.46 +    bool empty() const { return !constructed; }
    1.47 +
    1.48 +    void construct() {
    1.49 +      MOZ_ASSERT(!constructed);
    1.50 +      ::new (storage.addr()) T();
    1.51 +      constructed = true;
    1.52 +    }
    1.53 +
    1.54 +    template<class T1>
    1.55 +    void construct(const T1& t1) {
    1.56 +      MOZ_ASSERT(!constructed);
    1.57 +      ::new (storage.addr()) T(t1);
    1.58 +      constructed = true;
    1.59 +    }
    1.60 +
    1.61 +    template<class T1, class T2>
    1.62 +    void construct(const T1& t1, const T2& t2) {
    1.63 +      MOZ_ASSERT(!constructed);
    1.64 +      ::new (storage.addr()) T(t1, t2);
    1.65 +      constructed = true;
    1.66 +    }
    1.67 +
    1.68 +    template<class T1, class T2, class T3>
    1.69 +    void construct(const T1& t1, const T2& t2, const T3& t3) {
    1.70 +      MOZ_ASSERT(!constructed);
    1.71 +      ::new (storage.addr()) T(t1, t2, t3);
    1.72 +      constructed = true;
    1.73 +    }
    1.74 +
    1.75 +    template<class T1, class T2, class T3, class T4>
    1.76 +    void construct(const T1& t1, const T2& t2, const T3& t3, const T4& t4) {
    1.77 +      MOZ_ASSERT(!constructed);
    1.78 +      ::new (storage.addr()) T(t1, t2, t3, t4);
    1.79 +      constructed = true;
    1.80 +    }
    1.81 +
    1.82 +    template<class T1, class T2, class T3, class T4, class T5>
    1.83 +    void construct(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5) {
    1.84 +      MOZ_ASSERT(!constructed);
    1.85 +      ::new (storage.addr()) T(t1, t2, t3, t4, t5);
    1.86 +      constructed = true;
    1.87 +    }
    1.88 +
    1.89 +    template<class T1, class T2, class T3, class T4, class T5,
    1.90 +             class T6>
    1.91 +    void construct(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5,
    1.92 +                   const T6& t6) {
    1.93 +      MOZ_ASSERT(!constructed);
    1.94 +      ::new (storage.addr()) T(t1, t2, t3, t4, t5, t6);
    1.95 +      constructed = true;
    1.96 +    }
    1.97 +
    1.98 +    template<class T1, class T2, class T3, class T4, class T5,
    1.99 +             class T6, class T7>
   1.100 +    void construct(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5,
   1.101 +                   const T6& t6, const T7& t7) {
   1.102 +      MOZ_ASSERT(!constructed);
   1.103 +      ::new (storage.addr()) T(t1, t2, t3, t4, t5, t6, t7);
   1.104 +      constructed = true;
   1.105 +    }
   1.106 +
   1.107 +    template<class T1, class T2, class T3, class T4, class T5,
   1.108 +             class T6, class T7, class T8>
   1.109 +    void construct(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5,
   1.110 +                   const T6& t6, const T7& t7, const T8& t8) {
   1.111 +      MOZ_ASSERT(!constructed);
   1.112 +      ::new (storage.addr()) T(t1, t2, t3, t4, t5, t6, t7, t8);
   1.113 +      constructed = true;
   1.114 +    }
   1.115 +
   1.116 +    template<class T1, class T2, class T3, class T4, class T5,
   1.117 +             class T6, class T7, class T8, class T9>
   1.118 +    void construct(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5,
   1.119 +                   const T6& t6, const T7& t7, const T8& t8, const T9& t9) {
   1.120 +      MOZ_ASSERT(!constructed);
   1.121 +      ::new (storage.addr()) T(t1, t2, t3, t4, t5, t6, t7, t8, t9);
   1.122 +      constructed = true;
   1.123 +    }
   1.124 +
   1.125 +    template<class T1, class T2, class T3, class T4, class T5,
   1.126 +             class T6, class T7, class T8, class T9, class T10>
   1.127 +    void construct(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5,
   1.128 +                   const T6& t6, const T7& t7, const T8& t8, const T9& t9, const T10& t10) {
   1.129 +      MOZ_ASSERT(!constructed);
   1.130 +      ::new (storage.addr()) T(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10);
   1.131 +      constructed = true;
   1.132 +    }
   1.133 +
   1.134 +    T* addr() {
   1.135 +      MOZ_ASSERT(constructed);
   1.136 +      return &asT();
   1.137 +    }
   1.138 +
   1.139 +    T& ref() {
   1.140 +      MOZ_ASSERT(constructed);
   1.141 +      return asT();
   1.142 +    }
   1.143 +
   1.144 +    const T& ref() const {
   1.145 +      MOZ_ASSERT(constructed);
   1.146 +      return const_cast<Maybe*>(this)->asT();
   1.147 +    }
   1.148 +
   1.149 +    void destroy() {
   1.150 +      ref().~T();
   1.151 +      constructed = false;
   1.152 +    }
   1.153 +
   1.154 +    void destroyIfConstructed() {
   1.155 +      if (!empty())
   1.156 +        destroy();
   1.157 +    }
   1.158 +
   1.159 +  private:
   1.160 +    Maybe(const Maybe& other) MOZ_DELETE;
   1.161 +    const Maybe& operator=(const Maybe& other) MOZ_DELETE;
   1.162 +};
   1.163 +
   1.164 +} // namespace mozilla
   1.165 +
   1.166 +#endif /* mozilla_Maybe_h */

mercurial