hemplate

Simple XML template engine
git clone git://git.dimitrijedobrota.com/hemplate.git
Log | Files | Refs | README | LICENSE | HACKING | CONTRIBUTING | CODE_OF_CONDUCT | BUILDING

commit 47d893bbb0127d01048076fbce364a7ba6f5eb1a
parent a73311e8cc6778081f10947ac9a82d16975cda4c
author Dimitrije Dobrota < mail@dimitrijedobrota.com >
date Thu, 24 Apr 2025 15:27:03 +0200

Get rid of state and fix special tags

Diffstat:
M include/hemplate/classes.hpp | +++++++++++ ------
M include/hemplate/element.hpp | +++++++++++++++++++ ----------------------------------------------
M include/hemplate/html.hpp | +++++++++ -
M source/element.cpp | ++++++++ -------------

4 files changed, 47 insertions(+), 66 deletions(-)


diff --git a/ include/hemplate/classes.hpp b/ include/hemplate/classes.hpp

@@ -14,19 +14,24 @@ namespace hemplate

using comment = element_builder<"comment", element::Type::Comment>;
using transparent = element_builder<"transparent", element::Type::Transparent>;

class HEMPLATE_EXPORT xml : public element_builder<"xml", element::Type::Xml>
class HEMPLATE_EXPORT xml
: public element_builder<"xml", element::Type::Special>
{
public:
static constexpr const auto default_version = "1.0";
static constexpr const auto default_encoding = "UTF-8";

static auto data(std::string_view version, std::string_view encoding)
{
const attribute_list attrs {{"version", version}, {"encoding", encoding}};
return "?xml " + std::string(attrs) + "?";
}

explicit xml(
std::string version = default_version,
std::string encoding = default_encoding
std::string_view version = default_version,
std::string_view encoding = default_encoding
)
: element_builder(attribute_list {
{"version", std::move(version)}, {"encoding", std::move(encoding)}
})
: element_builder(data(version, encoding))
{
}
};

diff --git a/ include/hemplate/element.hpp b/ include/hemplate/element.hpp

@@ -1,5 +1,7 @@

#pragma once

#include <span>
#include <sstream>
#include <string>
#include <vector>

@@ -24,7 +26,7 @@ public:

Atomic,
Boolean,
Comment,
Xml,
Special,
Transparent,
};

@@ -34,7 +36,6 @@ private:

template<based::string_literal Tag, element::Type MyType>
friend class element_builder;

bool* m_state;
Type m_type;
std::string m_tag;

@@ -42,50 +43,37 @@ private:

std::string m_data;

explicit element(
bool& state,
Type type,
std::string_view tag,
const is_element auto&... children
Type type, std::string_view tag, const is_element auto&... children
)
: m_state(&state)
, m_type(type)
: m_type(type)
, m_tag(tag)
, m_children(std::initializer_list<element> {children...})
{
}

explicit element(
bool& state, Type type, std::string_view tag, std::string_view data
)
: m_state(&state)
, m_type(type)
explicit element(Type type, std::string_view tag, std::string_view data)
: m_type(type)
, m_tag(tag)
, m_data(data)
{
}

explicit element(
bool& state,
Type type,
std::string_view tag,
std::span<const element> children
Type type, std::string_view tag, std::span<const element> children
)
: m_state(&state)
, m_type(type)
: m_type(type)
, m_tag(tag)
, m_children(children.begin(), children.end())
{
}

explicit element(
bool& state,
Type type,
std::string_view tag,
attribute_list attributes,
const is_element auto&... children
)
: attribute_list(std::move(attributes))
, m_state(&state)
, m_type(type)
, m_tag(tag)
, m_children(std::initializer_list<element> {children...})

@@ -93,14 +81,12 @@ private:

}

explicit element(
bool& state,
Type type,
std::string_view tag,
attribute_list attributes,
std::string_view data
)
: attribute_list(std::move(attributes))
, m_state(&state)
, m_type(type)
, m_tag(tag)
, m_data(data)

@@ -108,14 +94,12 @@ private:

}

explicit element(
bool& state,
Type type,
std::string_view tag,
attribute_list attributes,
std::span<const element> children
)
: attribute_list(std::move(attributes))
, m_state(&state)
, m_type(type)
, m_tag(tag)
, m_children(children.begin(), children.end())

@@ -125,55 +109,44 @@ private:

