GridFormat 0.4.0
I/O-Library for grid-like data structures
Loading...
Searching...
No Matches
appendix.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2022-2023 Dennis Gläser <dennis.glaeser@iws.uni-stuttgart.de>
2// SPDX-License-Identifier: MIT
8#ifndef GRIDFORMAT_VTK_APPENDIX_HPP_
9#define GRIDFORMAT_VTK_APPENDIX_HPP_
10
11#include <concepts>
12#include <utility>
13#include <ostream>
14#include <string>
15#include <vector>
16#include <memory>
17#include <limits>
18#include <type_traits>
19
20#include <gridformat/common/concepts.hpp>
21#include <gridformat/common/indentation.hpp>
22#include <gridformat/xml/element.hpp>
26
27namespace GridFormat::VTK {
28
36 public:
37 void register_offset(std::size_t offset) {
38 _offsets.push_back(offset);
39 }
40
41 const std::vector<std::size_t>& offsets() const {
42 return _offsets;
43 }
44
45 private:
46 std::vector<std::size_t> _offsets;
47};
48
53class Appendix {
54 struct DataArrayModel {
55 virtual ~DataArrayModel() = default;
56
57 DataArrayModel() = default;
58 DataArrayModel(DataArrayModel&&) = default;
59 DataArrayModel(const DataArrayModel&) = delete;
60 DataArrayModel& operator=(DataArrayModel&&) = default;
61 DataArrayModel& operator=(const DataArrayModel&) = delete;
62
63 friend std::ostream& operator<<(std::ostream& s, const DataArrayModel& arr) {
64 arr.stream(s);
65 return s;
66 }
67
68 private:
69 virtual void stream(std::ostream& s) const = 0;
70 };
71
72 template<Concepts::StreamableWith<std::ostream> DataArray>
73 class DataArrayImpl : public DataArrayModel {
74 public:
75 explicit DataArrayImpl(DataArray&& arr)
76 : _data_array(std::move(arr))
77 {}
78
79 private:
80 DataArray _data_array;
81
82 void stream(std::ostream& s) const override {
83 s << _data_array;
84 }
85 };
86
87 public:
88 template<typename... Args>
89 void add(DataArray<Args...>&& data_array) {
90 _emplace_back(DataArrayImpl{std::move(data_array)});
91 }
92
93 friend std::ostream& operator<<(std::ostream& s, const Appendix& app) {
94 const auto start_pos = s.tellp();
95 for (const auto& array_ptr : app._content) {
96 const auto pos_before = s.tellp();
97 s << *array_ptr;
98 if (app._observer)
99 app._observer->register_offset(pos_before - start_pos);
100 }
101 return s;
102 }
103
104 void set_observer(AppendixStreamObserver* observer) {
105 _observer = observer;
106 }
107
108 private:
109 template<typename DA>
110 void _emplace_back(DataArrayImpl<DA>&& impl) {
111 _content.emplace_back(
112 std::make_unique<DataArrayImpl<DA>>(std::move(impl))
113 );
114 }
115
116 std::vector<std::unique_ptr<const DataArrayModel>> _content;
117 AppendixStreamObserver* _observer{nullptr};
118};
119
120
121#ifndef DOXYGEN
122namespace XML::Detail {
123
124 struct XMLAppendixContent {
125 const Appendix& appendix;
126
127 friend std::ostream& operator<<(std::ostream& s, const XMLAppendixContent& c) {
128 s << " _"; // prefix required by vtk
129 s << c.appendix;
130 s << "\n"; // newline such that closing xml element is easily visible
131 return s;
132 }
133 };
134
135 void write_xml_element_with_offsets(const XMLElement& e,
136 std::ostream& s,
137 Indentation& ind,
138 std::vector<std::size_t>& offset_positions) {
139 const std::string empty_string_for_max_header(
140 std::to_string(std::numeric_limits<std::size_t>::max()).size(),
141 ' '
142 );
143
144 const auto cache_offset_xml_pos = [&] () {
145 s << " offset=\"";
146 offset_positions.push_back(s.tellp());
147 s << empty_string_for_max_header;
148 s << "\"";
149 };
150
151 if (!e.has_content() && e.number_of_children() == 0) {
152 s << ind;
153 GridFormat::XML::Detail::write_xml_tag_open(e, s, "");
154 if (e.name() == "DataArray")
155 cache_offset_xml_pos();
156 s << "/>";
157 } else {
158 s << ind;
159 GridFormat::XML::Detail::write_xml_tag_open(e, s);
160 if (e.name() == "DataArray")
161 cache_offset_xml_pos();
162 s << "\n";
163
164 if (e.has_content()) {
165 e.stream_content(s);
166 s << "\n";
167 }
168
169 ++ind;
170 for (const auto& c : children(e)) {
171 write_xml_element_with_offsets(c, s, ind, offset_positions);
172 s << "\n";
173 }
174 --ind;
175
176 s << ind;
177 GridFormat::XML::Detail::write_xml_tag_close(e, s);
178 }
179 }
180
181 std::vector<std::size_t> write_xml_element_with_offsets(const XMLElement& e,
182 std::ostream& s,
183 Indentation& ind) {
184 std::vector<std::size_t> offset_positions;
185 write_xml_element_with_offsets(e, s, ind, offset_positions);
186 return offset_positions;
187 }
188
189 template<typename Context, typename Encoder>
190 requires(!std::is_const_v<std::remove_reference_t<Context>>)
191 inline void write_with_appendix(Context&& context,
192 std::ostream& s,
193 const Encoder& encoder,
194 Indentation indentation = {}) {
195 if (produces_valid_xml(encoder))
196 s << "<?xml version=\"1.0\"?>\n";
197
198 AppendixStreamObserver observer;
199 context.appendix.set_observer(&observer);
200
201 auto& app_element = context.xml_representation.add_child("AppendedData");
202 app_element.set_attribute("encoding", attribute_name(encoder));
203 app_element.set_content(Detail::XMLAppendixContent{context.appendix});
204
205 const auto offset_positions = write_xml_element_with_offsets(
206 context.xml_representation, s, indentation
207 );
208 const auto& offsets = observer.offsets();
209 if (offsets.size() != offset_positions.size())
210 throw SizeError("Number of written & registered offsets does not match");
211
212 const auto cur_pos = s.tellp();
213 for (std::size_t i = 0; i < offsets.size(); ++i) {
214 s.seekp(offset_positions[i]);
215 const std::string offset_str = std::to_string(offsets[i]);
216 s.write(offset_str.data(), offset_str.size());
217 }
218 s.seekp(cur_pos);
219 }
220
221} // namespace XML::Detail
222#endif // DOXYGEN
223
224} // namespace GridFormat::VTK
225
226#endif // GRIDFORMAT_VTK_APPENDIX_HPP_
Helper functions to get the VTK-specific names of things.
Observer for appendices. Allows registering the offsets when streaming all fields that are part of th...
Definition: appendix.hpp:35
Stores vtk data arrays to be exported as vtk-xml appendix.
Definition: appendix.hpp:53
Wraps a field and exposes it as VTK data array. Essentially, this implements the operator<< to stream...
Definition: data_array.hpp:34
Common functionality for VTK writers.