nemo/TimeSeries.h
Go to the documentation of this file.00001 #ifndef _NEMO_TIME_SERIES_H_ 00002 #define _NEMO_TIME_SERIES_H_ 00003 00004 #include "IntrusiveCowSupport.h" 00005 #include "IntrusiveCounted.h" 00006 #include "Collection.h" 00007 #include "detail/nemo-cpp11.h" 00008 00009 #include <stdexcept> 00010 #include <vector> 00011 #include <algorithm> 00012 00013 00014 #include <iostream> 00015 00016 00017 00018 namespace nemo { 00019 00020 /* Note: absolute-time + duration for values possible by using 00021 * timestamp-objects that combine both??? 00022 */ 00023 00024 00025 00026 template <typename T> 00027 class TimeOffset; 00028 template <typename T> 00029 static TimeOffset<T> offset(T o); 00030 00035 template <typename T> 00036 class TimeOffset { 00037 public: 00038 inline const T& get() const {return o;} 00039 friend TimeOffset<T> offset<T>(T o); 00040 TimeOffset(const TimeOffset &other) : o(other.o) {} 00041 private: 00042 TimeOffset(T oP) : o(oP) {} 00043 TimeOffset& operator=(const TimeOffset& other){o = other.o; return *this;} 00044 T o; 00045 }; 00046 00050 template <typename T> 00051 static inline TimeOffset<T> offset(T o){ 00052 return TimeOffset<T>(o); 00053 } 00054 00058 template <typename TimestampType, typename ValueType> 00059 class TimeSeriesEntry { 00060 public: 00061 TimestampType timestamp; 00062 ValueType value; 00063 00064 TimeSeriesEntry(TimestampType timestampP, ValueType valueP) 00065 : timestamp(timestampP), value(valueP) {} 00066 bool operator==(const TimeSeriesEntry<TimestampType,ValueType> &other) const { 00067 return (timestamp==other.timestamp) && (value==other.value); 00068 } 00069 bool operator!=(const TimeSeriesEntry<TimestampType,ValueType> &other) const { 00070 return !(*this==other); 00071 } 00072 }; 00073 00074 00075 00093 template <typename TimestampType, typename ValueType, bool strictOrdering=false> 00094 class TimeSeries : public Collection<TimeSeriesEntry<TimestampType,ValueType> > { 00095 public: 00096 typedef _nemo_get_type_(TimestampType()-TimestampType()) DurationType; 00097 typedef TimeSeries<TimestampType,ValueType,strictOrdering> ThisType; 00098 typedef TimeSeriesEntry<TimestampType,ValueType> EntryType; 00099 00100 00101 private: 00102 #ifndef NEMO_PARSED_BY_DOXYGEN 00103 class TimeSeriesData : public IntrusiveCounted<TimeSeriesData> { 00104 public: 00105 mutable std::vector<ValueType> values; 00106 mutable std::vector<TimestampType> timestamps; 00107 //DurationType lastEntryDuration; 00108 }; 00109 IntrusiveCowSupport<TimeSeriesData> data; 00110 00111 00112 00113 template <typename OtherTimestampType,typename OtherValueType> 00114 class EntryComparator { 00115 public: 00116 typedef TimeSeriesEntry<OtherTimestampType,OtherValueType> OtherEntryType; 00117 bool operator()(OtherEntryType first, OtherEntryType second){ 00118 return (first.timestamp < second.timestamp); 00119 } 00120 }; 00121 #endif 00122 00123 00124 // ============================================================================= 00125 // Content View Abstractions 00126 // ============================================================================= 00127 public: 00128 class TimestampView; 00129 class ValueView; 00130 00131 #ifndef NEMO_PARSED_BY_DOXYGEN 00132 template <typename T> 00133 class ViewIterator{ 00134 private: 00135 ViewIterator(int indexP, std::vector<T> &viewDataP) : index(indexP), viewData(viewDataP) {} 00136 public: 00137 friend class TimestampView; 00138 friend class ValueView; 00139 00140 ViewIterator(const ViewIterator& it) : index(it.index), viewData(it.viewData) {} 00141 ViewIterator& operator=(const ViewIterator &it){ 00142 if(this==&it){return *this;} 00143 this->index = it.index; 00144 this->viewData = it.viewData; 00145 return *this; 00146 } 00147 00148 typedef int difference_type; 00149 typedef T value_type; 00150 typedef T* pointer; 00151 typedef T reference; 00152 typedef std::random_access_iterator_tag iterator_category; 00153 00154 T operator*() const{ 00155 if(index<0 || (int)viewData.size()<=index){_NEMO_LOGIC_ERROR("Iterator out of range");} 00156 return viewData[index]; 00157 } 00158 T operator[](difference_type offset) const{ 00159 if(index+offset<0 || (int)viewData.size()<=index+offset){_NEMO_LOGIC_ERROR("Iterator out of range");} 00160 return viewData[index+offset]; 00161 } 00162 ViewIterator& operator++(){ 00163 index++; 00164 return const_cast<ViewIterator&>(*this); 00165 } 00166 ViewIterator operator++(int){ 00167 ViewIterator copy = *this; 00168 index++; 00169 return copy; 00170 } 00171 ViewIterator& operator--(){ 00172 index--; 00173 return const_cast<ViewIterator&>(*this); 00174 } 00175 ViewIterator operator--(int){ 00176 ViewIterator copy = *this; 00177 index--; 00178 return copy; 00179 } 00180 ViewIterator operator+(difference_type off) const { 00181 ViewIterator it = *this; 00182 it.index += off; 00183 return it; 00184 } 00185 ViewIterator operator-(difference_type off) const { 00186 ViewIterator it = *this; 00187 it.index -= off; 00188 return it; 00189 } 00190 difference_type operator-(const ViewIterator& rhs) const { 00191 return index - rhs.index; 00192 } 00193 bool operator==(const ViewIterator &it) const{ 00194 return (&viewData==&it.viewData) && (index==it.index); 00195 } 00196 bool operator!=(const ViewIterator &it) const{ 00197 return !(*this==it); 00198 } 00199 bool operator<=(const ViewIterator &it) const{ 00200 return index<=it.index; 00201 } 00202 bool operator<(const ViewIterator &it) const{ 00203 return index<it.index; 00204 } 00205 bool operator>=(const ViewIterator &it) const{ 00206 return index>=it.index; 00207 } 00208 bool operator>(const ViewIterator &it) const{ 00209 return index>it.index; 00210 } 00211 private: 00212 int index; 00213 std::vector<T> &viewData; 00214 }; 00215 #endif 00216 00224 class TimestampView : public Collection<TimestampType> { 00225 private: 00226 TimestampView(TimeSeries<TimestampType,ValueType,strictOrdering> &seriesP) 00227 : series(seriesP) {} 00228 TimestampView(const TimestampView &other) 00229 : series(other.series) {_NEMO_LOGIC_ERROR("");} 00230 TimestampView& operator=(const TimestampView& other){ 00231 series = other.series; 00232 return *this; 00233 } 00234 00235 void rearrangeSeries(std::vector<EntryType> &newTimestamps){ 00236 // get new timestamps in a sorted order 00237 std::sort(newTimestamps.begin(), newTimestamps.end(), EntryComparator<TimestampType,ValueType>()); 00238 00239 // insert timestamps and pick up correct values 00240 series.data.detach(); 00241 for(unsigned int i = 0; i < newTimestamps.size(); i++){ 00242 series.data->timestamps[i] = newTimestamps[i].timestamp; 00243 series.data->values[i] = newTimestamps[i].value; 00244 } 00245 } 00246 public: 00247 00248 friend class TimeSeries<TimestampType,ValueType,strictOrdering>; 00249 00250 // ======== General access ======== 00251 00255 TimestampType operator[](unsigned int index) const { 00256 series.checkIndex(index); 00257 return series.data->timestamps[index]; // return const-ref??? 00258 } 00259 00268 void set(unsigned int index, TimestampType value){ 00269 series.checkIndex(index); 00270 series.data.detach(); 00271 // TODO simplify this code 00272 if(0<index && !series.compareTime(series.data->timestamps[index-1], value)){ 00273 // timestamp smaller than left element 00274 // right-rotation of content required 00275 unsigned int leftLimit = 0; 00276 for(int i = index-1; 0 <= i; i--){ 00277 if(series.compareTime(series.data->timestamps[i], value)){ 00278 leftLimit = i+1; 00279 break; 00280 } 00281 } 00282 if(strictOrdering && !series.compareTime(value, series.data->timestamps[leftLimit])){ 00283 _NEMO_ARGUMENT_ERROR("Timeseries: timestamp already exists"); 00284 } 00285 series.data->timestamps[index] = value; 00286 std::rotate( 00287 series.data->timestamps.begin()+leftLimit, 00288 series.data->timestamps.begin()+index, 00289 series.data->timestamps.begin()+index+1 00290 ); 00291 std::rotate( 00292 series.data->values.begin()+leftLimit, 00293 series.data->values.begin()+index, 00294 series.data->values.begin()+index+1 00295 ); 00296 } 00297 else if(index < series.length()-1 && !series.compareTime(value, series.data->timestamps[index+1])){ 00298 // timestamp bigger than right element 00299 // left-rotation of content required 00300 unsigned int rightLimit = series.length(); 00301 for(int i = index+1; i < (int)series.length(); i++){ 00302 if(series.compareTime(value, series.data->timestamps[i])){ 00303 rightLimit = i; 00304 break; 00305 } 00306 } 00307 if(strictOrdering && !series.compareTime(series.data->timestamps[rightLimit-1], value)){ 00308 _NEMO_ARGUMENT_ERROR("Timeseries: timestamp already exists"); 00309 } 00310 series.data->timestamps[index] = value; 00311 std::rotate( 00312 series.data->timestamps.begin()+index, 00313 series.data->timestamps.begin()+index+1, 00314 series.data->timestamps.begin()+rightLimit 00315 ); 00316 std::rotate( 00317 series.data->values.begin()+index, 00318 series.data->values.begin()+index+1, 00319 series.data->values.begin()+rightLimit 00320 ); 00321 } 00322 else{ 00323 series.data->timestamps[index] = value; 00324 } 00325 } 00326 00332 void remove(unsigned int index){ 00333 series.checkIndex(index); 00334 series.data.detach(); 00335 series.data->values.erase( series.data->values.begin() + index ); 00336 series.data->timestamps.erase( series.data->timestamps.begin() + index ); 00337 } 00338 00339 // ======== Collection API ======== 00340 unsigned int numElements() const{ 00341 return series.length(); 00342 } 00343 TimestampType getElement(unsigned int elementIndex) const{ 00344 return operator[](elementIndex); 00345 } 00346 void setElement(unsigned int elementIndex, TimestampType value){ 00347 set(elementIndex, value); 00348 } 00349 void transform(Mapping<TimestampType,TimestampType> m){ 00350 std::vector<EntryType> newTimestamps; 00351 for(unsigned int i=0; i<series.length(); i++){ 00352 newTimestamps.push_back( 00353 EntryType( m(series.data->timestamps[i]), series.data->values[i]) 00354 ); 00355 } 00356 rearrangeSeries(newTimestamps); 00357 } 00358 template <typename OutType> 00359 TimeSeries<OutType,ValueType,strictOrdering> map(Mapping<TimestampType,OutType> m) const { 00360 // compute new timestamps 00361 std::vector<TimeSeriesEntry<OutType,ValueType> > newTimestamps; 00362 for(unsigned int i=0; i<series.length(); i++){ 00363 newTimestamps.push_back( 00364 TimeSeriesEntry<OutType,ValueType>( m(series.data->timestamps[i]), series.data->values[i]) 00365 ); 00366 } 00367 00368 // sort and append them 00369 TimeSeries<OutType,ValueType,strictOrdering> mapped; 00370 std::sort(newTimestamps.begin(), newTimestamps.end(), EntryComparator<OutType,ValueType>()); 00371 for(unsigned int i = 0; i < newTimestamps.size(); i++){ 00372 mapped.append(newTimestamps[i].timestamp, newTimestamps[i].value); 00373 } 00374 return mapped; 00375 } 00376 00377 // ======== STL compliant iterator interface ======== 00378 00382 ViewIterator<TimestampType> begin() const { 00383 return ViewIterator<TimestampType>(0, series.data->timestamps); 00384 } 00388 ViewIterator<TimestampType> end() const { 00389 return ViewIterator<TimestampType>(series.length(), series.data->timestamps); 00390 } 00391 private: 00392 TimeSeries<TimestampType,ValueType,strictOrdering> &series; 00393 }; 00394 00402 class ValueView : public Collection<ValueType> { 00403 private: 00404 ValueView(TimeSeries<TimestampType,ValueType,strictOrdering> &seriesP) 00405 : series(seriesP) {} 00406 ValueView(const ValueView &other) 00407 : series(other.series) {_NEMO_LOGIC_ERROR("");} 00408 ValueView& operator=(const ValueView& other){ 00409 series = other.series; 00410 return *this; 00411 } 00412 public: 00413 00414 friend class TimeSeries<TimestampType,ValueType,strictOrdering>; 00415 00416 // ======== General access ======== 00417 00421 ValueType operator[](unsigned int index) const { 00422 series.checkIndex(index); 00423 return series.data->values[index]; // return const-ref??? 00424 } 00425 00429 void set(unsigned int index, ValueType value){ 00430 series.checkIndex(index); 00431 series.data.detach(); 00432 series.data->values[index] = value; 00433 } 00434 00435 void remove(unsigned int index){ 00436 series.checkIndex(index); 00437 series.data.detach(); 00438 series.data->values.erase( series.data->values.begin() + index ); 00439 series.data->timestamps.erase( series.data->timestamps.begin() + index ); 00440 } 00441 00442 // ======== Collection API ======== 00443 unsigned int numElements() const{ 00444 return series.length(); 00445 } 00446 ValueType getElement(unsigned int elementIndex) const{ 00447 return operator[](elementIndex); 00448 } 00449 void setElement(unsigned int elementIndex, ValueType value){ 00450 set(elementIndex, value); 00451 } 00452 void transform(Mapping<ValueType,ValueType> m){ 00453 series.data.detach(); 00454 for(unsigned int i=0; i<series.length(); i++){ 00455 series.data->values[i] = m(series.data->values[i]); 00456 } 00457 } 00458 template <typename OutType> 00459 TimeSeries<TimestampType,OutType,strictOrdering> map(Mapping<ValueType,OutType> m) const { 00460 TimeSeries<TimestampType,OutType,strictOrdering> mapped = series; 00461 mapped.data.detach(); 00462 for(unsigned int i=0; i<series.length(); i++){ 00463 mapped.data->values[i] = m(series.data->values[i]); 00464 } 00465 return mapped; 00466 } 00467 00468 // ======== STL compliant iterator interface ======== 00469 00473 ViewIterator<ValueType> begin() const { 00474 return ViewIterator<ValueType>(0, series.data->values); 00475 } 00479 ViewIterator<ValueType> end() const { 00480 return ViewIterator<ValueType>(series.length(), series.data->values); 00481 } 00482 00483 private: 00484 TimeSeries<TimestampType,ValueType,strictOrdering> &series; 00485 }; 00486 00487 00491 TimestampView timestamps; 00495 ValueView values; 00496 00497 #ifndef NEMO_PARSED_BY_DOXYGEN 00498 friend class TimestampView; 00499 friend class ValueView; 00500 #endif 00501 00502 // ============================================================================= 00503 // Construction 00504 // ============================================================================= 00505 public: 00506 // FIXME use of *this maybe problematic??? 00507 TimeSeries() : data(new TimeSeriesData()), timestamps(*this), values(*this) {} 00508 TimeSeries(const ThisType &o) : data(o.data), timestamps(*this), values(*this) {} 00509 TimeSeries<TimestampType,ValueType,strictOrdering>& operator=(const ThisType &o){ 00510 if(this!=&o){ 00511 data = o.data; 00512 timestamps = TimestampView(*this); 00513 values = ValueView(*this); 00514 } 00515 return *this; 00516 } 00517 00518 // ============================================================================= 00519 // General Access 00520 // ============================================================================= 00521 00524 unsigned int length() const { 00525 return data->values.size(); 00526 } 00529 bool isEmpty() const { 00530 return data->values.empty(); 00531 } 00539 ValueType operator[](TimestampType timeP) const { 00540 unsigned int index = findTimestampIndex(timeP); 00541 return data->values[index]; 00542 } 00543 00544 // ============================================================================= 00545 // General Manipulation 00546 // ============================================================================= 00547 00554 void append(TimestampType timeP, ValueType valueP){ 00555 checkTimestampAppend(timeP); 00556 data.detach(); 00557 data->values.push_back(valueP); 00558 data->timestamps.push_back(timeP); 00559 } 00570 void append(const TimeOffset<DurationType> &offset, ValueType valueP){ 00571 TimestampType time = isEmpty() ? 00572 TimestampType() + offset.get() : 00573 data->timestamps.back() + offset.get(); 00574 checkTimestampAppend(time); 00575 data.detach(); 00576 data->values.push_back(valueP); 00577 data->timestamps.push_back(time); 00578 } 00584 void append(ThisType otherSeries){ 00585 if(!otherSeries.isEmpty()){ 00586 checkTimestampAppend(otherSeries.timestamp(0)); 00587 data.detach(); 00588 for(unsigned int i=0; i<otherSeries.length(); i++){ 00589 data->values.push_back(otherSeries.data->values[i]); 00590 data->timestamps.push_back(otherSeries.data->timestamps[i]); 00591 } 00592 } 00593 } 00600 void append(const TimeOffset<DurationType> &offset, ThisType otherSeries){ 00601 if(!otherSeries.isEmpty()){ 00602 DurationType shift = isEmpty() ? 00603 offset.get() : 00604 (data->timestamps.back() - otherSeries.data->timestamps.front()) + offset.get(); 00605 TimestampType firstTime = data->timestamps.back()+shift; 00606 checkTimestampAppend(firstTime); 00607 data.detach(); 00608 for(unsigned int i=0; i<otherSeries.length(); i++){ 00609 data->values.push_back(otherSeries.data->values[i]); 00610 data->timestamps.push_back(otherSeries.data->timestamps[i]+shift); 00611 } 00612 } 00613 } 00621 void setValue(TimestampType timeP, ValueType valueP){ 00622 unsigned int index = findTimestampIndex(timeP); 00623 data.detach(); 00624 data->values[index] = valueP; 00625 } 00633 void insert(TimestampType timeP, ValueType valueP){ 00634 typedef _nemo_get_type_(data->timestamps.begin()) Iterator; 00635 // use STL binary search 00636 // first element with timestamp greater (non-equal) than timeP 00637 Iterator pos = upper_bound(data->timestamps.begin(), data->timestamps.end(), timeP); 00638 00639 // check ordering constraint 00640 if(strictOrdering && pos!=data->timestamps.begin() && *(pos-1)==timeP){ 00641 _NEMO_ARGUMENT_ERROR("Existing timestamp can not be inserted with strict-ordering"); 00642 } 00643 00644 unsigned int index = pos - data->timestamps.begin(); 00645 data.detach(); 00646 data->timestamps.insert(pos, timeP); 00647 data->values.insert(data->values.begin()+index, valueP); 00648 } 00654 void remove(TimestampType timeP){ 00655 unsigned int index = findTimestampIndex(timeP); 00656 data.detach(); 00657 data->values.erase( data->values.begin() + index ); 00658 data->timestamps.erase( data->timestamps.begin() + index ); 00659 } 00660 00661 // TODO do we need a 'removeAll' method for strictOrdering==false ? 00662 00668 void removeFirst(){ 00669 checkIndex(0); 00670 data.detach(); 00671 data->values.erase( data->values.begin() ); 00672 data->timestamps.erase( data->timestamps.begin() ); 00673 } 00679 void removeFirst(unsigned int k){ 00680 if(k!=0){ checkIndex(k-1); } 00681 data.detach(); 00682 data->values.erase( data->values.begin(), data->values.begin()+k ); 00683 data->timestamps.erase( data->timestamps.begin(), data->timestamps.begin()+k ); 00684 } 00685 00686 // ============================================================================= 00687 // Comparison 00688 // ============================================================================= 00693 bool operator==(const ThisType &r) const{ 00694 if(length() != r.length()){ 00695 return false; 00696 } 00697 for(unsigned int i=0; i<length(); i++){ 00698 if(data->values[i] != r.data->values[i]){ 00699 return false; 00700 } 00701 if(data->timestamps[i] != r.data->timestamps[i]){ 00702 return false; 00703 } 00704 } 00705 // else 00706 return true; 00707 } 00708 00712 bool operator!=(const ThisType &r) const{ 00713 return !operator==(r); 00714 } 00715 00716 // ============================================================================= 00717 // Collection API 00718 // ============================================================================= 00719 unsigned int numElements() const{ 00720 return length(); 00721 } 00722 00727 EntryType getElement(unsigned int elementIndex) const{ 00728 checkIndex(elementIndex); 00729 return EntryType(data->timestamps[elementIndex], data->values[elementIndex]); 00730 } 00731 00737 void setElement(unsigned int elementIndex, EntryType entry){\ 00738 checkIndex(elementIndex); 00739 values.set(elementIndex, entry.value); // value first 00740 timestamps.set(elementIndex, entry.timestamp); // timestamp might cause re-ordering 00741 } 00742 00743 void transform(Mapping<EntryType,EntryType> m){ 00744 data.detach(); 00745 std::vector<EntryType> newEntries; 00746 for(unsigned int i = 0; i < length(); i++){ 00747 newEntries.push_back( m(EntryType(data->timestamps[i], data->values[i])) ); 00748 } 00749 // FIXME more efficient ways to do this? 00750 data->timestamps.clear(); 00751 data->values.clear(); 00752 std::sort( newEntries.begin(), newEntries.end(), EntryComparator<TimestampType,ValueType>() ); 00753 for(unsigned int i = 0; i < newEntries.size(); i++){ 00754 append( newEntries[i].timestamp, newEntries[i].value ); 00755 } 00756 } 00757 00758 template <typename OtherTimestampType, typename OtherValueType> 00759 TimeSeries<OtherTimestampType,OtherValueType,strictOrdering> map( 00760 Mapping<EntryType,TimeSeriesEntry<OtherTimestampType,OtherValueType> > m) 00761 const { 00762 TimeSeries<OtherTimestampType,OtherValueType,strictOrdering> mapped; 00763 for(unsigned int i=0; i<length(); i++){ 00764 TimeSeriesEntry<OtherTimestampType,OtherValueType> newEntry = m(EntryType(data->timestamps[i], data->values[i])); 00765 mapped.append( newEntry.timestamp, newEntry.value ); 00766 } 00767 return mapped; 00768 } 00769 // ============================================================================= 00770 // STL compliant iterator interface 00771 // ============================================================================= 00772 #ifndef NEMO_PARSED_BY_DOXYGEN 00773 class EntryIterator{ 00774 private: 00775 EntryIterator(int indexP, ThisType &seriesP) : index(indexP), series(seriesP) {} 00776 public: 00777 friend class TimeSeries<TimestampType,ValueType,strictOrdering>; 00778 00779 EntryIterator(const EntryIterator& it) : index(it.index), series(it.series) {} 00780 EntryIterator& operator=(const EntryIterator &it){ 00781 if(this==&it){return *this;} 00782 this->index = it.index; 00783 this->series = it.series; 00784 return *this; 00785 } 00786 00787 typedef int difference_type; 00788 typedef EntryType value_type; 00789 typedef EntryType* pointer; 00790 typedef EntryType reference; 00791 typedef std::random_access_iterator_tag iterator_category; 00792 00793 EntryType operator*() const{ 00794 if(index<0 || (int)series.length()<=index){_NEMO_LOGIC_ERROR("Iterator out of range");} 00795 return series.getElement(index); 00796 } 00797 EntryType operator[](difference_type offset) const{ 00798 if(index+offset<0 || (int)series.length()<=index+offset){_NEMO_LOGIC_ERROR("Iterator out of range");} 00799 return series.getElement(index+offset); 00800 } 00801 EntryIterator& operator++(){ 00802 index++; 00803 return const_cast<EntryIterator&>(*this); 00804 } 00805 EntryIterator operator++(int){ 00806 EntryIterator copy = *this; 00807 index++; 00808 return copy; 00809 } 00810 EntryIterator& operator--(){ 00811 index--; 00812 return const_cast<EntryIterator&>(*this); 00813 } 00814 EntryIterator operator--(int){ 00815 EntryIterator copy = *this; 00816 index--; 00817 return copy; 00818 } 00819 EntryIterator operator+(difference_type off) const { 00820 EntryIterator it = *this; 00821 it.index += off; 00822 return it; 00823 } 00824 EntryIterator operator-(difference_type off) const { 00825 EntryIterator it = *this; 00826 it.index -= off; 00827 return it; 00828 } 00829 difference_type operator-(const EntryIterator& rhs) const { 00830 return index - rhs.index; 00831 } 00832 bool operator==(const EntryIterator &it) const{ 00833 return (&series==&it.series) && (index==it.index); 00834 } 00835 bool operator!=(const EntryIterator &it) const{ 00836 return !(*this==it); 00837 } 00838 bool operator<=(const EntryIterator &it) const{ 00839 return index<=it.index; 00840 } 00841 bool operator<(const EntryIterator &it) const{ 00842 return index<it.index; 00843 } 00844 bool operator>=(const EntryIterator &it) const{ 00845 return index>=it.index; 00846 } 00847 bool operator>(const EntryIterator &it) const{ 00848 return index>it.index; 00849 } 00850 private: 00851 int index; 00852 ThisType &series; 00853 }; 00854 #endif 00855 00859 EntryIterator begin() const { 00860 return EntryIterator(0, const_cast<ThisType&>(*this)); 00861 } 00865 EntryIterator end() const { 00866 return EntryIterator(length(), const_cast<ThisType&>(*this)); 00867 } 00868 00869 private: 00870 inline void checkIndex(unsigned int index) const{ 00871 if(data->values.size() <= index){ 00872 _NEMO_ARGUMENT_ERROR("TimeSeries: index out of range"); 00873 } 00874 } 00875 inline void checkTimestampAppend(const TimestampType &ts) const { 00876 if(!isEmpty()){ 00877 if( !compareTime(data->timestamps.back(), ts) ){ 00878 _NEMO_ARGUMENT_ERROR("TimeSeries: timestamp not behind latest"); 00879 } 00880 } 00881 } 00882 inline bool compareTime(const TimestampType &first, const TimestampType &second) const{ 00883 if(strictOrdering){ 00884 return first < second; 00885 } 00886 else{ 00887 return first <= second; 00888 } 00889 } 00890 unsigned int findTimestampIndex(const TimestampType &ts) const { 00891 typedef _nemo_get_type_(data->timestamps.begin()) Iterator; 00892 // use STL binary search 00893 Iterator pos = lower_bound(data->timestamps.begin(), data->timestamps.end(), ts); 00894 if(pos==data->timestamps.end() || *pos!=ts){ 00895 _NEMO_ARGUMENT_ERROR("Timestamp could not be found in TimeSeries"); 00896 } 00897 return pos-data->timestamps.begin(); 00898 } 00899 00900 }; 00901 00902 template <class V, class T> 00903 std::ostream& operator<<(std::ostream& out, const TimeSeriesEntry<V,T> &entry){ 00904 out << entry.timestamp << "\t" << entry.value; 00905 return out; 00906 } 00907 template <class V, class T> 00908 std::ostream& operator<<(std::ostream& out, const TimeSeries<V,T> &series){ 00909 00910 for(unsigned int i=0; i<series.length(); i++){ 00911 out << series.timestamps[i] << "\t" << series.values[i] << "\n"; 00912 } 00913 return out; 00914 } 00915 00916 00917 } // end namespace 00918 00919 #endif 00920
Generated on Mon Feb 25 12:49:59 2013 for NemoMath by
![doxygen](doxygen.png)