HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
timeCodeRange.h
Go to the documentation of this file.
1 //
2 // Copyright 2019 Pixar
3 //
4 // Licensed under the terms set forth in the LICENSE.txt file available at
5 // https://openusd.org/license.
6 //
7 #ifndef PXR_USD_USD_UTILS_TIME_CODE_RANGE_H
8 #define PXR_USD_USD_UTILS_TIME_CODE_RANGE_H
9 
10 /// \file usdUtils/timeCodeRange.h
11 
12 #include "pxr/pxr.h"
13 #include "pxr/usd/usdUtils/api.h"
14 
15 #include "pxr/base/gf/math.h"
16 #include "pxr/base/tf/diagnostic.h"
18 #include "pxr/usd/usd/timeCode.h"
19 
20 #include <iosfwd>
21 #include <iterator>
22 #include <string>
23 
24 
26 
27 
28 #define USDUTILS_TIME_CODE_RANGE_TOKENS \
29  ((EmptyTimeCodeRange, "NONE")) \
30  ((RangeSeparator, ":")) \
31  ((StrideSeparator, "x"))
32 
34  UsdUtilsTimeCodeRangeTokens,
37 
38 
39 /// \class UsdUtilsTimeCodeRange
40 ///
41 /// Represents a range of UsdTimeCode values as start and end time codes and a
42 /// stride value.
43 ///
44 /// A UsdUtilsTimeCodeRange can be iterated to retrieve all time code values in
45 /// the range. The range may be empty, it may contain a single time code, or it
46 /// may represent multiple time codes from start to end. The interval defined
47 /// by the start and end time codes is closed on both ends.
48 ///
49 /// Note that when constructing a UsdUtilsTimeCodeRange,
50 /// UsdTimeCode::EarliestTime() and UsdTimeCode::Default() cannot be used as
51 /// the start or end time codes. Also, the end time code cannot be less than
52 /// the start time code for positive stride values, and the end time code
53 /// cannot be greater than the start time code for negative stride values.
54 /// Finally, the stride value cannot be zero. If any of these conditions are
55 /// not satisfied, then an invalid empty range will be returned.
57 {
58 public:
59 
60  /// \class const_iterator
61  ///
62  /// A forward iterator into a UsdUtilsTimeCodeRange.
64  {
65  public:
66  using iterator_category = std::forward_iterator_tag;
68  using reference = const UsdTimeCode&;
69  using pointer = const UsdTimeCode*;
70  using difference_type = std::ptrdiff_t;
71 
72  /// Returns the UsdTimeCode referenced by this iterator.
74  return _currTimeCode;
75  }
76 
77  /// Returns a pointer to the UsdTimeCode referenced by this iterator.
79  return &_currTimeCode;
80  }
81 
82  /// Pre-increment operator. Advances this iterator to the next
83  /// UsdTimeCode in the range.
84  ///
85  /// This iterator is returned.
87  if (_timeCodeRange) {
88  ++_currStep;
89  _currTimeCode =
91  _timeCodeRange->_startTimeCode.GetValue() +
92  _timeCodeRange->_stride * _currStep);
93  }
94  _InvalidateIfExhausted();
95  return *this;
96  }
97 
98  /// Post-increment operator. Advances this iterator to the next
99  /// UsdTimeCode in the range.
100  ///
101  /// A copy of this iterator prior to the increment is returned.
103  const_iterator preAdvanceIter = *this;
104  ++(*this);
105  return preAdvanceIter;
106  }
107 
108  /// Return true if this iterator is equivalent to \p other.
109  bool operator ==(const const_iterator& other) const {
110  return _timeCodeRange == other._timeCodeRange &&
111  _currStep == other._currStep;
112  }
113 
114  /// Return true if this iterator is not equivalent to \p other.
115  bool operator !=(const const_iterator& other) const {
116  return !(*this == other);
117  }
118 
119  private:
120  friend class UsdUtilsTimeCodeRange;
121 
122  const_iterator(const UsdUtilsTimeCodeRange* timeCodeRange) :
123  _timeCodeRange(timeCodeRange),
124  _currStep(0u),
125  _maxSteps(0u),
126  _currTimeCode()
127  {
128  if (_timeCodeRange) {
129  const double startVal = _timeCodeRange->_startTimeCode.GetValue();
130  const double endVal = _timeCodeRange->_endTimeCode.GetValue();
131  const double stride = _timeCodeRange->_stride;
132 
133  _maxSteps = static_cast<size_t>(
134  GfFloor((endVal - startVal + stride) / stride));
135  _currTimeCode = _timeCodeRange->_startTimeCode;
136  }
137 
138  _InvalidateIfExhausted();
139  }
140 
141  void _InvalidateIfExhausted() {
142  bool finished = false;
143  if (!_timeCodeRange) {
144  finished = true;
145  } else if (_currStep >= _maxSteps) {
146  finished = true;
147  }
148 
149  if (finished) {
150  _timeCodeRange = nullptr;
151  _currStep = 0u;
152  _maxSteps = 0u;
153  _currTimeCode = UsdTimeCode();
154  }
155  }
156 
157  const UsdUtilsTimeCodeRange* _timeCodeRange;
158  size_t _currStep;
159  size_t _maxSteps;
160  UsdTimeCode _currTimeCode;
161  };
162 
164 
165  /// Create a time code range from \p frameSpec.
166  ///
167  /// A FrameSpec is a compact string representation of a time code range.
168  /// A FrameSpec may contain up to three floating point values for the start
169  /// time code, end time code, and stride values of a time code range.
170  ///
171  /// A FrameSpec containing just a single floating point value represents
172  /// a time code range containing only that time code.
173  ///
174  /// A FrameSpec containing two floating point values separated by the range
175  /// separator (':') represents a time code range from the first value as
176  /// the start time code to the second values as the end time code.
177  ///
178  /// A FrameSpec that specifies both a start and end time code value may
179  /// also optionally specify a third floating point value as the stride,
180  /// separating it from the first two values using the stride separator
181  /// ('x').
182  ///
183  /// The following are examples of valid FrameSpecs:
184  /// 123
185  /// 101:105
186  /// 105:101
187  /// 101:109x2
188  /// 101:110x2
189  /// 101:104x0.5
190  ///
191  /// An empty string corresponds to an invalid empty time code range.
192  ///
193  /// A coding error will be issued if the given string is malformed.
196  const std::string& frameSpec);
197 
198  /// Construct an invalid empty range.
199  ///
200  /// The start time code will be initialized to zero, and any iteration of
201  /// the range will yield no time codes.
203  {
204  _Invalidate();
205  }
206 
207  /// Construct a range containing only the given \p timeCode.
208  ///
209  /// An iteration of the range will yield only that time code.
211  UsdUtilsTimeCodeRange(timeCode, timeCode)
212  {
213  }
214 
215  /// Construct a range containing the time codes from \p startTimeCode to
216  /// \p endTimeCode.
217  ///
218  /// If \p endTimeCode is greater than or equal to \p startTimeCode, then
219  /// the stride will be 1.0. Otherwise, the stride will be -1.0.
221  const UsdTimeCode startTimeCode,
222  const UsdTimeCode endTimeCode) :
224  startTimeCode,
225  endTimeCode,
226  (endTimeCode >= startTimeCode) ? 1.0 : -1.0)
227  {
228  }
229 
230  /// Construct a range containing the time codes from \p startTimeCode to
231  /// \p endTimeCode using the stride value \p stride.
232  ///
233  /// UsdTimeCode::EarliestTime() and UsdTimeCode::Default() cannot be used
234  /// as \p startTimeCode or \p endTimeCode. If \p stride is a positive
235  /// value, then \p endTimeCode cannot be less than \p startTimeCode. If
236  /// \p stride is a negative value, then \p endTimeCode cannot be greater
237  /// than \p startTimeCode. Finally, the stride value cannot be zero. If any
238  /// of these conditions are not satisfied, then a coding error will be
239  /// issued and an invalid empty range will be returned.
241  const UsdTimeCode startTimeCode,
242  const UsdTimeCode endTimeCode,
243  const double stride) :
244  _startTimeCode(startTimeCode),
245  _endTimeCode(endTimeCode),
246  _stride(stride)
247  {
248  if (_startTimeCode.IsEarliestTime()) {
250  "startTimeCode cannot be UsdTimeCode::EarliestTime()");
251  _Invalidate();
252  return;
253  }
254  if (_startTimeCode.IsDefault()) {
256  "startTimeCode cannot be UsdTimeCode::Default()");
257  _Invalidate();
258  return;
259  }
260  if (_endTimeCode.IsEarliestTime()) {
262  "endTimeCode cannot be UsdTimeCode::EarliestTime()");
263  _Invalidate();
264  return;
265  }
266  if (_endTimeCode.IsDefault()) {
268  "endTimeCode cannot be UsdTimeCode::Default()");
269  _Invalidate();
270  return;
271  }
272 
273  if (_stride > 0.0) {
274  if (_endTimeCode < _startTimeCode) {
276  "endTimeCode cannot be less than startTimeCode with "
277  "positive stride");
278  _Invalidate();
279  return;
280  }
281  } else if (_stride < 0.0) {
282  if (_endTimeCode > _startTimeCode) {
284  "endTimeCode cannot be greater than startTimeCode with "
285  "negative stride");
286  _Invalidate();
287  return;
288  }
289  } else {
290  TF_CODING_ERROR("stride cannot be zero");
291  _Invalidate();
292  return;
293  }
294  }
295 
296  /// Return the start time code of this range.
298  return _startTimeCode;
299  }
300 
301  /// Return the end time code of this range.
303  return _endTimeCode;
304  }
305 
306  /// Return the stride value of this range.
307  double GetStride() const {
308  return _stride;
309  }
310 
311  /// Return an iterator to the start of this range.
312  iterator begin() const {
313  return iterator(this);
314  }
315 
316  /// Return a const_iterator to the start of this range.
318  return const_iterator(this);
319  }
320 
321  /// Return the past-the-end iterator for this range.
322  iterator end() const {
323  return iterator(nullptr);
324  }
325 
326  /// Return the past-the-end const_iterator for this range.
328  return const_iterator(nullptr);
329  }
330 
331  /// Return true if this range contains no time codes, or false otherwise.
332  bool empty() const {
333  return begin() == end();
334  }
335 
336  /// Return true if this range contains one or more time codes, or false
337  /// otherwise.
338  bool IsValid() const {
339  return !empty();
340  }
341 
342  /// Return true if this range contains one or more time codes, or false
343  /// otherwise.
344  explicit operator bool() const {
345  return IsValid();
346  }
347 
348  /// Return true if this range is equivalent to \p other.
349  bool operator ==(const UsdUtilsTimeCodeRange& other) const {
350  return _startTimeCode == other._startTimeCode &&
351  _endTimeCode == other._endTimeCode &&
352  _stride == other._stride;
353  }
354 
355  /// Return true if this range is not equivalent to \p other.
356  bool operator !=(const UsdUtilsTimeCodeRange& other) const {
357  return !(*this == other);
358  }
359 
360 private:
361 
362  /// Sets the range such that it yields no time codes.
363  void _Invalidate() {
364  _startTimeCode = UsdTimeCode(0.0);
365  _endTimeCode = UsdTimeCode(-1.0);
366  _stride = 1.0;
367  }
368 
369  UsdTimeCode _startTimeCode;
370  UsdTimeCode _endTimeCode;
371  double _stride;
372 };
373 
374 // Stream I/O operators.
375 
376 /// Stream insertion operator.
378 std::ostream& operator<<(
379  std::ostream& os,
380  const UsdUtilsTimeCodeRange& timeCodeRange);
381 
382 /// Stream extraction operator.
384 std::istream& operator>>(
385  std::istream& is,
386  UsdUtilsTimeCodeRange& timeCodeRange);
387 
388 
390 
391 
392 #endif
UsdUtilsTimeCodeRange(const UsdTimeCode timeCode)
double GetValue() const
Definition: timeCode.h:157
reference operator*()
Returns the UsdTimeCode referenced by this iterator.
Definition: timeCodeRange.h:73
bool operator==(const UsdUtilsTimeCodeRange &other) const
Return true if this range is equivalent to other.
#define TF_CODING_ERROR
UsdTimeCode GetEndTimeCode() const
Return the end time code of this range.
iterator begin() const
Return an iterator to the start of this range.
static USDUTILS_API UsdUtilsTimeCodeRange CreateFromFrameSpec(const std::string &frameSpec)
bool IsEarliestTime() const
Definition: timeCode.h:139
UsdUtilsTimeCodeRange(const UsdTimeCode startTimeCode, const UsdTimeCode endTimeCode)
const_iterator cbegin() const
Return a const_iterator to the start of this range.
OutGridT const XformOp bool bool
iterator end() const
Return the past-the-end iterator for this range.
pointer operator->()
Returns a pointer to the UsdTimeCode referenced by this iterator.
Definition: timeCodeRange.h:78
bool operator!=(const UsdUtilsTimeCodeRange &other) const
Return true if this range is not equivalent to other.
UsdUtilsTimeCodeRange(const UsdTimeCode startTimeCode, const UsdTimeCode endTimeCode, const double stride)
bool IsDefault() const
Definition: timeCode.h:145
GLint GLenum GLboolean GLsizei stride
Definition: glcorearb.h:872
#define USDUTILS_TIME_CODE_RANGE_TOKENS
Definition: timeCodeRange.h:28
const_iterator cend() const
Return the past-the-end const_iterator for this range.
bool empty() const
Return true if this range contains no time codes, or false otherwise.
bool operator==(const const_iterator &other) const
Return true if this iterator is equivalent to other.
TF_DECLARE_PUBLIC_TOKENS(UsdUtilsTimeCodeRangeTokens, USDUTILS_API, USDUTILS_TIME_CODE_RANGE_TOKENS)
USDUTILS_API std::istream & operator>>(std::istream &is, UsdUtilsTimeCodeRange &timeCodeRange)
Stream extraction operator.
double GfFloor(double f)
Definition: math.h:208
bool operator!=(const const_iterator &other) const
Return true if this iterator is not equivalent to other.
PXR_NAMESPACE_CLOSE_SCOPE PXR_NAMESPACE_OPEN_SCOPE
Definition: path.h:1425
const_iterator iterator
std::forward_iterator_tag iterator_category
Definition: timeCodeRange.h:66
bool IsValid() const
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74
UsdTimeCode GetStartTimeCode() const
Return the start time code of this range.
#define USDUTILS_API
Definition: api.h:23
USDUTILS_API std::ostream & operator<<(std::ostream &os, const UsdUtilsTimeCodeRange &timeCodeRange)
Stream insertion operator.
double GetStride() const
Return the stride value of this range.