NASA Astrobee Robot Software  0.19.1
Flight software for the Astrobee robots operating inside the International Space Station.
timestamped_set.h
Go to the documentation of this file.
1 /* Copyright (c) 2017, United States Government, as represented by the
2  * Administrator of the National Aeronautics and Space Administration.
3  *
4  * All rights reserved.
5  *
6  * The Astrobee platform is licensed under the Apache License, Version 2.0
7  * (the "License"); you may not use this file except in compliance with the
8  * License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15  * License for the specific language governing permissions and limitations
16  * under the License.
17  */
18 
19 #ifndef LOCALIZATION_COMMON_TIMESTAMPED_SET_H_
20 #define LOCALIZATION_COMMON_TIMESTAMPED_SET_H_
21 
24 
25 #include <boost/optional.hpp>
26 #include <boost/serialization/serialization.hpp>
27 #include <boost/serialization/unordered_map.hpp>
28 
29 #include <algorithm>
30 #include <map>
31 #include <utility>
32 #include <vector>
33 
34 namespace localization_common {
35 // Helper wrapper class that returns a value and timestamp.
36 template <typename T>
39  explicit TimestampedValue(const std::pair<const Time, T>& pair) : timestamp(pair.first), value(pair.second) {}
41  // TODO(rsoussan): Store this as const ref? Make it optional to be ref or not?
42  T value;
43 };
44 
45 // Stores a set of timesetamped values and provides many functions to
46 // access and interact with the values using timestamps.
47 // Optionally enforce a size limit, which when exceeded will remove the first half of the elements in the set.
48 template <typename T>
50  public:
51  explicit TimestampedSet(const boost::optional<int> max_size = boost::none);
52  ~TimestampedSet() = default;
53 
54  // Assumes values have corresponding timestamps at the same index and each timestamp is unique.
55  TimestampedSet(const std::vector<Time>& timestamps, const std::vector<T>& values,
56  const boost::optional<int> max_size = boost::none);
57 
58  // Adds a value at the corresponding timestamp.
59  // Returns whether the value was successfully added.
60  bool Add(const Time timestamp, const T& value);
61 
62  // Removes a value at the provided timestamp if it exists.
63  // Returns whether the value was sucessfully removed.
64  bool Remove(const Time timestamp);
65 
66  // Get the timestamped value at the provied timestamp.
67  // Returns boost::none if no value exists.
68  boost::optional<TimestampedValue<T>> Get(const Time timestamp) const;
69 
70  // Returns the number of timestamped values in the set.
71  size_t size() const;
72 
73  // Returns whether the set is empty.
74  bool empty() const;
75 
76  // Clears all values and timestamps from the set.
77  void Clear();
78 
79  // Returns the oldest timestamped value in the set.
80  // Returns boost::none if the set is empty.
81  boost::optional<TimestampedValue<T>> Oldest() const;
82 
83  // Returns the oldest timestamp in the set.
84  // Returns boost::none if the set is empty.
85  boost::optional<Time> OldestTimestamp() const;
86 
87  // Returns the latest timestamped value in the set.
88  // Returns boost::none if the set is empty.
89  boost::optional<TimestampedValue<T>> Latest() const;
90 
91  // Returns the latest timestamp in the set.
92  // Returns boost::none if the set is empty.
93  boost::optional<Time> LatestTimestamp() const;
94 
95  // Returns whether oldest_timestamp <= timestamp <= latest timestamp for the set.
96  bool WithinBounds(const Time timestamp) const;
97 
98  // Returns the lower and upper bound timestamped values in the set corresponding to the
99  // provided timestamp. If the set has a value at the provided timestamp,
100  // both the lower and upper bound will be set to this value.
101  std::pair<boost::optional<TimestampedValue<T>>, boost::optional<TimestampedValue<T>>> LowerAndUpperBound(
102  const Time timestamp) const;
103 
104  // Returns the closest timestamped value in the set to the provided timestamp
105  // or boost::none if the set is empty.
106  boost::optional<TimestampedValue<T>> Closest(const Time timestamp) const;
107 
108  // Returns the lower bound or equal timestamped value in the set corresponding to the
109  // provided timestamp or boost::none if the set is empty.
110  boost::optional<TimestampedValue<T>> LowerBoundOrEqual(const Time timestamp) const;
111 
112  // Returns a vector containing the ordered (oldest to latest) timestamps contained
113  // in the set.
114  std::vector<Time> Timestamps() const;
115 
116  // Returns the total duration of time (latest_time - oldest_time) contained in the set.
117  double Duration() const;
118 
119  // Returns whether the set contains the provided timestamp.
120  bool Contains(const Time timestamp) const;
121 
122  // Returns the latest values not older than the provided oldest allowed timestamp.
123  // Orders values from older to later values.
124  std::vector<TimestampedValue<T>> LatestValues(const Time oldest_allowed_timestamp) const;
125 
126  // Returns timestamped values in the set older than the provided oldest allowed timestamp.
127  // Values are ordered from oldest to latest.
128  std::vector<TimestampedValue<T>> OldValues(const Time oldest_allowed_timestamp) const;
129 
130  // Returns values occuring at the provided timestamps.
131  // Orders values from older to later values.
132  template <typename TimestampSetType>
133  std::vector<TimestampedValue<T>> DownsampledValues(const TimestampSetType& allowed_timestamps) const;
134 
135  // Removes values older than the provided oldest_allowed_timestamp.
136  // Returns the number of removed values.
137  int RemoveOldValues(const Time oldest_allowed_timestamp);
138 
139  // Finds the lower bound element for timestamp and removes all values below this.
140  // Keeps the lower bound, unlike RemoveOldValues which only keeps a lower bound
141  // equal to the provided timestamp.
142  int RemoveBelowLowerBoundValues(const Time timestamp);
143 
144  // Removes and returns the oldest value if it exists.
145  boost::optional<TimestampedValue<T>> RemoveOldest();
146 
147  // Returns a const reference to the internal map containing timestamps and corresponding values.
148  const std::map<Time, T>& set() const;
149 
150  // Returns a reference to the internal map containing timestamps and corresponding values.
151  std::map<Time, T>& set();
152 
153  // Returns an end iterator for the internal map containing timestamps and corresponding values.
154  typename std::map<Time, T>::const_iterator cend() const;
155 
156  // Returns iterators to values in range of oldest and latest allowed timestamps.
157  // The second iterator is one-past the latest allowed element to allow for iterating
158  // using: for(auto it = pair.first; it != pair.second; ++it)
159  std::pair<typename std::map<Time, T>::const_iterator, typename std::map<Time, T>::const_iterator> InRangeValues(
160  const Time oldest_allowed_timestamp, const Time latest_allowed_timestamp);
161 
162  private:
163  friend class boost::serialization::access;
164  template <class ARCHIVE>
165  void serialize(ARCHIVE& ar, const unsigned int /*version*/);
166 
167  std::map<Time, T> timestamp_value_map_;
168  boost::optional<int> max_size_;
169 };
170 
171 // Implementation
172 template <typename T>
173 TimestampedSet<T>::TimestampedSet(const boost::optional<int> max_size) : max_size_(max_size) {}
174 
175 template <typename T>
176 TimestampedSet<T>::TimestampedSet(const std::vector<Time>& timestamps, const std::vector<T>& values,
177  const boost::optional<int> max_size)
178  : max_size_(max_size) {
179  for (int i = 0; i < values.size(); ++i) {
180  Add(timestamps[i], values[i]);
181  }
182 }
183 
184 template <typename T>
185 bool TimestampedSet<T>::Add(const Time timestamp, const T& value) {
186  if (Contains(timestamp)) return false;
187  timestamp_value_map_.emplace(timestamp, value);
188  // Optionally shrink elements to half of max size if max size exceeded. Removes first half of set.
189  if (max_size_ && size() > *max_size_) {
190  auto end_it = timestamp_value_map_.begin();
191  std::advance(end_it, *max_size_ / 2);
192  timestamp_value_map_.erase(timestamp_value_map_.begin(), end_it);
193  }
194  return true;
195 }
196 
197 template <typename T>
198 bool TimestampedSet<T>::Remove(const Time timestamp) {
199  if (!Contains(timestamp)) return false;
200  timestamp_value_map_.erase(timestamp);
201  return true;
202 }
203 
204 template <typename T>
205 boost::optional<TimestampedValue<T>> TimestampedSet<T>::Get(const Time timestamp) const {
206  if (!Contains(timestamp)) return boost::none;
207  return TimestampedValue<T>(timestamp, timestamp_value_map_.at(timestamp));
208 }
209 
210 template <typename T>
211 size_t TimestampedSet<T>::size() const {
212  return timestamp_value_map_.size();
213 }
214 
215 template <typename T>
217  return timestamp_value_map_.empty();
218 }
219 
220 template <typename T>
222  timestamp_value_map_.clear();
223 }
224 
225 template <typename T>
226 boost::optional<TimestampedValue<T>> TimestampedSet<T>::Oldest() const {
227  if (empty()) {
228  LogDebug("Oldest: No timestamps available.");
229  return boost::none;
230  }
231  return TimestampedValue<T>(*timestamp_value_map_.cbegin());
232 }
233 
234 template <typename T>
235 boost::optional<Time> TimestampedSet<T>::OldestTimestamp() const {
236  if (empty()) {
237  LogDebug("OldestTimestamp: No timestamps available.");
238  return boost::none;
239  }
240  return timestamp_value_map_.cbegin()->first;
241 }
242 
243 template <typename T>
244 boost::optional<TimestampedValue<T>> TimestampedSet<T>::Latest() const {
245  if (empty()) {
246  LogDebug("Latest: No values available.");
247  return boost::none;
248  }
249  return TimestampedValue<T>(*timestamp_value_map_.crbegin());
250 }
251 
252 template <typename T>
253 boost::optional<Time> TimestampedSet<T>::LatestTimestamp() const {
254  if (empty()) {
255  LogDebug("LatestTimestamp: No values available.");
256  return boost::none;
257  }
258  return timestamp_value_map_.crbegin()->first;
259 }
260 
261 template <typename T>
262 bool TimestampedSet<T>::WithinBounds(const Time time) const {
263  const auto oldest = Oldest();
264  const auto latest = Latest();
265  if (!oldest || !latest) {
266  LogError("WithinBounds: Failed to get time bounds.");
267  return false;
268  }
269  return (time >= oldest->timestamp && time <= latest->timestamp);
270 }
271 
272 template <typename T>
273 std::pair<boost::optional<TimestampedValue<T>>, boost::optional<TimestampedValue<T>>>
275  if (empty()) {
276  LogDebug("LowerAndUpperBound: No timestamps available.");
277  return {boost::none, boost::none};
278  }
279 
280  // lower bound returns first it >= query, call this upper bound
281  const auto upper_bound_it = timestamp_value_map_.lower_bound(timestamp);
282  if (upper_bound_it == timestamp_value_map_.cend()) {
283  LogDebug("LowerAndUpperBoundTimestamps: No upper bound timestamp exists.");
284  return {boost::optional<TimestampedValue<T>>(*(timestamp_value_map_.crbegin())), boost::none};
285  } else if (upper_bound_it->first == timestamp) {
286  // Handle equality, set lower and upper bound to same elements
287  return {boost::optional<TimestampedValue<T>>(*upper_bound_it),
288  boost::optional<TimestampedValue<T>>(*upper_bound_it)};
289  } else if (upper_bound_it == timestamp_value_map_.cbegin()) {
290  LogDebug("LowerAndUpperBoundTimestamps: No lower bound timestamp exists.");
291  return {boost::none, boost::optional<TimestampedValue<T>>(*upper_bound_it)};
292  }
293  const auto lower_bound_it = std::prev(upper_bound_it);
294 
295  return {boost::optional<TimestampedValue<T>>(*lower_bound_it), boost::optional<TimestampedValue<T>>(*upper_bound_it)};
296 }
297 
298 template <typename T>
299 boost::optional<TimestampedValue<T>> TimestampedSet<T>::LowerBoundOrEqual(const Time timestamp) const {
300  const auto lower_and_upper_bound_values = LowerAndUpperBound(timestamp);
301  if (!lower_and_upper_bound_values.first && !lower_and_upper_bound_values.second) {
302  LogDebug("LowerBoundOrEqual: Failed to get lower or upper bound values.");
303  return boost::none;
304  }
305 
306  // Only return upper bound values if it is equal to timestamp
307  if (lower_and_upper_bound_values.second && lower_and_upper_bound_values.second->timestamp == timestamp) {
308  return lower_and_upper_bound_values.second;
309  }
310 
311  return lower_and_upper_bound_values.first;
312 }
313 
314 template <typename T>
315 std::vector<Time> TimestampedSet<T>::Timestamps() const {
316  std::vector<Time> timestamps;
317  for (const auto& timestamped_value : timestamp_value_map_) {
318  timestamps.emplace_back(timestamped_value.first);
319  }
320  return timestamps;
321 }
322 
323 template <typename T>
325  if (empty()) return 0;
326  return (*LatestTimestamp() - *OldestTimestamp());
327 }
328 
329 template <typename T>
330 boost::optional<TimestampedValue<T>> TimestampedSet<T>::Closest(const Time timestamp) const {
331  if (empty()) {
332  LogDebug("Closest: No values available.");
333  return boost::none;
334  }
335 
336  const auto lower_and_upper_bound_values = LowerAndUpperBound(timestamp);
337  if (!lower_and_upper_bound_values.first && !lower_and_upper_bound_values.second) {
338  LogDebug("Closest: Failed to get lower or upper bound values.");
339  return boost::none;
340  }
341 
342  if (!lower_and_upper_bound_values.first) {
343  return lower_and_upper_bound_values.second;
344  } else if (!lower_and_upper_bound_values.second) {
345  return lower_and_upper_bound_values.first;
346  } else {
347  const Time lower_bound_timestamp = lower_and_upper_bound_values.first->timestamp;
348  const Time upper_bound_timestamp = lower_and_upper_bound_values.second->timestamp;
349  const double upper_bound_dt = std::abs(timestamp - upper_bound_timestamp);
350  const double lower_bound_dt = std::abs(timestamp - lower_bound_timestamp);
351  return (upper_bound_dt < lower_bound_dt) ? lower_and_upper_bound_values.second : lower_and_upper_bound_values.first;
352  }
353 }
354 
355 template <typename T>
356 bool TimestampedSet<T>::Contains(const Time timestamp) const {
357  return timestamp_value_map_.count(timestamp) > 0;
358 }
359 
360 template <typename T>
361 std::vector<TimestampedValue<T>> TimestampedSet<T>::LatestValues(const Time oldest_allowed_timestamp) const {
362  std::vector<TimestampedValue<T>> latest_values;
363  std::transform(timestamp_value_map_.lower_bound(oldest_allowed_timestamp), timestamp_value_map_.end(),
364  std::back_inserter(latest_values),
365  [](const std::pair<Time, T>& value) { return TimestampedValue<T>(value); });
366  return latest_values;
367 }
368 
369 template <typename T>
370 std::vector<TimestampedValue<T>> TimestampedSet<T>::OldValues(const Time oldest_allowed_timestamp) const {
371  std::vector<TimestampedValue<T>> old_values;
372  std::transform(timestamp_value_map_.begin(), timestamp_value_map_.lower_bound(oldest_allowed_timestamp),
373  std::back_inserter(old_values),
374  [](const std::pair<Time, T>& value) { return TimestampedValue<T>(value); });
375  return old_values;
376 }
377 
378 template <typename T>
379 template <typename TimestampSetType>
380 std::vector<TimestampedValue<T>> TimestampedSet<T>::DownsampledValues(
381  const TimestampSetType& allowed_timestamps) const {
382  std::vector<TimestampedValue<T>> downsampled_values;
383  for (const auto& pair : timestamp_value_map_) {
384  if (allowed_timestamps.count(pair.first) > 0) {
385  downsampled_values.emplace_back(TimestampedValue<T>(pair));
386  }
387  }
388  return downsampled_values;
389 }
390 
391 template <typename T>
392 int TimestampedSet<T>::RemoveOldValues(const Time oldest_allowed_timestamp) {
393  const int initial_num_values = size();
394  timestamp_value_map_.erase(timestamp_value_map_.begin(), timestamp_value_map_.lower_bound(oldest_allowed_timestamp));
395  return initial_num_values - size();
396 }
397 
398 template <typename T>
400  const int initial_num_values = size();
401  const auto upper_bound = timestamp_value_map_.lower_bound(timestamp);
402  const auto lower_bound =
403  upper_bound != timestamp_value_map_.cbegin() ? std::prev(upper_bound) : timestamp_value_map_.cbegin();
404  timestamp_value_map_.erase(timestamp_value_map_.begin(), lower_bound);
405  return initial_num_values - size();
406 }
407 
408 template <typename T>
409 boost::optional<TimestampedValue<T>> TimestampedSet<T>::RemoveOldest() {
410  const auto oldest = Oldest();
411  if (oldest) Remove(oldest->timestamp);
412  return oldest;
413 }
414 
415 template <typename T>
416 const std::map<Time, T>& TimestampedSet<T>::set() const {
417  return timestamp_value_map_;
418 }
419 
420 template <typename T>
421 std::map<Time, T>& TimestampedSet<T>::set() {
422  return timestamp_value_map_;
423 }
424 
425 template <typename T>
426 typename std::map<Time, T>::const_iterator TimestampedSet<T>::cend() const {
427  return timestamp_value_map_.cend();
428 }
429 
430 template <typename T>
431 std::pair<typename std::map<Time, T>::const_iterator, typename std::map<Time, T>::const_iterator>
432 TimestampedSet<T>::InRangeValues(const Time oldest_allowed_timestamp, const Time latest_allowed_timestamp) {
433  auto upper_bound = timestamp_value_map_.upper_bound(latest_allowed_timestamp);
434  auto lower_bound = timestamp_value_map_.lower_bound(oldest_allowed_timestamp);
435  // No values less than latest allowed time
436  if (upper_bound == timestamp_value_map_.cbegin()) return {cend(), cend()};
437  return std::make_pair(timestamp_value_map_.lower_bound(oldest_allowed_timestamp), upper_bound);
438 }
439 
440 template <typename T>
441 template <class ARCHIVE>
442 void TimestampedSet<T>::serialize(ARCHIVE& ar, const unsigned int /*version*/) {
443  ar& BOOST_SERIALIZATION_NVP(timestamp_value_map_);
444  ar& BOOST_SERIALIZATION_NVP(max_size_);
445 }
446 } // namespace localization_common
447 
448 #endif // LOCALIZATION_COMMON_TIMESTAMPED_SET_H_
localization_common
Definition: averager.h:33
localization_common::TimestampedSet::LatestTimestamp
boost::optional< Time > LatestTimestamp() const
Definition: timestamped_set.h:253
localization_common::TimestampedSet::WithinBounds
bool WithinBounds(const Time timestamp) const
Definition: timestamped_set.h:262
localization_common::TimestampedSet::RemoveBelowLowerBoundValues
int RemoveBelowLowerBoundValues(const Time timestamp)
Definition: timestamped_set.h:399
localization_common::TimestampedSet::DownsampledValues
std::vector< TimestampedValue< T > > DownsampledValues(const TimestampSetType &allowed_timestamps) const
Definition: timestamped_set.h:380
logger.h
localization_common::TimestampedSet::size
size_t size() const
Definition: timestamped_set.h:211
LogError
#define LogError(msg)
Definition: logger.h:55
localization_common::TimestampedSet::LatestValues
std::vector< TimestampedValue< T > > LatestValues(const Time oldest_allowed_timestamp) const
Definition: timestamped_set.h:361
localization_common::TimestampedSet::LowerBoundOrEqual
boost::optional< TimestampedValue< T > > LowerBoundOrEqual(const Time timestamp) const
Definition: timestamped_set.h:299
localization_common::TimestampedSet::Closest
boost::optional< TimestampedValue< T > > Closest(const Time timestamp) const
Definition: timestamped_set.h:330
localization_common::TimestampedSet::set
const std::map< Time, T > & set() const
Definition: timestamped_set.h:416
localization_common::TimestampedSet::Clear
void Clear()
Definition: timestamped_set.h:221
localization_common::TimestampedSet::Remove
bool Remove(const Time timestamp)
Definition: timestamped_set.h:198
localization_common::TimestampedSet
Definition: timestamped_set.h:49
localization_common::TimestampedSet::Contains
bool Contains(const Time timestamp) const
Definition: timestamped_set.h:356
localization_common::TimestampedSet::OldValues
std::vector< TimestampedValue< T > > OldValues(const Time oldest_allowed_timestamp) const
Definition: timestamped_set.h:370
localization_common::TimestampedSet::Duration
double Duration() const
Definition: timestamped_set.h:324
localization_common::TimestampedValue::TimestampedValue
TimestampedValue(const Time timestamp, const T &value)
Definition: timestamped_set.h:38
localization_common::TimestampedSet::TimestampedSet
TimestampedSet(const boost::optional< int > max_size=boost::none)
Definition: timestamped_set.h:173
time.h
localization_common::TimestampedSet::Timestamps
std::vector< Time > Timestamps() const
Definition: timestamped_set.h:315
localization_common::TimestampedSet::RemoveOldValues
int RemoveOldValues(const Time oldest_allowed_timestamp)
Definition: timestamped_set.h:392
localization_common::TimestampedSet::~TimestampedSet
~TimestampedSet()=default
localization_common::TimestampedValue::timestamp
Time timestamp
Definition: timestamped_set.h:40
localization_common::TimestampedSet::Oldest
boost::optional< TimestampedValue< T > > Oldest() const
Definition: timestamped_set.h:226
localization_common::TimestampedSet::cend
std::map< Time, T >::const_iterator cend() const
Definition: timestamped_set.h:426
localization_common::TimestampedValue
Definition: timestamped_set.h:37
localization_common::TimestampedValue::value
T value
Definition: timestamped_set.h:42
localization_common::TimestampedSet::OldestTimestamp
boost::optional< Time > OldestTimestamp() const
Definition: timestamped_set.h:235
localization_common::TimestampedSet::Get
boost::optional< TimestampedValue< T > > Get(const Time timestamp) const
Definition: timestamped_set.h:205
localization_common::TimestampedValue::TimestampedValue
TimestampedValue(const std::pair< const Time, T > &pair)
Definition: timestamped_set.h:39
localization_common::TimestampedSet::LowerAndUpperBound
std::pair< boost::optional< TimestampedValue< T > >, boost::optional< TimestampedValue< T > > > LowerAndUpperBound(const Time timestamp) const
Definition: timestamped_set.h:274
localization_common::TimestampedSet::InRangeValues
std::pair< typename std::map< Time, T >::const_iterator, typename std::map< Time, T >::const_iterator > InRangeValues(const Time oldest_allowed_timestamp, const Time latest_allowed_timestamp)
Definition: timestamped_set.h:432
LogDebug
#define LogDebug(msg)
Definition: logger.h:69
localization_common::TimestampedSet::RemoveOldest
boost::optional< TimestampedValue< T > > RemoveOldest()
Definition: timestamped_set.h:409
localization_common::TimestampedSet::Latest
boost::optional< TimestampedValue< T > > Latest() const
Definition: timestamped_set.h:244
localization_common::TimestampedSet::empty
bool empty() const
Definition: timestamped_set.h:216
localization_common::Time
double Time
Definition: time.h:23
localization_common::TimestampedSet::Add
bool Add(const Time timestamp, const T &value)
Definition: timestamped_set.h:185