/*
 * @(#) bytearr.h - Void and byte arrays class library header.
 * (c) 1998 Ivan Maidanski <ivmai@chat.ru> http://ivmai.chat.ru
 * Freeware class library source. All rights reserved.
 **
 * Language: ISO/ANSI C++
 * Tested with: Microsoft Visual C++ (R) v4.2, Watcom C++ 16/32 v11.0
 * Last modified: 1998-09-06 23:25:00 GMT+04:00
 */

// Library source file: bytearr.cpp

// class TVoidArray;
// class TByteArray;
// ARRAYS_CHECK_INDEX

#ifndef _BYTEARR_H_INCLUDED
#define _BYTEARR_H_INCLUDED

#ifndef __cplusplus
#error This file is for use with C++
#endif

// common macros declaration section (may be overriden)

#ifndef ARRAYS_CHECK_INDEX // index checking enable/disable toggler
#if defined(DEBUG) || defined(_DEBUG)
#define ARRAYS_CHECK_INDEX 1
#else
#define ARRAYS_CHECK_INDEX 0
#endif
#endif

// special compiler directives

#ifdef _MSC_VER
#pragma warning(disable: 4514) // "unreferenced inline function removed"
#endif

// classes declaration section

class TVoidArray // resizable C-style void array
{
public: // constructors & destructor
 TVoidArray();
 TVoidArray(unsigned InitSize);
 TVoidArray(const void *, unsigned InitSize);
 TVoidArray(const TVoidArray &);
 TVoidArray(const TVoidArray &, unsigned InitSize);
 ~TVoidArray();
public: // entier copiers & swapper
 TVoidArray &operator=(const TVoidArray &);
 TVoidArray &Copy(const TVoidArray &);
 TVoidArray &Copy(const TVoidArray &, unsigned CopySize);
 TVoidArray &Copy(const TVoidArray &, unsigned SrcOffset, unsigned CopySize);
 TVoidArray &Copy(const void *, unsigned CopySize);
 static void Swap(TVoidArray &, TVoidArray &);
public: // data direct access
 operator const void *() const;
 const void *GetData() const;
 void *GetData();
public: // size manipulators
 unsigned Size(unsigned);
 unsigned Size() const;
 unsigned CalcNewSize(unsigned NewCount) const;
 static unsigned SizeAdd(unsigned, unsigned IncVal);
 static unsigned SizeMul(unsigned, unsigned MulVal);
public: // block filler & copiers
 TVoidArray &SetAt(unsigned, char, unsigned RepCount=1);
 TVoidArray &CopyAt(unsigned, const TVoidArray &, unsigned CopySize);
 TVoidArray &CopyAt(unsigned, const TVoidArray &,
                    unsigned SrcOffset, unsigned CopySize);
 TVoidArray &CopyAt(unsigned, const void *, unsigned CopySize);
 void *CopyAt(void *, unsigned SrcOffset, unsigned CopySize) const;
public: // block swappers
 TVoidArray &SwapAt(unsigned OffsetA, unsigned OffsetB, unsigned SwapSize);
 TVoidArray &SwapAt(unsigned OffsetA, TVoidArray &ArrayB, unsigned OffsetB,
                    unsigned SwapSize);
 TVoidArray &SwapAt(unsigned OffsetA, void *PDataB, unsigned SwapSize);
public: // exceptions
 class TError {};
 class TBadIndexError : public TError {};
 class TOutOfMemoryError : public TError {};
private: // internal data fields
 void *Ptr;
 unsigned SizeVal;
};

