Skip to content

Commit

Permalink
Move universal formatter inside format function
Browse files Browse the repository at this point in the history
  • Loading branch information
Yaraslaut committed Jul 8, 2024
1 parent ff56695 commit 25c2994
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 117 deletions.
66 changes: 16 additions & 50 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ To test it you can use provided Dockerfile to get compiler and build project
docker build . --progress=plain
```

Some additional examples can be found in [proposal](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2996r3.html)
Some additional examples you can find in [proposal](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2996r3.html)

## Create variant of all types inside namespace

Expand All @@ -22,66 +22,30 @@ struct ClearHistoryAndReset {};
using list_variant = [:form::util::create_variant(^list):];
```
## Enum/Variant to string
## Enum to string
``` c++
enum class Color { red, green, blue };
void VariantToString() {
list_variant v{list::CancelSelection{}};
std::println("{}", form::variant_type_to_string(v)); // CancelSelection
}
void EnumToString() {
std::println("{}", form::enum_to_string(Color::red)); // red
}
```

## Universal formatter


## Variant type to string

``` c++

struct S {
unsigned i : 2, j : 6;
};

struct X {
int m1 = 1;
};

struct Y {
int m2 = 2;
};

class Z : public X, private Y {
int m3 = 3;
int m4 = 4;
};


template <typename T>
requires form::util::is_one_of<T, Z>
struct std::formatter<T> : std::formatter<std::string> {
auto format(const T &val, std::format_context &ctx) const {
return std::format_to(ctx.out(), "{}",
form::universal_formatter::format(val));
}
};


int main() {
std::println("{}", Z()); // Z{X{.m1=1}, Y{.m2=2}, .m3=3, .m4=4}
void VariantToString() {
list_variant v{list::CancelSelection{}};
std::println("{}", form::variant_type_to_string(v)); // CancelSelection
}


```

## Serialization into different formats

```c++

using ColumnCount = boxed::boxed<int>;
Expand All @@ -106,20 +70,24 @@ void SerializationIntoDifferentFormats() {
std::println("{}", form::format_json(c));
std::println("===== YAML =====");
std::println("{}", form::format_yaml(c));
std::println("===== UNIVERSAL =====");
std::println("{}", form::format_universal(c));
}

/*
===== JSON =====
{"live":false,"v":90,"b":90,page_size: {lines: {"value":10},columns: {"value":10}}}
===== YAML =====
live: "false"
v: "90"
b: "90"
live: false
v: 90
b: 90
page_size:
lines:
value: "10"
value: 10
columns:
value: "10"
value: 10
===== UNIVERSAL =====
{.live=false,.v=90,.b=90,.page_size={.lines={.value=10},.columns={.value=10}}}
*/
```
Expand Down Expand Up @@ -164,5 +132,3 @@ void runTests() { form::run_tests<^for_tests>(); }
*/

```
`
15 changes: 0 additions & 15 deletions include/form/form.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,21 +32,6 @@ constexpr std::string enum_to_string(E value) {
return result;
}

template <typename T> std::string format_yaml(T const &t) {
return format<^yaml>(t);
}

template <typename T> std::string format_json(T const &t) {
return format<^json>(t);
}

template <typename T> T from_yaml(auto input) {
auto node = YAML::Load(input);
T t;
from_yaml_node(node, t);
return t;
}

template <typename T> bool compare(T const &lhs, T const &rhs) {
bool result = true;
if constexpr (std::is_arithmetic_v<T>)
Expand Down
74 changes: 39 additions & 35 deletions include/form/format.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ auto withLevel(std::string const in, int indent) {
return out;
}
auto withLevel(std::string const in) { return withLevel(in, yaml_indent); }
auto withLevelKnown() { return withLevel("{}: \"{}\""); }
auto withLevelKnown() { return withLevel("{}: {}"); }
auto withLevelNested() { return withLevel("{}:\n{}"); }
void increase_level() { yaml_indent += 1; }
void decrease_level() { yaml_indent -= 1; }
Expand All @@ -30,42 +30,23 @@ constexpr auto delimiter() { return ","; }
constexpr auto start() { return "{"; }
constexpr auto end() { return "}"; }
auto withLevelKnown() { return "\"{}\":{}"; }
auto withLevelNested() { return "{}: {}"; }
auto withLevelNested() { return "\"{}\": {}"; }
void increase_level() {}
void decrease_level() {}

} // namespace json

namespace universal_formatter {
namespace universal {

template <typename T> std::string format(T const &t) {
std::string formatted;
auto out = std::back_inserter(formatted);
std::format_to(out, "{}{{", name_of<std::string_view>(^T));

auto delim = [first = true, &out]() mutable {
if (!first) {
*out++ = ',';
*out++ = ' ';
}
first = false;
};

[:util::expand(bases_of(^T)):] >> [&]<auto base> {
delim();
std::format_to(out, "{}", format((typename[:type_of(base):] const &)(t)));
};

[:util::expand(nonstatic_data_members_of(^T)):] >> [&]<auto mem> {
delim();
std::format_to(out, ".{}={}", name_of<std::string_view>(mem), t.[:mem:]);
};

*out++ = '}';
return formatted;
}
constexpr auto delimiter() { return ","; }
constexpr auto start() { return "{"; }
constexpr auto end() { return "}"; }
auto withLevelKnown() { return ".{}={}"; }
auto withLevelNested() { return ".{}={}"; }
void increase_level() {}
void decrease_level() {}

}; // namespace universal_formatter
} // namespace universal

