FE 0.6.0
A header-only C++ library for writing frontends
Loading...
Searching...
No Matches
format.h
Go to the documentation of this file.
1#pragma once
2
3#ifdef FE_STD_FORMAT_SUPPORT
4# include <format>
5#else
6# include <fmt/format.h>
7#endif
8
9#include "fe/loc.h"
10#include "fe/utf8.h"
11
12namespace fe {
13
14namespace format {
15#ifdef FE_STD_FORMAT_SUPPORT
16using namespace ::std;
17#else
18using namespace ::fmt;
19#endif
20} // namespace format
21
22/// Make types that support ostream operators available for `std::format`.
23/// Use like this:
24/// ```
25/// template<> struct std::formatter<T> : fe::ostream_formatter {};
26/// ```
27/// @sa [Stack Overflow](https://stackoverflow.com/a/75738462).
28template<class Char> struct basic_ostream_formatter : format::formatter<std::basic_string_view<Char>, Char> {
29 template<class T, class O> O format(const T& value, format::basic_format_context<O, Char>& ctx) const {
30 std::basic_stringstream<Char> ss;
31 ss << value;
32#if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION < 170000
33 return std::formatter<std::basic_string_view<Char>, Char>::format(ss.str(), ctx);
34#else
35 return format::formatter<std::basic_string_view<Char>, Char>::format(ss.view(), ctx);
36#endif
37 }
38};
39
41
42/// @name out/outln/err/errln
43/// Print to `std::cout`/`std::cerr` via `std::format`; the `*ln` variants conclude with `std::endl`.
44///@{
45// clang-format off
46template<class... Args> void err (format::format_string<Args...> fmt, Args&&... args) { std::cerr << format::format(fmt, std::forward<Args&&>(args)...); }
47template<class... Args> void out (format::format_string<Args...> fmt, Args&&... args) { std::cout << format::format(fmt, std::forward<Args&&>(args)...); }
48template<class... Args> void errln(format::format_string<Args...> fmt, Args&&... args) { std::cerr << format::format(fmt, std::forward<Args&&>(args)...) << std::endl; }
49template<class... Args> void outln(format::format_string<Args...> fmt, Args&&... args) { std::cout << format::format(fmt, std::forward<Args&&>(args)...) << std::endl; }
50// clang-format on
51
52/// Keeps track of indentation level during output
53class Tab {
54public:
55 Tab(const Tab&) = default;
56 Tab(std::string_view tab = {"\t"}, size_t indent = 0)
57 : tab_(tab)
58 , indent_(indent) {}
59
60 /// @name Getters
61 ///@{
62 size_t indent() const { return indent_; }
63 std::string_view tab() const { return tab_; }
64 ///@}
65
66 /// @name Setters
67 ///@{
68 Tab& operator=(size_t indent) {
69 indent_ = indent;
70 return *this;
71 }
72 Tab& operator=(std::string tab) {
73 tab_ = tab;
74 return *this;
75 }
76 ///@}
77
78 // clang-format off
79 /// @name Indent/Dedent
80 ///@{
81 Tab& operator++() { ++indent_; return *this; }
82 Tab& operator--() { assert(indent_ > 0); --indent_; return *this; }
83 Tab& operator+=(size_t indent) { indent_ += indent; return *this; }
84 Tab& operator-=(size_t indent) { assert(indent_ > 0); indent_ -= indent; return *this; }
85 Tab operator++(int) { auto res = *this; ++indent_; return res; }
86 Tab operator--(int) { assert(indent_ > 0); auto res = *this; --indent_; return res; }
87 Tab operator+(size_t indent) const { return {tab_, indent_ + indent}; }
88 Tab operator-(size_t indent) const { assert(indent_ > 0); return {tab_, indent_ - indent}; }
89 ///@}
90 // clang-format on
91
92 friend std::ostream& operator<<(std::ostream& os, Tab tab) {
93 for (size_t i = 0; i != tab.indent_; ++i) os << tab.tab_;
94 return os;
95 }
96
97private:
98 std::string_view tab_;
99 size_t indent_ = 0;
100};
101
102} // namespace fe
103
104#ifndef DOXYGEN
105template<> struct fe::format::formatter<fe::Pos> : fe::ostream_formatter {};
106template<> struct fe::format::formatter<fe::Loc> : fe::ostream_formatter {};
107template<> struct fe::format::formatter<fe::Sym> : fe::ostream_formatter {};
108template<> struct fe::format::formatter<fe::Tab> : fe::ostream_formatter {};
109template<> struct fe::format::formatter<fe::utf8::Char32> : fe::ostream_formatter {};
110#endif
Keeps track of indentation level during output.
Definition format.h:53
Tab operator-(size_t indent) const
Definition format.h:88
Tab & operator--()
Definition format.h:82
Tab & operator-=(size_t indent)
Definition format.h:84
friend std::ostream & operator<<(std::ostream &os, Tab tab)
Definition format.h:92
Tab(std::string_view tab={"\t"}, size_t indent=0)
Definition format.h:56
size_t indent() const
Definition format.h:62
Tab operator+(size_t indent) const
Definition format.h:87
Tab operator++(int)
Definition format.h:85
Tab & operator+=(size_t indent)
Definition format.h:83
Tab & operator=(std::string tab)
Definition format.h:72
Tab & operator=(size_t indent)
Definition format.h:68
Tab(const Tab &)=default
Tab & operator++()
Definition format.h:81
Tab operator--(int)
Definition format.h:86
std::string_view tab() const
Definition format.h:63
Definition arena.h:9
void err(format::format_string< Args... > fmt, Args &&... args)
Definition format.h:46
void out(format::format_string< Args... > fmt, Args &&... args)
Definition format.h:47
void errln(format::format_string< Args... > fmt, Args &&... args)
Definition format.h:48
void outln(format::format_string< Args... > fmt, Args &&... args)
Definition format.h:49
Make types that support ostream operators available for std::format.
Definition format.h:28
O format(const T &value, format::basic_format_context< O, Char > &ctx) const
Definition format.h:29