/*---------------------------------------------------------------------------* * IT++ * *---------------------------------------------------------------------------* * Copyright (c) 1995-2004 by Tony Ottosson, Thomas Eriksson, Pål Frenger, * * Tobias Ringström, and Jonas Samuelsson. * * * * Permission to use, copy, modify, and distribute this software and its * * documentation under the terms of the GNU General Public License is hereby * * granted. No representations are made about the suitability of this * * software for any purpose. It is provided "as is" without expressed or * * implied warranty. See the GNU General Public License for more details. * *---------------------------------------------------------------------------*/ /*! \file \brief Array class (container) \author Tobias Ringstrom This file is not separated into a .h and a .cpp file. The reason is to avoid problems with template initializations of this class. An \c Array can contain any type and it is not possible to initialize and pre-compile all types that might be put into an \c Array. 1.33 2004/10/17 21:00:51 */ #ifndef __array_h #define __array_h #include #include #include "itconfig.h" #include "base/itassert.h" #include "base/factory.h" #include "../src/base/copy_vector.h" namespace itpp { // Forward declarations template class Array; template Array concat(const Array &a, const T e); template Array concat(const T e, const Array &a); template Array concat(const Array &a1, const Array &a2); template Array concat(const Array &a1, const Array &a2, const Array &a3); /*! \brief General array class This class is a general linear array class for arbitrary types. The operations and functions are the same as for the vector Vec class (except for the arithmetics). For rarely used types you will need to instantiate the class by \code template class Array; \endcode The following example shows how to define an Array of vectors: \code vec a = randn(10); vec b = randn(20); vec c = randn(30); Array my_array(3); my_array(0) = a; my_array(1) = b; my_array(2) = c; \endcode For types T with istream operator>> defined, the set_array functions (see Related Functions) can be used to assign a string literal to an Array, with the same format that is used by the istream/ostream operators: \code // Declare an Array of Arrays of vectors Array > an_array; // Assign with an Array containing 2 Arrays, // the first Array containing [1 2] and // the second Array containing [3 4 5] and [6 7] set_array(an_array, "{{[1 2]} {[3 4 5] [6 7]}}"); \endcode By default, the Array elements are created using the default constructor for the element type. This can be changed by specifying a suitable Factory in the Array constructor call; see Detailed Description for Factory. */ template class Array { public: //! Default constructor. An element factory \c f can be specified explicit Array(const Factory &f = DEFAULT_FACTORY); //! Create an Array of size \c n. An element factory \c f can be specified Array(const int n, const Factory &f = DEFAULT_FACTORY); //! Copy constructor Array(const Array &a); //! Constructor, similar to the copy constructor, but also takes an element factory \c f as argument Array(const Array &a, const Factory &f); //! Destructor virtual ~Array(); //! Get the \c i element T &operator()(const int i) { it_assert0(i>=0&&i=0&&i operator()(const int i1, const int i2) const; //! Sub-array with the elements given by the integer Array Array operator()(const Array &indices) const; //! Assignment operator void operator=(const T e); //! Assignment operator void operator=(const Array &a); //! Append element \c e to the end of the Array \c a friend Array concat <>(const Array &a1, const T e); //! Concat element \c e to the beginning of the Array \c a friend Array concat <>(const T e, const Array &a); //! Concat Arrays \c a1 and \c a2 friend Array concat <>(const Array &a1,const Array &a2); //! Concat Arrays \c a1, \c a2 and \c a3 friend Array concat <>(const Array &a1, const Array &a2, const Array &a3); //! Returns the number of data elements in the array object int size() const { return ndata; } //! Returns the number of data elements in the array object int length() const { return ndata; } //! Resizing an Array. void set_size(const int n, const bool copy=false); //! Resizing an Array. void set_length(const int n, const bool copy=false) { set_size(n, copy); } //! Shift in data at position 0. return data at last position. T shift_right(const T e); //! Shift in array at position 0. return data at last position. Array shift_right(const Array &a); //! Shift in data at position Ndata()-1. return data at last position. T shift_left(const T e); //! Shift in array at position Ndata()-1. return data at last position. Array shift_left(const Array &a); //! Swap elements i and j. void swap(const int i, const int j); //! Set the subarray defined by indicies i1 to i2 to Array a. void set_subarray(int i1, int i2, const Array &a); //! Set the subarray defined by indicies i1 to i2 the element value t. void set_subarray(int i1, int i2, const T t); protected: //! Check whether index \c i is in the allowed range bool in_range(const int i) { return ((i=0)); } //! The current number of elements in the Array int ndata; //! A pointer to the data area T *data; //! Element factory (set to DEFAULT_FACTORY to use T default constructors only) const Factory &factory; private: void alloc(int n); void free(); }; // --------------------------- Implementation starts here ---------------------------------- template Array::Array(const Factory &f) : factory(f) { data=NULL; ndata=0; } template Array::Array(const int n, const Factory &f) : factory(f) { alloc(n); } template Array::Array(const Array &a) : factory(a.factory) { alloc(a.ndata); for (int i=0; i Array::Array(const Array &a, const Factory &f) : factory(f) { alloc(a.ndata); for (int i=0; i Array::~Array() { free(); } template void Array::alloc(const int n) { if (n == 0) { data = NULL; ndata = 0; } else { create_elements(data, n, factory); it_assert1(data!=0, "Out of memory in Array::alloc"); } ndata = n; } template void Array::free() { delete [] data; data = 0; ndata = 0; } template Array Array::operator()(const int i1, const int i2) const { it_assert0(i1>=0 && i2>=0 && i1=i1, "Array::operator()(i1,i2)"); Array s(i2-i1+1); int i; for (i=0; i Array Array::operator()(const Array &indices) const { Array a(indices.size()); for (int i=0; i=0&&indices(i) void Array::operator=(const Array &a) { set_size(a.ndata); for (int i=0; i void Array::operator=(const T e) { if (ndata==0) set_size(1); for (int i=0; i void Array::set_size(const int sz, const bool copy) { int i, min; T *tmp; if (ndata == sz) return; if (copy) { tmp = data; min = ndata < sz ? ndata : sz; alloc(sz); for (i=0; i T Array::shift_right(const T x) { T ret; it_assert1(ndata>0, "shift_right"); ret = data[ndata-1]; for (int i=ndata-1; i>0; i--) data[i] = data[i-1]; data[0] = x; return ret; } template Array Array::shift_right(const Array &a) { int i; Array out(a.ndata); it_assert1(a.ndata<=ndata, "Shift Array too large"); for (i=0; i=a.ndata; i--) data[i] = data[i-a.ndata]; for (i=0; i T Array::shift_left(const T x) { T temp = data[0]; for (int i=0; i Array Array::shift_left(const Array &a) { int i; Array out(a.ndata); it_assert1(a.ndata<=ndata, "Shift Array too large"); for (i=0; i void Array::swap(const int i, const int j) { it_assert1(in_range(i) && in_range(j) , "Shift Array too large"); T temp = data[i]; data[i] = data[j]; data[j] = temp; } template void Array::set_subarray(int i1, int i2, const Array &a) { if (i1 == -1) i1 = ndata-1; if (i2 == -1) i2 = ndata-1; it_assert1(in_range(i1) && in_range(i2), "Array::set_subarray(): indicies out of range"); it_assert1(i2>=i1, "Array::set_subarray(): i2 >= i1 necessary"); it_assert1(i2-i1+1 == a.ndata, "Array::set_subarray(): wrong sizes"); copy_vector(a.ndata, a.data, data+i1); } template void Array::set_subarray(int i1, int i2, const T t) { if (i1 == -1) i1 = ndata-1; if (i2 == -1) i2 = ndata-1; it_assert1(in_range(i1) && in_range(i2), "Array::set_subarray(): indicies out of range"); it_assert1(i2>=i1, "Array::set_subarray(): i2 >= i1 necessary"); for (int i=i1;i<=i2;i++) data[i] = t; } template Array concat(const Array &a, const T e) { Array temp(a.size()+1); for (int i=0; i Array concat(const T e, const Array &a) { Array temp(a.size()+1); temp(0) = e; for (int i=0; i Array concat(const Array &a1, const Array &a2) { int i; Array temp(a1.size()+a2.size()); for (i=0;i Array concat(const Array &a1, const Array &a2, const Array &a3) { // There should be some error control? int i; Array temp(a1.size()+a2.size()+a3.size()); for (i=0;i. T must have ostream operator<< defined. */ template std::ostream &operator<<(std::ostream &os, const Array &a) { os << "{"; for (int i=0; i 0) os << a(a.size()-1); os << "}"; return os; } /*! \relates Array \brief Input stream for Array. T must have istream operator>> defined. */ template std::istream &operator>>(std::istream &is, Array &a) { int nrof_elements = 0; char c; is >> c; if (c == '{') { is >> c; while (c != '}') { if (is.eof()) { is.setstate(std::ios_base::failbit); break; } if (c != ',') { // Discard comma signs between elements is.putback(c); } if (++nrof_elements > a.size()) { a.set_size(nrof_elements, true); // Too slow? } is >> a(nrof_elements-1); is >> c; } if (a.size() > nrof_elements) { a.set_size(nrof_elements, true); } } else { is.setstate(std::ios_base::failbit); } return is; } /*! \relates Array \brief Assign a C-style string to an Array. T must have istream operator>> defined. */ template void set_array(Array &a, const char *values) { std::istringstream buffer(values); buffer >> a; } /*! \relates Array \brief Assign a string to an Array. T must have istream operator>> defined. */ template void set_array(Array &a, const std::string &str) { set_array(a, str.c_str()); } } //namespace itpp #endif // __array_h