template <auto refl, typename T> std::string format(T const &t) {
std::string out;
Expand Down Expand Up @@ -93,12 +74,14 @@ template <auto refl, typename T> std::string format(T const &t) {
constexpr auto type = type_of(mem);
delim();

// std::println("Handling member: {} with type: {}", name,
// name_of(type_of(mem)));
if constexpr (util::is_trivial_type<[:type_of(mem):]>) {
if constexpr (std::is_arithmetic_v<[:type_of(mem):]>) {
std::format_to(std::back_inserter(out),
std::runtime_format([:refl:] ::withLevelKnown()), name,
t.[:mem:]);
} else if constexpr (std::same_as<[:type_of(mem):], std::string>) {
std::format_to(std::back_inserter(out),
std::runtime_format([:refl:] ::withLevelKnown()), name,
std::format("\"{}\"", t.[:mem:]));
} else if constexpr (std::is_constructible_v<
std::formatter<[:type_of(mem):]>>) {
std::format_to(std::back_inserter(out),
Expand All @@ -125,7 +108,8 @@ template <typename T> void from_yaml_node(YAML::Node const &node, T &t) {
constexpr auto mem = util::member_info<T>(I);
auto name = std::string{util::name_of(mem)};
// std::println("get value of: {}", name_of(mem));
if constexpr (util::is_trivial_type<[:type_of(mem):]>) {
if constexpr (std::is_arithmetic_v<[:type_of(mem):]> ||
std::same_as<[:type_of(mem):], std::string>) {
t.[:mem:] = node[name].template as<[:type_of(mem):]>();
} else if constexpr (std::is_constructible_v<
std::formatter<[:type_of(mem):]>>) {
Expand All @@ -146,7 +130,8 @@ template <typename T> void from_yaml_node(YAML::Node const &node, T &t) {
util::for_range<0, util::number_of_members<[:type_of(base):]>()>(
[&]<auto II>() {
constexpr auto mem = util::member_info<[:type_of(base):]>(II);
if constexpr (util::is_trivial_type<[:type_of(mem):]>) {
if constexpr (std::is_arithmetic_v<[:type_of(mem):]> ||
std::same_as<[:type_of(mem):], std::string>) {
auto name = std::string{util::name_of(mem)};
t.[:mem:] = node[name].template as<[:type_of(mem):]>();
} else if constexpr (std::formattable<[:type_of(mem):], char>) {
Expand All @@ -157,4 +142,23 @@ template <typename T> void from_yaml_node(YAML::Node const &node, T &t) {
});
}

template <typename T> std::string format_yaml(T const &t) {
return format<^yaml>(t);
}

template <typename T> std::string format_json(T const &t) {
return format<^json>(t);
}

template <typename T> std::string format_universal(T const &t) {
return format<^universal>(t);
}

template <typename T> T from_yaml(auto input) {
auto node = YAML::Load(input);
T t;
from_yaml_node(node, t);
return t;
}

} // namespace form
14 changes: 2 additions & 12 deletions include/form/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,6 @@ namespace form::util {

consteval auto name_of(auto type) { return name_of<std::string_view>(type); }

template <typename T>
concept is_trivial_type =
std::is_arithmetic<T>::value || std::is_same_v<T, std::string>;

template <typename... Ts, typename F> constexpr void enumerate_types(F &&f) {
[&f]<auto... Is>(std::index_sequence<Is...>) {
(f.template operator()<Ts, Is>(), ...);
Expand Down Expand Up @@ -53,12 +49,6 @@ template <typename T> consteval auto number_of_base() {
return bases_of(^T).size();
}

template <typename T>
concept has_value_type = requires { typename T::value_type; };

template <typename T>
concept has_inner_type = requires { typename T::inner_type; };

namespace __impl {
template <auto... vals> struct replicator_type {
template <typename F> constexpr void operator>>(F body) const {
Expand Down Expand Up @@ -91,7 +81,7 @@ consteval auto create_variant(auto reflection) {
members_of(reflection)});
}

template <typename Check, typename ...T>
concept is_one_of = std::disjunction_v<std::is_same<Check,T>...>;
template <typename Check, typename... T>
concept is_one_of = std::disjunction_v<std::is_same<Check, T>...>;

} // namespace form::util
3 changes: 2 additions & 1 deletion src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ void SerializationIntoDifferentFormats() {
std::println("{}", form::format_json(c));
std::println("===== YAML =====");
std::println("{}", form::format_yaml(c));
std::println("===== UNIVERSAL =====");
std::println("{}", form::format_universal(c));
}

void VariantToString() {
Expand All @@ -56,6 +58,5 @@ void runTests() { form::run_tests<^for_tests>(); }

int main() {
form::run_seq<^run>();

return 0;
}
5 changes: 1 addition & 4 deletions src/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,12 @@ template <typename T>
requires form::util::is_one_of<T, Z>
struct std::formatter<T> : std::formatter<std::string> {
auto format(const T &val, std::format_context &ctx) const {
return std::format_to(ctx.out(), "{}",
form::universal_formatter::format(val));
return std::format_to(ctx.out(), "{}", form::format_univ(val));
}
};

int main() {
form::run_tests<^form::tests>();
form::run_tests<^form::tests>();
form::run_tests<^form::round_trip_tests>();
form::run_tests<^form::examples>();
std::println("{}", Z());
}
6 changes: 6 additions & 0 deletions src/util.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#ifndef UTIL_H_
#define UTIL_H_



#endif // UTIL_H_

0 comments on commit 25c2994

Please # to comment.