// data structures, includes dynamically allocated vectors and arrays
// (c) 1999-2003, Pawel Jalocha

#ifndef __STRUC_H__
#define __STRUC_H__

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// ========================================================================
// array re(sizing), copy, move, preset, etc.

template <class type>
 inline int ReallocArray(type **Array, size_t Size)
  {
// CINT doesn't accept NULL pointers to realloc
#ifdef __CINT__
//    if(*Array) free(*Array);
//    (*Array)=(type *)malloc(Size*sizeof(type));
    if(*Array) (*Array)=(type *)realloc(*Array,Size*sizeof(type));
          else (*Array)=(type *)malloc(Size*sizeof(type));
#else
    (*Array)=(type *)realloc(*Array,Size*sizeof(type));
#endif
    return (*Array)==0 ? -1:0; }

template <class type>
 int ReallocArraySafe(type **Array, size_t OldSize, size_t NewSize)
  { type *New; size_t Size;
    New=(type *)malloc(NewSize*sizeof(type)); if(New==0) return -1;
    Size=OldSize; if(NewSize<OldSize) Size=NewSize;
    if(Size) memcpy(New,*Array,Size*sizeof(type));
    free(*Array); (*Array)=New; return 0; }

template <class type>
 inline int AllocArray(type **Array, size_t Size)
  { (*Array)=(type *)malloc(Size*sizeof(type));
    return (*Array)==0; }

template <class type>
 inline void ClearArray(type *Array, size_t Size)
  { memset(Array,0,Size*sizeof(type)); }

template <class type>
 void PresetArray(type *Array, size_t Size, const type &Val)
  { size_t i; for(i=0; i<Size; i++) Array[i]=Val; }

template <class type>
 inline void CopyArray(type *Dst, type *Src, size_t Size)
  { memcpy(Dst,Src,Size*sizeof(type)); }

template <class type>
 inline void MoveArray(type *Dst, type *Src, size_t Size)
  { memmove(Dst,Src,Size*sizeof(type)); }

template <class type>
 void PrintArray(type *Array, size_t Size,
                 char *ValueFormat, char *IndexFormat=(char *)"%3d", size_t Columns=10)
{ size_t Idx,Col;
  for(Col=0,Idx=0; Idx<Size; Idx++)
  { if(Col==0)
    { printf(IndexFormat,Idx); printf(":"); }
    printf(" ");
    printf(ValueFormat,Array[Idx]);
    Col++; if(Col>=Columns) { printf("\n"); Col=0; }
  }
  if(Col>0) printf("\n");
}

// -----------------------------------------------------------------------
// 2-dimensional array (re)sizing

template <class type> int AllocArray2D(type ***Array, size_t Rows, size_t Cols)
{ size_t i;
  (*Array)=(type **)malloc(Rows*(sizeof(type *)));
  if((*Array)==0) return -1;
  for(i=0; i<Rows; i++) (*Array)[i]=0;
  for(i=0; i<Rows; i++)
  { (*Array)[i]=(type *)malloc(Cols*sizeof(type));
    if((*Array)[i]==0) goto Error; }
  return 0;
Error:
  for(i=0; i<Rows; i++) free((*Array)[i]); free(*Array); (*Array)=0; return -1;
}
/*
template <class type> int AddRowsToArray2D(type ***Array, size_t Rows, size_t Cols,
                                           size_t NewRows=1)
{ size_t i;
  type **NewArray;
  NewArray=(type **)malloc((Rows+NewRows)*(sizeof(type *)));
  if(NewArray==0) return -1;
  memcpy(NewArray,*Array,Rows*sizeof(type *));
  return 0;
}
*/
template <class type> void FreeArray2D(type **Array, size_t Rows)
{ size_t i; for(i=0; i<Rows; i++) free(Array[i]); free(Array); }

template <class type> void ClearArray2D(type **Array, size_t Rows, size_t Cols)
{ size_t i; for(i=0; i<Rows; i++) ClearArray(Array[i],Cols); }

template <class type> void PresetArray2D(type **Array, size_t Rows, size_t Cols, type &Val)
{ size_t i; for(i=0; i<Rows; i++) PresetArray(Array[i],Cols,Val); }

// ========================================================================
// a sequence of any (fixed size) items

