// @(#)root/hist:$Id$
// Author: Axel Naumann, Nov 2011

/*************************************************************************
 * Copyright (C) 1995-2012, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#ifndef ROOT_TNDArray
#define ROOT_TNDArray

#ifndef ROOT_TObject
#include "TObject.h"
#endif
#ifndef ROOT_TError
#include "TError.h"
#endif

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TNDArray                                                             //
//                                                                      //
// N-Dim array class.                                                   //
//                                                                      //
// Storage layout:                                                      //
// Assume 3 dimensions, array sizes 2, 4 and 3 i.e. 24 bins:            //
// Data is stored as [0,0,0], [0,0,1], [0,0,2], [0,1,0],...             //
//                                                                      //
// fSizes stores the combined size of each bin in a dimension, i.e. in  //
// above example it would contain 24, 12, 3, 1.                         //
//                                                                      //
// Storage is allocated lazily, only when data is written to the array. //
//                                                                      //
// TNDArrayRef gives access to a sub-dimension, e.g. arr[0][1] in above //
// three-dimensional example, up to an element with conversion operator //
// to double: double value = arr[0][1][2];                              //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

// Array layout:
// nbins[0] = 2, nbins[1] = 4, nbins[2] = 3 => 24 bins
//
// fSizes: 24, 12, 3 [, 1

class TNDArray: public TObject {
public:
   TNDArray(): fNdimPlusOne(), fSizes() {}

   TNDArray(Int_t ndim, const Int_t* nbins, bool addOverflow = false):
   fNdimPlusOne(), fSizes() {
      TNDArray::Init(ndim, nbins, addOverflow);
   }
   ~TNDArray() {
      delete[] fSizes;
   }

   virtual void Init(Int_t ndim, const Int_t* nbins, bool addOverflow = false) {
      // Calculate fSize based on ndim dimensions, nbins for each dimension,
      // possibly adding over- and underflow bin to each dimensions' nbins.
      delete[] fSizes;
      fNdimPlusOne = ndim + 1;
      fSizes = new Long64_t[ndim + 1];
      Int_t overBins = addOverflow ? 2 : 0;
      fSizes[ndim] = 1;
      for (Int_t i = 0; i < ndim; ++i) {
         fSizes[ndim - i - 1] = fSizes[ndim - i] * (nbins[ndim - i - 1] + overBins);
      }
   }

   virtual void Reset(Option_t* option = "") = 0;

   Int_t GetNdimensions() const { return fNdimPlusOne - 1; }
   Long64_t GetNbins() const { return fSizes[0]; }
   Long64_t GetCellSize(Int_t dim) const { return fSizes[dim + 1]; }

   Long64_t GetBin(const Int_t* idx) const {
      // Get the linear bin number for each dimension's bin index
      Long64_t bin = idx[fNdimPlusOne - 2];
      for (Int_t d = 0; d < fNdimPlusOne - 2; ++d) {
         bin += fSizes[d + 1] * idx[d];
      }
      return bin;
   }

   virtual Double_t AtAsDouble(ULong64_t linidx) const = 0;
   virtual void SetAsDouble(ULong64_t linidx, Double_t value) = 0;
   virtual void AddAt(ULong64_t linidx, Double_t value) = 0;

private:
   TNDArray(const TNDArray&); // intentionally not implemented
   TNDArray& operator=(const TNDArray&); // intentionally not implemented

protected:
   Int_t  fNdimPlusOne; // Number of dimensions plus one
   Long64_t* fSizes; //[fNdimPlusOne] bin count
   ClassDef(TNDArray, 1); //Base for n-dimensional array
};

template <typename T>
class TNDArrayRef {
public:
   TNDArrayRef(const T* data, const Long64_t* sizes):
   fData(data), fSizes(sizes) {}

   TNDArrayRef<T> operator[] (Int_t idx) const {
      if (!fData) return TNDArrayRef<T>(0, 0);
      R__ASSERT(idx < fSizes[-1] / fSizes[0] && "index out of range!");
      return TNDArrayRef<T>(fData + idx * fSizes[0], (fSizes[0] == 1) ? 0 : (fSizes + 1));
   }
   operator T() const {
      if (!fData) return T();
      R__ASSERT(fSizes == 0 && "Element operator can only be used on non-array element. Missing an operator[] level?");
      return *fData;
   }

private:
   const T* fData; // pointer into TNDArray's fData
   const Long64_t* fSizes; // pointer into TNDArray's fSizes
   ClassDefNV(TNDArrayRef, 0); // subdimension of a TNDArray
};

template <typename T>
class TNDArrayT: public TNDArray {
public:
   TNDArrayT(): fNumData(), fData() {}

   TNDArrayT(Int_t ndim, const Int_t* nbins, bool addOverflow = false):
   TNDArray(ndim, nbins, addOverflow),
   fNumData(), fData() {
      fNumData = fSizes[0];
   }
   ~TNDArrayT() {
      delete[] fData;
   }

   void Init(Int_t ndim, const Int_t* nbins, bool addOverflow = false) {
      delete[] fData;
      fData = 0;
      TNDArray::Init(ndim, nbins, addOverflow);
      fNumData = fSizes[0];
   }

   void Reset(Option_t* /*option*/ = "") {
      // Reset the content

      // Use placement-new with value initialization:
      if (fData) {
         new (fData) T[fNumData]();
      }
   }

