arg_router  1.4.0
C++ command line argument parsing and routing
dynamic_token_adapter.hpp
1 // Copyright (C) 2022-2023 by Camden Mannett.
2 // Distributed under the Boost Software License, Version 1.0.
3 // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt)
4 
5 #pragma once
6 
7 #include "arg_router/parsing/token_type.hpp"
8 
10 {
23 {
24 public:
28  using size_type = std::size_t;
29 
31  class iterator
32  {
33  public:
35  using difference_type = std::ptrdiff_t;
39  using pointer = const value_type*;
41  using reference = const value_type&;
43  using iterator_category = std::forward_iterator_tag;
44 
51  {
52  i_ += offset;
53  return *this;
54  }
55 
61  iterator& operator-=(difference_type offset) noexcept { return (*this += -offset); }
62 
69  [[nodiscard]] friend iterator operator+(iterator it, difference_type offset) noexcept
70  {
71  return it += offset;
72  }
73 
80  [[nodiscard]] friend iterator operator-(iterator it, difference_type offset) noexcept
81  {
82  return it -= offset;
83  }
84 
91  [[nodiscard]] friend iterator operator+(difference_type offset, iterator it) noexcept
92  {
93  return it += offset;
94  }
95 
102  [[nodiscard]] friend iterator operator-(difference_type offset, iterator it) noexcept
103  {
104  return it -= offset;
105  }
106 
115  [[nodiscard]] friend iterator operator-(iterator lhs, iterator rhs) noexcept
116  {
117  return {lhs.owner_, lhs.i_ - rhs.i_};
118  }
119 
127  [[nodiscard]] friend bool operator<(iterator lhs, iterator rhs) noexcept
128  {
129  return lhs.i_ < rhs.i_;
130  }
131 
140  [[nodiscard]] friend bool operator>(iterator lhs, iterator rhs) noexcept
141  {
142  return rhs < lhs;
143  }
144 
153  [[nodiscard]] friend bool operator<=(iterator lhs, iterator rhs) noexcept
154  {
155  return !(lhs > rhs);
156  }
157 
166  [[nodiscard]] friend bool operator>=(iterator lhs, iterator rhs) noexcept
167  {
168  return !(lhs < rhs);
169  }
170 
175  iterator& operator++() noexcept { return (*this += 1); }
176 
181  iterator operator++(int) noexcept
182  {
183  auto tmp = *this;
184  *this += 1;
185  return tmp;
186  }
187 
192  iterator& operator--() noexcept { return (*this -= 1); }
193 
198  iterator operator--(int) noexcept
199  {
200  auto tmp = *this;
201  *this -= 1;
202  return tmp;
203  }
204 
210  [[nodiscard]] reference operator*() const noexcept
211  {
212  if (i_ >= static_cast<difference_type>(processed().size())) {
213  const auto i = i_ - processed().size();
214  return unprocessed()[i];
215  }
216 
217  return processed()[i_];
218  }
219 
225  [[nodiscard]] pointer operator->() const noexcept { return &(*(*this)); }
226 
233  [[nodiscard]] reference operator[](difference_type offset) const noexcept
234  {
235  return *(*this + offset);
236  }
237 
245  [[nodiscard]] bool operator==(iterator other) const noexcept
246  {
247  const auto is_this_end = is_end();
248  const auto is_other_end = other.is_end();
249 
250  // Both end() iterators
251  if (is_this_end && is_other_end) {
252  return true;
253  }
254  if (is_this_end || is_other_end) {
255  return false;
256  }
257 
258  return (owner_ == other.owner_) && (i_ == other.i_);
259  }
260 
268  [[nodiscard]] bool operator!=(iterator other) const noexcept { return !(*this == other); }
269 
280  void set(value_type value)
281  {
282  owner_->transfer(*this);
283  processed()[i_] = value;
284  }
285 
286  private:
287  friend class dynamic_token_adapter;
288 
289  iterator() : owner_{nullptr}, i_{0} {}
290 
291  iterator(dynamic_token_adapter* owner, difference_type i) : owner_{owner}, i_{i} {}
292 
293  [[nodiscard]] bool is_end() const noexcept
294  {
295  return !owner_ || (i_ >= static_cast<difference_type>(owner_->size()));
296  }
297 
298  [[nodiscard]] vector<token_type>& processed() const { return *(owner_->processed_); }
299 
300  [[nodiscard]] vector<token_type>& unprocessed() const { return *(owner_->unprocessed_); }
301 
302  dynamic_token_adapter* owner_;
303  difference_type i_;
304  };
305 
312  processed_{&processed}, unprocessed_{&unprocessed}
313  {
314  // Perform a reserve for all the tokens. There is a resonable chance that more processed
315  // than unprocessed tokens will be needed (due to short-form expansion, value separation,
316  // etc.), but this should still dramatically reduce the number of allocations needed
317  unprocessed_->reserve(size());
318  }
319 
327  [[nodiscard]] bool operator==(dynamic_token_adapter other) const
328  {
329  return (processed_ == other.processed_) && (unprocessed_ == other.unprocessed_);
330  }
331 
339  [[nodiscard]] bool operator!=(dynamic_token_adapter other) const { return !(*this == other); }
340 
347  [[nodiscard]] iterator begin() { return {this, 0}; }
348 
353  // NOLINTNEXTLINE(readability-convert-member-functions-to-static)
354  [[nodiscard]] iterator end() { return {}; }
355 
360  [[nodiscard]] size_type size() const { return processed_->size() + unprocessed_->size(); }
361 
364  [[nodiscard]] bool empty() const { return processed_->empty() && unprocessed_->empty(); }
365 
370  [[nodiscard]] vector<value_type>& processed() { return *processed_; }
371 
376  [[nodiscard]] vector<value_type>& unprocessed() { return *unprocessed_; }
377 
386  {
387  // Only transfer up to the element before the target position, otherwise we transfer that
388  // and then insert the new value, which isn't expected
389  transfer(it - 1);
390  auto processed_it = it.is_end() ? processed_->end() : //
391  processed_->begin() + it.i_;
392 
393  processed_->insert(processed_it, value);
394  return {this, it.i_};
395  }
396 
404  template <typename Iter>
405  iterator insert(iterator it, Iter first, Iter last)
406  {
407  // Only transfer up to the element before the target position, otherwise we transfer that
408  // and then insert the new value, which isn't expected
409  transfer(it - 1);
410  auto processed_it = it.is_end() ? processed_->end() : //
411  processed_->begin() + it.i_;
412 
413  processed_->insert(processed_it, first, last);
414  return {this, it.i_};
415  }
416 
424  {
425  // If the iterator is an end(), it's a no-op
426  if (it.is_end()) {
427  return it;
428  }
429 
430  const auto processed_size = static_cast<iterator::difference_type>(processed_->size());
431  if (it.i_ < processed_size) {
432  processed_->erase(processed_->begin() + it.i_);
433  } else {
434  const auto offset = it.i_ - processed_size;
435  unprocessed_->erase(unprocessed_->begin() + offset);
436  }
437 
438  return it;
439  }
440 
448  {
449  // If the iterator is an end(), then consume all the unprocessed tokens
450  if (it.is_end()) {
451  it.i_ = size() - 1;
452  }
453 
454  if ((it.i_ < 0) || (it.i_ < static_cast<iterator::difference_type>(processed_->size()))) {
455  return;
456  }
457 
458  const auto count = (it.i_ + 1) - processed_->size();
459  processed_->insert(processed_->end(), unprocessed_->begin(), unprocessed_->begin() + count);
460  unprocessed_->erase(unprocessed_->begin(), unprocessed_->begin() + count);
461  }
462 
463 private:
464  vector<token_type>* processed_;
465  vector<token_type>* unprocessed_;
466 };
467 } // namespace arg_router::parsing
friend iterator operator+(difference_type offset, iterator it) noexcept
friend iterator operator-(iterator lhs, iterator rhs) noexcept
friend bool operator<=(iterator lhs, iterator rhs) noexcept
iterator & operator+=(difference_type offset) noexcept
reference operator[](difference_type offset) const noexcept
friend bool operator<(iterator lhs, iterator rhs) noexcept
iterator & operator-=(difference_type offset) noexcept
friend bool operator>=(iterator lhs, iterator rhs) noexcept
friend iterator operator-(difference_type offset, iterator it) noexcept
friend iterator operator+(iterator it, difference_type offset) noexcept
friend bool operator>(iterator lhs, iterator rhs) noexcept
friend iterator operator-(iterator it, difference_type offset) noexcept
dynamic_token_adapter(vector< token_type > &processed, vector< token_type > &unprocessed)
bool operator!=(dynamic_token_adapter other) const
iterator insert(iterator it, value_type value)
bool operator==(dynamic_token_adapter other) const
iterator insert(iterator it, Iter first, Iter last)
std::vector< T, config::allocator< T > > vector
Definition: basic_types.hpp:39