class TByteArray : public TVoidArray // resizable C-style byte array
{
public: // constructors & destructor
 TByteArray();
 TByteArray(unsigned InitCount);
 TByteArray(unsigned char Byte, unsigned InitCount);
 TByteArray(const unsigned char *, unsigned InitCount);
 TByteArray(const TByteArray &);
 TByteArray(const TByteArray &, unsigned SrcIndex, unsigned InitCount);
 ~TByteArray();
public: // entier copiers & swapper
 TByteArray &operator=(const TByteArray &);
 TByteArray &Copy(const unsigned char *, unsigned CopyCount);
 TByteArray &Copy(const TByteArray &);
 TByteArray &Copy(const TByteArray &, unsigned SrcIndex, unsigned CopyCount);
 static void Swap(TByteArray &, TByteArray &);
public: // data direct access
 const unsigned char *GetData() const;
 unsigned char *GetData();
public: // element count manipulators
 unsigned Count(unsigned);
 unsigned Count() const;
 void GrowAtIndex(unsigned, unsigned RegionSize=1);
 void RemoveAll();
 int IsEmpty() const;
public: // size manipulators
 unsigned Size(unsigned);
 unsigned Size() const;
 void FreeExtra();
public: // index validity checkers
 void CheckIndex(unsigned, unsigned CheckRange=1) const;
 unsigned IndexOf(const unsigned char &) const;
public: // elements access (zero-based)
 unsigned char operator[](unsigned) const;
 unsigned char &operator[](unsigned);
 const unsigned char &ElementAt(unsigned) const;
 unsigned char &ElementAt(unsigned);
 unsigned char &ElementAtGrow(unsigned);
 unsigned char GetAt(unsigned) const;
 TByteArray &SetAt(unsigned, unsigned char Byte);
 TByteArray &SetAt(unsigned, unsigned char Byte, unsigned RepCount);
 TByteArray &SetAtGrow(unsigned, unsigned char Byte);
 TByteArray &SetAtGrow(unsigned, unsigned char Byte, unsigned RepCount);
public: // elements access starting at end
 const unsigned char &ElementAtEnd(unsigned Offset=0) const;
 unsigned char &ElementAtEnd(unsigned Offset=0);
 unsigned char GetAtEnd(unsigned Offset=0) const;
 TByteArray &SetAtEnd(unsigned char Byte, unsigned Offset=0);
public: // elements group copiers
 TByteArray &CopyAt(unsigned, const unsigned char *, unsigned CopyCount);
 TByteArray &CopyAt(unsigned, const TByteArray &, unsigned SrcIndex,
                    unsigned CopyCount);
 unsigned char *CopyAt(unsigned char *,
                       unsigned SrcIndex, unsigned CopyCount) const;
public: // elements group swappers
 TByteArray &SwapAt(unsigned IndexA, unsigned IndexB, unsigned SwapCount);
 TByteArray &SwapAt(unsigned IndexA, TByteArray &ArrayB, unsigned IndexB,
                    unsigned SwapCount);
 TByteArray &SwapAt(unsigned IndexA, unsigned char *PBytesB,
                    unsigned SwapCount);
 TByteArray &SwapAt(unsigned IndexA, unsigned char &ByteB);
 TByteArray &ReverseAt(unsigned, unsigned RevCount);
public: // array & elements concatenation
 TByteArray operator+(const TByteArray &) const;
 TByteArray &operator+=(const TByteArray &);
 TByteArray &Append(unsigned char Byte, unsigned RepCount=1);
 TByteArray &Append(const unsigned char *, unsigned CopyCount);
 TByteArray &Append(const TByteArray &);
 TByteArray &Append(const TByteArray &,
                    unsigned SrcIndex, unsigned CopyCount);
public: // array & elements insertion/extraction/removal
 TByteArray &InsertAt(unsigned, unsigned char Byte, unsigned RepCount=1);
 TByteArray &InsertAt(unsigned, const unsigned char *, unsigned CopyCount);
 TByteArray &InsertAt(unsigned, const TByteArray &);
 TByteArray &InsertAt(unsigned, const TByteArray &,
                      unsigned SrcIndex, unsigned CopyCount);
 TByteArray &ExtractAt(unsigned, unsigned char &DestByte);
 unsigned char ExtractAt(unsigned);
 TByteArray &ExtractAt(unsigned,
                       unsigned ExtrCount, unsigned char *PDestBytes);
 TByteArray &ExtractAt(unsigned, unsigned ExtrCount, TByteArray &DestArray);
 TByteArray &RemoveAt(unsigned, unsigned RemoveCount=1);
 TByteArray &RemoveAtEnd(unsigned RemoveCount=1);
public: // elements stack-oriented access
 TByteArray &Push(unsigned char);
 TByteArray &Pop(unsigned char &);
 unsigned char Pop();
public: // elements reversed stack-oriented access
 TByteArray &ReversePush(unsigned char);
 TByteArray &ReversePop(unsigned char &);
 unsigned char ReversePop();
public: // elements queue-oriented access
 TByteArray &QueuePut(unsigned char);
 TByteArray &QueueGet(unsigned char &);
 unsigned char QueueGet();
public: // bitwise comparison
 int operator==(const TByteArray &) const;
 int operator!=(const TByteArray &) const;
 unsigned GetEqualLenAt(unsigned IndexA,
                        const TByteArray &ArrayB, unsigned IndexB,
                        unsigned CompareCount) const;
 unsigned GetEqualLenAt(unsigned IndexA, const unsigned char *PBytesB,
                        unsigned CompareCount) const;
public: // bitwise search
 unsigned FindAt(unsigned, unsigned char Byte) const;
 unsigned FindAt(unsigned, const TByteArray &) const;
 unsigned FindAt(unsigned, const TByteArray &,
                 unsigned SrcIndex, unsigned SrcCount) const;
 unsigned FindAt(unsigned, const unsigned char *, unsigned SrcCount) const;
public: // bitwise reversed search
 unsigned ReverseFindAt(unsigned,
                        unsigned char Byte) const;
 unsigned ReverseFindAt(unsigned, const TByteArray &) const;
 unsigned ReverseFindAt(unsigned, const TByteArray &,
                        unsigned SrcIndex, unsigned SrcCount) const;
 unsigned ReverseFindAt(unsigned, const unsigned char *,
                        unsigned SrcCount) const;
private: // internal data fields
 unsigned Cnt;
};

