// @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 Array : public std::vector { 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& 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 std::ostream& operator<<(std::ostream& os, const Array& array); /** \relates Array */ template int hashCode(const Array& array); /** \relates Array */ template std::string toString(const Array& array); template inline Array::Array() : std::vector() {} template inline Array::Array(int n) : std::vector(n) {} template inline Array::Array(int n, const T& t) : std::vector(n, t) {} template void Array::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 inline T& Array::operator[](int i) { #ifdef HAVE_TEUCHOS_ARRAY_BOUNDSCHECK indexCheckCrash(i); #endif return std::vector::operator[](i); } template inline const T& Array::operator[](int i) const { #ifdef HAVE_TEUCHOS_ARRAY_BOUNDSCHECK indexCheckCrash(i); #endif return std::vector::operator[](i); } template inline bool Array::hasBoundsChecking() { #ifdef HAVE_TEUCHOS_ARRAY_BOUNDSCHECK return true; #else return false; #endif } template inline void Array::indexCheckCrash(int i) const { TEST_FOR_EXCEPTION( !( 0 <= i && i < length() ), std::range_error, "Array<"<::name()<<">::indexCheckCrash: " "index " << i << " out of range [0, "<< length() << ")" ); } // print in form (), (1), or (1,2) template inline std::ostream& operator<<(std::ostream& os, const Array& array) { return os << Teuchos::toString(array); } template inline int hashCode(const Array& array) { int rtn = hashCode(array.length()); for (int i=0; i inline std::string Array::toString() const { std::ostringstream ss; ss << "{"; for (int i=0; i inline std::string toString(const Array& array) { return array.toString(); } /** \brief Converts from std::string representation (as created by * toString()) back into the array object. * * \param arrayStr * [in] The std::string representation of the array (see below). * * Exceptions: If the std::string representation is not valid, then an * std::exception of type InvalidArrayStringRepresentation with be * thrown with a decent error message attached. * * The formating of the std::string arrayStr must look like: \verbatim { val[0], val[1], val[2], val[3], ..., val[n-1] } \endverbatim * Currently operator>>() is used to convert the entries from their * std::string representation to objects of type T. 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 operator>>() does not exist * for certain types. * * Warning! Currently this function only supports reading in flat * array objects for basic types like bool, int, and * double and does not yet support nested arrays (i.e. no * Array >) or other such fancy nested types. Support * for nested arrays and other user defined types T 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 T who's std::string representation contains * the characters ',' or '}'. This implementation can be * modified to allow any such types by watching for the nesting of common * enclosing structures like [...], {...} or * (...) within each entry of the std::string representation. However, * this should all just work fine on most machines for the types * int, bool, float, double etc. * * Warning! Trying to read in an array in std::string format of doubles in * scientific notation such as {1e+2,3.53+6,...} into an array * object such as Array will not yield the correct results. * If one wants to allow a neutral std::string representation to be read in as an * Array object or an Array object, then * general formating such as {100,3530000,...} should be used. * This templated function is unable to deal std::complex type conversion issues. * * \relates Array. */ template Array 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" < 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" <> 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" < inline Array tuple(const T& a) { Array rtn(1, a); return rtn; } /** \relates Array \brief Create an array with two entries */ template inline Array tuple(const T& a, const T& b) { Array rtn(2); rtn[0] = a; rtn[1] = b; return rtn; } /** \relates Array \brief Create an array with three entries */ template inline Array tuple(const T& a, const T& b, const T& c) { Array rtn(3); rtn[0] = a; rtn[1] = b; rtn[2] = c; return rtn; } /** \relates Array \brief Create an array with four entries */ template inline Array tuple(const T& a, const T& b, const T& c, const T& d) { Array 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 inline Array tuple(const T& a, const T& b, const T& c, const T& d, const T& e) { Array 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 inline Array tuple(const T& a, const T& b, const T& c, const T& d, const T& e, const T& f) { Array 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 inline Array tuple(const T& a, const T& b, const T& c, const T& d, const T& e, const T& f, const T& g) { Array 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 inline Array 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 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 inline Array 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 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 inline Array 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 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