Fileseq C++ API
A library for parsing file sequence strings commonly used in VFX and animation applications.
ranges.h
1 #ifndef FILESEQ_RANGES_P_H_
2 #define FILESEQ_RANGES_P_H_
3 
4 #include <algorithm>
5 #include <ostream>
6 #include <string>
7 #include <vector>
8 
9 namespace fileseq {
10 
11 // Fwd Decl
12 class Range;
13 class Ranges;
14 class Status;
15 
16 
17 // tracks the iteration state across an Range instance
19 
20 public:
21  explicit RangeIterator( const Range* range=NULL );
22 
23  // Reset the iterator with a new Range.
24  void reset( const Range* range );
25 
26  // Dereference current value.
27  long operator*();
28 
29  // Returns if the iterator has exhausted all
30  // values, without consuming another value like
31  // a call to next()
32  bool isDone();
33 
34  // Advance to the next value.
35  bool next();
36 
37  // Returns whether the iterator points to a valid range
38  bool isValid() const { return m_range != NULL; }
39 
40 private:
41  const Range* m_range;
42  ssize_t m_index;
43 };
44 
45 
46 class Range {
47 
48 public:
49 
50  // Range represents a start and end
51  // value, and a stepping amount between each
52  // value in the range. The range includes the end value.
53  // It dynamically acts like a slice of values
54  // in an integer range, without needing to store
55  // the discreet values. So it can represent very
56  // large ranges.
57  //
58  // If step value == 0, it will automatically default
59  // to a propert increment depending on whether start is
60  // less than or greather than end.
61  Range(long start, long end, long step=0);
62 
63  virtual ~Range() {}
64 
65  // returns the number of values in the range
66  size_t length() const;
67 
68  // returns the start of the range
69  long start() const { return m_start; }
70 
71  // returns the end of the range. This value may
72  // be different from the end value given when the
73  // range was first initialized, since it takes into
74  // account the stepping value. The end value may be
75  // shifted to the closest valid value within the
76  // stepped range.
77  long end() const;
78 
79  // returns the stepping value used in the range
80  long step() const { return m_step; }
81 
82  // returns the smallest value in the range
83  long min() const { return (start() < end() ? start() : end()); }
84 
85  // returns the highest value in the range
86  long max() const { return (start() > end() ? start() : end()); }
87 
88  // returns true if the given value is a valid
89  // value within the value range.
90  bool contains(long value) const;
91 
92  // returns the value at the given index in
93  // the range. If the index is invalid/exceeds the valid
94  // range, and a Status pointer is given, it will be filled
95  // with the error state.
96  long value(size_t idx, Status* ok=NULL) const;
97 
98  // returns the 0-based index of the first occurrence
99  // given value, within the range.
100  // If the value does not exist in the range, -1 will
101  // be returned
102  ssize_t index(long value) const;
103 
104  // returns an iterator that will loop through
105  // every value in the range.
106  // Call to RangeIterator.next() populates first
107  // value and returns whether there are more values available.
108  RangeIterator iterValues() const { return RangeIterator(this); }
109 
110  // The string representation of the range
111  std::string string() const;
112 
113  operator std::string() const { return string(); }
114 
115  friend std::ostream& operator<< (std::ostream& stream, const Range& fs) {
116  stream << fs.string();
117  return stream;
118  };
119 
120 protected:
121 
122  // closestInRange finds the closest valid value within the range,
123  // to a given value. Values outside the range are clipped to either
124  // the range min or max.
125  long closestInRange(long value, long start, long end, long step=0) const;
126 
127 private:
128  long m_start;
129  long m_end;
130  long m_step;
131 
132  mutable long m_cachedEnd;
133  mutable bool m_isEndCached;
134 
135  mutable size_t m_cachedSize;
136  mutable bool m_isSizeCached;
137 };
138 
139 
140 // tracks the iteration state across an Ranges instance
142 
143 public:
144  explicit RangesIterator( const Ranges* ranges=NULL );
145 
146  // Reset the iterator with a new Ranges.
147  void reset( const Ranges* ranges );
148 
149  // Dereference current value.
150  long operator*();
151 
152  // Returns if the iterator has exhausted all
153  // values, without consuming another value like
154  // a call to next()
155  bool isDone();
156 
157  // Advance to the next value and return whether
158  // a value is available
159  bool next();
160 
161  // Returns whether the interator points to a valid range
162  bool isValid() const { return m_ranges != NULL; }
163 
164 private:
165  bool ready();
166 
167  const Ranges* m_ranges;
168  RangeIterator m_current;
169  size_t m_index;
170 };
171 
172 
173 // Ranges is able to represent multiple non-contiguous
174 // Range pointers, with non-uniform stepping, ie. 1-10,20-30x2,100,120
175 // Because range values are evaluated dynamically as
176 // offsets within the start/stop, they can represent
177 // very large ranges.
178 class Ranges {
179 
180 public:
181  Ranges() : m_blocks() {}
182 
183  ~Ranges();
184 
185  // Copy constructor
186  Ranges(const Ranges& rhs);
187 
188  // Assignment
189  Ranges& operator=(Ranges rhs) {
190  swap(*this, rhs);
191  return *this;
192  }
193 
194  // Swap functionality
195  friend void swap(Ranges &first, Ranges &second) {
196  using std::swap;
197 
198  swap(first.m_blocks, second.m_blocks);
199  }
200 
201  // returns the formatted representation of
202  // the combination of all internal InclusiveRange instances
203  std::string string() const;
204 
205  // returns the total number of values across all ranges
206  size_t length() const;
207 
208  // returns the first value of the first range
209  long start() const;
210 
211  // returns the last value of the last range
212  long end() const;
213 
214  // returns the smallest value in the total range
215  long min() const;
216 
217  // returns the highest value in the total range
218  long max() const;
219 
220  // creates and adds another range of values
221  // to the total range list.
222  // Values in new range may duplicate values in
223  // existing ranges.
224  void append(long start, long end, long step=0) {
225  m_blocks.push_back(new Range(start, end, step));
226  }
227 
228  // creates and adds another range of values
229  // to the total range list. Only unique values from the
230  // given range are appended to the total range.
231  void appendUnique(long start, long end, long step=0);
232 
233  // returns true if a given value is a valid
234  // value within the total range.
235  bool contains(long value) const;
236 
237  // returns the value at the given index in
238  // the total range. If the index is invalid/exceeds the valid
239  // range, an error will be returned.
240  long value(size_t idx, Status* ok=NULL) const;
241 
242  // returns the 0-based index of the first occurrence
243  // of the given value, within the range.
244  // If the value does not exist in the range, a
245  // value of -1 will be returned.
246  ssize_t index(long value) const;
247 
248  // returns an iterator that will loop through
249  // every value in the range.
250  // Call to RangesIterator.next() populates first
251  // value and returns whether there are more values available.
252  RangesIterator iterValues() const { return RangesIterator(this); }
253 
254  // fills a new instance with a range containing
255  // all values within the start/end that are not in the current range.
256  // Original ordering is not preserved. New inverted range will be
257  // in an increasing value.
258  void inverted(Ranges &out) const { normalized(out, true); }
259 
260  // fills a new instance, where all values have
261  // been sorted and compacted (where possible)
262  void normalized(Ranges &out) const { normalized(out, false); }
263 
264 private:
265  friend class RangesIterator;
266 
267  // fills a new instance, where all values have
268  // been sorted and compacted (where possible).
269  // If invert is true, then return all values within the start/end that
270  // are not in the current range.
271  void normalized(Ranges &outRanges, bool invert) const;
272 
273  // rangeAt returns the underlying InclusiveRange instance
274  // that was appended, at a given index
275  const Range* rangeAt(size_t idx) const {
276  return (idx >= m_blocks.size()) ? NULL : m_blocks[idx];
277  }
278 
279  typedef std::vector<Range*> Blocks;
280  Blocks m_blocks;
281 
282 };
283 
284 } // fileseq
285 
286 #endif // FILESEQ_RANGES_P_H_
Definition: ranges.h:18
Definition: ranges.h:46
Definition: ranges.h:141
Definition: ranges.h:178
Definition: error.h:31