Files
mlpack/fastlib/trilinos/include/Teuchos_Array.hpp
T

492 lines
14 KiB
C++

// @HEADER
// ***********************************************************************
//
// Teuchos: Common Tools Package
// Copyright (2004) Sandia Corporation
//
// Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
// license for use of this work by or on behalf of the U.S. Government.
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 2.1 of the
// License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA
// Questions? Contact Michael A. Heroux (maherou@sandia.gov)
//
// ***********************************************************************
// @HEADER
#ifndef TEUCHOS_ARRAY_H
#define TEUCHOS_ARRAY_H
/*! \file Teuchos_Array.hpp
\brief Templated array class derived from the STL std::vector
*/
#include "Teuchos_ConfigDefs.hpp"
#include "Teuchos_TestForException.hpp"
#include "Teuchos_Utils.hpp"
#include "Teuchos_TypeNameTraits.hpp"
namespace Teuchos
{
/** \brief .
* \relates Array
*/
class InvalidArrayStringRepresentation : public std::logic_error
{public:InvalidArrayStringRepresentation(const std::string& what_arg) : std::logic_error(what_arg) {}};
/**
* \brief Array is a templated array class derived from the STL std::vector, but with
* index boundschecking and an extended interface.
*/
template<class T>
class Array : public std::vector<T>
{
public:
//! Empty constructor
Array();
//! Allocate an array with n elements
Array(int n);
//! Allocate n elements, and fill with value \c t
Array(int n, const T& t);
//! Add a new entry at the end of the array. Resize to allow space for the new entry.
inline Array<T>& append(const T& entry) {this->push_back(entry); return *this;}
//! Remove the i-th element from the array, with optional boundschecking.
void remove(int i);
/*! \brief Return number of elements in the array.
* Equivalent to size(), but included for backwards compatibility.
*/
int length() const {return this->size();}
//! Read/Write access to a the i-th element, with optional boundschecking.
inline T& operator[](int i);
//! Read-only access to a the i-th element, with optional boundschecking.
inline const T& operator[](int i) const;
//! Write Array as a std::string
std::string toString() const ;
//! Return true if Array has been compiled with boundschecking on
static bool hasBoundsChecking();
private:
/** check for a bounds violation if HAVE_ARRAY_BOUNDSCHECK has been
* defined as 1. */
void indexCheckCrash(int i) const;
};
/** \relates Array
\brief Write an Array to a stream
*/
template<class T> std::ostream& operator<<(std::ostream& os,
const Array<T>& array);
/** \relates Array */
template<class T> int hashCode(const Array<T>& array);
/** \relates Array */
template<class T> std::string toString(const Array<T>& array);
template<class T> inline Array<T>::Array()
: std::vector<T>()
{}
template<class T> inline Array<T>::Array(int n)
: std::vector<T>(n)
{}
template<class T> inline Array<T>::Array(int n, const T& t)
: std::vector<T>(n, t)
{}
template<class T>
void Array<T>::remove(int i) {
#ifdef HAVE_TEUCHOS_ARRAY_BOUNDSCHECK
indexCheckCrash(i);
#endif
// Erase the i-th element of this array.
this->erase( this->begin() + i );
}
template<class T> inline
T& Array<T>::operator[](int i) {
#ifdef HAVE_TEUCHOS_ARRAY_BOUNDSCHECK
indexCheckCrash(i);
#endif
return std::vector<T>::operator[](i);
}
template<class T> inline
const T& Array<T>::operator[](int i) const {
#ifdef HAVE_TEUCHOS_ARRAY_BOUNDSCHECK
indexCheckCrash(i);
#endif
return std::vector<T>::operator[](i);
}
template<class T> inline
bool Array<T>::hasBoundsChecking()
{
#ifdef HAVE_TEUCHOS_ARRAY_BOUNDSCHECK
return true;
#else
return false;
#endif
}
template<class T> inline
void Array<T>::indexCheckCrash(int i) const
{
TEST_FOR_EXCEPTION(
!( 0 <= i && i < length() ), std::range_error,
"Array<"<<TypeNameTraits<T>::name()<<">::indexCheckCrash: "
"index " << i << " out of range [0, "<< length() << ")"
);
}
// print in form (), (1), or (1,2)
template<class T> inline std::ostream& operator<<(std::ostream& os, const Array<T>& array)
{
return os << Teuchos::toString(array);
}
template<class T> inline int hashCode(const Array<T>& array)
{
int rtn = hashCode(array.length());
for (int i=0; i<array.length(); i++)
{
rtn += hashCode(array[i]);
}
return rtn;
}
template<class T> inline std::string Array<T>::toString() const
{
std::ostringstream ss;
ss << "{";
for (int i=0; i<length(); i++)
{
ss << operator[](i);
if (i<length()-1) ss << ", ";
}
ss << "}";
return ss.str();
}
/** \relates Array. */
template<class T> inline
std::string toString(const Array<T>& array)
{
return array.toString();
}
/** \brief Converts from std::string representation (as created by
* <tt>toString()</tt>) back into the array object.
*
* \param arrayStr
* [in] The std::string representation of the array (see below).
*
* <b>Exceptions:</b> If the std::string representation is not valid, then an
* std::exception of type <tt>InvalidArrayStringRepresentation</tt> with be
* thrown with a decent error message attached.
*
* The formating of the std::string <tt>arrayStr</tt> must look like:
\verbatim
{ val[0], val[1], val[2], val[3], ..., val[n-1] }
\endverbatim
* Currently <tt>operator>>()</tt> is used to convert the entries from their
* std::string representation to objects of type <tt>T</tt>. White space is
* unimportant and the parser keys off of ',', '{' and '}' so even newlines
* are allowed. In the future, a traits class might be defined that will
* allow for finer-grained control of how the conversion from strings to
* values is performed in cases where <tt>operator>>()</tt> does not exist
* for certain types.
*
* <b>Warning!</b> Currently this function only supports reading in flat
* array objects for basic types like <tt>bool</tt>, <tt>int</tt>, and
* <tt>double</tt> and does not yet support nested arrays (i.e. no
* <tt>Array<Array<int> ></tt>) or other such fancy nested types. Support
* for nested arrays and other user defined types <tt>T</tt> can be added in
* the future with no impact on user code. Only the parser for the array
* needs to be improved. More specifically, the current implementation will
* not work for any types <tt>T</tt> who's std::string representation contains
* the characters <tt>','</tt> or <tt>'}'</tt>. This implementation can be
* modified to allow any such types by watching for the nesting of common
* enclosing structures like <tt>[...]</tt>, <tt>{...}</tt> or
* <tt>(...)</tt> within each entry of the std::string representation. However,
* this should all just work fine on most machines for the types
* <tt>int</tt>, <tt>bool</tt>, <tt>float</tt>, <tt>double</tt> etc.
*
* <b>Warning!</b> Trying to read in an array in std::string format of doubles in
* scientific notation such as <tt>{1e+2,3.53+6,...}</tt> into an array
* object such as <tt>Array<int></tt> will not yield the correct results.
* If one wants to allow a neutral std::string representation to be read in as an
* <tt>Array<double></tt> object or an <tt>Array<int></tt> object, then
* general formating such as <tt>{100,3530000,...}</tt> should be used.
* This templated function is unable to deal std::complex type conversion issues.
*
* \relates Array.
*/
template<class T>
Array<T> fromStringToArray(const std::string& arrayStr)
{
const std::string str = Utils::trimWhiteSpace(arrayStr);
std::istringstream iss(str);
TEST_FOR_EXCEPTION(
( str[0]!='{' || str[str.length()-1] != '}' )
,InvalidArrayStringRepresentation
,"Error, the std::string:\n"
"----------\n"
<<str<<
"\n----------\n"
"is not a valid array represntation!"
);
char c;
c = iss.get(); // Read initial '{'
TEST_FOR_EXCEPT(c!='{'); // Should not throw!
// Now we are ready to begin reading the entries of the array!
Array<T> a;
while( !iss.eof() ) {
// Get the basic entry std::string
std::string entryStr;
std::getline(iss,entryStr,','); // Get next entry up to ,!
// ToDo: Above, we might have to be careful to look for the opening and
// closing of parentheses in order not to pick up an internal ',' in the
// middle of an entry (for a std::complex number for instance). The above
// implementation assumes that there will be no commas in the middle of
// the std::string representation of an entry. This is certainly true for
// the types bool, int, float, and double.
//
// Trim whitespace from beginning and end
entryStr = Utils::trimWhiteSpace(entryStr);
// Remove the final '}' if this is the last entry and we did not
// actually terminate the above getline(...) on ','
bool found_end = false;
if(entryStr[entryStr.length()-1]=='}') {
entryStr = entryStr.substr(0,entryStr.length()-1);
found_end = true;
if( entryStr.length()==0 && a.size()==0 )
return a; // This is the empty array "{}" (with any spaces in it!)
}
TEST_FOR_EXCEPTION(
0 == entryStr.length()
,InvalidArrayStringRepresentation
,"Error, the std::string:\n"
"----------\n"
<<str<<
"\n----------\n"
"is not a valid array represntation!"
);
// Finally we can convert the entry and add it to the array!
std::istringstream entryiss(entryStr);
T entry;
entryiss >> entry; // Assumes type has operator>>(...) defined!
// ToDo: We may need to define a traits class to allow us to specialized
// how conversion from a std::string to a object is done!
a.push_back(entry);
// At the end of the loop body here, if we have reached the last '}'
// then the input stream iss should be empty and iss.eof() should be
// true, so the loop should terminate. We put an std::exception test here
// just in case something has gone wrong.
TEST_FOR_EXCEPTION(
found_end && !iss.eof()
,InvalidArrayStringRepresentation
,"Error, the std::string:\n"
"----------\n"
<<str<<
"\n----------\n"
"is not a valid array represntation!"
);
}
return a;
}
/** \relates Array
\brief Create an array with one entry
*/
template<class T> inline
Array<T> tuple(const T& a)
{
Array<T> rtn(1, a);
return rtn;
}
/** \relates Array
\brief Create an array with two entries
*/
template<class T> inline
Array<T> tuple(const T& a, const T& b)
{
Array<T> rtn(2);
rtn[0] = a;
rtn[1] = b;
return rtn;
}
/** \relates Array
\brief Create an array with three entries
*/
template<class T> inline
Array<T> tuple(const T& a, const T& b, const T& c)
{
Array<T> rtn(3);
rtn[0] = a;
rtn[1] = b;
rtn[2] = c;
return rtn;
}
/** \relates Array
\brief Create an array with four entries
*/
template<class T> inline
Array<T> tuple(const T& a, const T& b, const T& c, const T& d)
{
Array<T> rtn(4);
rtn[0] = a;
rtn[1] = b;
rtn[2] = c;
rtn[3] = d;
return rtn;
}
/** \relates Array
\brief Create an array with five entries
*/
template<class T> inline
Array<T> tuple(const T& a, const T& b, const T& c, const T& d, const T& e)
{
Array<T> rtn(5);
rtn[0] = a;
rtn[1] = b;
rtn[2] = c;
rtn[3] = d;
rtn[4] = e;
return rtn;
}
/** \relates Array
\brief Create an array with six entries
*/
template<class T> inline
Array<T> tuple(const T& a, const T& b, const T& c, const T& d, const T& e,
const T& f)
{
Array<T> rtn(6);
rtn[0] = a;
rtn[1] = b;
rtn[2] = c;
rtn[3] = d;
rtn[4] = e;
rtn[5] = f;
return rtn;
}
/** \relates Array
\brief Create an array with seven entries
*/
template<class T> inline
Array<T> tuple(const T& a, const T& b, const T& c, const T& d, const T& e,
const T& f, const T& g)
{
Array<T> rtn(7);
rtn[0] = a;
rtn[1] = b;
rtn[2] = c;
rtn[3] = d;
rtn[4] = e;
rtn[5] = f;
rtn[6] = g;
return rtn;
}
/** \relates Array
\brief Create an array with eight entries
*/
template<class T> inline
Array<T> tuple(const T& a, const T& b, const T& c, const T& d, const T& e,
const T& f, const T& g, const T& h)
{
Array<T> rtn(8);
rtn[0] = a;
rtn[1] = b;
rtn[2] = c;
rtn[3] = d;
rtn[4] = e;
rtn[5] = f;
rtn[6] = g;
rtn[7] = h;
return rtn;
}
/** \relates Array
\brief Create an array with nine entries
*/
template<class T> inline
Array<T> tuple(const T& a, const T& b, const T& c, const T& d, const T& e,
const T& f, const T& g, const T& h, const T& i)
{
Array<T> rtn(9);
rtn[0] = a;
rtn[1] = b;
rtn[2] = c;
rtn[3] = d;
rtn[4] = e;
rtn[5] = f;
rtn[6] = g;
rtn[7] = h;
rtn[8] = i;
return rtn;
}
/** \relates Array
\brief Create an array with ten entries
*/
template<class T> inline
Array<T> tuple(const T& a, const T& b, const T& c, const T& d, const T& e,
const T& f, const T& g, const T& h, const T& i, const T& j)
{
Array<T> rtn(10);
rtn[0] = a;
rtn[1] = b;
rtn[2] = c;
rtn[3] = d;
rtn[4] = e;
rtn[5] = f;
rtn[6] = g;
rtn[7] = h;
rtn[8] = i;
rtn[9] = j;
return rtn;
}
}
#endif // TEUCHOS_ARRAY_H