src/DataImpl.h

Go to the documentation of this file.
00001 /*
00002  * Fimex
00003  * 
00004  * (C) Copyright 2008, met.no
00005  *
00006  * Project Info:  https://wiki.met.no/fimex/start
00007  *
00008  * This library is free software; you can redistribute it and/or modify it
00009  * under the terms of the GNU Lesser General Public License as published by
00010  * the Free Software Foundation; either version 2.1 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * This library is distributed in the hope that it will be useful, but
00014  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
00015  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
00016  * License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with this library; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
00021  * USA.
00022  */
00023 
00024 #ifndef DATAIMPL_H_
00025 #define DATAIMPL_H_
00026 
00027 #include <typeinfo>
00028 #include <boost/shared_ptr.hpp>
00029 #include <string>
00030 #include <sstream>
00031 #include <iostream>
00032 #include <cmath>
00033 #include "Data.h"
00034 #include "CDMDataType.h"
00035 #include "CDMException.h"
00036 #include "Utils.h"
00037 
00038 namespace MetNoFimex
00039 {
00040 
00048         template<typename T1, typename T2>
00049         boost::shared_array<T1> duplicateArrayType(const boost::shared_array<T2>& inData, long length);
00057         template<typename T1, typename T2>
00058         const boost::shared_array<T1> constConvertArrayType(const boost::shared_array<T2>& inData, long length);
00059                 
00060 
00061         
00062         template<typename C>
00063         class DataImpl : public Data
00064         {
00065         public:
00067                 explicit DataImpl(long length)
00068                 : length(length), theData(new C[length]) {}
00069                 explicit DataImpl(boost::shared_array<C> array, long length)
00070                 : length(length), theData(array) {}
00071                 virtual ~DataImpl() {}
00072 
00073                 virtual size_t size() const {return length;}
00074                 virtual int bytes_for_one() const {return sizeof(C);}
00075                 virtual void* getDataPtr() {return &theData[0];}
00076                 virtual void toStream(std::ostream& os, std::string separator = "") const;
00077 
00081                 virtual const boost::shared_array<C> asBase() const {return theData;}
00085                 template<typename T>
00086                 const boost::shared_array<T> as() const {return constConvertArrayType<T, C>(theData, length);}
00087                 template<typename T>
00088                 boost::shared_array<T> as() {return duplicateArrayType<T, C>(theData, length);}
00089                 // conversion function
00090                 const virtual boost::shared_array<char> asConstChar() const {return as<char>();}
00091                 virtual boost::shared_array<char> asChar() {return as<char>();}
00092                 const virtual boost::shared_array<short> asConstShort() const {return as<short>();}
00093                 virtual boost::shared_array<short> asShort() {return as<short>();}
00094                 const virtual boost::shared_array<int> asConstInt() const {return as<int>();}
00095                 virtual boost::shared_array<int> asInt() {return as<int>();}
00096                 const virtual boost::shared_array<float> asConstFloat() const {return as<float>();}
00097                 virtual boost::shared_array<float> asFloat() {return as<float>();}
00098                 const virtual boost::shared_array<double> asConstDouble() const {return as<double>();}
00099                 virtual boost::shared_array<double> asDouble() {return as<double>();}
00100                 virtual std::string asString(std::string separator = "") const;
00101 
00102                 
00103                 virtual void setValue(long pos, double val) {theData[pos] = static_cast<C>(val);}
00104                 virtual void setValues(size_t startPos, const Data& data, size_t first = 0, size_t last = -1) throw(CDMException);
00105                 virtual boost::shared_ptr<Data> slice(std::vector<size_t> orgDimSize, std::vector<size_t> startDims, std::vector<size_t> outputDimSize) throw(CDMException);
00106                 virtual boost::shared_ptr<Data> convertDataType(double oldFill, double oldScale, double oldOffset, CDMDataType newType, double newFill, double newScale, double newOffset) throw(CDMException);
00110                 template<class InputIterator>
00111                 void setValues(InputIterator first, InputIterator last, size_t dataStartPos = 0) throw(CDMException);
00112                 
00113         private:
00114                 size_t length;
00115                 boost::shared_array<C> theData;
00116                 void copyData(size_t startPos, const boost::shared_array<C>& otherData, size_t otherSize, size_t otherStart, size_t otherEnd) throw(CDMException);
00117         };
00118         
00128         template<class InputIterator>
00129         boost::shared_ptr<Data> createData(CDMDataType datatype, size_t length, InputIterator first, InputIterator last) throw(CDMException);
00130         
00131         // below follow implementations of templates
00132         // (template definitions should be in header files (depending on compiler))
00133         template<typename C>
00134         void DataImpl<C>::toStream(std::ostream& os, std::string separator) const {
00135                 for (size_t i = 0; i < (length-1); i++) {
00136                         os << theData[i] << separator;
00137                 }
00138                 os << theData[length-1];
00139         }
00140 
00141         template<typename C>
00142         std::string DataImpl<C>::asString(std::string separator) const {
00143                 std::ostringstream o;
00144                 toStream(o, separator);
00145                 return o.str();
00146         }
00147 
00148         template<typename C>
00149         void DataImpl<C>::copyData(size_t startPos, const boost::shared_array<C>& otherData, size_t otherSize, size_t otherFirst, size_t otherLast) throw(CDMException) {
00150                 if (otherFirst > otherSize) {
00151                         throw(CDMException("data-region-start "+ type2string(otherFirst) + " outside range: "+ type2string(otherSize)));
00152                 }
00153                 // fixing max range
00154                 otherLast = std::min(otherLast, otherSize);
00155                 otherLast = std::min(size()-startPos+otherFirst, otherLast);
00156                 if (otherLast > otherFirst) {
00157                         std::copy(&otherData[otherFirst], &otherData[otherLast], &theData[startPos]);
00158                 }
00159         }
00160         template<typename C>
00161         void DataImpl<C>::setValues(size_t startPos, const Data& data, size_t first, size_t last) throw(CDMException){
00162                 throw(CDMException("setValues not implemented for this datatype"));
00163         }
00164         template<>
00165         void DataImpl<char>::setValues(size_t startPos, const Data& data, size_t first, size_t last) throw(CDMException);
00166         template<>
00167         void DataImpl<short>::setValues(size_t startPos, const Data& data, size_t first, size_t last) throw(CDMException);
00168         template<>
00169         void DataImpl<int>::setValues(size_t startPos, const Data& data, size_t first, size_t last) throw(CDMException);
00170         template<>
00171         void DataImpl<float>::setValues(size_t startPos, const Data& data, size_t first, size_t last) throw(CDMException);
00172         template<>
00173         void DataImpl<double>::setValues(size_t startPos, const Data& data, size_t first, size_t last) throw(CDMException);
00174         
00189         template<typename C>
00190         void recursiveCopyMultiDimData(C** orgData, C** newData, const std::vector<size_t>& orgDimSize, const std::vector<size_t>& orgSliceSize, const std::vector<size_t>& newStart, const std::vector<size_t>& newSize, size_t currentDim) {
00191                 (*orgData) += newStart[currentDim] * orgSliceSize[currentDim];
00192                 if (currentDim == 0) {
00193                         // putting loop inside if/else for performance
00194                         for (size_t i = 0; i < newSize[0]; i++) {
00195                                 *(*newData)++ = *(*orgData)++;
00196                         }
00197                 } else {
00198                         for (size_t i = 0; i < newSize[currentDim]; i++) {
00199                                 recursiveCopyMultiDimData(orgData, newData, orgDimSize, orgSliceSize, newStart, newSize, currentDim - 1);
00200                         }
00201                 }
00202                 (*orgData) += (orgDimSize[currentDim] - (newStart[currentDim] + newSize[currentDim])) * orgSliceSize[currentDim];
00203         }
00204         
00205         template<typename C>
00206         boost::shared_ptr<Data> DataImpl<C>::slice(std::vector<size_t> orgDimSize, std::vector<size_t> startDims, std::vector<size_t> outputDimSize) throw(CDMException) {
00207                 // get the sizes of the original data and the output data
00208                 size_t orgSize = 1;
00209                 size_t outputSize = 1;
00210                 for (size_t i = 0; i < orgDimSize.size(); ++i) {
00211                         outputSize *= outputDimSize[i];
00212                         orgSize *= orgDimSize[i];
00213                         if (orgDimSize[i] < (startDims[i] + outputDimSize[i])) throw CDMException("dimension-size error, start+size > orgSize: " + type2string(startDims[i]+outputDimSize[i]) + ">" + type2string(orgDimSize[i]) );
00214                 }
00215                 if (orgSize != size()) throw CDMException("dimension-mismatch: " + type2string(size()) + "!=" + type2string(orgSize));
00216                 
00217                 // get the old and new datacontainer
00218                 boost::shared_ptr<DataImpl<C> > output(new DataImpl<C>(outputSize));
00219                 C* newData = output->theData.get();
00220                 C* oldData = theData.get();
00221 
00222                 // pre-calculation of the slice-size of the different dimensions
00223                 std::vector<size_t> orgSliceSize; 
00224                 orgSliceSize.reserve(orgDimSize.size());
00225                 orgSliceSize[0] = 1;
00226                 for (size_t dim = 1; dim < orgDimSize.size(); dim++) {
00227                         orgSliceSize[dim] = orgSliceSize[dim-1] * orgDimSize[dim-1];
00228                 }
00229                 // slice the data
00230                 recursiveCopyMultiDimData(&oldData, &newData, orgDimSize, orgSliceSize, startDims, outputDimSize, orgDimSize.size() - 1);
00231                 
00232                 return output;
00233         }
00234         
00235         
00236         template<typename C>
00237         template<class InputIterator>
00238         void DataImpl<C>::setValues(InputIterator first, InputIterator last, size_t dataStartPos) throw(CDMException) {
00239                 size_t dataPos = dataStartPos;
00240                 if (dataPos < 0) {
00241                         throw CDMException("dataPos < 0, cannot set data");
00242                 }
00243                 for (; first != last; ++first) {
00244                         if (dataPos < length) {
00245                                 theData[dataPos] = static_cast<C>(*first);
00246                         } else {
00247                                 throw CDMException("dataPos " + type2string(dataPos) + " >= dataLength " + type2string(length));
00248                         }
00249                         ++dataPos;
00250                 }
00251         }
00252 
00253         template<typename T1, typename T2>
00254         boost::shared_array<T1> convertArrayType(const boost::shared_array<T2>& inData, size_t length, double oldFill, double oldScale, double oldOffset, double newFill, double newScale, double newOffset) {
00255                 boost::shared_array<T1> outData(new T1[length]);
00256                 T2* inDataPos = &inData[0];
00257                 T2* inDataLast = &inData[length];
00258                 T1* outDataPos = &outData[0];
00259                 T1 fill = static_cast<T1>(newFill);
00260                 while (inDataPos != inDataLast) {
00261                         if (*inDataPos == oldFill || isinf(static_cast<double>(*inDataPos))) {
00262                                 *outDataPos = fill;
00263                         } else {
00264                                 *outDataPos = static_cast<T1>(((oldScale*(*inDataPos) + oldOffset)-newOffset)/newScale);
00265                         }
00266                         *inDataPos++;
00267                         *outDataPos++;
00268                 }
00269                 return outData;
00270         }
00271         
00272         template<typename C>
00273         boost::shared_ptr<Data> DataImpl<C>::convertDataType(double oldFill, double oldScale, double oldOffset, CDMDataType newType, double newFill, double newScale, double newOffset) throw(CDMException) 
00274         {
00275                 boost::shared_ptr<Data> data(new DataImpl<char>(0)); // dummy default
00276                 switch (newType) {
00277                 case CDM_CHAR: data = boost::shared_ptr<Data>(new DataImpl<char>(convertArrayType<char>(theData, size(), oldFill, oldScale, oldOffset, newFill, newScale, newOffset), size())); break;
00278                 case CDM_SHORT: data = boost::shared_ptr<Data>(new DataImpl<short>(convertArrayType<short>(theData, size(), oldFill, oldScale, oldOffset, newFill, newScale, newOffset), size())); break;
00279                 case CDM_INT: data = boost::shared_ptr<Data>(new DataImpl<int>(convertArrayType<int>(theData, size(), oldFill, oldScale, oldOffset, newFill, newScale, newOffset), size())); break;
00280                 case CDM_FLOAT: data = boost::shared_ptr<Data>(new DataImpl<float>(convertArrayType<float>(theData, size(), oldFill, oldScale, oldOffset, newFill, newScale, newOffset), size())); break;
00281                 case CDM_DOUBLE: data = boost::shared_ptr<Data>(new DataImpl<double>(convertArrayType<double>(theData, size(), oldFill, oldScale, oldOffset, newFill, newScale, newOffset), size())); break;
00282                 case CDM_STRING: throw CDMException("cannot convert string datatype"); break;
00283                 case CDM_NAT: throw CDMException("cannot convert CDM_NAT datatype"); break;
00284                 }
00285                 return data;
00286         }
00287 
00288         
00289         template<typename T1, typename T2>
00290         boost::shared_array<T1> duplicateArrayType(const boost::shared_array<T2>& inData, long length) {
00291                 boost::shared_array<T1> outData(new T1[length]);
00292                 T2* inDataPos = &inData[0];
00293                 T2* inDataLast = &inData[length];
00294                 T1* outDataPos = &outData[0];
00295                 while (inDataPos != inDataLast) {
00296                         *outDataPos++ = static_cast<T1>(*inDataPos++);
00297                 }
00298                 return outData;
00299         }
00300         // this version is identical to duplicateArrayType one, except that it allows for specializations
00301         // in the case of T1 == T2 (see Data.cc)
00302         template<typename T1, typename T2>
00303         const boost::shared_array<T1> constConvertArrayType(const boost::shared_array<T2>& inData, long length) {
00304                 return duplicateArrayType<T1,T2>(inData, length);
00305         }
00306 
00307         template<class InputIterator>
00308         boost::shared_ptr<Data> createData(CDMDataType datatype, size_t length, InputIterator first, InputIterator last) throw(CDMException) {
00309                 switch (datatype) {
00310                         case CDM_DOUBLE: { boost::shared_ptr<DataImpl<double> > data(new DataImpl<double>(length)); data->setValues(first, last); return data; }  
00311                         case CDM_FLOAT:  { boost::shared_ptr<DataImpl<float> > data(new DataImpl<float>(length));   data->setValues(first, last); return data; }
00312                         case CDM_INT:    { boost::shared_ptr<DataImpl<int> > data(new DataImpl<int>(length));       data->setValues(first, last); return data; }
00313                         case CDM_SHORT:  { boost::shared_ptr<DataImpl<short> > data(new DataImpl<short>(length));   data->setValues(first, last); return data; }
00314                         case CDM_CHAR:   { boost::shared_ptr<DataImpl<char> > data(new DataImpl<char>(length));     data->setValues(first, last); return data; }
00315                         case CDM_NAT: ;
00316                         default: ;
00317                 }
00318                 return boost::shared_ptr<Data>(new DataImpl<char>(0)); // a dummy dataset
00319 
00320         }
00321 
00322 }
00323 
00324 #endif /*DATAIMPL_H_*/

Generated on Thu Jun 5 14:58:22 2008 for MI - Fimex by  doxygen 1.4.6