template <class type> class Seq
{ public:
   Seq(); ~Seq();          // default constructor/destructor
   Seq(Seq<type> &SrcSeq); // copy constructor
   void Init();            // user callable "constructor"
   int EnsureSpace(size_t ReqSpace); // make sure that there is enough space
   int EnsureSpace(void) { return EnsureSpace(Len); }
   int SetLen(size_t NewLen) { Len=NewLen; return EnsureSpace(Len); }
   int ReallocLen(size_t NewLen);
   int EnsureSpaceSafe(size_t ReqSpace);
   void Free(void);            // free all allocated space, remove all data
   void Clear(void) { Len=0; } // clear the sequence (set length to zero)
   size_t Index(type *Item) { return (size_t)(Item-Elem); }
   type &operator[] (int idx) { return (Elem[idx]); }   // [index] operator
   Seq<type> const &operator=(Seq<type> const &SrcSeq); // assignment operator
   type *First(void) { return Elem; }
   type *Last(void) { return Elem+(Len-1); }
   type *Append(size_t Num=1); // add one or more elements at the seq. end, returns the pointer to the new element(s)
   type *Insert(size_t Pos=0, size_t Num=1); // insert Num elements at Pos
   void Delete(size_t Pos=0, size_t Num=1); // delete Num elements at Pos
   void Shift(int Pos, const type &Fill); // shift left or right with filling
   int Truncate(size_t Margin=0); // remove unused but allocated space
   int Copy(type *Data, size_t DataLen);
   int Copy(Seq<type> &Src, size_t StartPos=0)  // copy the contains of another sequence
   { return Copy(Src.Elem+StartPos,Src.Len-StartPos); }
   int Copy(Seq<type> &Seq, size_t StartPos, size_t MaxLen);
   void Move(Seq<type> &Seq); // move the contains of another sequence, clear the other sequence
   int Join(const type &Data);
   int Join(type *Data, size_t DataLen); // join (append) given data
   int Join(Seq<type> &Seq) { return Join(Seq.Elem,Seq.Len); } // join a copy of the other sequence
   int NullTerm(void); // null-terminate (for character strings)
   void Reverse(void); // reverse the sequence order
   void FillWith(const type &Data, size_t StartPos=0); // fill with given value
   void Print(char *Format, size_t Columns=10);
   int SaveToFile(FILE *File);
   int LoadFromFile(FILE *File);
  public:
   size_t Space; // that many elements are allocated in *Elem
   size_t Len;	// that many elements are used up
   type *Elem;  // the storage space, contains Len elements
} ;

template <class type> Seq<type>::Seq() { Elem=0; Len=Space=0; }

template <class type> void Seq<type>::Init() { Elem=0; Len=Space=0; }

template <class type> Seq<type>::~Seq() { free(Elem); }

template <class type> Seq<type>::Seq(Seq<type> &SrcSeq)
{ if(EnsureSpace(SrcSeq.Len)==0)
  { Len=SrcSeq.Len; memcpy(Elem,SrcSeq.Elem,Len*sizeof(type)); }
}

template <class type> void Seq<type>::Free(void)
{ free(Elem); Elem=0; Space=Len=0; }

template <class type> int Seq<type>::EnsureSpace(size_t ReqSpace)
{ if(ReqSpace<=Space) return 0;
// CINT doesn't accept NULL pointers to realloc()
#ifdef __CINT__
  if(Elem) Elem=(type *)realloc(Elem,ReqSpace*sizeof(type));
      else Elem=(type *)malloc(ReqSpace*sizeof(type));
#else
  Elem=(type *)realloc(Elem,ReqSpace*sizeof(type));
#endif
  if(Elem==0) { Space=Len=0; return -1; }
  Space=ReqSpace; return 0; }

template <class type>
 Seq<type> const &Seq<type>::operator=(Seq<type> const &SrcSeq)
{ if((this!=&SrcSeq)&&(EnsureSpace(SrcSeq.Len)==0))
  { Len=SrcSeq.Len; memcpy(Elem,SrcSeq.Elem,Len*sizeof(type)); }
  return (*this); }

template <class type> int Seq<type>::ReallocLen(size_t NewLen)
{ Elem=(type *)realloc(Elem,NewLen*sizeof(type));
  if(Elem==0) { Space=Len=0; return -1; }
  Space=Len=NewLen; return 0; }

template <class type> int Seq<type>::Truncate(size_t Margin)
{ if(Space==(Len+Margin)) return 0;
  Elem=(type *)realloc(Elem,(Len+Margin)*sizeof(type));
  if(Elem==0) { Space=Len=0; return -1; }
  Space=Len+Margin; return 0; }

template <class type> void Seq<type>::Move(Seq<type> &Seq)
{ free(Elem);
  Len=Seq.Len; Space=Seq.Space; Elem=Seq.Elem;
  Seq.Elem=0; Seq.Len=Seq.Space=0; }

