40 SOURCEMETA_FORCEINLINE
auto reserve(std::size_t bytes) ->
void {
41 this->buffer_.reserve(bytes);
47 this->tag_open_ =
false;
48 assert(!this->tag_stack_.empty());
49 if (this->tag_stack_.empty()) [[unlikely]] {
52 const auto &closing{this->tag_stack_.back()};
55 this->buffer_.reserve_additional(closing.bytes.size());
56 this->buffer_.append_unchecked(
57 std::string_view{closing.bytes.data(), closing.bytes.size()});
58 this->buffer_.remove_suffix(closing.bytes.size() - closing.size);
59 this->tag_stack_.pop_back();
65 SOURCEMETA_FORCEINLINE
auto attribute(std::string_view name,
66 std::string_view value)
68 assert(this->tag_open_);
73 this->buffer_.reserve_additional(name.size() + 7);
74 this->buffer_.append_unchecked(
" ");
75 this->buffer_.append_unchecked(name);
76 this->buffer_.append_unchecked(
"=\"");
78 this->buffer_.reserve_additional(4);
79 if (this->tag_open_is_void_) {
80 this->buffer_.append_unchecked(
"\" />");
82 this->buffer_.append_unchecked(
"\">");
100 assert(this->tag_open_);
102 this->buffer_.reserve_additional(name.size() + 1);
103 this->buffer_.append_unchecked(
" ");
104 this->buffer_.append_unchecked(name);
105 this->end_open_tag();
125 this->tag_open_ =
false;
126 if (this->buffer_.size() > 0 && this->buffer_.back() !=
'\n') {
127 this->buffer_.append(
'\n');
146 [[nodiscard]] SOURCEMETA_FORCEINLINE
auto take() -> std::string {
147 this->tag_open_ =
false;
148 this->tag_stack_.clear();
149 return this->buffer_.take();
163 SOURCEMETA_FORCEINLINE
auto clear() ->
void {
164 this->tag_open_ =
false;
165 this->tag_stack_.clear();
166 this->buffer_.clear();
176 this->tag_open_ =
false;
184 this->tag_open_ =
false;
185 this->buffer_.append(content);
190 [[nodiscard]] SOURCEMETA_FORCEINLINE
auto str() ->
const std::string & {
191 return this->buffer_.str();
195 auto write(std::ostream &stream) -> void;
202#pragma warning(disable : 4251)
212#define HTML_WRITER_CONTAINER(name) \
213 SOURCEMETA_FORCEINLINE auto name() -> HTMLWriter & { \
214 this->open_tag("<" #name ">", ClosingTag{"</" #name ">"}); \
217 SOURCEMETA_FORCEINLINE auto name(std::string_view text_content) \
219 this->open_tag("<" #name ">", ClosingTag{"</" #name ">"}); \
220 this->text(text_content); \
228#define HTML_WRITER_CONTAINER_NAMED(name, tag) \
229 SOURCEMETA_FORCEINLINE auto name() -> HTMLWriter & { \
230 this->open_tag("<" #tag ">", ClosingTag{"</" #tag ">"}); \
233 SOURCEMETA_FORCEINLINE auto name(std::string_view text_content) \
235 this->open_tag("<" #tag ">", ClosingTag{"</" #tag ">"}); \
236 this->text(text_content); \
245#define HTML_WRITER_VOID(name) \
246 SOURCEMETA_FORCEINLINE auto name() -> HTMLWriter & { \
247 this->void_tag("<" #name " />"); \
258 HTML_WRITER_CONTAINER(html)
260 HTML_WRITER_VOID(base)
262 HTML_WRITER_CONTAINER(head)
264 HTML_WRITER_VOID(link)
266 HTML_WRITER_VOID(meta)
268 HTML_WRITER_CONTAINER(style)
270 HTML_WRITER_CONTAINER(title)
272 HTML_WRITER_CONTAINER(body)
279 HTML_WRITER_CONTAINER(address)
281 HTML_WRITER_CONTAINER(article)
283 HTML_WRITER_CONTAINER(aside)
285 HTML_WRITER_CONTAINER(footer)
287 HTML_WRITER_CONTAINER(header)
289 HTML_WRITER_CONTAINER(h1)
291 HTML_WRITER_CONTAINER(h2)
293 HTML_WRITER_CONTAINER(h3)
295 HTML_WRITER_CONTAINER(h4)
297 HTML_WRITER_CONTAINER(h5)
299 HTML_WRITER_CONTAINER(h6)
301 HTML_WRITER_CONTAINER(hgroup)
303 HTML_WRITER_CONTAINER(main)
305 HTML_WRITER_CONTAINER(nav)
307 HTML_WRITER_CONTAINER(section)
309 HTML_WRITER_CONTAINER(search)
316 HTML_WRITER_CONTAINER(blockquote)
318 HTML_WRITER_CONTAINER(dd)
320 HTML_WRITER_CONTAINER(div)
322 HTML_WRITER_CONTAINER(dl)
324 HTML_WRITER_CONTAINER(dt)
326 HTML_WRITER_CONTAINER(figcaption)
328 HTML_WRITER_CONTAINER(figure)
332 HTML_WRITER_CONTAINER(li)
334 HTML_WRITER_CONTAINER(menu)
336 HTML_WRITER_CONTAINER(ol)
338 HTML_WRITER_CONTAINER(p)
340 HTML_WRITER_CONTAINER(pre)
342 HTML_WRITER_CONTAINER(ul)
349 HTML_WRITER_CONTAINER(a)
351 HTML_WRITER_CONTAINER(abbr)
353 HTML_WRITER_CONTAINER(b)
355 HTML_WRITER_CONTAINER(bdi)
357 HTML_WRITER_CONTAINER(bdo)
361 HTML_WRITER_CONTAINER(cite)
363 HTML_WRITER_CONTAINER(code)
365 HTML_WRITER_CONTAINER(data)
367 HTML_WRITER_CONTAINER(dfn)
369 HTML_WRITER_CONTAINER(em)
371 HTML_WRITER_CONTAINER(i)
373 HTML_WRITER_CONTAINER(kbd)
375 HTML_WRITER_CONTAINER(mark)
377 HTML_WRITER_CONTAINER(q)
379 HTML_WRITER_CONTAINER(rp)
381 HTML_WRITER_CONTAINER(rt)
383 HTML_WRITER_CONTAINER(ruby)
385 HTML_WRITER_CONTAINER(s)
387 HTML_WRITER_CONTAINER(samp)
389 HTML_WRITER_CONTAINER(small)
391 HTML_WRITER_CONTAINER(span)
393 HTML_WRITER_CONTAINER(strong)
395 HTML_WRITER_CONTAINER(sub)
397 HTML_WRITER_CONTAINER(sup)
399 HTML_WRITER_CONTAINER(time)
401 HTML_WRITER_CONTAINER(u)
403 HTML_WRITER_CONTAINER(var)
405 HTML_WRITER_VOID(wbr)
412 HTML_WRITER_VOID(area)
414 HTML_WRITER_CONTAINER(audio)
416 HTML_WRITER_VOID(img)
418 HTML_WRITER_CONTAINER(map)
420 HTML_WRITER_VOID(track)
422 HTML_WRITER_CONTAINER(video)
429 HTML_WRITER_VOID(embed)
431 HTML_WRITER_CONTAINER(iframe)
433 HTML_WRITER_CONTAINER(
object)
435 HTML_WRITER_CONTAINER(picture)
437 HTML_WRITER_CONTAINER(portal)
439 HTML_WRITER_VOID(source)
446 HTML_WRITER_CONTAINER(canvas)
448 HTML_WRITER_CONTAINER(noscript)
450 HTML_WRITER_CONTAINER(
script)
457 HTML_WRITER_CONTAINER(del)
459 HTML_WRITER_CONTAINER(ins)
466 HTML_WRITER_CONTAINER(caption)
468 HTML_WRITER_VOID(col)
470 HTML_WRITER_CONTAINER(colgroup)
472 HTML_WRITER_CONTAINER(table)
474 HTML_WRITER_CONTAINER(tbody)
476 HTML_WRITER_CONTAINER(td)
478 HTML_WRITER_CONTAINER(tfoot)
480 HTML_WRITER_CONTAINER(th)
482 HTML_WRITER_CONTAINER(thead)
484 HTML_WRITER_CONTAINER(tr)
491 HTML_WRITER_CONTAINER(button)
493 HTML_WRITER_CONTAINER(datalist)
495 HTML_WRITER_CONTAINER(fieldset)
497 HTML_WRITER_CONTAINER(form)
499 HTML_WRITER_VOID(input)
501 HTML_WRITER_CONTAINER(label)
503 HTML_WRITER_CONTAINER(legend)
505 HTML_WRITER_CONTAINER(meter)
507 HTML_WRITER_CONTAINER(optgroup)
509 HTML_WRITER_CONTAINER(option)
511 HTML_WRITER_CONTAINER(output)
513 HTML_WRITER_CONTAINER(progress)
515 HTML_WRITER_CONTAINER(select)
517 HTML_WRITER_CONTAINER(textarea)
524 HTML_WRITER_CONTAINER(details)
526 HTML_WRITER_CONTAINER(dialog)
528 HTML_WRITER_CONTAINER(summary)
535 HTML_WRITER_CONTAINER(slot)
540 HTML_WRITER_CONTAINER_NAMED(template_,
template)
543#undef HTML_WRITER_CONTAINER
544#undef HTML_WRITER_CONTAINER_NAMED
545#undef HTML_WRITER_VOID
552 constexpr explicit ClosingTag(
const std::string_view tag) noexcept
553 : size{
static_cast<std::uint8_t
>(tag.size())} {
554 for (std::size_t index = 0; index < tag.size(); index += 1) {
555 this->bytes[index] = tag[index];
559 std::array<char, 16> bytes{};
563 SOURCEMETA_FORCEINLINE
auto open_tag(std::string_view opening,
564 const ClosingTag &closing) ->
void {
565 this->buffer_.append(opening);
566 this->tag_stack_.push_back(closing);
567 this->tag_open_ =
true;
568 this->tag_open_is_void_ =
false;
571 SOURCEMETA_FORCEINLINE
auto void_tag(std::string_view opening) ->
void {
572 this->buffer_.append(opening);
573 this->tag_open_ =
true;
574 this->tag_open_is_void_ =
true;
579 SOURCEMETA_FORCEINLINE
auto reopen_tag() ->
void {
580 this->buffer_.remove_suffix(this->tag_open_is_void_ ? 3 : 1);
583 SOURCEMETA_FORCEINLINE
auto end_open_tag() ->
void {
584 if (this->tag_open_is_void_) {
585 this->buffer_.append(
" />");
587 this->buffer_.append(
'>');
592 std::vector<ClosingTag> tag_stack_;
593 bool tag_open_{
false};
594 bool tag_open_is_void_{
false};