OSVR-Core
HistoryContainer.h
Go to the documentation of this file.
1 
11 // Copyright 2016 Sensics, Inc.
12 //
13 // Licensed under the Apache License, Version 2.0 (the "License");
14 // you may not use this file except in compliance with the License.
15 // You may obtain a copy of the License at
16 //
17 // http://www.apache.org/licenses/LICENSE-2.0
18 //
19 // Unless required by applicable law or agreed to in writing, software
20 // distributed under the License is distributed on an "AS IS" BASIS,
21 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 // See the License for the specific language governing permissions and
23 // limitations under the License.
24 
25 #ifndef INCLUDED_HistoryContainer_h_GUID_7CD22B1E_6EAC_49BF_F9FB_030C4BE3FA54
26 #define INCLUDED_HistoryContainer_h_GUID_7CD22B1E_6EAC_49BF_F9FB_030C4BE3FA54
27 
28 // Internal Includes
29 // - none
30 
31 // Library/third-party includes
32 #include <osvr/Util/TimeValue.h>
33 
34 // Standard includes
35 #include <deque>
36 #include <stdexcept>
37 #include <iterator>
38 
39 namespace osvr {
40 namespace vbtracker {
41  namespace history {
42 
43  namespace detail {
44  using timestamp = osvr::util::time::TimeValue;
45 
46  template <typename ValueType>
47  using full_value_type = std::pair<timestamp, ValueType>;
48 
49  template <typename ValueType>
50  using inner_container_type = std::deque<full_value_type<ValueType>>;
51 
52  template <typename ValueType>
53  using container_size_type =
54  typename inner_container_type<ValueType>::size_type;
55 
56  template <typename ValueType>
57  using iterator =
58  typename inner_container_type<ValueType>::const_iterator;
59 
60  template <typename ValueType>
61  using nonconst_iterator =
62  typename inner_container_type<ValueType>::iterator;
63 
66  template <typename ValueType> class TimestampPairLessThan {
67  public:
68  bool operator()(timestamp const &lhs,
69  full_value_type<ValueType> const &rhs) {
70  return lhs < rhs.first;
71  }
72 
73  bool operator()(full_value_type<ValueType> const &lhs,
74  timestamp const &rhs) {
75  return lhs.first < rhs;
76  }
77  };
81  template <typename ValueType> class HistorySubsetRange {
82  public:
83  using iterator = detail::iterator<ValueType>;
84  using const_iterator = detail::iterator<ValueType>;
85  HistorySubsetRange(iterator begin_, iterator end_)
86  : m_begin(begin_), m_end(end_) {
88  }
89 
90  iterator begin() const { return m_begin; }
91  const_iterator cbegin() const { return m_begin; }
92  iterator end() const { return m_end; }
93  const_iterator cend() const { return m_end; }
94 
95  private:
96  iterator m_begin;
97  iterator m_end;
98  };
99  } // namespace detail
100 
103  template <typename ValueType, bool AllowDuplicateTimes_ = true>
105  public:
106  using value_type = ValueType;
107 
109  using full_value_type = detail::full_value_type<value_type>;
110  using container_type = detail::inner_container_type<value_type>;
111  using size_type = detail::container_size_type<value_type>;
112 
113  using iterator = detail::iterator<value_type>;
114  using const_iterator = iterator;
115 
117 
119 
122  static const bool AllowDuplicateTimes = AllowDuplicateTimes_;
123 
125  size_type size() const { return m_history.size(); }
126 
128  size_type highWaterMark() const { return m_sizeHighWaterMark; }
129 
131  bool empty() const { return m_history.empty(); }
132 
133  timestamp_type const &oldest_timestamp() const {
134  if (empty()) {
135  throw std::logic_error(
136  "Can't get time of oldest entry in an "
137  "empty history container!");
138  }
139  return m_history.front().first;
140  }
141 
142  value_type const &oldest() const {
143  if (empty()) {
144  throw std::logic_error("Can't get oldest entry in an "
145  "empty history container!");
146  }
147  return m_history.front().first;
148  }
149 
157  if (empty()) {
158  throw std::logic_error(
159  "Can't get time of newest entry in an "
160  "empty history container!");
161  }
162 
163  return m_history.back().first;
164  }
165 
166  value_type const &newest() const {
167  if (empty()) {
168  throw std::logic_error("Can't get newest entry in an "
169  "empty history container!");
170  }
171 
172  return m_history.back().second;
173  }
174 
178 
179  void pop_oldest() { m_history.pop_front(); }
180  void pop_newest() { m_history.pop_back(); }
181 
182  const_iterator begin() const { return m_history.cbegin(); }
183  const_iterator cbegin() const { return m_history.cbegin(); }
184  const_iterator end() const { return m_history.cend(); }
185  const_iterator cend() const { return m_history.cend(); }
186 
187  void clear() { m_history.clear(); }
188 
189  private:
192  using nonconst_iterator = detail::nonconst_iterator<value_type>;
193 
194  nonconst_iterator ncbegin() { return m_history.begin(); }
195  nonconst_iterator ncend() { return m_history.end(); }
196 
197  public:
201  bool is_strictly_newest(timestamp_type const &tv) const {
202  return empty() || newest_timestamp() < tv;
203  }
204 
208  bool is_as_new_as_newest(timestamp_type const &tv) const {
209  return empty() || !(tv < newest_timestamp());
210  }
211 
216  return empty() || tv > newest_timestamp() ||
217  (AllowDuplicateTimes && newest_timestamp() == tv);
218  }
219 
222  const_iterator upper_bound(timestamp_type const &tv) const {
223  return std::upper_bound(begin(), end(), tv, comparator());
224  }
228  const_iterator lower_bound(timestamp_type const &tv) const {
229  return std::lower_bound(begin(), end(), tv, comparator());
230  }
231 
232  private:
238  nonconst_iterator nc_upper_bound(timestamp_type const &tv) {
239  return std::upper_bound(ncbegin(), ncend(), tv, comparator());
240  }
247  nonconst_iterator nc_lower_bound(timestamp_type const &tv) {
248  return std::lower_bound(ncbegin(), ncend(), tv, comparator());
249  }
250 
251  public:
255  const_iterator closest_not_newer(timestamp_type const &tv) const {
256  if (empty()) {
257  return end();
258  }
261  auto it = upper_bound(tv);
262  if (begin() == it) {
263  // can't back iterator off if it's already at the beginning
264  return end();
265  }
266  --it;
267  return it;
268  }
269 
276  return subset_range_type(upper_bound(tv), end());
277  }
278 
279 #if 0
280  size_type pop_before(timestamp_type const &tv) {
284  auto count = size_type{0};
285  while (!empty() && oldest_timestamp() < tv) {
286  pop_oldest();
287  ++count;
288  }
289  return count;
290  }
291 #else
292  size_type pop_before(timestamp_type const &tv) {
296  if (empty()) {
297  return 0;
298  }
299  auto lastIt = nc_lower_bound(tv);
300  if (ncend() == lastIt) {
301  // If we got end() back, that's ambiguous: is the last entry
302  // really >= our timestamp?
304  if (is_strictly_newest(tv)) {
305  // It's not - lower_bound couldn't find anything.
306  return 0;
307  }
308  }
309  auto count = std::distance(ncbegin(), lastIt);
310  m_history.erase(ncbegin(), lastIt);
311  return count;
312  }
313 #endif
314 
315 #if 0
316 
320  size_type pop_after(timestamp_type const &tv) {
321  auto count = size_type{0};
322  while (!empty() && tv < newest_timestamp()) {
323  pop_newest();
324  ++count;
325  }
326  return count;
327  }
328 #else
329  size_type pop_after(timestamp_type const &tv) {
333  if (empty()) {
334  return 0;
335  }
336  auto firstIt = nc_upper_bound(tv);
337  if (ncend() == firstIt) {
338  // If we got end() back, nothing found after our timestamp.
339  return 0;
340  }
341  auto count = std::distance(firstIt, ncend());
342  m_history.erase(firstIt, ncend());
343  return count;
344  }
345 #endif
346 
351  value_type const &value) {
352  if (is_valid_to_push_newest(tv)) {
353  m_history.emplace_back(tv, value);
354  updateSizeHighWaterMark();
355  } else {
356  throw std::logic_error(
357  "Can't push_newest a value that's older "
358  "than the most recent value!");
359  }
360  }
361 
362  private:
363  void updateSizeHighWaterMark() {
364  m_sizeHighWaterMark =
365  (std::max)(m_history.size(), m_sizeHighWaterMark);
366  }
367  container_type m_history;
368  size_type m_sizeHighWaterMark = 0;
369  };
370  } // namespace history
371 
373 
374 } // namespace vbtracker
375 } // namespace osvr
376 #endif // INCLUDED_HistoryContainer_h_GUID_7CD22B1E_6EAC_49BF_F9FB_030C4BE3FA54
bool is_valid_to_push_newest(timestamp_type const &tv)
Returns true if the given timestamp meets the criteria of push_newest: strictly newest if AllowDuplic...
Definition: HistoryContainer.h:215
Comparison functor for std algorithms usage with HistoryContainer and related containers.
Definition: HistoryContainer.h:66
timestamp_type const & newest_timestamp() const
Returns the newest timestamp in the container.
Definition: HistoryContainer.h:156
Convenience class to refer to a subset of the range of history, primarily for use in range-for loops...
Definition: HistoryContainer.h:81
The main namespace for all C++ elements of the framework, internal and external.
Definition: namespace_osvr.dox:3
const_iterator lower_bound(timestamp_type const &tv) const
Wrapper around std::lower_bound: returns iterator to first element with timestamp equal or newer than...
Definition: HistoryContainer.h:228
Stores values over time, in chronological order, in a deque for two-ended access. ...
Definition: HistoryContainer.h:104
::OSVR_TimeValue TimeValue
C++-friendly typedef for the OSVR_TimeValue structure.
Definition: TimeValue.h:48
size_type size() const
Get number of entries in history.
Definition: HistoryContainer.h:125
A safe way to store and transport an orientation measurement or an angular velocity measurement witho...
Definition: CannedIMUMeasurement.h:44
Definition: newuoa.h:1888
void push_newest(osvr::util::time::TimeValue const &tv, value_type const &value)
Adds a new value to history.
Definition: HistoryContainer.h:350
Header providing a C++ wrapper around TimeValueC.h.
bool is_strictly_newest(timestamp_type const &tv) const
Returns true if the given timestamp is strictly newer than the newest timestamp in the container...
Definition: HistoryContainer.h:201
bool empty() const
Gets whether history is empty or not.
Definition: HistoryContainer.h:131
const_iterator upper_bound(timestamp_type const &tv) const
Wrapper around std::upper_bound: returns iterator to first element newer than timestamp given or end(...
Definition: HistoryContainer.h:222
bool is_as_new_as_newest(timestamp_type const &tv) const
Returns true if the given timestamp is no older than the newest timestamp in the container, or if the container is empty (thus making the timestamp trivially newest)
Definition: HistoryContainer.h:208
subset_range_type get_range_newer_than(timestamp_type const &tv) const
Returns a proxy object that can be treated as a range in a range-for loop to iterate over all element...
Definition: HistoryContainer.h:275
Standardized, portable parallel to struct timeval for representing both absolute times and time inter...
Definition: TimeValueC.h:81
size_type highWaterMark() const
Get the maximum number of entries ever recorded.
Definition: HistoryContainer.h:128
static comparator_type comparator()
Returns a comparison functor (comparing timestamps) for use with standard algorithms like lower_bound...
Definition: HistoryContainer.h:177
const_iterator closest_not_newer(timestamp_type const &tv) const
Return an iterator to the newest, last pair of timestamp and value that is not newer than the given t...
Definition: HistoryContainer.h:255
HistorySubsetRange(iterator begin_, iterator end_)
Definition: HistoryContainer.h:85