Vince's CSV Parser
Loading...
Searching...
No Matches
checked_field_range.hpp
1#pragma once
2
3#include <cstddef>
4#include <iterator>
5#include <type_traits>
6#include <utility>
7
8#include "common.hpp"
9#include "csv_exceptions.hpp"
10
11namespace csv {
12namespace internals {
13 // Keep the field itself alive through conversion: a DataFrameCell may
14 // own an edited string, so a view into a temporary cell would dangle.
15 template<typename Field>
17 public:
18 template<typename Row>
19 CheckedFieldValue(Row& row, size_t index, CSVError& error)
20 : field_(row.try_field(index, error)), error_(&error) {}
21
22 template<typename Consumer>
23 void with_view(Consumer&& consumer) const {
24 // A failed try_field() need not return a readable field. Consume
25 // immediately so even an owning get_sv() result outlives the call.
26 if (!*error_) std::forward<Consumer>(consumer)(field_.get_sv());
27 }
28
29 private:
30 Field field_;
31 const CSVError* error_;
32 };
33
38 template<typename Row>
40 using field_type = typename std::decay<decltype(std::declval<Row&>()
41 .try_field(size_t{0}, std::declval<CSVError&>()))>::type;
42
43 public:
45
46 class iterator {
47 public:
48 using iterator_category = std::input_iterator_tag;
49 using value_type = field_value;
50 using difference_type = std::ptrdiff_t;
51 using reference = field_value;
52 using pointer = void;
53
54 iterator() = default;
55 iterator(const CheckedFieldRange* owner, size_t index)
56 : owner_(owner), index_(index) {}
57
58 field_value operator*() const {
59 return field_value(*owner_->row_, index_, *owner_->error_);
60 }
61
62 iterator& operator++() {
63 if (!owner_->failed()) ++index_;
64 return *this;
65 }
66
67 iterator operator++(int) {
68 iterator previous = *this;
69 ++*this;
70 return previous;
71 }
72
73 bool operator==(const iterator& other) const {
74 return owner_ == other.owner_
75 && (index_ == other.index_ || (owner_ && owner_->failed()));
76 }
77
78 bool operator!=(const iterator& other) const { return !(*this == other); }
79
80 private:
81 const CheckedFieldRange* owner_ = nullptr;
82 size_t index_ = 0;
83 };
84
85 CheckedFieldRange(Row& row, CSVError& error)
86 : row_(&row), error_(&error) {
87 if (error) return;
88 // Validate even zero-width proxies, before asking for their size.
89 if (!record_valid(row, 0)) {
90 fail_static(error, CSVErrorCode::InvalidProxy, "CSV row or column proxy is invalid.");
91 return;
92 }
93 size_ = row.size();
94 }
95
96 iterator begin() const { return iterator(this, 0); }
97 iterator end() const { return iterator(this, size_); }
98
99 private:
100 template<typename T>
101 static auto record_valid(const T& row, int) -> decltype(row.is_valid(), bool()) {
102 return row.is_valid();
103 }
104
105 template<typename T>
106 static bool record_valid(const T&, long) { return true; }
107
108 bool failed() const { return static_cast<bool>(*error_); }
109
110 Row* row_;
111 CSVError* error_;
112 size_t size_ = 0;
113 };
114
115 template<typename Row>
116 CheckedFieldRange<Row> checked_field_range(Row& row, CSVError& error) {
117 return CheckedFieldRange<Row>(row, error);
118 }
119}
120}
Borrow a row and error state for synchronous, single-pass field access.
A standalone header file containing shared code.
Shared exception message templates and throw helpers.
The all encompassing namespace.
@ InvalidProxy
A proxy is unbound or a column proxy was invalidated by structural mutation.
A diagnostic whose text remains valid for the lifetime of the error.
Definition csv_error.hpp:94