summaryrefslogtreecommitdiff
path: root/sax/inc/sax_attributes.hh
blob: 4ab1a44846f2d034600cfd9888f52383e2b9b80f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#ifndef SAX_ATTRIBUTES_HH
#define SAX_ATTRIBUTES_HH

#include <iterator>
#include <optional>
#include <string_view>

namespace modxml {
namespace sax {

struct Attribute {
  std::string_view name;
  std::string_view value;

  Attribute(std::string_view name, std::string_view value);
};

/**
 * A view of attributes, with utility functions.
 */
class Attributes {
 public:
  virtual ~Attributes() = default;

  class iterator {
   public:
    using iterator_category = std::random_access_iterator_tag;
    using difference_type = std::ptrdiff_t;
    using element_type = Attribute;
    using pointer = element_type const *;
    using reference = element_type const &;

    iterator()
        : attributes_(nullptr), index_(0) {}
    iterator(iterator const& it)
        : attributes_(it.attributes_), index_(it.index_) {}
    iterator& operator=(iterator const& it) {
      attributes_ = it.attributes_;
      index_ = it.index_;
      return *this;
    }

    /**
     * Comparing two iterators from different Attributes instances is undefined.
     */
    bool operator==(iterator const& it) const {
      return index_ == it.index_;
    }
    std::strong_ordering operator<=>(iterator const& it) const {
      return index_ <=> it.index_;
    }

    pointer operator->() const { return &attributes_->at(index_); }
    reference operator*() const { return attributes_->at(index_); }
    reference operator[](difference_type i) const {
      return attributes_->at(index_ + i);
    }

    iterator& operator++() {
      ++index_;
      return *this;
    }
    iterator operator++(int) {
      auto ret = *this;
      ++index_;
      return ret;
    }
    iterator& operator+=(difference_type i) {
      index_ += i;
      return *this;
    }
    iterator operator+(difference_type i) const {
      return iterator(attributes_, index_ + i);
    }
    friend iterator operator+(difference_type i, iterator const &it) {
      return iterator(it.attributes_, it.index_ + i);
    }
    iterator& operator--() {
      --index_;
      return *this;
    }
    iterator operator--(int) {
      auto ret = *this;
      --index_;
      return ret;
    }
    iterator& operator-=(difference_type i) {
      index_ -= i;
      return *this;
    }
    difference_type operator-(iterator const& it) const {
      return index_ - it.index_;
    }
    iterator operator-(difference_type i) const {
      return iterator(attributes_, index_ - i);
    }

   protected:
    iterator(Attributes const* attributes, std::size_t index)
        : attributes_(attributes), index_(index) {}

   private:
    Attributes const* attributes_;
    std::size_t index_;
  };

  static_assert(std::random_access_iterator<iterator>);

  virtual iterator begin() const = 0;
  virtual iterator end() const = 0;

  virtual std::size_t size() const = 0;
  /**
   * name and value of attribute are valid as long as Attributes instance is.
   */
  virtual Attribute const& at(std::size_t index) const = 0;

  Attribute const& operator[](std::size_t index) const { return at(index); }

  /**
   * Return the first attribute with name, if any.
   */
  virtual std::optional<std::string_view> find_first(
      std::string_view name) const;

  /**
   * Return the last attribute with name, if any.
   */
  virtual std::optional<std::string_view> find_last(
      std::string_view name) const;

  /**
   * Return the index of the attribute with name, starting with offset.
   */
  virtual std::optional<std::size_t> find(std::string_view name,
                                          std::size_t index = 0) const;

 protected:
  Attributes() = default;
};

}  // namespace sax
}  // namespace modxml


#endif  // SAX_ATTRIBUTES_HH