template <class type> int Seq<type>::Copy(type *Data, size_t DataLen)
{ if(EnsureSpace(DataLen)) return -1;
  memcpy(Elem,Data,DataLen*sizeof(type)); Len=DataLen; return 0; }

template <class type> int Seq<type>::Copy(Seq<type> &Src, size_t StartPos, size_t MaxLen)
{ int DataLen; DataLen=Src.Len-StartPos; if(DataLen>MaxLen) DataLen=MaxLen;
  if(EnsureSpace(DataLen)) return -1;
  memcpy(Elem,Src.Elem+StartPos,DataLen*sizeof(type)); Len=DataLen; return 0; }

template <class type> int Seq<type>::Join(const type &Data)
{ if(EnsureSpace(Len+1)) return -1;
  Elem[Len++]=Data; return 0; }

template <class type> int Seq<type>::Join(type *Data, size_t DataLen)
{ if(EnsureSpace(Len+DataLen)) return -1;
  memcpy(Elem+Len,Data,DataLen*sizeof(type)); Len+=DataLen; return 0; }

template <class type> type *Seq<type>::Insert(size_t Pos, size_t Num)
{ if(EnsureSpace(Len+Num)) return 0;
  // int p; for(p=Len-1; p>=Pos; p--) Elem[p+Num]=Elem[p];
  if((Len-Pos)>0) memmove(Elem+Pos+Num,Elem+Pos,(Len-Pos)*sizeof(type));
  Len+=Num; return Elem+Pos; }

template <class type> void Seq<type>::Delete(size_t Pos, size_t Num)
{ if((Len-Pos-Num)>0) memmove(Elem+Pos,Elem+Pos+Num,(Len-Pos-Num)*sizeof(type));
  Len-=Num; }

template <class type> type *Seq<type>::Append(size_t Num)
{ if(EnsureSpace(Len+Num)) return 0;
  Len+=Num; return Elem+(Len-Num); }
/*
template <class type> int Seq<type>::NullTerm(void)
{ if(EnsureSpace(Len+1)) return -1;
  Elem[Len]=0; return 0; }

int Seq<char>::NullTerm(void)
{ if(EnsureSpace(Len+1)) return -1;
  Elem[Len]=0; return 0; }
*/
template <class type> void Seq<type>::Reverse(void)
{ size_t i,j; type T;
  for(i=0,j=Len-1; i<j; i++,j--)
  { T=Elem[i]; Elem[i]=Elem[j]; Elem[j]=T; }
}

template <class type> void Seq<type>::FillWith(const type &Data, size_t StartPos)
{ size_t i; for(i=StartPos; i<Len; i++) Elem[i]=Data; }

template <class type> void Seq<type>::Shift(int Pos, const type &Fill)
{ size_t i;
  if(Pos>0) // shift toward higher positions - data inserted at the start of the sequence
  { if(Pos<Len) memmove(Elem+Pos,Elem,(Len-Pos)*sizeof(type)); else Pos=Len;
    for(i=0; i<Pos; i++) Elem[i]=Fill; }
  else if(Pos<0) // shift toward lower positions - data inserted at the end
  { Pos=(-Pos);
    if(Pos<Len) memmove(Elem,Elem+Pos,(Len-Pos)*sizeof(type)); else Pos=Len;
    for(i=Len-Pos; i<Len; i++) Elem[i]=Fill; }
}

template <class type> void Seq<type>::Print(char *Format, size_t Columns)
{ size_t i,Col;
  for(Col=0, i=0; i<Len; i++)
  { if(Col==0) { printf("%3d:",i); }
    printf(" "); printf(Format,Elem[i]); Col++;
    if(Col>=Columns) { printf("\n"); Col=0; } }
  if(Col>0) printf("\n");
}

// ========================================================================
// A 2-dimensional sequence

template <class type> class Seq2d
{ public:
   Seq2d(); ~Seq2d();
   int EnsureSpace(size_t rows, size_t cols); // make sure that there is enough space
   void Free(void);                     // free all space
   void Clear(void) { Rows=0; Cols=0; } // clear the sequence (set length to zero)
   // type &operator[] (int idx) { return (Elem[idx]); } // [idx] operator
   // type *Add(int Num=1); // add one or more elements, returns the index to the new element(s)
   size_t Rows,Cols;	    // that much is filled up
   size_t AllocRows,AllocCols; // that much is allocated
   type **Elem;  // contains Len elements
} ;

