view.cpp
Go to the documentation of this file.
1 // Copyright (c) 2009, Willow Garage, Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
6 //
7 // * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // * Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // * Neither the name of Willow Garage, Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived from
14 // this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 // POSSIBILITY OF SUCH DAMAGE.
27 
28 #include "rosbag/view.h"
29 #include "rosbag/bag.h"
31 
32 #include <set>
33 #include <assert.h>
34 
35 using std::map;
36 using std::string;
37 using std::vector;
38 using std::multiset;
39 
40 namespace rosbag {
41 
42 // View::iterator
43 
44 View::iterator::iterator() : view_(NULL), view_revision_(0), message_instance_(NULL) { }
45 
47 {
48  if (message_instance_ != NULL)
49  delete message_instance_;
50 }
51 
52 View::iterator::iterator(View* view, bool end) : view_(view), view_revision_(0), message_instance_(NULL) {
53  if (view != NULL && !end)
54  populate();
55 }
56 
57 View::iterator::iterator(const iterator& i) : view_(i.view_), iters_(i.iters_), view_revision_(i.view_revision_), message_instance_(NULL) { }
58 
60  if (this != &i) {
61  view_ = i.view_;
62  iters_ = i.iters_;
64  if (message_instance_ != NULL) {
65  delete message_instance_;
66  message_instance_ = NULL;
67  }
68  }
69  return *this;
70 }
71 
73  assert(view_ != NULL);
74 
75  iters_.clear();
76  for (MessageRange const* range : view_->ranges_)
77  if (range->begin != range->end)
78  iters_.push_back(ViewIterHelper(range->begin, range));
79 
80  std::sort(iters_.begin(), iters_.end(), ViewIterHelperCompare());
81  view_revision_ = view_->view_revision_;
82 }
83 
84 void View::iterator::populateSeek(multiset<IndexEntry>::const_iterator iter) {
85  assert(view_ != NULL);
86 
87  iters_.clear();
88  for (MessageRange const* range : view_->ranges_) {
89  multiset<IndexEntry>::const_iterator start = std::lower_bound(range->begin, range->end, iter->time, IndexEntryCompare());
90  if (start != range->end)
91  iters_.push_back(ViewIterHelper(start, range));
92  }
93 
94  std::sort(iters_.begin(), iters_.end(), ViewIterHelperCompare());
95  while (iter != iters_.back().iter)
96  increment();
97 
98  view_revision_ = view_->view_revision_;
99 }
100 
101 bool View::iterator::equal(View::iterator const& other) const {
102  // We need some way of verifying these are actually talking about
103  // the same merge_queue data since we shouldn't be able to compare
104  // iterators from different Views.
105 
106  if (iters_.empty())
107  return other.iters_.empty();
108  if (other.iters_.empty())
109  return false;
110 
111  return iters_.back().iter == other.iters_.back().iter;
112 }
113 
115  assert(view_ != NULL);
116 
117  // Our message instance is no longer valid
118  if (message_instance_ != NULL)
119  {
120  delete message_instance_;
121  message_instance_ = NULL;
122  }
123 
124  view_->update();
125 
126  // Note, updating may have blown away our message-ranges and
127  // replaced them in general the ViewIterHelpers are no longer
128  // valid, but the iterator it stores should still be good.
129  if (view_revision_ != view_->view_revision_)
130  populateSeek(iters_.back().iter);
131 
132  if (view_->reduce_overlap_)
133  {
134  std::multiset<IndexEntry>::const_iterator last_iter = iters_.back().iter;
135 
136  while (!iters_.empty() && iters_.back().iter == last_iter)
137  {
138  iters_.back().iter++;
139  if (iters_.back().iter == iters_.back().range->end)
140  iters_.pop_back();
141 
142  std::sort(iters_.begin(), iters_.end(), ViewIterHelperCompare());
143  }
144 
145  } else {
146 
147  iters_.back().iter++;
148  if (iters_.back().iter == iters_.back().range->end)
149  iters_.pop_back();
150 
151  std::sort(iters_.begin(), iters_.end(), ViewIterHelperCompare());
152  }
153 }
154 
156  ViewIterHelper const& i = iters_.back();
157 
158  if (message_instance_ == NULL)
159  message_instance_ = view_->newMessageInstance(i.range->connection_info, *(i.iter), *(i.range->bag_query->bag));
160 
161  return *message_instance_;
162 }
163 
164 // View
165 
166 View::View(bool const& reduce_overlap) : view_revision_(0), size_cache_(0), size_revision_(0), reduce_overlap_(reduce_overlap) { }
167 
168 View::View(Bag const& bag, ros::Time const& start_time, ros::Time const& end_time, bool const& reduce_overlap) : view_revision_(0), size_cache_(0), size_revision_(0), reduce_overlap_(reduce_overlap) {
169  addQuery(bag, start_time, end_time);
170 }
171 
172 View::View(Bag const& bag, boost::function<bool(ConnectionInfo const*)> query, ros::Time const& start_time, ros::Time const& end_time, bool const& reduce_overlap) : view_revision_(0), size_cache_(0), size_revision_(0), reduce_overlap_(reduce_overlap) {
173  addQuery(bag, query, start_time, end_time);
174 }
175 
177  for (MessageRange* range : ranges_)
178  delete range;
179  for (BagQuery* query : queries_)
180  delete query;
181 }
182 
183 
185 {
186  update();
187 
189 
190  for (rosbag::MessageRange* range : ranges_)
191  {
192  if (range->begin->time < begin)
193  begin = range->begin->time;
194  }
195 
196  return begin;
197 }
198 
200 {
201  update();
202 
204 
205  for (rosbag::MessageRange* range : ranges_)
206  {
207  std::multiset<IndexEntry>::const_iterator e = range->end;
208  e--;
209 
210  if (e->time > end)
211  end = e->time;
212  }
213 
214  return end;
215 }
216 
219  update();
220  return iterator(this);
221 }
222 
224 View::iterator View::end() { return iterator(this, true); }
225 
226 uint32_t View::size() {
227 
228  update();
229 
231  {
232  size_cache_ = 0;
233 
234  for (MessageRange* range : ranges_)
235  {
236  size_cache_ += std::distance(range->begin, range->end);
237  }
238 
240  }
241 
242  return size_cache_;
243 }
244 
245 void View::addQuery(Bag const& bag, ros::Time const& start_time, ros::Time const& end_time) {
246  if ((bag.getMode() & bagmode::Read) != bagmode::Read)
247  throw BagException("Bag not opened for reading");
248 
249  boost::function<bool(ConnectionInfo const*)> query = TrueQuery();
250 
251  queries_.push_back(new BagQuery(&bag, Query(query, start_time, end_time), bag.bag_revision_));
252 
253  updateQueries(queries_.back());
254 }
255 
256 void View::addQuery(Bag const& bag, boost::function<bool(ConnectionInfo const*)> query, ros::Time const& start_time, ros::Time const& end_time) {
257  if ((bag.getMode() & bagmode::Read) != bagmode::Read)
258  throw BagException("Bag not opened for reading");
259 
260  queries_.push_back(new BagQuery(&bag, Query(query, start_time, end_time), bag.bag_revision_));
261 
262  updateQueries(queries_.back());
263 }
264 
266  for (map<uint32_t, ConnectionInfo*>::const_iterator i = q->bag->connections_.begin(); i != q->bag->connections_.end(); i++) {
267  ConnectionInfo const* connection = i->second;
268 
269  // Skip if the query doesn't evaluate to true
270  if (!q->query.getQuery()(connection))
271  continue;
272 
273  map<uint32_t, multiset<IndexEntry> >::const_iterator j = q->bag->connection_indexes_.find(connection->id);
274 
275  // Skip if the bag doesn't have the corresponding index
276  if (j == q->bag->connection_indexes_.end())
277  continue;
278  multiset<IndexEntry> const& index = j->second;
279 
280  // lower_bound/upper_bound do a binary search to find the appropriate range of Index Entries given our time range
281  IndexEntry start_time_lookup_entry = { q->query.getStartTime(), 0, 0 };
282  IndexEntry end_time_lookup_entry = { q->query.getEndTime() , 0, 0 };
283  std::multiset<IndexEntry>::const_iterator begin = index.lower_bound(start_time_lookup_entry);
284  std::multiset<IndexEntry>::const_iterator end = index.upper_bound(end_time_lookup_entry);
285 
286  // Make sure we are at the right beginning
287  while (begin != index.begin() && begin->time >= q->query.getStartTime())
288  {
289  begin--;
290  if (begin->time < q->query.getStartTime())
291  {
292  begin++;
293  break;
294  }
295  }
296 
297  if (begin != end)
298  {
299  // todo: make faster with a map of maps
300  bool found = false;
301  for (vector<MessageRange*>::iterator k = ranges_.begin(); k != ranges_.end(); k++) {
302  MessageRange* r = *k;
303 
304  // If the topic and query are already in our ranges, we update
305  if (r->bag_query == q && r->connection_info->id == connection->id) {
306  r->begin = begin;
307  r->end = end;
308  found = true;
309  break;
310  }
311  }
312  if (!found)
313  ranges_.push_back(new MessageRange(begin, end, connection, q));
314  }
315  }
316 
317  view_revision_++;
318 }
319 
320 void View::update() {
321  for (BagQuery* query : queries_) {
322  if (query->bag->bag_revision_ != query->bag_revision) {
323  updateQueries(query);
324  query->bag_revision = query->bag->bag_revision_;
325  }
326  }
327 }
328 
329 std::vector<const ConnectionInfo*> View::getConnections()
330 {
331  std::vector<const ConnectionInfo*> connections;
332  connections.reserve(ranges_.size());
333 
334  for (MessageRange* range : ranges_)
335  {
336  connections.push_back(range->connection_info);
337  }
338 
339  return connections;
340 }
341 
342 MessageInstance* View::newMessageInstance(ConnectionInfo const* connection_info, IndexEntry const& index, Bag const& bag)
343 {
344  return new MessageInstance(connection_info, index, bag);
345 }
346 
347 
348 } // namespace rosbag
rosbag::Bag::getMode
BagMode getMode() const
Get the mode the bag is in.
Definition: bag.cpp:191
rosbag::View::update
void update()
Definition: view.cpp:320
rosbag::Bag
Definition: bag.h:131
rosbag::BagQuery::bag
Bag const * bag
Definition: query.h:136
rosbag::View::iterator::~iterator
~iterator()
Definition: view.cpp:46
rosbag::View::size
uint32_t size()
Definition: view.cpp:226
rosbag::View::iterator::equal
bool equal(iterator const &other) const
Definition: view.cpp:101
rosbag::View::iterator::operator=
iterator & operator=(iterator const &i)
Definition: view.cpp:59
rosbag::View::iterator::populate
void populate()
Definition: view.cpp:72
rosbag::MessageInstance
A class pointing into a bag file.
Definition: message_instance.h:91
rosbag::View::addQuery
void addQuery(Bag const &bag, ros::Time const &start_time=ros::TIME_MIN, ros::Time const &end_time=ros::TIME_MAX)
Add a query to a view.
Definition: view.cpp:245
rosbag::View::iterator::iterator
iterator()
Definition: view.cpp:44
rosbag::View::iterator
friend class iterator
Definition: view.h:219
rosbag::View::ranges_
std::vector< MessageRange * > ranges_
Definition: view.h:231
rosbag::Query
Definition: query.h:84
rosbag::IndexEntryCompare
Definition: structures.h:117
rosbag::View::iterator::dereference
MessageInstance & dereference() const
Definition: view.cpp:155
rosbag::View::iterator::increment
void increment()
Definition: view.cpp:114
rosbag::ConnectionInfo
Definition: structures.h:79
message_instance.h
rosbag::Bag::connections_
std::map< uint32_t, ConnectionInfo * > connections_
Definition: bag.h:367
rosbag::View::iterator::view_
View * view_
Definition: view.h:151
rosbag::View::size_revision_
uint32_t size_revision_
Definition: view.h:236
rosbag::View::updateQueries
void updateQueries(BagQuery *q)
Definition: view.cpp:265
rosbag::bagmode::Read
@ Read
Definition: bag.h:185
rosbag::BagException
Base class for rosbag exceptions.
Definition: exceptions.h:75
rosbag::View::~View
~View()
Definition: view.cpp:176
rosbag::Bag::connection_indexes_
std::map< uint32_t, std::multiset< IndexEntry > > connection_indexes_
Definition: bag.h:371
rosbag::View::queries_
std::vector< BagQuery * > queries_
Definition: view.h:232
rosbag::Query::getStartTime
ros::Time const & getStartTime() const
Get the start-time.
Definition: query.cpp:49
rosbag::View::iterator::populateSeek
void populateSeek(std::multiset< IndexEntry >::const_iterator iter)
Definition: view.cpp:84
rosbag::View::View
View(bool const &reduce_overlap=false)
Create a view on a bag.
Definition: view.cpp:166
rosbag::View::view_revision_
uint32_t view_revision_
Definition: view.h:233
rosbag::View::size_cache_
uint32_t size_cache_
Definition: view.h:235
ros::TIME_MIN
const Time TIME_MIN(0, 1)
rosbag::ViewIterHelperCompare
Definition: query.h:163
rosbag::View::getConnections
std::vector< const ConnectionInfo * > getConnections()
Definition: view.cpp:329
rosbag::View
Definition: view.h:80
rosbag::MessageRange::connection_info
ConnectionInfo const * connection_info
Definition: query.h:150
rosbag::View::iterator::iters_
std::vector< ViewIterHelper > iters_
Definition: view.h:152
rosbag::View::TrueQuery
Definition: view.h:159
rosbag::ViewIterHelper::range
MessageRange const * range
pointer to vector of ranges in View
Definition: query.h:160
rosbag::MessageRange::bag_query
BagQuery const * bag_query
pointer to vector of queries in View
Definition: query.h:151
rosbag::MessageRange::begin
std::multiset< IndexEntry >::const_iterator begin
Definition: query.h:148
rosbag::ViewIterHelper::iter
std::multiset< IndexEntry >::const_iterator iter
Definition: query.h:159
bag.h
rosbag::IndexEntry
Definition: structures.h:108
rosbag::View::reduce_overlap_
bool reduce_overlap_
Definition: view.h:238
start
ROSCPP_DECL void start()
rosbag::View::iterator
An iterator that points to a MessageInstance from a bag.
Definition: view.h:124
ros::TIME_MAX
const ROSTIME_DECL Time TIME_MAX
rosbag::View::getBeginTime
ros::Time getBeginTime()
Definition: view.cpp:184
ros::Time
rosbag::View::iterator::view_revision_
uint32_t view_revision_
Definition: view.h:153
view.h
rosbag::ConnectionInfo::id
uint32_t id
Definition: structures.h:115
rosbag::View::newMessageInstance
MessageInstance * newMessageInstance(ConnectionInfo const *connection_info, IndexEntry const &index, Bag const &bag)
Definition: view.cpp:342
rosbag::Query::getEndTime
ros::Time const & getEndTime() const
Get the end-time.
Definition: query.cpp:50
rosbag::MessageRange::end
std::multiset< IndexEntry >::const_iterator end
Definition: query.h:149
rosbag
Definition: aes_encryptor.h:43
rosbag::View::getEndTime
ros::Time getEndTime()
Definition: view.cpp:199
rosbag::MessageRange
Definition: query.h:141
rosbag::ViewIterHelper
The actual iterator data structure.
Definition: query.h:155
rosbag::Query::getQuery
boost::function< bool(ConnectionInfo const *)> const & getQuery() const
Get the query functor.
Definition: query.cpp:45
assert.h
rosbag::View::end
iterator end()
Default constructed iterator signifies end.
Definition: view.cpp:224
rosbag::Bag::bag_revision_
uint32_t bag_revision_
Definition: bag.h:352
rosbag::View::begin
iterator begin()
Simply copy the merge_queue state into the iterator.
Definition: view.cpp:218
rosbag::BagQuery::query
Query query
Definition: query.h:137
rosbag::BagQuery
Pairs of queries and the bags they come from (used internally by View)
Definition: query.h:132


rosbag_storage
Author(s): Dirk Thomas , Jacob Perron
autogenerated on Sat Sep 14 2024 02:59:52