// inline methods definition section

inline TVoidArray::TVoidArray() :
 Ptr(0), SizeVal(0)
{
}

inline TVoidArray::TVoidArray(unsigned InitSize) :
 Ptr(0), SizeVal(0)
{
 Size(InitSize);
}

inline TVoidArray &TVoidArray::Copy(const TVoidArray &Array)
{
 return operator=(Array);
}

inline TVoidArray &TVoidArray::Copy(const TVoidArray &Array,
                                    unsigned CopySize)
{
 return Copy(Array,0,CopySize);
}

inline TVoidArray::operator const void *() const
{
 return Ptr;
}

inline const void *TVoidArray::GetData() const
{
 return Ptr;
}

inline void *TVoidArray::GetData()
{
 return Ptr;
}

inline unsigned TVoidArray::Size() const
{
 return SizeVal;
}

inline unsigned TVoidArray::SizeAdd(unsigned NewSize, unsigned IncVal)
{
 if ((NewSize=NewSize+IncVal)<IncVal)
  throw TOutOfMemoryError();
 return NewSize;
}

inline unsigned TVoidArray::SizeMul(unsigned NewSize, unsigned MulVal)
{
 if (MulVal>1 && (~(unsigned)0)/MulVal<NewSize)
  throw TOutOfMemoryError();
 return NewSize*MulVal;
}

inline TVoidArray &TVoidArray::CopyAt(unsigned Offset,
                                      const TVoidArray &Array,
                                      unsigned CopySize)
{
 return CopyAt(Offset,Array,0,CopySize);
}

inline TVoidArray &TVoidArray::SwapAt(unsigned OffsetA, unsigned OffsetB,
                                      unsigned SwapSize)
{
 return SwapAt(OffsetA,*this,OffsetB,SwapSize);
}

inline TByteArray::TByteArray() :
 Cnt(0)
{
}

inline TByteArray::~TByteArray()
{
 Cnt=0;
}

inline const unsigned char *TByteArray::GetData() const
{
 return (const unsigned char *)TVoidArray::GetData();
}

inline unsigned char *TByteArray::GetData()
{
 return (unsigned char *)TVoidArray::GetData();
}

inline unsigned TByteArray::Count() const
{
 return Cnt;
}

inline void TByteArray::RemoveAll()
{
 TVoidArray::Size(CalcNewSize(0));
 Cnt=0;
}

inline int TByteArray::IsEmpty() const
{
 return !Cnt;
}

