#ifndef ROOT_TNDArray
#define ROOT_TNDArray
#ifndef ROOT_TObject
#include "TObject.h"
#endif
#ifndef ROOT_TError
#include "TError.h"
#endif
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) {
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 {
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&);
TNDArray& operator=(const TNDArray&);
protected:
Int_t fNdimPlusOne;
Long64_t* fSizes;
ClassDef(TNDArray, 1);
};
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;
const Long64_t* fSizes;
ClassDefNV(TNDArrayRef, 0);
};
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* = "") {
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;
T* fData;
ClassDef(TNDArray, 1);
};
#endif // ROOT_TNDArray