Home | History | Annotate | Download | only in gtl
      1 /* Copyright 2015 The TensorFlow Authors. All Rights Reserved.
      2 
      3 Licensed under the Apache License, Version 2.0 (the "License");
      4 you may not use this file except in compliance with the License.
      5 You may obtain a copy of the License at
      6 
      7     http://www.apache.org/licenses/LICENSE-2.0
      8 
      9 Unless required by applicable law or agreed to in writing, software
     10 distributed under the License is distributed on an "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 See the License for the specific language governing permissions and
     13 limitations under the License.
     14 ==============================================================================*/
     15 
     16 // ManualConstructor statically-allocates space in which to store some
     17 // object, but does not initialize it.  You can then call the constructor
     18 // and destructor for the object yourself as you see fit.  This is useful
     19 // for memory management optimizations, where you want to initialize and
     20 // destroy an object multiple times but only allocate it once.
     21 //
     22 // (When I say ManualConstructor statically allocates space, I mean that
     23 // the ManualConstructor object itself is forced to be the right size.)
     24 
     25 #ifndef TENSORFLOW_LIB_GTL_MANUAL_CONSTRUCTOR_H_
     26 #define TENSORFLOW_LIB_GTL_MANUAL_CONSTRUCTOR_H_
     27 
     28 #include <stddef.h>
     29 #include <new>
     30 #include <utility>
     31 
     32 #include "tensorflow/core/platform/macros.h"
     33 #include "tensorflow/core/platform/mem.h"
     34 
     35 namespace tensorflow {
     36 namespace gtl {
     37 namespace internal {
     38 
     39 //
     40 // Provides a char array with the exact same alignment as another type. The
     41 // first parameter must be a complete type, the second parameter is how many
     42 // of that type to provide space for.
     43 //
     44 //   TF_LIB_GTL_ALIGNED_CHAR_ARRAY(struct stat, 16) storage_;
     45 //
     46 // Because MSVC and older GCCs require that the argument to their alignment
     47 // construct to be a literal constant integer, we use a template instantiated
     48 // at all the possible powers of two.
     49 #ifndef SWIG
     50 template <int alignment, int size>
     51 struct AlignType {};
     52 template <int size>
     53 struct AlignType<0, size> {
     54   typedef char result[size];
     55 };
     56 #if defined(COMPILER_MSVC)
     57 #define TF_LIB_GTL_ALIGN_ATTRIBUTE(X) __declspec(align(X))
     58 #define TF_LIB_GTL_ALIGN_OF(T) __alignof(T)
     59 #elif defined(COMPILER_GCC3) || __GNUC__ >= 3 || defined(__APPLE__) || \
     60     defined(COMPILER_ICC) || defined(OS_NACL) || defined(__clang__)
     61 #define TF_LIB_GTL_ALIGN_ATTRIBUTE(X) __attribute__((aligned(X)))
     62 #define TF_LIB_GTL_ALIGN_OF(T) __alignof__(T)
     63 #endif
     64 
     65 #if defined(TF_LIB_GTL_ALIGN_ATTRIBUTE)
     66 
     67 #define TF_LIB_GTL_ALIGNTYPE_TEMPLATE(X)                     \
     68   template <int size>                                        \
     69   struct AlignType<X, size> {                                \
     70     typedef TF_LIB_GTL_ALIGN_ATTRIBUTE(X) char result[size]; \
     71   }
     72 
     73 TF_LIB_GTL_ALIGNTYPE_TEMPLATE(1);
     74 TF_LIB_GTL_ALIGNTYPE_TEMPLATE(2);
     75 TF_LIB_GTL_ALIGNTYPE_TEMPLATE(4);
     76 TF_LIB_GTL_ALIGNTYPE_TEMPLATE(8);
     77 TF_LIB_GTL_ALIGNTYPE_TEMPLATE(16);
     78 TF_LIB_GTL_ALIGNTYPE_TEMPLATE(32);
     79 TF_LIB_GTL_ALIGNTYPE_TEMPLATE(64);
     80 TF_LIB_GTL_ALIGNTYPE_TEMPLATE(128);
     81 TF_LIB_GTL_ALIGNTYPE_TEMPLATE(256);
     82 TF_LIB_GTL_ALIGNTYPE_TEMPLATE(512);
     83 TF_LIB_GTL_ALIGNTYPE_TEMPLATE(1024);
     84 TF_LIB_GTL_ALIGNTYPE_TEMPLATE(2048);
     85 TF_LIB_GTL_ALIGNTYPE_TEMPLATE(4096);
     86 TF_LIB_GTL_ALIGNTYPE_TEMPLATE(8192);
     87 // Any larger and MSVC++ will complain.
     88 
     89 #define TF_LIB_GTL_ALIGNED_CHAR_ARRAY(T, Size)                          \
     90   typename tensorflow::gtl::internal::AlignType<TF_LIB_GTL_ALIGN_OF(T), \
     91                                                 sizeof(T) * Size>::result
     92 
     93 #undef TF_LIB_GTL_ALIGNTYPE_TEMPLATE
     94 #undef TF_LIB_GTL_ALIGN_ATTRIBUTE
     95 
     96 #else  // defined(TF_LIB_GTL_ALIGN_ATTRIBUTE)
     97 #error "You must define TF_LIB_GTL_ALIGNED_CHAR_ARRAY for your compiler."
     98 #endif  // defined(TF_LIB_GTL_ALIGN_ATTRIBUTE)
     99 
    100 #else  // !SWIG
    101 
    102 // SWIG can't represent alignment and doesn't care about alignment on data
    103 // members (it works fine without it).
    104 template <typename Size>
    105 struct AlignType {
    106   typedef char result[Size];
    107 };
    108 #define TF_LIB_GTL_ALIGNED_CHAR_ARRAY(T, Size) \
    109   tensorflow::gtl::internal::AlignType<Size * sizeof(T)>::result
    110 
    111 // Enough to parse with SWIG, will never be used by running code.
    112 #define TF_LIB_GTL_ALIGN_OF(Type) 16
    113 
    114 #endif  // !SWIG
    115 
    116 }  // namespace internal
    117 }  // namespace gtl
    118 
    119 template <typename Type>
    120 class ManualConstructor {
    121  public:
    122   // No constructor or destructor because one of the most useful uses of
    123   // this class is as part of a union, and members of a union cannot have
    124   // constructors or destructors.  And, anyway, the whole point of this
    125   // class is to bypass these.
    126 
    127   // Support users creating arrays of ManualConstructor<>s.  This ensures that
    128   // the array itself has the correct alignment.
    129   static void* operator new[](size_t size) {
    130     return port::AlignedMalloc(size, TF_LIB_GTL_ALIGN_OF(Type));
    131   }
    132   static void operator delete[](void* mem) { port::AlignedFree(mem); }
    133 
    134   inline Type* get() { return reinterpret_cast<Type*>(space_); }
    135   inline const Type* get() const {
    136     return reinterpret_cast<const Type*>(space_);
    137   }
    138 
    139   inline Type* operator->() { return get(); }
    140   inline const Type* operator->() const { return get(); }
    141 
    142   inline Type& operator*() { return *get(); }
    143   inline const Type& operator*() const { return *get(); }
    144 
    145   inline void Init() { new (space_) Type; }
    146 
    147 // Init() constructs the Type instance using the given arguments
    148 // (which are forwarded to Type's constructor). In C++11, Init() can
    149 // take any number of arguments of any type, and forwards them perfectly.
    150 // On pre-C++11 platforms, it can take up to 11 arguments, and may not be
    151 // able to forward certain kinds of arguments.
    152 //
    153 // Note that Init() with no arguments performs default-initialization,
    154 // not zero-initialization (i.e it behaves the same as "new Type;", not
    155 // "new Type();"), so it will leave non-class types uninitialized.
    156 #ifdef LANG_CXX11
    157   template <typename... Ts>
    158   inline void Init(Ts&&... args) {                 // NOLINT
    159     new (space_) Type(std::forward<Ts>(args)...);  // NOLINT
    160   }
    161 #else   // !defined(LANG_CXX11)
    162   template <typename T1>
    163   inline void Init(const T1& p1) {
    164     new (space_) Type(p1);
    165   }
    166 
    167   template <typename T1, typename T2>
    168   inline void Init(const T1& p1, const T2& p2) {
    169     new (space_) Type(p1, p2);
    170   }
    171 
    172   template <typename T1, typename T2, typename T3>
    173   inline void Init(const T1& p1, const T2& p2, const T3& p3) {
    174     new (space_) Type(p1, p2, p3);
    175   }
    176 
    177   template <typename T1, typename T2, typename T3, typename T4>
    178   inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4) {
    179     new (space_) Type(p1, p2, p3, p4);
    180   }
    181 
    182   template <typename T1, typename T2, typename T3, typename T4, typename T5>
    183   inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
    184                    const T5& p5) {
    185     new (space_) Type(p1, p2, p3, p4, p5);
    186   }
    187 
    188   template <typename T1, typename T2, typename T3, typename T4, typename T5,
    189             typename T6>
    190   inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
    191                    const T5& p5, const T6& p6) {
    192     new (space_) Type(p1, p2, p3, p4, p5, p6);
    193   }
    194 
    195   template <typename T1, typename T2, typename T3, typename T4, typename T5,
    196             typename T6, typename T7>
    197   inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
    198                    const T5& p5, const T6& p6, const T7& p7) {
    199     new (space_) Type(p1, p2, p3, p4, p5, p6, p7);
    200   }
    201 
    202   template <typename T1, typename T2, typename T3, typename T4, typename T5,
    203             typename T6, typename T7, typename T8>
    204   inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
    205                    const T5& p5, const T6& p6, const T7& p7, const T8& p8) {
    206     new (space_) Type(p1, p2, p3, p4, p5, p6, p7, p8);
    207   }
    208 
    209   template <typename T1, typename T2, typename T3, typename T4, typename T5,
    210             typename T6, typename T7, typename T8, typename T9>
    211   inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
    212                    const T5& p5, const T6& p6, const T7& p7, const T8& p8,
    213                    const T9& p9) {
    214     new (space_) Type(p1, p2, p3, p4, p5, p6, p7, p8, p9);
    215   }
    216 
    217   template <typename T1, typename T2, typename T3, typename T4, typename T5,
    218             typename T6, typename T7, typename T8, typename T9, typename T10>
    219   inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
    220                    const T5& p5, const T6& p6, const T7& p7, const T8& p8,
    221                    const T9& p9, const T10& p10) {
    222     new (space_) Type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);
    223   }
    224 
    225   template <typename T1, typename T2, typename T3, typename T4, typename T5,
    226             typename T6, typename T7, typename T8, typename T9, typename T10,
    227             typename T11>
    228   inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
    229                    const T5& p5, const T6& p6, const T7& p7, const T8& p8,
    230                    const T9& p9, const T10& p10, const T11& p11) {
    231     new (space_) Type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11);
    232   }
    233 #endif  // LANG_CXX11
    234 
    235   inline void Destroy() { get()->~Type(); }
    236 
    237  private:
    238   TF_LIB_GTL_ALIGNED_CHAR_ARRAY(Type, 1) space_;
    239 };
    240 
    241 #undef TF_LIB_GTL_ALIGNED_CHAR_ARRAY
    242 #undef TF_LIB_GTL_ALIGN_OF
    243 
    244 }  // namespace tensorflow
    245 
    246 #endif  // TENSORFLOW_LIB_GTL_MANUAL_CONSTRUCTOR_H_
    247