inline unsigned TByteArray::Size(unsigned NewSize)
{
#if ARRAYS_CHECK_INDEX
 if (Cnt>NewSize)
  throw TBadIndexError();
#endif
 return TVoidArray::Size(NewSize);
}

inline unsigned TByteArray::Size() const
{
 return TVoidArray::Size();
}

inline void TByteArray::FreeExtra()
{
 TVoidArray::Size(Cnt);
}

inline void TByteArray::CheckIndex(unsigned Index,
                                   unsigned CheckRange) const
{
 if (Index+CheckRange<CheckRange || Index+CheckRange>Cnt)
  throw TBadIndexError();
}

inline unsigned char TByteArray::operator[](unsigned Index) const
{
 return ElementAt(Index);
}

inline unsigned char &TByteArray::operator[](unsigned Index)
{
 return ElementAt(Index);
}

inline const unsigned char &TByteArray::ElementAt(unsigned Index) const
{
#if ARRAYS_CHECK_INDEX
 if (Index>=Cnt)
  throw TBadIndexError();
#endif
 return *((const unsigned char *)TVoidArray::GetData()+Index);
}

inline unsigned char &TByteArray::ElementAt(unsigned Index)
{
#if ARRAYS_CHECK_INDEX
 if (Index>=Cnt)
  throw TBadIndexError();
#endif
 return *((unsigned char *)TVoidArray::GetData()+Index);
}

inline unsigned char &TByteArray::ElementAtGrow(unsigned Index)
{
 GrowAtIndex(Index);
 return *((unsigned char *)TVoidArray::GetData()+Index);
}

inline unsigned char TByteArray::GetAt(unsigned Index) const
{
 return ElementAt(Index);
}

inline TByteArray &TByteArray::SetAt(unsigned Index, unsigned char Byte)
{
 ElementAt(Index)=Byte;
 return *this;
}

inline TByteArray &TByteArray::SetAt(unsigned Index,
                                     unsigned char Byte, unsigned RepCount)
{
#if ARRAYS_CHECK_INDEX
 if (Index+RepCount>Cnt)
  throw TBadIndexError();
#endif
 TVoidArray::SetAt(Index,(char)Byte,RepCount);
 return *this;
}

inline TByteArray &TByteArray::SetAtGrow(unsigned Index, unsigned char Byte)
{
 ElementAtGrow(Index)=Byte;
 return *this;
}

inline TByteArray &TByteArray::SetAtGrow(unsigned Index, unsigned char Byte,
                                         unsigned RepCount)
{
 GrowAtIndex(Index,RepCount);
 TVoidArray::SetAt(Index,(char)Byte,RepCount);
 return *this;
}

inline unsigned char TByteArray::GetAtEnd(unsigned Offset) const
{
 return ElementAtEnd(Offset);
}

inline TByteArray &TByteArray::SetAtEnd(unsigned char Byte, unsigned Offset)
{
 ElementAtEnd(Offset)=Byte;
 return *this;
}

inline TByteArray &TByteArray::CopyAt(unsigned Index,
                                      const unsigned char *PBytes,
                                      unsigned CopyCount)
{
#if ARRAYS_CHECK_INDEX
 if (Index+CopyCount>Cnt)
  throw TBadIndexError();
#endif
 TVoidArray::CopyAt(Index,(const void *)PBytes,CopyCount);
 return *this;
}

inline TByteArray &TByteArray::CopyAt(unsigned Index,
                                      const TByteArray &Array,
                                      unsigned SrcIndex, unsigned CopyCount)
{
#if ARRAYS_CHECK_INDEX
 if (Index+CopyCount>Cnt || SrcIndex+CopyCount>Array.Cnt)
  throw TBadIndexError();
#endif
 TVoidArray::CopyAt(Index,Array,SrcIndex,CopyCount);
 return *this;
}

inline unsigned char *TByteArray::CopyAt(unsigned char *PDestBytes,
                                         unsigned SrcIndex,
                                         unsigned CopyCount) const
{
#if ARRAYS_CHECK_INDEX
 if (SrcIndex+CopyCount>Cnt)
  throw TBadIndexError();
#endif
 TVoidArray::CopyAt((void *)PDestBytes,SrcIndex,CopyCount);
 return PDestBytes;
}

