summaryrefslogtreecommitdiff
path: root/sax/inc/sax_attributes.hh
diff options
context:
space:
mode:
Diffstat (limited to 'sax/inc/sax_attributes.hh')
-rw-r--r--sax/inc/sax_attributes.hh146
1 files changed, 146 insertions, 0 deletions
diff --git a/sax/inc/sax_attributes.hh b/sax/inc/sax_attributes.hh
new file mode 100644
index 0000000..4ab1a44
--- /dev/null
+++ b/sax/inc/sax_attributes.hh
@@ -0,0 +1,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