Echo Writes Code

format.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#include "crucible/core/format.inl"

#include "crucible/core/demangle.inl"
#include "crucible/core/string.inl"
#include "crucible/core/utility.inl"

namespace crucible::core
{
  FormatContext::FormatContext(std::size_t const indent_size, std::size_t const nesting) :
    my_indent_size { indent_size },
    my_nesting { nesting }
  {}

  auto FormatContext::get_indent() const -> String
  {
    constexpr String_View SPACE { " " };
    return SPACE.repeat(my_indent_size * my_nesting);
  }

  auto FormatContext::nest() const -> FormatContext
  {
    return FormatContext { my_indent_size, my_nesting + 1 };
  }

  auto FormatContextBuilder::set_indent_size(std::size_t const indent_size) -> FormatContextBuilder &
  {
    my_indent_size = indent_size;
    return *this;
  }

  auto FormatContextBuilder::get() const -> FormatContext
  {
    return FormatContext { my_indent_size, 0 };
  }

  Formatter::Formatter(String_View const name, FormatContext const &context) :
    my_name { name },
    my_outer_context { context },
    my_inner_context { context.nest() }
  {}

  auto Formatter::get() const -> String
  {
    return my_name + " {\n" + my_buffer + my_outer_context.get_indent() + "}";
  }

  auto build_format_context() -> FormatContextBuilder
  {
    return FormatContextBuilder {};
  }

  auto build_formatter(String_View const name, FormatContext const &context) -> Formatter
  {
    return Formatter { name, context };
  }

  auto format_bool(bool const value) -> String
  {
    if (value)
    {
      return String { "true" };
    }

    return String { "false" };
  }

  auto format_address(void const *value) -> String
  {
    if (value == nullptr)
    {
      return String { "nullptr" };
    }

    return format_unsigned_hexadecimal(reinterpret_cast<std::uintptr_t>(value));
  }

  auto format_cstring(char const *value, std::size_t const size) -> String
  {
    String result;

    result += "\"";
    result += String { value, size };
    result += "\"";

    return result;
  }

  auto format_std_string(std::string const &value) -> String
  {
    return "std::string { [synthetic] contents: \"" + String { value.data(), value.size() } + "\" }";
  }

  auto format_std_byte(std::byte const &value) -> String
  {
    return "std::byte { " + format_unsigned_hexadecimal(std::to_integer<std::uint8_t>(value)) + " }";
  }

  auto format_std_type_info(std::type_info const &value) -> String
  {
    char const *value_name_data { value.name() };
    std::size_t const value_name_size { std::strlen(value_name_data) };
    String_View const value_name { value_name_data, value_name_size };

    auto const handle_failure {
      [&value_name](Demangle_Error const &error) -> String {
        return value_name + " (" + error.describe() + ")";
      }
    };

    auto const demangled_name {
      demangle(value_name.view_data())
        .resolve(handle_failure, identity<String>)
    };

    return "std::type_info { [synthetic] name: " + format_cstring(demangled_name.data(), demangled_name.size()) + " }";
  }
}