Back to index

enigmail  1.4.3
Util.h
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
00002  * vim: set ts=8 sw=4 et tw=99 ft=cpp:
00003  *
00004  * ***** BEGIN LICENSE BLOCK *****
00005  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00006  *
00007  * The contents of this file are subject to the Mozilla Public License Version
00008  * 1.1 (the "License"); you may not use this file except in compliance with
00009  * the License. You may obtain a copy of the License at:
00010  * http://www.mozilla.org/MPL/
00011  *
00012  * Software distributed under the License is distributed on an "AS IS" basis,
00013  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00014  * for the specific language governing rights and limitations under the
00015  * License.
00016  *
00017  * The Original Code is Mozilla Code.
00018  *
00019  * The Initial Developer of the Original Code is
00020  *   The Mozilla Foundation
00021  * Portions created by the Initial Developer are Copyright (C) 2011
00022  * the Initial Developer. All Rights Reserved.
00023  *
00024  * Contributor(s):
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 /*
00041  * Miscellaneous uncategorized functionality.  Please add new functionality to
00042  * new headers, or to other appropriate existing headers, not here.
00043  */
00044 
00045 #ifndef mozilla_Util_h_
00046 #define mozilla_Util_h_
00047 
00048 #include "mozilla/Assertions.h"
00049 #include "mozilla/Attributes.h"
00050 #include "mozilla/Types.h"
00051 
00052 #ifdef __cplusplus
00053 
00054 namespace mozilla {
00055 
00073 template <typename T>
00074 struct DebugOnly
00075 {
00076 #ifdef DEBUG
00077     T value;
00078 
00079     DebugOnly() {}
00080     DebugOnly(const T& other) : value(other) {}
00081     DebugOnly(const DebugOnly& other) : value(other.value) {}
00082     DebugOnly& operator=(const T& rhs) {
00083         value = rhs;
00084         return *this;
00085     }
00086     void operator++(int) {
00087         value++;
00088     }
00089     void operator--(int) {
00090         value--;
00091     }
00092 
00093     operator T&() { return value; }
00094     operator const T&() const { return value; }
00095 
00096     T& operator->() { return value; }
00097 
00098 #else
00099     DebugOnly() {}
00100     DebugOnly(const T&) {}
00101     DebugOnly(const DebugOnly&) {}
00102     DebugOnly& operator=(const T&) { return *this; }
00103     void operator++(int) {}
00104     void operator--(int) {}
00105 #endif
00106 
00107     /*
00108      * DebugOnly must always have a destructor or else it will
00109      * generate "unused variable" warnings, exactly what it's intended
00110      * to avoid!
00111      */
00112     ~DebugOnly() {}
00113 };
00114 
00115 /*
00116  * This class, and the corresponding macro MOZ_ALIGNOF, figure out how many 
00117  * bytes of alignment a given type needs.
00118  */
00119 template<class T>
00120 struct AlignmentFinder
00121 {
00122 private:
00123   struct Aligner
00124   {
00125     char c;
00126     T t;
00127   };
00128 
00129 public:
00130   static const int alignment = sizeof(Aligner) - sizeof(T);
00131 };
00132 
00133 #define MOZ_ALIGNOF(T) mozilla::AlignmentFinder<T>::alignment
00134 
00135 /*
00136  * Declare the MOZ_ALIGNED_DECL macro for declaring aligned types.
00137  *
00138  * For instance,
00139  *
00140  *   MOZ_ALIGNED_DECL(char arr[2], 8);
00141  *
00142  * will declare a two-character array |arr| aligned to 8 bytes.
00143  */
00144 
00145 #if defined(__GNUC__)
00146 #  define MOZ_ALIGNED_DECL(_type, _align) \
00147      _type __attribute__((aligned(_align)))
00148 #elif defined(_MSC_VER)
00149 #  define MOZ_ALIGNED_DECL(_type, _align) \
00150      __declspec(align(_align)) _type
00151 #else
00152 #  warning "We don't know how to align variables on this compiler."
00153 #  define MOZ_ALIGNED_DECL(_type, _align) _type
00154 #endif
00155 
00156 /*
00157  * AlignedElem<N> is a structure whose alignment is guaranteed to be at least N bytes.
00158  *
00159  * We support 1, 2, 4, 8, and 16-bit alignment.
00160  */
00161 template<size_t align>
00162 struct AlignedElem;
00163 
00164 /*
00165  * We have to specialize this template because GCC doesn't like __attribute__((aligned(foo))) where
00166  * foo is a template parameter.
00167  */
00168 
00169 template<>
00170 struct AlignedElem<1>
00171 {
00172   MOZ_ALIGNED_DECL(uint8_t elem, 1);
00173 };
00174 
00175 template<>
00176 struct AlignedElem<2>
00177 {
00178   MOZ_ALIGNED_DECL(uint8_t elem, 2);
00179 };
00180 
00181 template<>
00182 struct AlignedElem<4>
00183 {
00184   MOZ_ALIGNED_DECL(uint8_t elem, 4);
00185 };
00186 
00187 template<>
00188 struct AlignedElem<8>
00189 {
00190   MOZ_ALIGNED_DECL(uint8_t elem, 8);
00191 };
00192 
00193 template<>
00194 struct AlignedElem<16>
00195 {
00196   MOZ_ALIGNED_DECL(uint8_t elem, 16);
00197 };
00198 
00199 /*
00200  * This utility pales in comparison to Boost's aligned_storage. The utility
00201  * simply assumes that uint64_t is enough alignment for anyone. This may need
00202  * to be extended one day...
00203  *
00204  * As an important side effect, pulling the storage into this template is
00205  * enough obfuscation to confuse gcc's strict-aliasing analysis into not giving
00206  * false negatives when we cast from the char buffer to whatever type we've
00207  * constructed using the bytes.
00208  */
00209 template <size_t nbytes>
00210 struct AlignedStorage
00211 {
00212     union U {
00213         char bytes[nbytes];
00214         uint64_t _;
00215     } u;
00216 
00217     const void *addr() const { return u.bytes; }
00218     void *addr() { return u.bytes; }
00219 };
00220 
00221 template <class T>
00222 struct AlignedStorage2
00223 {
00224     union U {
00225         char bytes[sizeof(T)];
00226         uint64_t _;
00227     } u;
00228 
00229     const T *addr() const { return (const T *)u.bytes; }
00230     T *addr() { return (T *)(void *)u.bytes; }
00231 };
00232 
00233 /*
00234  * Small utility for lazily constructing objects without using dynamic storage.
00235  * When a Maybe<T> is constructed, it is |empty()|, i.e., no value of T has
00236  * been constructed and no T destructor will be called when the Maybe<T> is
00237  * destroyed. Upon calling |construct|, a T object will be constructed with the
00238  * given arguments and that object will be destroyed when the owning Maybe<T>
00239  * is destroyed.
00240  *
00241  * N.B. GCC seems to miss some optimizations with Maybe and may generate extra
00242  * branches/loads/stores. Use with caution on hot paths.
00243  */
00244 template <class T>
00245 class Maybe
00246 {
00247     AlignedStorage2<T> storage;
00248     bool constructed;
00249 
00250     T &asT() { return *storage.addr(); }
00251 
00252     explicit Maybe(const Maybe &other);
00253     const Maybe &operator=(const Maybe &other);
00254 
00255   public:
00256     Maybe() { constructed = false; }
00257     ~Maybe() { if (constructed) asT().~T(); }
00258 
00259     bool empty() const { return !constructed; }
00260 
00261     void construct() {
00262         MOZ_ASSERT(!constructed);
00263         new(storage.addr()) T();
00264         constructed = true;
00265     }
00266 
00267     template <class T1>
00268     void construct(const T1 &t1) {
00269         MOZ_ASSERT(!constructed);
00270         new(storage.addr()) T(t1);
00271         constructed = true;
00272     }
00273 
00274     template <class T1, class T2>
00275     void construct(const T1 &t1, const T2 &t2) {
00276         MOZ_ASSERT(!constructed);
00277         new(storage.addr()) T(t1, t2);
00278         constructed = true;
00279     }
00280 
00281     template <class T1, class T2, class T3>
00282     void construct(const T1 &t1, const T2 &t2, const T3 &t3) {
00283         MOZ_ASSERT(!constructed);
00284         new(storage.addr()) T(t1, t2, t3);
00285         constructed = true;
00286     }
00287 
00288     template <class T1, class T2, class T3, class T4>
00289     void construct(const T1 &t1, const T2 &t2, const T3 &t3, const T4 &t4) {
00290         MOZ_ASSERT(!constructed);
00291         new(storage.addr()) T(t1, t2, t3, t4);
00292         constructed = true;
00293     }
00294 
00295     T *addr() {
00296         MOZ_ASSERT(constructed);
00297         return &asT();
00298     }
00299 
00300     T &ref() {
00301         MOZ_ASSERT(constructed);
00302         return asT();
00303     }
00304 
00305     const T &ref() const {
00306         MOZ_ASSERT(constructed);
00307         return const_cast<Maybe *>(this)->asT();
00308     }
00309 
00310     void destroy() {
00311         ref().~T();
00312         constructed = false;
00313     }
00314 
00315     void destroyIfConstructed() {
00316         if (!empty())
00317             destroy();
00318     }
00319 };
00320 
00321 /*
00322  * Safely subtract two pointers when it is known that end >= begin.  This avoids
00323  * the common compiler bug that if (size_t(end) - size_t(begin)) has the MSB
00324  * set, the unsigned subtraction followed by right shift will produce -1, or
00325  * size_t(-1), instead of the real difference.
00326  */
00327 template <class T>
00328 MOZ_ALWAYS_INLINE size_t
00329 PointerRangeSize(T* begin, T* end)
00330 {
00331     MOZ_ASSERT(end >= begin);
00332     return (size_t(end) - size_t(begin)) / sizeof(T);
00333 }
00334 
00335 /*
00336  * Compute the length of an array with constant length.  (Use of this method
00337  * with a non-array pointer will not compile.)
00338  *
00339  * Beware of the implicit trailing '\0' when using this with string constants.
00340  */
00341 template<typename T, size_t N>
00342 size_t
00343 ArrayLength(T (&arr)[N])
00344 {
00345     return N;
00346 }
00347 
00348 /*
00349  * Compute the address one past the last element of a constant-length array.
00350  *
00351  * Beware of the implicit trailing '\0' when using this with string constants.
00352  */
00353 template<typename T, size_t N>
00354 T*
00355 ArrayEnd(T (&arr)[N])
00356 {
00357     return arr + ArrayLength(arr);
00358 }
00359 
00360 } /* namespace mozilla */
00361 
00362 #endif /* __cplusplus */
00363 
00364 #endif  /* mozilla_Util_h_ */