#ifndef __CINT__
   TNDArrayRef<T> operator[](Int_t idx) const {
      if (!fData) return TNDArrayRef<T>(0, 0);
      R__ASSERT(idx < fSizes[0] / fSizes[1] && "index out of range!");
      return TNDArrayRef<T>(fData + idx * fSizes[1], fSizes + 2);
   }
#endif // __CINT__

   T At(const Int_t* idx) const {
      return At(GetBin(idx));
   }
   T& At(const Int_t* idx) {
      return At(GetBin(idx));
   }
   T At(ULong64_t linidx) const {
      if (!fData) return T();
      return fData[linidx];
   }
   T& At(ULong64_t linidx) {
      if (!fData) fData = new T[fNumData]();
      return fData[linidx];
   }

   Double_t AtAsDouble(ULong64_t linidx) const {
      if (!fData) return 0.;
      return fData[linidx];
   }
   void SetAsDouble(ULong64_t linidx, Double_t value) {
      if (!fData) fData = new T[fNumData]();
      fData[linidx] = (T) value;
   }
   void AddAt(ULong64_t linidx, Double_t value) {
      if (!fData) fData = new T[fNumData]();
      fData[linidx] += (T) value;
   }

protected:
   int fNumData; // number of bins, product of fSizes
   T*  fData; //[fNumData] data
   ClassDef(TNDArray, 1); // N-dimensional array
};