inline TByteArray &TByteArray::SwapAt(unsigned IndexA, unsigned IndexB,
                                      unsigned SwapCount)
{
#if ARRAYS_CHECK_INDEX
 if ((IndexA>IndexB? IndexA : IndexB)+SwapCount>Cnt)
  throw TBadIndexError();
#endif
 TVoidArray::SwapAt(IndexA,*this,IndexB,SwapCount);
 return *this;
}

inline TByteArray &TByteArray::SwapAt(unsigned IndexA, TByteArray &ArrayB,
                                      unsigned IndexB, unsigned SwapCount)
{
#if ARRAYS_CHECK_INDEX
 if (IndexA+SwapCount>Cnt || IndexB+SwapCount>ArrayB.Cnt)
  throw TBadIndexError();
#endif
 TVoidArray::SwapAt(IndexA,ArrayB,IndexB,SwapCount);
 return *this;
}

inline TByteArray &TByteArray::SwapAt(unsigned IndexA,
                                      unsigned char *PBytesB,
                                      unsigned SwapCount)
{
#if ARRAYS_CHECK_INDEX
 if (IndexA+SwapCount>Cnt)
  throw TBadIndexError();
#endif
 TVoidArray::SwapAt(IndexA,(void *)PBytesB,SwapCount);
 return *this;
}

inline TByteArray TByteArray::operator+(const TByteArray &Array) const
{
 return TByteArray(*this).Append(Array,0,Array.Cnt);
}

inline TByteArray &TByteArray::operator+=(const TByteArray &Array)
{
 return Append(Array,0,Array.Cnt);
}

inline TByteArray &TByteArray::Append(const TByteArray &Array)
{
 return Append(Array,0,Array.Cnt);
}

inline TByteArray &TByteArray::InsertAt(unsigned Index,
                                        const TByteArray &Array)
{
 return InsertAt(Index,Array,0,Array.Cnt);
}

inline unsigned char TByteArray::ExtractAt(unsigned Index)
{
 unsigned char DestByte;
 ExtractAt(Index,DestByte);
 return DestByte;
}

inline TByteArray &TByteArray::RemoveAtEnd(unsigned RemoveCount)
{
#if ARRAYS_CHECK_INDEX
 if (RemoveCount>Cnt)
  throw TBadIndexError();
#endif
 TVoidArray::Size(CalcNewSize(Cnt-=RemoveCount));
 return *this;
}

inline unsigned char TByteArray::Pop()
{
 unsigned char DestByte;
 Pop(DestByte);
 return DestByte;
}

inline TByteArray &TByteArray::ReversePush(unsigned char Byte)
{
 return InsertAt(0,Byte);
}

inline TByteArray &TByteArray::ReversePop(unsigned char &DestByte)
{
 return ExtractAt(0,DestByte);
}

inline unsigned char TByteArray::ReversePop()
{
 unsigned char DestByte;
 ReversePop(DestByte);
 return DestByte;
}

inline TByteArray &TByteArray::QueuePut(unsigned char Byte)
{
 return Push(Byte);
}

inline TByteArray &TByteArray::QueueGet(unsigned char &DestByte)
{
 return ReversePop(DestByte);
}

inline unsigned char TByteArray::QueueGet()
{
 unsigned char DestByte;
 QueueGet(DestByte);
 return DestByte;
}

inline int TByteArray::operator==(const TByteArray &Array) const
{
 return Cnt==Array.Cnt && GetEqualLenAt(0,Array,0,Cnt)==Cnt;
}

inline int TByteArray::operator!=(const TByteArray &Array) const
{
 return Cnt!=Array.Cnt || GetEqualLenAt(0,Array,0,Cnt)!=Cnt;
}

inline unsigned TByteArray::FindAt(unsigned Index,
                                   const TByteArray &Array) const
{
 return FindAt(Index,Array,0,Array.Cnt);
}

inline unsigned TByteArray::ReverseFindAt(unsigned Index,
                                          const TByteArray &Array) const
{
 return ReverseFindAt(Index,Array,0,Array.Cnt);
}

#endif