void render_atomic(std::ostream& out, std::size_t indent_value) const;
void render_boolean(std::ostream& out, std::size_t indent_value) const;
void render_comment(std::ostream& out, std::size_t indent_value) const;
void render_xml(std::ostream& out, std::size_t indent_value) const;
void render_special(std::ostream& out, std::size_t indent_value) const;
void render_children(std::ostream& out, std::size_t indent_value) const;
void render(std::ostream& out, std::size_t indent_value) const;

public:
friend std::ostream& operator<<(std::ostream& out, const element& element)
explicit operator std::string() const
{
element.render(out, 0);
return out;
std::stringstream ss;
ss << *this;
return ss.str();
}

element& add(const element& elem)
friend std::ostream& operator<<(std::ostream& out, const element& element)
{
m_children.emplace_back(elem);
return *this;
element.render(out, 0);
return out;
}

bool get_state() const { return *m_state; }
bool tgl_state() const { return *m_state = !*m_state; }
};

template<based::string_literal Tag, element::Type MyType>
class HEMPLATE_EXPORT element_builder : public element
{
static bool m_state;

public:
// NOLINTBEGIN *-no-array-decay
template<typename... Args>
explicit element_builder(Args&&... args)
: element(m_state, MyType, Tag.data(), std::forward<Args>(args)...)
: element(MyType, Tag.data(), std::forward<Args>(args)...)
{
}

template<typename... Args>
explicit element_builder(attribute_list list, Args&&... args)
: element(
m_state,
MyType,
Tag.data(),
std::move(list),
std::forward<Args>(args)...
MyType, Tag.data(), std::move(list), std::forward<Args>(args)...
)
{
}
// NOLINTEND *-no-array-decay
};

template<based::string_literal Tag, element::Type Type>
bool element_builder<Tag, Type>::m_state = false; // NOLINT

} // namespace hemplate

diff --git a/ include/hemplate/html.hpp b/ include/hemplate/html.hpp

@@ -11,6 +11,15 @@ using hemplate::transform;

using hemplate::transparent;
using hemplate::xml;

class doctype : public element_builder<"DOCTYPE", element::Type::Special>
{
public:
explicit doctype()
: element_builder("!DOCTYPE html")
{
}
};

// clang-format off
// NOLINTBEGIN *-identifier-naming
using abbr = element_builder<"abbr", element::Type::Boolean>;

@@ -43,7 +52,6 @@ using dfn = element_builder<"dfn", element::Type::Boolean>;

using dialog = element_builder<"dialog", element::Type::Boolean>;
using div = element_builder<"div", element::Type::Boolean>;
using dl = element_builder<"dl", element::Type::Boolean>;
using doctype = element_builder<"!DOCTYPE html", element::Type::Atomic>;
using dt = element_builder<"dt", element::Type::Boolean>;
using embed = element_builder<"embed", element::Type::Atomic>;
using em = element_builder<"em", element::Type::Boolean>;

diff --git a/ source/element.cpp b/ source/element.cpp

@@ -10,21 +10,19 @@ namespace hemplate

void element::render_comment(std::ostream& out, std::size_t indent_value) const
{
const std::string indent(indent_value, ' ');

out << indent << "<!-- " << m_data << " -->\n";
}

void element::render_atomic(std::ostream& out, std::size_t indent_value) const
{
const std::string indent(indent_value, ' ');

out << indent << std::format("<{} {}/>\n", m_tag, attributes());
}

void element::render_xml(std::ostream& out, std::size_t indent_value) const
void element::render_special(std::ostream& out, std::size_t indent_value) const
{
const std::string indent(indent_value, ' ');
out << indent << std::format("<?xml {}?>\n", attributes());
out << indent << std::format("<{}>\n", m_data);
}

void element::render_children(std::ostream& out, std::size_t indent_value) const

@@ -45,8 +43,8 @@ void element::render(std::ostream& out, std::size_t indent_value) const

case Type::Comment:
render_comment(out, indent_value);
return;
case Type::Xml:
render_xml(out, indent_value);
case Type::Special:
render_special(out, indent_value);
return;
case Type::Transparent:
render_children(out, indent_value);

@@ -73,17 +71,14 @@ void element::render(std::ostream& out, std::size_t indent_value) const

return;
}

if (m_children.empty()) {
if (tgl_state()) {
out << indent << std::format("<{} {}>\n", m_tag, attributes());
} else {
out << indent << std::format("</{}>\n", m_tag);
}
} else {
if (!m_children.empty()) {
out << indent << std::format("<{} {}>\n", m_tag, attributes());
render_children(out, indent_value + 2);
out << indent << std::format("</{}>\n", m_tag);
return;
}

out << indent << std::format("<{0} {1}></{0}>\n", m_tag, attributes());
}

} // namespace hemplate