template <class type> Seq2d<type>::Seq2d()
{ Elem=0; AllocRows=Rows=AllocCols=Cols=0; }

template <class type> Seq2d<type>::~Seq2d()
{ size_t r; for(r=0; r<AllocRows; r++) free(Elem[r]); free(Elem); }

template <class type> void Seq2d<type>::Free(void)
{ size_t r; for(r=0; r<AllocRows; r++) free(Elem[r]); free(Elem);
  Elem=0; AllocRows=Rows=AllocCols=Cols=0; }

template <class type> int Seq2d<type>::EnsureSpace(size_t rows, size_t cols)
{ size_t r; type **New;
  if(rows>AllocRows)
  { New=(type**)malloc(rows*sizeof(type*));
    if(New==0) { Free(); return -1; }
    // printf("[Seq2d::EnsureSpace] AllocRows %d->%d\n",AllocRows,rows);
    if(Elem) { memcpy(New,Elem,AllocRows*sizeof(type**)); free(Elem); }
    Elem=New;
    for(r=AllocRows; r<rows; r++)
    { if(AllocCols)
      { Elem[r]=(type*)malloc(AllocCols*sizeof(type));
	if(Elem[r]==0) { Free(); return -1; }
      } else Elem[r]=0;
      AllocRows++; }
  }
  if(cols>AllocCols)
  { for(r=0; r<AllocRows; r++)
    { Elem[r]=(type*)realloc(Elem[r],cols*sizeof(type));
      if(Elem[r]==0) { Free(); return -1; } }
    // printf("[Seq2d::EnsureSpace] AllocCols %d->%d\n",AllocCols,cols);
    AllocCols=cols; }
  return 0; }


// ========================================================================

// A buffer structure for processing a continues series of samples.
// It is a linear array:
// - data between "Read" and "Write" is ready to be readout
// - data between "Write" and "Size" is still beeing written or processed
// - data before "Read" has been read-out and is thus obsolete
// As more data comes the samples must be shifted and the obsolete data removed:
// this is done by: RemovePastData()

template <class Type>
 class SampleBuffer
{ public:
   SampleBuffer()
     { Sample=0; AllocSize=Size=Read=Write=0; }
   ~SampleBuffer()
     { free(Sample); }
   void Free(void)
     { free(Sample); Sample=0; AllocSize=Size=Read=Write=0; }
   int EnsureSize(size_t MaxSize)
     { // printf(" SampleBuffer::EnsureSize(%d)\n",MaxSize);
       if(MaxSize<=AllocSize) return 0;
#ifdef __CINT__  // CINT doesn't accept NULL pointers to realloc()
       if(Sample) Sample=(Type *)realloc(Sample,MaxSize*sizeof(Type));
             else Sample=(Type *)malloc(MaxSize*sizeof(Type));
#else
       Sample=(Type *)realloc(Sample,MaxSize*sizeof(Type));
#endif
       if(Sample==0) { AllocSize=Size=0; return -1; }
       AllocSize=MaxSize; return 0; }
   int EnsureWriteLen(size_t MaxWriteLen)  // ensure enough space for writing new data
     { return EnsureSize(Write+MaxWriteLen); }
   void SetEmpty(void)                  // remove all data, make buffer empty
     { Read=Write=Size=0; }
   void RemovePastData(void)            // remove data before the read pointer
     { memcpy(Sample,Sample+Read,(Size-Read)*sizeof(Type));
       Write-=Read; Size-=Read; Read=0; }
   Type &operator[] (size_t Idx)        // access data given by index
     { return Sample[Idx]; }
   size_t ReadLen(void)                 // length of data to be read
     { return Write-Read; }
   Type *ReadPtr(void)                  // get pointer to read data
     { return Sample+Read; }
   size_t WriteLen(void)                // length of data that can be written
     { return Size-Write; }
   Type *WritePtr(void)                 // get pointer to write data
     { return Sample+Write; }
   void Print(char *Title=0)
     { printf("%s Sample=%08X, Read=%d, Write=%d, Size=%d, AllocSize=%d\n",
              Title ? Title:"SampleBuffer:", (int)Sample, Read, Write, Size, AllocSize); }
  public:
   Type *Sample;      // allocated storage pointer
   size_t Read;       // index to data that is ready to be read
   size_t Write;      // index to data that is still to be written
   size_t Size;       // current size of data (includes data before the read pointer)
   size_t AllocSize;  // allocated size for data
} ;

// ========================================================================

#endif // __STRUC_H__