#endif // ROOT_TNDArray
 TNDArray.h:1
 TNDArray.h:2
 TNDArray.h:3
 TNDArray.h:4
 TNDArray.h:5
 TNDArray.h:6
 TNDArray.h:7
 TNDArray.h:8
 TNDArray.h:9
 TNDArray.h:10
 TNDArray.h:11
 TNDArray.h:12
 TNDArray.h:13
 TNDArray.h:14
 TNDArray.h:15
 TNDArray.h:16
 TNDArray.h:17
 TNDArray.h:18
 TNDArray.h:19
 TNDArray.h:20
 TNDArray.h:21
 TNDArray.h:22
 TNDArray.h:23
 TNDArray.h:24
 TNDArray.h:25
 TNDArray.h:26
 TNDArray.h:27
 TNDArray.h:28
 TNDArray.h:29
 TNDArray.h:30
 TNDArray.h:31
 TNDArray.h:32
 TNDArray.h:33
 TNDArray.h:34
 TNDArray.h:35
 TNDArray.h:36
 TNDArray.h:37
 TNDArray.h:38
 TNDArray.h:39
 TNDArray.h:40
 TNDArray.h:41
 TNDArray.h:42
 TNDArray.h:43
 TNDArray.h:44
 TNDArray.h:45
 TNDArray.h:46
 TNDArray.h:47
 TNDArray.h:48
 TNDArray.h:49
 TNDArray.h:50
 TNDArray.h:51
 TNDArray.h:52
 TNDArray.h:53
 TNDArray.h:54
 TNDArray.h:55
 TNDArray.h:56
 TNDArray.h:57
 TNDArray.h:58
 TNDArray.h:59
 TNDArray.h:60
 TNDArray.h:61
 TNDArray.h:62
 TNDArray.h:63
 TNDArray.h:64
 TNDArray.h:65
 TNDArray.h:66
 TNDArray.h:67
 TNDArray.h:68
 TNDArray.h:69
 TNDArray.h:70
 TNDArray.h:71
 TNDArray.h:72
 TNDArray.h:73
 TNDArray.h:74
 TNDArray.h:75
 TNDArray.h:76
 TNDArray.h:77
 TNDArray.h:78
 TNDArray.h:79
 TNDArray.h:80
 TNDArray.h:81
 TNDArray.h:82
 TNDArray.h:83
 TNDArray.h:84
 TNDArray.h:85
 TNDArray.h:86
 TNDArray.h:87
 TNDArray.h:88
 TNDArray.h:89
 TNDArray.h:90
 TNDArray.h:91
 TNDArray.h:92
 TNDArray.h:93
 TNDArray.h:94
 TNDArray.h:95
 TNDArray.h:96
 TNDArray.h:97
 TNDArray.h:98
 TNDArray.h:99
 TNDArray.h:100
 TNDArray.h:101
 TNDArray.h:102
 TNDArray.h:103
 TNDArray.h:104
 TNDArray.h:105
 TNDArray.h:106
 TNDArray.h:107
 TNDArray.h:108
 TNDArray.h:109
 TNDArray.h:110
 TNDArray.h:111
 TNDArray.h:112
 TNDArray.h:113
 TNDArray.h:114
 TNDArray.h:115
 TNDArray.h:116
 TNDArray.h:117
 TNDArray.h:118
 TNDArray.h:119
 TNDArray.h:120
 TNDArray.h:121
 TNDArray.h:122
 TNDArray.h:123
 TNDArray.h:124
 TNDArray.h:125
 TNDArray.h:126
 TNDArray.h:127
 TNDArray.h:128
 TNDArray.h:129
 TNDArray.h:130
 TNDArray.h:131
 TNDArray.h:132
 TNDArray.h:133
 TNDArray.h:134
 TNDArray.h:135
 TNDArray.h:136
 TNDArray.h:137
 TNDArray.h:138
 TNDArray.h:139
 TNDArray.h:140
 TNDArray.h:141
 TNDArray.h:142
 TNDArray.h:143
 TNDArray.h:144
 TNDArray.h:145
 TNDArray.h:146
 TNDArray.h:147
 TNDArray.h:148
 TNDArray.h:149
 TNDArray.h:150
 TNDArray.h:151
 TNDArray.h:152
 TNDArray.h:153
 TNDArray.h:154
 TNDArray.h:155
 TNDArray.h:156
 TNDArray.h:157
 TNDArray.h:158
 TNDArray.h:159
 TNDArray.h:160
 TNDArray.h:161
 TNDArray.h:162
 TNDArray.h:163
 TNDArray.h:164
 TNDArray.h:165
 TNDArray.h:166
 TNDArray.h:167
 TNDArray.h:168
 TNDArray.h:169
 TNDArray.h:170
 TNDArray.h:171
 TNDArray.h:172
 TNDArray.h:173
 TNDArray.h:174
 TNDArray.h:175
 TNDArray.h:176
 TNDArray.h:177
 TNDArray.h:178
 TNDArray.h:179
 TNDArray.h:180
 TNDArray.h:181
 TNDArray.h:182
 TNDArray.h:183
 TNDArray.h:184
 TNDArray.h:185
 TNDArray.h:186
 TNDArray.h:187
 TNDArray.h:188
 TNDArray.h:189
 TNDArray.h:190
 TNDArray.h:191
 TNDArray.h:192
 TNDArray.h:193
 TNDArray.h:194
 TNDArray.h:195
 TNDArray.h:196
 TNDArray.h:197
 TNDArray.h:198