hemplateSimple 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
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