Tensor.h
00001 // This file is part of Eigen, a lightweight C++ template library
00002 // for linear algebra.
00003 //
00004 // Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
00005 // Copyright (C) 2013 Christian Seiler <christian@iwakd.de>
00006 //
00007 // This Source Code Form is subject to the terms of the Mozilla
00008 // Public License v. 2.0. If a copy of the MPL was not distributed
00009 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
00010 
00011 #ifndef EIGEN_CXX11_TENSOR_TENSOR_H
00012 #define EIGEN_CXX11_TENSOR_TENSOR_H
00013 
00014 namespace Eigen {
00015 
00062 template<typename Scalar_, int NumIndices_, int Options_, typename IndexType_>
00063 class Tensor : public TensorBase<Tensor<Scalar_, NumIndices_, Options_, IndexType_> >
00064 {
00065   public:
00066     typedef Tensor<Scalar_, NumIndices_, Options_, IndexType_> Self;
00067     typedef TensorBase<Tensor<Scalar_, NumIndices_, Options_, IndexType_> > Base;
00068     typedef typename Eigen::internal::nested<Self>::type Nested;
00069     typedef typename internal::traits<Self>::StorageKind StorageKind;
00070     typedef typename internal::traits<Self>::Index Index;
00071     typedef Scalar_ Scalar;
00072     typedef typename NumTraits<Scalar>::Real RealScalar;
00073     typedef typename Base::CoeffReturnType CoeffReturnType;
00074 
00075     enum {
00076       IsAligned = bool(EIGEN_MAX_ALIGN_BYTES>0) & !(Options_&DontAlign),
00077       Layout = Options_ & RowMajor ? RowMajor : ColMajor,
00078       CoordAccess = true,
00079       RawAccess = true
00080     };
00081 
00082     static const int Options = Options_;
00083     static const int NumIndices = NumIndices_;
00084     typedef DSizes<Index, NumIndices_> Dimensions;
00085 
00086   protected:
00087     TensorStorage<Scalar, Dimensions, Options> m_storage;
00088 
00089 #ifdef EIGEN_HAS_SFINAE
00090     template<typename CustomIndices>
00091     struct isOfNormalIndex{
00092       static const bool is_array = internal::is_base_of<array<Index, NumIndices>, CustomIndices>::value;
00093       static const bool is_int = NumTraits<CustomIndices>::IsInteger;
00094       static const bool value = is_array | is_int;
00095     };
00096 #endif
00097 
00098   public:
00099     // Metadata
00100     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index                         rank()                   const { return NumIndices; }
00101     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index                         dimension(std::size_t n) const { return m_storage.dimensions()[n]; }
00102     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions&             dimensions()             const { return m_storage.dimensions(); }
00103     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index                         size()                   const { return m_storage.size(); }
00104     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar                        *data()                        { return m_storage.data(); }
00105     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar                  *data()                  const { return m_storage.data(); }
00106 
00107     // This makes EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED
00108     // work, because that uses base().coeffRef() - and we don't yet
00109     // implement a similar class hierarchy
00110     inline Self& base()             { return *this; }
00111     inline const Self& base() const { return *this; }
00112 
00113 #if EIGEN_HAS_VARIADIC_TEMPLATES
00114     template<typename... IndexTypes>
00115     EIGEN_DEVICE_FUNC inline const Scalar& coeff(Index firstIndex, Index secondIndex, IndexTypes... otherIndices) const
00116     {
00117       // The number of indices used to access a tensor coefficient must be equal to the rank of the tensor.
00118       EIGEN_STATIC_ASSERT(sizeof...(otherIndices) + 2 == NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE)
00119       return coeff(array<Index, NumIndices>{{firstIndex, secondIndex, otherIndices...}});
00120     }
00121 #endif
00122 
00123     // normal indices
00124     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& coeff(const array<Index, NumIndices>& indices) const
00125     {
00126       eigen_internal_assert(checkIndexRange(indices));
00127       return m_storage.data()[linearizedIndex(indices)];
00128     }
00129 
00130     // custom indices
00131 #ifdef EIGEN_HAS_SFINAE
00132     template<typename CustomIndices,
00133              EIGEN_SFINAE_ENABLE_IF( !(isOfNormalIndex<CustomIndices>::value) )
00134     >
00135     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& coeff(CustomIndices& indices) const
00136     {
00137         return coeff(internal::customIndices2Array<Index,NumIndices>(indices));
00138     }
00139 #endif
00140 
00141     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& coeff() const
00142     {
00143       EIGEN_STATIC_ASSERT(NumIndices == 0, YOU_MADE_A_PROGRAMMING_MISTAKE);
00144       return m_storage.data()[0];
00145     }
00146 
00147     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& coeff(Index index) const
00148     {
00149       eigen_internal_assert(index >= 0 && index < size());
00150       return m_storage.data()[index];
00151     }
00152 
00153 #if EIGEN_HAS_VARIADIC_TEMPLATES
00154     template<typename... IndexTypes>
00155     inline Scalar& coeffRef(Index firstIndex, Index secondIndex, IndexTypes... otherIndices)
00156     {
00157       // The number of indices used to access a tensor coefficient must be equal to the rank of the tensor.
00158       EIGEN_STATIC_ASSERT(sizeof...(otherIndices) + 2 == NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE)
00159       return coeffRef(array<Index, NumIndices>{{firstIndex, secondIndex, otherIndices...}});
00160     }
00161 #endif
00162 
00163     // normal indices
00164     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(const array<Index, NumIndices>& indices)
00165     {
00166       eigen_internal_assert(checkIndexRange(indices));
00167       return m_storage.data()[linearizedIndex(indices)];
00168     }
00169 
00170     // custom indices
00171 #ifdef EIGEN_HAS_SFINAE
00172     template<typename CustomIndices,
00173              EIGEN_SFINAE_ENABLE_IF( !(isOfNormalIndex<CustomIndices>::value) )
00174              >
00175     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(CustomIndices& indices)
00176     {
00177         return coeffRef(internal::customIndices2Array<Index,NumIndices>(indices));
00178     }
00179 #endif
00180 
00181     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef()
00182     {
00183       EIGEN_STATIC_ASSERT(NumIndices == 0, YOU_MADE_A_PROGRAMMING_MISTAKE);
00184       return m_storage.data()[0];
00185     }
00186 
00187     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index index)
00188     {
00189       eigen_internal_assert(index >= 0 && index < size());
00190       return m_storage.data()[index];
00191     }
00192 
00193 #if EIGEN_HAS_VARIADIC_TEMPLATES
00194     template<typename... IndexTypes>
00195     inline const Scalar& operator()(Index firstIndex, Index secondIndex, IndexTypes... otherIndices) const
00196     {
00197       // The number of indices used to access a tensor coefficient must be equal to the rank of the tensor.
00198       EIGEN_STATIC_ASSERT(sizeof...(otherIndices) + 2 == NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE)
00199       return this->operator()(array<Index, NumIndices>{{firstIndex, secondIndex, otherIndices...}});
00200     }
00201 #else
00202     EIGEN_DEVICE_FUNC
00203     EIGEN_STRONG_INLINE const Scalar& operator()(Index i0, Index i1) const
00204     {
00205       return coeff(array<Index, 2>(i0, i1));
00206     }
00207     EIGEN_DEVICE_FUNC
00208     EIGEN_STRONG_INLINE const Scalar& operator()(Index i0, Index i1, Index i2) const
00209     {
00210       return coeff(array<Index, 3>(i0, i1, i2));
00211     }
00212     EIGEN_DEVICE_FUNC
00213     EIGEN_STRONG_INLINE const Scalar& operator()(Index i0, Index i1, Index i2, Index i3) const
00214     {
00215       return coeff(array<Index, 4>(i0, i1, i2, i3));
00216     }
00217     EIGEN_DEVICE_FUNC
00218     EIGEN_STRONG_INLINE const Scalar& operator()(Index i0, Index i1, Index i2, Index i3, Index i4) const
00219     {
00220       return coeff(array<Index, 5>(i0, i1, i2, i3, i4));
00221     }
00222 #endif
00223 
00224     // custom indices
00225 #ifdef EIGEN_HAS_SFINAE
00226     template<typename CustomIndices,
00227              EIGEN_SFINAE_ENABLE_IF( !(isOfNormalIndex<CustomIndices>::value) )
00228     >
00229     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& operator()(CustomIndices& indices) const
00230     {
00231         return coeff(internal::customIndices2Array<Index,NumIndices>(indices));
00232     }
00233 #endif
00234 
00235     // normal indices
00236     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& operator()(const array<Index, NumIndices>& indices) const
00237     {
00238       return coeff(indices);
00239     }
00240 
00241     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& operator()(Index index) const
00242     {
00243       eigen_internal_assert(index >= 0 && index < size());
00244       return coeff(index);
00245     }
00246 
00247     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& operator()() const
00248     {
00249       EIGEN_STATIC_ASSERT(NumIndices == 0, YOU_MADE_A_PROGRAMMING_MISTAKE);
00250       return coeff();
00251     }
00252 
00253     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& operator[](Index index) const
00254     {
00255       // The bracket operator is only for vectors, use the parenthesis operator instead.
00256       EIGEN_STATIC_ASSERT(NumIndices == 1, YOU_MADE_A_PROGRAMMING_MISTAKE);
00257       return coeff(index);
00258     }
00259 
00260 #if EIGEN_HAS_VARIADIC_TEMPLATES
00261     template<typename... IndexTypes>
00262     inline Scalar& operator()(Index firstIndex, Index secondIndex, IndexTypes... otherIndices)
00263     {
00264       // The number of indices used to access a tensor coefficient must be equal to the rank of the tensor.
00265       EIGEN_STATIC_ASSERT(sizeof...(otherIndices) + 2 == NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE)
00266       return operator()(array<Index, NumIndices>{{firstIndex, secondIndex, otherIndices...}});
00267     }
00268 #else
00269     EIGEN_DEVICE_FUNC
00270     EIGEN_STRONG_INLINE Scalar& operator()(Index i0, Index i1)
00271     {
00272       return coeffRef(array<Index, 2>(i0, i1));
00273     }
00274     EIGEN_DEVICE_FUNC
00275     EIGEN_STRONG_INLINE Scalar& operator()(Index i0, Index i1, Index i2)
00276     {
00277       return coeffRef(array<Index, 3>(i0, i1, i2));
00278     }
00279     EIGEN_DEVICE_FUNC
00280     EIGEN_STRONG_INLINE Scalar& operator()(Index i0, Index i1, Index i2, Index i3)
00281     {
00282       return coeffRef(array<Index, 4>(i0, i1, i2, i3));
00283     }
00284     EIGEN_DEVICE_FUNC
00285     EIGEN_STRONG_INLINE Scalar& operator()(Index i0, Index i1, Index i2, Index i3, Index i4)
00286     {
00287       return coeffRef(array<Index, 5>(i0, i1, i2, i3, i4));
00288     }
00289 #endif
00290 
00291     // normal indices
00292     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& operator()(const array<Index, NumIndices>& indices)
00293     {
00294       return coeffRef(indices);
00295     }
00296 
00297     // custom indices
00298 #ifdef EIGEN_HAS_SFINAE
00299     template<typename CustomIndices,
00300              EIGEN_SFINAE_ENABLE_IF( !(isOfNormalIndex<CustomIndices>::value) )
00301     >
00302     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& operator()(CustomIndices& indices)
00303     {
00304       return coeffRef(internal::customIndices2Array<Index,NumIndices>(indices));
00305     }
00306 #endif
00307 
00308     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& operator()(Index index)
00309     {
00310       eigen_assert(index >= 0 && index < size());
00311       return coeffRef(index);
00312     }
00313 
00314     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& operator()()
00315     {
00316       EIGEN_STATIC_ASSERT(NumIndices == 0, YOU_MADE_A_PROGRAMMING_MISTAKE);
00317       return coeffRef();
00318     }
00319 
00320     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& operator[](Index index)
00321     {
00322       // The bracket operator is only for vectors, use the parenthesis operator instead
00323       EIGEN_STATIC_ASSERT(NumIndices == 1, YOU_MADE_A_PROGRAMMING_MISTAKE)
00324       return coeffRef(index);
00325     }
00326 
00327     EIGEN_DEVICE_FUNC
00328     EIGEN_STRONG_INLINE Tensor()
00329       : m_storage()
00330     {
00331     }
00332 
00333     EIGEN_DEVICE_FUNC
00334     EIGEN_STRONG_INLINE Tensor(const Self& other)
00335       : m_storage(other.m_storage)
00336     {
00337     }
00338 
00339 #if EIGEN_HAS_VARIADIC_TEMPLATES
00340     template<typename... IndexTypes>
00341     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Tensor(Index firstDimension, IndexTypes... otherDimensions)
00342         : m_storage(firstDimension, otherDimensions...)
00343     {
00344       // The number of dimensions used to construct a tensor must be equal to the rank of the tensor.
00345       EIGEN_STATIC_ASSERT(sizeof...(otherDimensions) + 1 == NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE)
00346     }
00347 #else
00348     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit Tensor(Index dim1)
00349       : m_storage(dim1, array<Index, 1>(dim1))
00350     {
00351       EIGEN_STATIC_ASSERT(1 == NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE)
00352     }
00353     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Tensor(Index dim1, Index dim2)
00354       : m_storage(dim1*dim2, array<Index, 2>(dim1, dim2))
00355     {
00356       EIGEN_STATIC_ASSERT(2 == NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE)
00357     }
00358     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Tensor(Index dim1, Index dim2, Index dim3)
00359       : m_storage(dim1*dim2*dim3, array<Index, 3>(dim1, dim2, dim3))
00360     {
00361       EIGEN_STATIC_ASSERT(3 == NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE)
00362     }
00363     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Tensor(Index dim1, Index dim2, Index dim3, Index dim4)
00364       : m_storage(dim1*dim2*dim3*dim4, array<Index, 4>(dim1, dim2, dim3, dim4))
00365     {
00366       EIGEN_STATIC_ASSERT(4 == NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE)
00367     }
00368     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Tensor(Index dim1, Index dim2, Index dim3, Index dim4, Index dim5)
00369       : m_storage(dim1*dim2*dim3*dim4*dim5, array<Index, 5>(dim1, dim2, dim3, dim4, dim5))
00370     {
00371       EIGEN_STATIC_ASSERT(5 == NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE)
00372     }
00373 #endif
00374 
00376     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit Tensor(const array<Index, NumIndices>& dimensions)
00377         : m_storage(internal::array_prod(dimensions), dimensions)
00378     {
00379       EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED
00380     }
00381 
00382     template<typename OtherDerived>
00383     EIGEN_DEVICE_FUNC
00384     EIGEN_STRONG_INLINE Tensor(const TensorBase<OtherDerived, ReadOnlyAccessors>& other)
00385     {
00386       typedef TensorAssignOp<Tensor, const OtherDerived> Assign;
00387       Assign assign(*this, other.derived());
00388       resize(TensorEvaluator<const Assign, DefaultDevice>(assign, DefaultDevice()).dimensions());
00389       internal::TensorExecutor<const Assign, DefaultDevice>::run(assign, DefaultDevice());
00390     }
00391     template<typename OtherDerived>
00392     EIGEN_DEVICE_FUNC
00393     EIGEN_STRONG_INLINE Tensor(const TensorBase<OtherDerived, WriteAccessors>& other)
00394     {
00395       typedef TensorAssignOp<Tensor, const OtherDerived> Assign;
00396       Assign assign(*this, other.derived());
00397       resize(TensorEvaluator<const Assign, DefaultDevice>(assign, DefaultDevice()).dimensions());
00398       internal::TensorExecutor<const Assign, DefaultDevice>::run(assign, DefaultDevice());
00399     }
00400 
00401     EIGEN_DEVICE_FUNC
00402     EIGEN_STRONG_INLINE Tensor& operator=(const Tensor& other)
00403     {
00404       typedef TensorAssignOp<Tensor, const Tensor> Assign;
00405       Assign assign(*this, other);
00406       resize(TensorEvaluator<const Assign, DefaultDevice>(assign, DefaultDevice()).dimensions());
00407       internal::TensorExecutor<const Assign, DefaultDevice>::run(assign, DefaultDevice());
00408       return *this;
00409     }
00410     template<typename OtherDerived>
00411     EIGEN_DEVICE_FUNC
00412     EIGEN_STRONG_INLINE Tensor& operator=(const OtherDerived& other)
00413     {
00414       typedef TensorAssignOp<Tensor, const OtherDerived> Assign;
00415       Assign assign(*this, other);
00416       resize(TensorEvaluator<const Assign, DefaultDevice>(assign, DefaultDevice()).dimensions());
00417       internal::TensorExecutor<const Assign, DefaultDevice>::run(assign, DefaultDevice());
00418       return *this;
00419     }
00420 
00421 #if EIGEN_HAS_VARIADIC_TEMPLATES
00422     template<typename... IndexTypes> EIGEN_DEVICE_FUNC
00423     void resize(Index firstDimension, IndexTypes... otherDimensions)
00424     {
00425       // The number of dimensions used to resize a tensor must be equal to the rank of the tensor.
00426       EIGEN_STATIC_ASSERT(sizeof...(otherDimensions) + 1 == NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE)
00427       resize(array<Index, NumIndices>{{firstDimension, otherDimensions...}});
00428     }
00429 #endif
00430 
00432     EIGEN_DEVICE_FUNC void resize(const array<Index, NumIndices>& dimensions)
00433     {
00434       int i;
00435       Index size = Index(1);
00436       for (i = 0; i < NumIndices; i++) {
00437         internal::check_rows_cols_for_overflow<Dynamic>::run(size, dimensions[i]);
00438         size *= dimensions[i];
00439       }
00440       #ifdef EIGEN_INITIALIZE_COEFFS
00441         bool size_changed = size != this->size();
00442         m_storage.resize(size, dimensions);
00443         if(size_changed) EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED
00444       #else
00445         m_storage.resize(size, dimensions);
00446       #endif
00447     }
00448 
00449     // Why this overload, DSizes is derived from array ??? //
00450     EIGEN_DEVICE_FUNC void resize(const DSizes<Index, NumIndices>& dimensions) {
00451       array<Index, NumIndices> dims;
00452       for (int i = 0; i < NumIndices; ++i) {
00453         dims[i] = dimensions[i];
00454       }
00455       resize(dims);
00456     }
00457 
00458     EIGEN_DEVICE_FUNC
00459     void resize()
00460     {
00461       EIGEN_STATIC_ASSERT(NumIndices == 0, YOU_MADE_A_PROGRAMMING_MISTAKE);
00462       // Nothing to do: rank 0 tensors have fixed size
00463     }
00464 
00466 #ifdef EIGEN_HAS_SFINAE
00467     template<typename CustomDimension,
00468              EIGEN_SFINAE_ENABLE_IF( !(isOfNormalIndex<CustomDimension>::value) )
00469     >
00470     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void resize(CustomDimension& dimensions)
00471     {
00472       resize(internal::customIndices2Array<Index,NumIndices>(dimensions));
00473     }
00474 #endif
00475 
00476 #ifndef EIGEN_EMULATE_CXX11_META_H
00477     template <typename std::ptrdiff_t... Indices>
00478     EIGEN_DEVICE_FUNC
00479     void resize(const Sizes<Indices...>& dimensions) {
00480       array<Index, NumIndices> dims;
00481       for (int i = 0; i < NumIndices; ++i) {
00482         dims[i] = static_cast<Index>(dimensions[i]);
00483       }
00484       resize(dims);
00485     }
00486 #else
00487     template <std::size_t V1, std::size_t V2, std::size_t V3, std::size_t V4, std::size_t V5>
00488     EIGEN_DEVICE_FUNC
00489     void resize(const Sizes<V1, V2, V3, V4, V5>& dimensions) {
00490       array<Index, NumIndices> dims;
00491       for (int i = 0; i < NumIndices; ++i) {
00492         dims[i] = static_cast<Index>(dimensions[i]);
00493       }
00494       resize(dims);
00495     }
00496 #endif
00497 
00498   protected:
00499 
00500     bool checkIndexRange(const array<Index, NumIndices>& indices) const
00501     {
00502       using internal::array_apply_and_reduce;
00503       using internal::array_zip_and_reduce;
00504       using internal::greater_equal_zero_op;
00505       using internal::logical_and_op;
00506       using internal::lesser_op;
00507 
00508       return
00509         // check whether the indices are all >= 0
00510         array_apply_and_reduce<logical_and_op, greater_equal_zero_op>(indices) &&
00511         // check whether the indices fit in the dimensions
00512         array_zip_and_reduce<logical_and_op, lesser_op>(indices, m_storage.dimensions());
00513     }
00514 
00515     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index linearizedIndex(const array<Index, NumIndices>& indices) const
00516     {
00517       if (Options&RowMajor) {
00518         return m_storage.dimensions().IndexOfRowMajor(indices);
00519       } else {
00520         return m_storage.dimensions().IndexOfColMajor(indices);
00521       }
00522     }
00523 };
00524 
00525 } // end namespace Eigen
00526 
00527 #endif // EIGEN_CXX11_TENSOR_TENSOR_H
 All Classes Functions Variables Typedefs Enumerator