24 #ifndef STATICLIB_IO_REPLACER_SOURCE_HPP
25 #define STATICLIB_IO_REPLACER_SOURCE_HPP
34 #include "staticlib/config.hpp"
47 template <
typename Source>
51 PREFIX, PLACEHOLDER, MOVED_FROM
61 bool exhausted =
false;
65 std::map<std::string, std::string> values;
69 std::function<void(const std::string&) > on_error;
81 size_t max_placeholder_len;
86 std::vector<char> buffer;
87 size_t buf_len_limit = 4096;
89 std::string placeholder;
90 size_t ind_prefix = 0;
91 size_t ind_postfix = 0;
92 State state = State::PREFIX;
103 std::function<
void(
const std::string&)> on_error,
104 std::string prefix =
"{{", std::string postfix =
"}}",
size_t max_placeholder_len = 255) :
106 values(std::move(values)),
108 prefix(std::move(prefix)),
109 postfix(std::move(postfix)),
110 max_placeholder_len(max_placeholder_len) { }
133 src(std::move(other.src)),
134 exhausted(other.exhausted),
135 values(std::move(other.values)),
136 on_error(std::move(other.on_error)),
137 prefix(std::move(other.prefix)),
138 postfix(std::move(other.postfix)),
139 max_placeholder_len(other.max_placeholder_len),
140 buffer(std::move(other.buffer)),
141 buf_len_limit(other.buf_len_limit),
143 placeholder(std::move(other.placeholder)),
144 ind_prefix(other.ind_prefix),
145 ind_postfix(other.ind_postfix),
147 other.exhausted =
true;
148 other.max_placeholder_len = 0;
149 other.buf_len_limit = 0;
151 other.ind_prefix = 0;
152 other.ind_postfix = 0;
153 other.state = State::MOVED_FROM;
163 src = std::move(other.src);
164 exhausted = other.exhausted;
165 other.exhausted =
true;
166 values = std::move(other.values);
167 on_error = std::move(other.on_error);
168 prefix = std::move(other.prefix);
169 postfix = std::move(other.postfix);
170 max_placeholder_len = other.max_placeholder_len;
171 other.max_placeholder_len = 0;
172 buffer = std::move(other.buffer);
173 buf_len_limit = other.buf_len_limit;
174 other.buf_len_limit = 0;
177 placeholder = std::move(other.placeholder);
178 ind_prefix = other.ind_prefix;
179 other.ind_prefix = 0;
180 ind_postfix = other.ind_postfix;
181 other.ind_postfix = 0;
183 other.state = State::MOVED_FROM;
194 size_t ulen = span.
size();
196 std::streamsize read_buffered = copy_buffered(span.
data(), ulen);
197 if (read_buffered > 0) {
198 return read_buffered;
204 size_t limitlen = ulen <= buf_len_limit ? ulen : buf_len_limit;
207 std::streamsize
read = 0;
208 while (0 == (read = src.
read({std::addressof(cur), 1})));
209 exhausted = std::char_traits<char>::eof() ==
read;
217 case State::PLACEHOLDER:
220 case State::MOVED_FROM:
221 throw io_exception(TRACEMSG(
"Invalid attempt to read from source in 'MOVED_FROM' state"));
223 if (buffer.size() >= limitlen) {
229 std::streamsize read_prepared = copy_buffered(
span.
data(), ulen);
230 if (read_prepared > 0) {
231 return read_prepared;
234 if (placeholder.length() > 0) {
235 std::string msg =
"Invalid unclosed placeholder: [" + placeholder +
"]";
238 return std::char_traits<char>::eof();
247 return src.get_source();
261 void do_prefix(
char cur) {
262 if (cur != prefix[ind_prefix]) {
263 if (ind_prefix > 0) {
264 size_t wp = buffer.size();
265 buffer.resize(wp + ind_prefix);
266 std::memcpy(buffer.data() + wp, prefix.c_str(), ind_prefix);
269 buffer.push_back(cur);
272 if (prefix.length() == ind_prefix) {
274 state = State::PLACEHOLDER;
279 void do_placeholder(
char cur) {
280 placeholder.push_back(cur);
281 if (placeholder.size() == max_placeholder_len) {
282 std::string msg =
"Parameter name: [" + placeholder +
"] is too long";
285 if (cur == postfix[ind_postfix]) {
287 if (postfix.length() == ind_postfix) {
289 placeholder.resize(placeholder.length() - postfix.length());
290 auto par = values.find(placeholder);
291 if (values.end() != par) {
292 size_t wp = buffer.size();
293 buffer.resize(wp + par->second.length());
294 std::memcpy(buffer.data() + wp, par->second.c_str(), par->second.length());
296 state = State::PREFIX;
298 std::string msg =
"Parameter: [" + placeholder +
"] not found";
307 std::streamsize copy_buffered(
char* buf,
size_t ulen) {
308 size_t avail = buffer.size() - pos;
310 size_t ucplen = avail <= ulen ? avail : ulen;
311 std::memcpy(buf, buffer.data() + pos, ucplen);
313 return static_cast<std::streamsize
>(ucplen);
327 template <
typename Source,
328 class =
typename std::enable_if<!std::is_lvalue_reference<Source>::value>::type>
330 std::function<
void(
const std::string&)> on_error) {
341 template <
typename Source>
343 std::function<
void(
const std::string&)> on_error) {