MIRA
StampedDataQueue.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2012 by
3  * MetraLabs GmbH (MLAB), GERMANY
4  * and
5  * Neuroinformatics and Cognitive Robotics Labs (NICR) at TU Ilmenau, GERMANY
6  * All rights reserved.
7  *
8  * Contact: info@mira-project.org
9  *
10  * Commercial Usage:
11  * Licensees holding valid commercial licenses may use this file in
12  * accordance with the commercial license agreement provided with the
13  * software or, alternatively, in accordance with the terms contained in
14  * a written agreement between you and MLAB or NICR.
15  *
16  * GNU General Public License Usage:
17  * Alternatively, this file may be used under the terms of the GNU
18  * General Public License version 3.0 as published by the Free Software
19  * Foundation and appearing in the file LICENSE.GPL3 included in the
20  * packaging of this file. Please review the following information to
21  * ensure the GNU General Public License version 3.0 requirements will be
22  * met: http://www.gnu.org/copyleft/gpl.html.
23  * Alternatively you may (at your option) use any later version of the GNU
24  * General Public License if such license has been publicly approved by
25  * MLAB and NICR (or its successors, if any).
26  *
27  * IN NO EVENT SHALL "MLAB" OR "NICR" BE LIABLE TO ANY PARTY FOR DIRECT,
28  * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
29  * THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF "MLAB" OR
30  * "NICR" HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  * "MLAB" AND "NICR" SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
33  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
34  * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
35  * ON AN "AS IS" BASIS, AND "MLAB" AND "NICR" HAVE NO OBLIGATION TO
36  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR MODIFICATIONS.
37  */
38 
47 #ifndef _MIRA_STAMPEDDATAQUEUE_H_
48 #define _MIRA_STAMPEDDATAQUEUE_H_
49 
50 #include <error/Exceptions.h>
51 #include <utils/Stamped.h>
52 
53 #include <math/Eigen.h>
54 
55 namespace mira {
56 
58 
83 template <typename T >
85 {
86 public:
87 
89  typedef std::list<Stamped<T>, Eigen::aligned_allocator<T>> Container;
90 
93 
95  typedef typename Container::const_iterator const_iterator;
96 
98  typedef typename Container::size_type size_type;
99 
100 public:
101 
106  StampedDataQueue(size_type maxCapacity=100,
107  Duration maxStorageTime = Duration::seconds(10) ) :
108  mMaxCapacity(maxCapacity), mMaxStorageTime(maxStorageTime) {}
109 
110 public:
111 
115  void setMaxStorageTime(Duration maxStorageTime)
116  {
117  mMaxStorageTime = maxStorageTime;
118  prune();
119  }
120 
121  // STL conform operations:
122 
127  size_type capacity() const { return mMaxCapacity; }
128 
136  void reserve(size_type n) {
137  if(n>mMaxCapacity)
138  mMaxCapacity=n;
139  }
140 
141 
143  size_type size() const { return mStorage.size(); }
144 
146  bool empty() const { return mStorage.empty(); }
147 
148 
154  bool insert(const Stamped<T>& data)
155  {
156  typename Container::iterator it = mStorage.begin();
157 
158  // check if new data is too old, if so, then skip it
159  if(it!=mStorage.end() && it->timestamp > data.timestamp + mMaxStorageTime)
160  return false;
161 
162  // find position to insert the data
163  for(;it != mStorage.end(); ++it)
164  {
165  // if the timestamp of the item at "it" is older, then we need to insert
166  // before "it"
167  if (data.timestamp >= it->timestamp)
168  break;
169  }
170 
171  // guarantee STRICTLY monotonic decreasing and overwrite
172  // an existing entry with the same timestamp, if any!
173  if(it!=mStorage.end() && it->timestamp==data.timestamp)
174  *it = data;
175  else {
176  // if data is older than all elements in the queue and queue is
177  // already full skip insertion
178  if (it == mStorage.end() && mStorage.size() == mMaxCapacity)
179  return false;
180  // otherwise insert the data before "it"
181  mStorage.insert(it, data);
182 
183  // prune the data (throw away oldest elements if necessary)
184  prune();
185  }
186 
187  return true;
188  }
189 
191  void clear() { mStorage.clear(); }
192 
193 public:
194 
199  const Stamped<T>& getData(const Time& timestamp) const
200  {
201  if (mStorage.empty())
202  MIRA_THROW(XRuntime, "Trying to get data from empty StampedDataQueue");
203 
204  const_iterator older = findFirstOlderItem(timestamp);
205  // older already is the first element -> there is no newer one
206  if(older==mStorage.begin())
207  return *older;
208 
209  const_iterator newer = older;
210  --newer;
211 
212  // there is no older element return the newer one (oldest in queue)
213  if(older==mStorage.end())
214  return *newer;
215 
216  // return closest value
217  if( (newer->timestamp - timestamp) <
218  (timestamp - older->timestamp))
219  return *newer;
220  else
221  return *older;
222  }
223 
240  std::pair<const_iterator,const_iterator> getInterval(const Time& timestamp,
241  std::size_t size,
242  std::size_t before,
243  std::size_t after)
244  {
245  assert(size==0 || size >= before+after);
246 
247  const_iterator older = findFirstOlderItem(timestamp);
248 
249  // |----|-----|------------|------|-----|
250  // ^ ^ ^ ^
251  // begin timestamp older end
252 
253  // move backward in time until we reach the end of the buffer,
254  // or got the requested number of slots
255  const_iterator last = older;
256  for(std::size_t i=0; i<before && last!=mStorage.end(); ++i, ++last) ;
257 
258  const_iterator first = older;
259  std::size_t i = 0;
260  for(; i<after && first!=mStorage.begin(); ++i, --first) ;
261 
262  // now ensure the size constraint (if there's one)
263  if(size!=0) {
264  std::size_t left = size-std::distance(first,last);
265  while(left>0 && first!=mStorage.begin()) {
266  --first;
267  --left;
268  }
269  while(left>0 && last!=mStorage.end()) {
270  ++last;
271  --left;
272  }
273 
274  if(left>0)
275  MIRA_THROW(XRuntime,
276  "Not enough items in StampedDataQueue to obtain "
277  "the requested interval: " << left <<
278  " items missing.")
279  }
280 
281  return std::make_pair(first, last);
282  }
283 
284 private:
285 
290  void prune()
291  {
292  // the oldest "allowed" timestamp
293  Time oldestTimestamp = mStorage.begin()->timestamp - mMaxStorageTime;
294 
295  // remove the elements at the end that are too old or if there are too many
296  while(!mStorage.empty() &&
297  (mStorage.rbegin()->timestamp < oldestTimestamp ||
298  mStorage.size() > mMaxCapacity) )
299  mStorage.pop_back();
300  }
301 
302 
303  // find the first iterator that is older than our searched timestamp
304  typename Container::const_iterator findFirstOlderItem(const Time& timestamp) const
305  {
306  // move from newest to oldest slot
307  for(typename Container::const_iterator it=mStorage.begin();
308  it!=mStorage.end(); ++it)
309  if(it->timestamp < timestamp)
310  return it;
311 
312  // if queue is empty or the oldest queue element is already newer than
313  // the requested timestamp, we end up here
314  return mStorage.end();
315  }
316 
317 private:
318 
319  size_type mMaxCapacity;
320  Duration mMaxStorageTime;
321 
322  Container mStorage;
323 };
324 
326 
327 }
328 
329 #endif
void reserve(size_type n)
Request a change in capacity.
Definition: StampedDataQueue.h:136
Include file for all eigen related things.
StampedDataQueue(size_type maxCapacity=100, Duration maxStorageTime=Duration::seconds(10))
Creates new StampedDataQueue with the specified maximum capacity (default 100) and maximum storage ti...
Definition: StampedDataQueue.h:106
Time timestamp
The time stamp when the data was obtained.
Definition: Stamped.h:104
specialize cv::DataType for our ImgPixel and inherit from cv::DataType<Vec>
Definition: IOService.h:67
std::list< Stamped< T >, Eigen::aligned_allocator< T > > Container
The type of the underlying container.
Definition: StampedDataQueue.h:89
Implements a queue where Stamped data can be added.
Definition: StampedDataQueue.h:84
#define MIRA_THROW(ex, msg)
Macro for throwing an exception.
Definition: Exception.h:82
Wrapper class for boost::posix_time::ptime for adding more functionality to it.
Definition: Time.h:418
void clear()
clears the whole queue and removes all elements
Definition: StampedDataQueue.h:191
Commonly used exception classes.
sec_type seconds() const
Returns normalized number of seconds (0..59)
Definition: Time.h:280
Use this class to represent time durations.
Definition: Time.h:106
std::pair< const_iterator, const_iterator > getInterval(const Time &timestamp, std::size_t size, std::size_t before, std::size_t after)
Returns two iterators that mark the begin and end of an interval of data.
Definition: StampedDataQueue.h:240
size_type capacity() const
Returns the maximum number of items that can be stored in the queue.
Definition: StampedDataQueue.h:127
size_type size() const
Returns the number of stored elements.
Definition: StampedDataQueue.h:143
Mix in for adding a time stamp, an optional frame id and an optional sequence id to data types like P...
Definition: Stamped.h:149
Container::size_type size_type
some typedefs for STL compliance
Definition: StampedDataQueue.h:98
Container::const_iterator const_iterator
some typedefs for STL compliance
Definition: StampedDataQueue.h:95
Mix in for adding a timestamp to data types.
bool empty() const
Returns true, if no element is stored.
Definition: StampedDataQueue.h:146
Stamped< T > value_type
some typedefs for STL compliance
Definition: StampedDataQueue.h:92
void setMaxStorageTime(Duration maxStorageTime)
Sets the maximum storage time.
Definition: StampedDataQueue.h:115
bool insert(const Stamped< T > &data)
Inserts new data to the queue.
Definition: StampedDataQueue.h:154
const Stamped< T > & getData(const Time &timestamp) const
Returns the data from the queue whose time stamp is closest to the specified timestamp.
Definition: StampedDataQueue.h:199