You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdegraphics/kviewshell/plugins/djvu/libdjvu/Arrays.h

998 lines
32 KiB

//C- -*- C++ -*-
//C- -------------------------------------------------------------------
//C- DjVuLibre-3.5
//C- Copyright (c) 2002 Leon Bottou and Yann Le Cun.
//C- Copyright (c) 2001 AT&T
//C-
//C- This software is subject to, and may be distributed under, the
//C- GNU General Public License, Version 2. The license should have
//C- accompanied the software or you may obtain a copy of the license
//C- from the Free Software Foundation at http://www.fsf.org .
//C-
//C- This program is distributed in the hope that it will be useful,
//C- but WITHOUT ANY WARRANTY; without even the implied warranty of
//C- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//C- GNU General Public License for more details.
//C-
//C- DjVuLibre-3.5 is derived from the DjVu(r) Reference Library
//C- distributed by Lizardtech Software. On July 19th 2002, Lizardtech
//C- Software authorized us to replace the original DjVu(r) Reference
//C- Library notice by the following text (see doc/lizard2002.djvu):
//C-
//C- ------------------------------------------------------------------
//C- | DjVu (r) Reference Library (v. 3.5)
//C- | Copyright (c) 1999-2001 LizardTech, Inc. All Rights Reserved.
//C- | The DjVu Reference Library is protected by U.S. Pat. No.
//C- | 6,058,214 and patents pending.
//C- |
//C- | This software is subject to, and may be distributed under, the
//C- | GNU General Public License, Version 2. The license should have
//C- | accompanied the software or you may obtain a copy of the license
//C- | from the Free Software Foundation at http://www.fsf.org .
//C- |
//C- | The computer code originally released by LizardTech under this
//C- | license and unmodified by other parties is deemed "the LIZARDTECH
//C- | ORIGINAL CODE." Subject to any third party intellectual property
//C- | claims, LizardTech grants recipient a worldwide, royalty-free,
//C- | non-exclusive license to make, use, sell, or otherwise dispose of
//C- | the LIZARDTECH ORIGINAL CODE or of programs derived from the
//C- | LIZARDTECH ORIGINAL CODE in compliance with the terms of the GNU
//C- | General Public License. This grant only confers the right to
//C- | infringe patent claims underlying the LIZARDTECH ORIGINAL CODE to
//C- | the extent such infringement is reasonably necessary to enable
//C- | recipient to make, have made, practice, sell, or otherwise dispose
//C- | of the LIZARDTECH ORIGINAL CODE (or portions thereof) and not to
//C- | any greater extent that may be necessary to utilize further
//C- | modifications or combinations.
//C- |
//C- | The LIZARDTECH ORIGINAL CODE is provided "AS IS" WITHOUT WARRANTY
//C- | OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
//C- | TO ANY WARRANTY OF NON-INFRINGEMENT, OR ANY IMPLIED WARRANTY OF
//C- | MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
//C- +------------------------------------------------------------------
//
// $Id: Arrays.h,v 1.10 2004/05/13 15:16:34 leonb Exp $
// $Name: release_3_5_15 $
#ifndef _ARRAYS_H_
#define _ARRAYS_H_
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#if NEED_GNUG_PRAGMAS
# pragma interface
#endif
#include "GException.h"
#include "GSmartPointer.h"
#include <string.h>
#ifdef HAVE_NAMESPACES
namespace DJVU {
# ifdef NOT_DEFINED // Just to fool emacs c++ mode
}
#endif
#endif
/** @name Arrays.h
Files #"Arrays.h"# and #"Arrays.cpp"# implement three array template classes.
Class \Ref{TArray} implements an array of objects of trivial types
such as #char#, #int#, #float#, etc. It is faster than general implementation
for any type done in \Ref{DArray} because it does not cope with
element's constructors, destructors and copy operators. Although
implemented as a template, which makes it possible to incorrectly use
\Ref{TArray} with non-trivial classes, it should not be done.
A lot of things is shared by these three arrays. That is why there are
more base classes:
\begin{itemize}
\item \Ref{ArrayBase} defines functions independent of the elements type
\item \Ref{ArrayBaseT} template class defining functions shared by
\Ref{DArray} and \Ref{TArray}
\end{itemize}
The main difference between \Ref{GArray} (now obsolete) and these ones
is the copy-on-demand strategy, which allows you to copy array objects
without copying the real data. It's the same thing, which has been
implemented in \Ref{GString} long ago: as long as you don't try to modify
the underlying data, it may be shared between several copies of array
objects. As soon as you attempt to make any changes, a private copy
is created automatically and transparently for you - the procedure, that
we call "copy-on-demand".
Also, please note that now there is no separate class, which does fast
sorting. Both \Ref{TArray} (dynamic array for trivial types) and
\Ref{DArray} (dynamic array for arbitrary types) can sort their elements.
{\bf Historical comments} --- Leon chose to implement his own arrays because
the STL classes were not universally available and the compilers were
rarely able to deal with such a template galore. Later it became clear
that there is no really good reason why arrays should be derived from
containers. It was also suggested to create separate arrays implementation
for simple classes and do the copy-on-demand strategy, which would allow
to assign array objects without immediate copying of their elements.
At this point \Ref{DArray} and \Ref{TArray} should only be used when
it is critical to have the copy-on-demand feature. The \Ref{GArray}
implementation is a lot more efficient.
@memo Template array classes.
@author
Andrei Erofeev <eaf@geocities.com> -- Copy-on-demand implementation.
@version
#$Id: Arrays.h,v 1.10 2004/05/13 15:16:34 leonb Exp $# */
//@{
// Auxiliary classes: Will be used in place of GPBase and GPEnabled objects
class _ArrayRep
{
friend class _ArrayBase;
public:
_ArrayRep(void) : count(0) {}
_ArrayRep(const _ArrayRep &) {}
virtual ~_ArrayRep(void) {}
_ArrayRep & operator=(const _ArrayRep &) { return *this; }
int get_count(void) const { return count; }
private:
int count;
void ref(void) { count++; }
void unref(void) { if (--count==0) delete this; }
};
class _ArrayBase
{
public:
_ArrayBase(void) : rep(0) {}
_ArrayBase(const _ArrayBase & ab) : rep(0)
{
if (ab.rep) ab.rep->ref();
rep=ab.rep;
}
_ArrayBase(_ArrayRep * ar) : rep(0)
{
if (ar) ar->ref();
rep=ar;
}
virtual ~_ArrayBase(void)
{
if (rep) { rep->unref(); rep=0; }
}
_ArrayRep * get(void) const { return rep; }
_ArrayBase & assign(_ArrayRep * ar)
{
if (ar) ar->ref();
if (rep) rep->unref();
rep=ar;
return *this;
}
_ArrayBase & operator=(const _ArrayBase & ab) { return assign(ab.rep); }
bool operator==(const _ArrayBase & ab) { return rep==ab.rep; }
private:
_ArrayRep * rep;
};
// Internal "Array repository" holding the pointer to the actual data,
// data bounds, etc. It copes with data elements with the help of five
// static functions which pointers are supposed to be passed to the
// constructor.
class ArrayRep : public _ArrayRep
{
public:
ArrayRep(int elsize,
void (* xdestroy)(void *, int, int),
void (* xinit1)(void *, int, int),
void (* xinit2)(void *, int, int, const void *, int, int),
void (* xcopy)(void *, int, int, const void *, int, int),
void (* xinsert)(void *, int, int, const void *, int));
ArrayRep(int elsize,
void (* xdestroy)(void *, int, int),
void (* xinit1)(void *, int, int),
void (* xinit2)(void *, int, int, const void *, int, int),
void (* xcopy)(void *, int, int, const void *, int, int),
void (* xinsert)(void *, int, int, const void *, int),
int hibound);
ArrayRep(int elsize,
void (* xdestroy)(void *, int, int),
void (* xinit1)(void *, int, int),
void (* xinit2)(void *, int, int, const void *, int, int),
void (* xcopy)(void *, int, int, const void *, int, int),
void (* xinsert)(void *, int, int, const void *, int),
int lobound, int hibound);
ArrayRep(const ArrayRep & rep);
virtual ~ArrayRep();
// Following is the standard interface to DArray. DArray will call these
// functions to access data.
int size() const;
int lbound() const;
int hbound() const;
void empty();
void touch(int n);
void resize(int lobound, int hibound);
void shift(int disp);
void del(int n, unsigned int howmany=1);
// ins() is an exception. It does it job only partially.
// The derived class is supposed to finish insertion.
void ins(int n, const void * what, unsigned int howmany);
ArrayRep & operator=(const ArrayRep & rep);
// All data is public because DArray... classes will need access to it
void *data;
int minlo;
int maxhi;
int lobound;
int hibound;
int elsize;
private:
// These functions can't be virtual as they're called from
// constructors and destructors :((
// destroy(): should destroy elements in data[] array from 'lo' to 'hi'
void (* destroy)(void * data, int lo, int hi);
// init1(): should initialize elements in data[] from 'lo' to 'hi'
// using default constructors
void (* init1)(void * data, int lo, int hi);
// init2(): should initialize elements in data[] from 'lo' to 'hi'
// using corresponding elements from src[] (copy constructor)
void (* init2)(void * data, int lo, int hi,
const void * src, int src_lo, int src_hi);
// copy(): should copy elements from src[] to dst[] (copy operator)
void (* copy)(void * dst, int dst_lo, int dst_hi,
const void * src, int src_lo, int src_hi);
// insert(): should insert '*what' at position 'where' 'howmany' times
// into array data[] having 'els' initialized elements
void (* insert)(void * data, int els, int where, const void * what,
int howmany);
};
inline int
ArrayRep::size() const
{
return hibound - lobound + 1;
}
inline int
ArrayRep::lbound() const
{
return lobound;
}
inline int
ArrayRep::hbound() const
{
return hibound;
}
inline void
ArrayRep::empty()
{
resize(0, -1);
}
inline void
ArrayRep::touch(int n)
{
if (hibound < lobound)
{
resize(n,n);
} else
{
int nlo = lobound;
int nhi = hibound;
if (n < nlo) nlo = n;
if (n > nhi) nhi = n;
resize(nlo, nhi);
}
}
/** Dynamic array base class.
This is an auxiliary base class for \Ref{DArray} and \Ref{TArray}
implementing some shared functions independent of the type of array
elements. It's not supposed to be constructed by hands. Use \Ref{DArray}
and \Ref{TArray} instead.
*/
class ArrayBase : protected _ArrayBase
{
protected:
void check(void);
void detach(void);
ArrayBase(void) {};
public:
/// Returns the number of elements in the array
int size() const;
/** Returns the lower bound of the valid subscript range. */
int lbound() const;
/** Returns the upper bound of the valid subscript range. */
int hbound() const;
/** Erases the array contents. All elements in the array are destroyed.
The valid subscript range is set to the empty range. */
void empty();
/** Extends the subscript range so that is contains #n#.
This function does nothing if #n# is already int the valid subscript range.
If the valid range was empty, both the lower bound and the upper bound
are set to #n#. Otherwise the valid subscript range is extended
to encompass #n#. This function is very handy when called before setting
an array element:
\begin{verbatim}
int lineno=1;
DArray<GString> a;
while (! end_of_file()) {
a.touch[lineno];
a[lineno++] = read_a_line();
}
\end{verbatim}
*/
void touch(int n);
/** Resets the valid subscript range to #0#---#hibound#.
This function may destroy some array elements and may construct
new array elements with the null constructor. Setting #hibound# to
#-1# resets the valid subscript range to the empty range.
@param hibound upper bound of the new subscript range. */
void resize(int hibound);
/** Resets the valid subscript range to #lobound#---#hibound#.
This function may destroy some array elements and may construct
new array elements with the null constructor. Setting #lobound# to #0# and
#hibound# to #-1# resets the valid subscript range to the empty range.
@param lobound lower bound of the new subscript range.
@param hibound upper bound of the new subscript range. */
void resize(int lobound, int hibound);
/** Shifts the valid subscript range. Argument #disp# is added to both
bounds of the valid subscript range. Array elements previously
located at subscript #x# will now be located at subscript #x+disp#. */
void shift(int disp);
/** Deletes array elements. The array elements corresponding to
subscripts #n#...#n+howmany-1# are destroyed. All array elements
previously located at subscripts greater or equal to #n+howmany#
are moved to subscripts starting with #n#. The new subscript upper
bound is reduced in order to account for this shift.
@param n subscript of the first element to delete.
@param howmany number of elements to delete. */
void del(int n, unsigned int howmany=1);
virtual ~ArrayBase(void) {};
};
inline void
ArrayBase::detach(void)
{
ArrayRep * new_rep=new ArrayRep(*(ArrayRep *) get());
assign(new_rep);
}
inline void
ArrayBase::check(void)
{
if (get()->get_count()>1) detach();
}
inline int
ArrayBase::size() const
{
return ((const ArrayRep *) get())->size();
}
inline int
ArrayBase::lbound() const
{
return ((const ArrayRep *) get())->lobound;
}
inline int
ArrayBase::hbound() const
{
return ((const ArrayRep *) get())->hibound;
}
inline void
ArrayBase::empty()
{
check();
((ArrayRep *) get())->empty();
}
inline void
ArrayBase::resize(int lo, int hi)
{
check();
((ArrayRep *) get())->resize(lo, hi);
}
inline void
ArrayBase::resize(int hi)
{
resize(0, hi);
}
inline void
ArrayBase::touch(int n)
{
check();
((ArrayRep *) get())->touch(n);
}
inline void
ArrayBase::shift(int disp)
{
check();
((ArrayRep *) get())->shift(disp);
}
inline void
ArrayBase::del(int n, unsigned int howmany)
{
check();
((ArrayRep *) get())->del(n, howmany);
}
/** Dynamic array template base class.
This is an auxiliary template base class for \Ref{DArray} and \Ref{TArray}
implementing some shared functions which {\em depend} on the type of
the array elements (this is contrary to \Ref{ArrayBase}).
It's not supposed to be constructed by hands. Use \Ref{DArray} and
\Ref{TArray} instead.
*/
template <class TYPE>
class ArrayBaseT : public ArrayBase
{
public:
virtual ~ArrayBaseT(void) {};
/** Returns a reference to the array element for subscript #n#. This
reference can be used for both reading (as "#a[n]#") and writing (as
"#a[n]=v#") an array element. This operation will not extend the valid
subscript range: an exception \Ref{GException} is thrown if argument #n#
is not in the valid subscript range. */
TYPE& operator[](int n);
/** Returns a constant reference to the array element for subscript #n#.
This reference can only be used for reading (as "#a[n]#") an array
element. This operation will not extend the valid subscript range: an
exception \Ref{GException} is thrown if argument #n# is not in the valid
subscript range. This variant of #operator[]# is necessary when dealing
with a #const DArray<TYPE>#. */
const TYPE& operator[](int n) const;
/** Returns a pointer for reading or writing the array elements. This
pointer can be used to access the array elements with the same
subscripts and the usual bracket syntax. This pointer remains valid as
long as the valid subscript range is unchanged. If you change the
subscript range, you must stop using the pointers returned by prior
invocation of this conversion operator. */
operator TYPE* ();
/** Returns a pointer for reading (but not modifying) the array elements.
This pointer can be used to access the array elements with the same
subscripts and the usual bracket syntax. This pointer remains valid as
long as the valid subscript range is unchanged. If you change the
subscript range, you must stop using the pointers returned by prior
invocation of this conversion operator. */
operator const TYPE* () const;
#ifndef __MWERKS__ //MCW can't compile
operator const TYPE* ();
#endif
/** Insert new elements into an array. This function inserts
#howmany# elements at position #n# into the array. The initial value #val#
is copied into the new elements. All array elements previously located at subscripts
#n# and higher are moved to subscripts #n+howmany# and higher. The upper bound of the
valid subscript range is increased in order to account for this shift.
@param n subscript of the first inserted element.
@param val initial value of the new elements.
@param howmany number of elements to insert. */
void ins(int n, const TYPE &val, unsigned int howmany=1);
/** Sort array elements. Sort all array elements in ascending order. Array
elements are compared using the less-or-equal comparison operator for
type #TYPE#. */
void sort();
/** Sort array elements in subscript range #lo# to #hi#. Sort all array
elements whose subscripts are in range #lo#..#hi# in ascending order.
The other elements of the array are left untouched. An exception is
thrown if arguments #lo# and #hi# are not in the valid subscript range.
Array elements are compared using the less-or-equal comparison operator
for type #TYPE#.
@param lo low bound for the subscripts of the elements to sort.
@param hi high bound for the subscripts of the elements to sort. */
void sort(int lo, int hi);
protected:
ArrayBaseT(void) {};
private:
// Callbacks called from ArrayRep
static void destroy(void * data, int lo, int hi);
static void init1(void * data, int lo, int hi);
static void init2(void * data, int lo, int hi,
const void * src, int src_lo, int src_hi);
static void copy(void * dst, int dst_lo, int dst_hi,
const void * src, int src_lo, int src_hi);
static void insert(void * data, int els, int where,
const void * what, int howmany);
};
template <class TYPE> inline
ArrayBaseT<TYPE>::operator TYPE* ()
{
check();
ArrayRep * rep=(ArrayRep *) get();
return &((TYPE *) rep->data)[-rep->minlo];
}
#ifndef __MWERKS__ //MCW can't compile
template <class TYPE> inline
ArrayBaseT<TYPE>::operator const TYPE* ()
{
const ArrayRep * rep=(const ArrayRep *) get();
return &((const TYPE *) rep->data)[-rep->minlo];
}
#endif
template <class TYPE> inline
ArrayBaseT<TYPE>::operator const TYPE* () const
{
const ArrayRep * rep=(const ArrayRep *) get();
return &((const TYPE *) rep->data)[-rep->minlo];
}
template <class TYPE> inline TYPE&
ArrayBaseT<TYPE>::operator[](int n)
{
check();
ArrayRep * rep=(ArrayRep *) get();
if (n<rep->lobound || n>rep->hibound)
G_THROW( ERR_MSG("arrays.ill_sub") );
return ((TYPE *) rep->data)[n - rep->minlo];
}
template <class TYPE> inline const TYPE&
ArrayBaseT<TYPE>::operator[](int n) const
{
const ArrayRep * rep=(const ArrayRep *) get();
if (n<rep->lobound || n>rep->hibound)
G_THROW( ERR_MSG("arrays.ill_sub") );
return ((const TYPE *) rep->data)[n - rep->minlo];
}
template <class TYPE> inline void
ArrayBaseT<TYPE>::ins(int n, const TYPE &val, unsigned int howmany)
{
check();
((ArrayRep *) get())->ins(n, &val, howmany);
}
template <class TYPE> void
ArrayBaseT<TYPE>::sort()
{
sort(lbound(), hbound());
}
template <class TYPE> void
ArrayBaseT<TYPE>::sort(int lo, int hi)
{
if (hi <= lo)
return;
// Test for insertion sort (optimize!)
if (hi <= lo + 20)
{
for (int i=lo+1; i<=hi; i++)
{
int j = i;
TYPE tmp = (*this)[i];
while ((--j>=lo) && !((*this)[j]<=tmp))
(*this)[j+1] = (*this)[j];
(*this)[j+1] = tmp;
}
return;
}
// -- determine suitable quick-sort pivot
TYPE tmp = (*this)[lo];
TYPE pivot = (*this)[(lo+hi)/2];
if (pivot <= tmp)
{ tmp = pivot; pivot=(*this)[lo]; }
if ((*this)[hi] <= tmp)
{ pivot = tmp; }
else if ((*this)[hi] <= pivot)
{ pivot = (*this)[hi]; }
// -- partition set
int h = hi;
int l = lo;
while (l < h)
{
while (! (pivot <= (*this)[l])) l++;
while (! ((*this)[h] <= pivot)) h--;
if (l < h)
{
tmp = (*this)[l];
(*this)[l] = (*this)[h];
(*this)[h] = tmp;
l = l+1;
h = h-1;
}
}
// -- recursively restart
sort(lo, h);
sort(l, hi);
}
/** Dynamic array for simple types.
Template class #TArray<TYPE># implements an array of
elements of {\em simple} type #TYPE#. {\em Simple} means that the type
may be #char#, #int#, #float# etc. The limitation is imposed by the
way in which the #TArray# is working with its elements: it's not trying
to execute elements' constructors, destructors or copy operators. It's
just doing bitwise copy. Except for this it's pretty much the same as
\Ref{DArray}.
Please note that most of the methods are implemented in the base classes
\Ref{ArrayBase} and \Ref{ArrayBaseT}.
*/
template <class TYPE>
class TArray : public ArrayBaseT<TYPE> {
public:
/** Constructs an empty array. The valid subscript range is initially
empty. Member function #touch# and #resize# provide convenient ways
to enlarge the subscript range. */
TArray();
/** Constructs an array with subscripts in range 0 to #hibound#.
The subscript range can be subsequently modified with member functions
#touch# and #resize#.
@param hibound upper bound of the initial subscript range. */
TArray(int hibound);
/** Constructs an array with subscripts in range #lobound# to #hibound#.
The subscript range can be subsequently modified with member functions
#touch# and #resize#.
@param lobound lower bound of the initial subscript range.
@param hibound upper bound of the initial subscript range. */
TArray(int lobound, int hibound);
virtual ~TArray() {};
private:
// Callbacks called from ArrayRep
static void destroy(void * data, int lo, int hi);
static void init1(void * data, int lo, int hi);
static void init2(void * data, int lo, int hi,
const void * src, int src_lo, int src_hi);
static void insert(void * data, int els, int where,
const void * what, int howmany);
};
template <class TYPE> void
TArray<TYPE>::destroy(void * data, int lo, int hi)
{
}
template <class TYPE> void
TArray<TYPE>::init1(void * data, int lo, int hi)
{
}
template <class TYPE> void
TArray<TYPE>::init2(void * data, int lo, int hi,
const void * src, int src_lo, int src_hi)
{
if (data && src)
{
int els=hi-lo+1;
if (els>src_hi-src_lo+1) els=src_hi-src_lo+1;
if (els>0)
memmove((void *) &((TYPE *) data)[lo],
(void *) &((TYPE *) src)[src_lo], els*sizeof(TYPE));
};
}
// inline removed
template <class TYPE> void
TArray<TYPE>::insert(void * data, int els, int where,
const void * what, int howmany)
{
memmove(((TYPE *) data)+where+howmany,
((TYPE *) data)+where, sizeof(TYPE)*(els-where));
for(int i=0;i<howmany;i++)
((TYPE *) data)[where+i]=*(TYPE *) what;
}
template <class TYPE>
TArray<TYPE>::TArray ()
{
this->assign(new ArrayRep(sizeof(TYPE), destroy, init1,
init2, init2, insert));
}
template <class TYPE>
TArray<TYPE>::TArray(int hi)
{
this->assign(new ArrayRep(sizeof(TYPE), destroy, init1,
init2, init2, insert, hi));
}
template <class TYPE>
TArray<TYPE>::TArray(int lo, int hi)
{
this->assign(new ArrayRep(sizeof(TYPE), destroy, init1,
init2, init2, insert, lo, hi));
}
//inline removal ends
/** Dynamic array for general types.
Template class #DArray<TYPE># implements an array of
elements of type #TYPE#. Each element is identified by an integer
subscript. The valid subscripts range is defined by dynamically
adjustable lower- and upper-bounds. Besides accessing and setting
elements, member functions are provided to insert or delete elements at
specified positions.
This template class must be able to access
\begin{itemize}
\item a null constructor #TYPE::TYPE()#,
\item a copy constructor #TYPE::TYPE(const TYPE &)#,
\item and a copy operator #TYPE & operator=(const TYPE &)#.
\end{itemize}
The class offers "copy-on-demand" policy, which means that when you
copy the array object, array elements will stay intact as long as you
don't try to modify them. As soon as you make an attempt to change
array contents, the copying is done automatically and transparently
for you - the procedure that we call "copy-on-demand". This is the main
difference between this class and \Ref{GArray} (now obsolete)
Please note that most of the methods are implemented in the base classes
\Ref{ArrayBase} and \Ref{ArrayBaseT}.
*/
template <class TYPE>
class DArray : public ArrayBaseT<TYPE> {
public:
/** Constructs an empty array. The valid subscript range is initially
empty. Member function #touch# and #resize# provide convenient ways
to enlarge the subscript range. */
DArray(void);
/** Constructs an array with subscripts in range 0 to #hibound#.
The subscript range can be subsequently modified with member functions
#touch# and #resize#.
@param hibound upper bound of the initial subscript range. */
DArray(const int hibound);
/** Constructs an array with subscripts in range #lobound# to #hibound#.
The subscript range can be subsequently modified with member functions
#touch# and #resize#.
@param lobound lower bound of the initial subscript range.
@param hibound upper bound of the initial subscript range. */
DArray(const int lobound, const int hibound);
virtual ~DArray() {};
private:
// Callbacks called from ArrayRep
static void destroy(void * data, int lo, int hi);
static void init1(void * data, int lo, int hi);
static void init2(void * data, int lo, int hi,
const void * src, int src_lo, int src_hi);
static void copy(void * dst, int dst_lo, int dst_hi,
const void * src, int src_lo, int src_hi);
static void insert(void * data, int els, int where,
const void * what, int howmany);
};
template <class TYPE> void
DArray<TYPE>::destroy(void * data, int lo, int hi)
{
if (data)
for(int i=lo;i<=hi;i++)
((TYPE *) data)[i].TYPE::~TYPE();
}
template <class TYPE> void
DArray<TYPE>::init1(void * data, int lo, int hi)
{
if (data)
for(int i=lo;i<=hi;i++)
new ((void *) &((TYPE *) data)[i]) TYPE;
}
template <class TYPE> void
DArray<TYPE>::init2(void * data, int lo, int hi,
const void * src, int src_lo, int src_hi)
{
if (data && src)
{
int i, j;
for(i=lo, j=src_lo;i<=hi && j<=src_hi;i++, j++)
new ((void *) &((TYPE *) data)[i]) TYPE(((TYPE *) src)[j]);
};
}
template <class TYPE> void
DArray<TYPE>::copy(void * dst, int dst_lo, int dst_hi,
const void * src, int src_lo, int src_hi)
{
if (dst && src)
{
int i, j;
for(i=dst_lo, j=src_lo;i<=dst_hi && j<=src_hi;i++, j++)
((TYPE *) dst)[i]=((TYPE *) src)[j];
};
}
template <class TYPE> inline void
DArray<TYPE>::insert(void * data, int els, int where,
const void * what, int howmany)
{
// Now do the insertion
TYPE * d=(TYPE *) data;
int i;
for (i=els+howmany-1; i>=els; i--)
{
if (i-where >= (int)howmany)
new ((void*) &d[i]) TYPE (d[i-howmany]);
else
new ((void*) &d[i]) TYPE (*(TYPE *) what);
}
for (i=els-1; i>=where; i--)
{
if (i-where >= (int)howmany)
d[i] = d[i-howmany];
else
d[i] = *(TYPE *) what;
}
}
template <class TYPE> inline
DArray<TYPE>::DArray ()
{
this->assign(new ArrayRep(sizeof(TYPE), destroy, init1,
init2, copy, insert));
}
template <class TYPE> inline
DArray<TYPE>::DArray(const int hi)
{
this->assign(new ArrayRep(sizeof(TYPE), destroy, init1,
init2, copy, insert, hi));
}
template <class TYPE> inline
DArray<TYPE>::DArray(const int lo, const int hi)
{
this->assign(new ArrayRep(sizeof(TYPE), destroy, init1,
init2, copy, insert, lo, hi));
}
/** Dynamic array for \Ref{GPBase}d classes.
There are many situations when it's necessary to create arrays of
\Ref{GP} pointers. For example, #DArray<GP<Dialog> ># or #DArray<GP<Button> >#.
This would result in compilation of two instances of \Ref{DArray} because
from the viewpoint of the compiler there are two different classes used
as array elements: #GP<Dialog># and #GP<Button>#. In reality though,
all \Ref{GP} pointers have absolutely the same binary structure because
they are derived from \Ref{GPBase} class and do not add any variables
or virtual functions. That's why it's possible to instantiate \Ref{DArray}
only once for \Ref{GPBase} elements and then just cast types.
To implement this idea we have created this #DPArray<TYPE># class,
which can be used instead of #DArray<GP<TYPE> >#. It behaves absolutely
the same way as \Ref{DArray} but has one big advantage: overhead of
using #DPArray# with one more type is negligible.
*/
template <class TYPE>
class DPArray : public DArray<GPBase> {
public:
// -- CONSTRUCTORS
DPArray();
DPArray(int hibound);
DPArray(int lobound, int hibound);
DPArray(const DPArray<TYPE> &gc);
// -- DESTRUCTOR
virtual ~DPArray();
// -- ACCESS
GP<TYPE>& operator[](int n);
const GP<TYPE>& operator[](int n) const;
// -- CONVERSION
operator GP<TYPE>* ();
#ifndef __MWERKS__ //MCW can't compile
operator const GP<TYPE>* ();
#endif
operator const GP<TYPE>* () const;
// -- ALTERATION
void ins(int n, const GP<TYPE> &val, unsigned int howmany=1);
DPArray<TYPE>& operator= (const DPArray &ga);
};
template<class TYPE>
DPArray<TYPE>::DPArray() {}
template<class TYPE>
DPArray<TYPE>::DPArray(int hibound) :
DArray<GPBase>(hibound) {}
template<class TYPE>
DPArray<TYPE>::DPArray(int lobound, int hibound) :
DArray<GPBase>(lobound, hibound) {}
template<class TYPE>
DPArray<TYPE>::DPArray(const DPArray<TYPE> &gc) :
DArray<GPBase>(gc) {}
template<class TYPE>
DPArray<TYPE>::~DPArray() {}
template<class TYPE>
inline GP<TYPE> &
DPArray<TYPE>::operator[](int n)
{
return (GP<TYPE> &) DArray<GPBase>::operator[](n);
}
template<class TYPE>
inline const GP<TYPE> &
DPArray<TYPE>::operator[](int n) const
{
return (const GP<TYPE> &) DArray<GPBase>::operator[](n);
}
template<class TYPE>
inline DPArray<TYPE>::operator GP<TYPE>* ()
{
return (GP<TYPE> *) DArray<GPBase>::operator GPBase*();
}
#ifndef __MWERKS__ //MCW can't compile
template<class TYPE>
inline DPArray<TYPE>::operator const GP<TYPE>* ()
{
return (const GP<TYPE> *) DArray<GPBase>::operator const GPBase*();
}
#endif
template<class TYPE>
inline DPArray<TYPE>::operator const GP<TYPE>* () const
{
return (const GP<TYPE> *) DArray<GPBase>::operator const GPBase*();
}
template<class TYPE>
inline void
DPArray<TYPE>::ins(int n, const GP<TYPE> & val, unsigned int howmany)
{
DArray<GPBase>::ins(n, val, howmany);
}
template<class TYPE>
inline DPArray<TYPE> &
DPArray<TYPE>::operator= (const DPArray &ga)
{
DArray<GPBase>::operator=(ga);
return *this;
}
// ------------ THE END
//@}
#ifdef HAVE_NAMESPACES
}
# ifndef NOT_USING_DJVU_NAMESPACE
using namespace DJVU;
# endif
#endif
#endif