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>
29struct basic_ostream_formatter : format::formatter<std::basic_string_view<Char>, Char> {
30 template<class T, class O>
31 O format(const T& value, format::basic_format_context<O, Char>& ctx) const {
32 std::basic_stringstream<Char> ss;
33 ss << value;
34#if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION < 170000
35 return std::formatter<std::basic_string_view<Char>, Char>::format(ss.str(), ctx);
36#else
37 return format::formatter<std::basic_string_view<Char>, Char>::format(ss.view(), ctx);
38#endif
39 }
40};
41
43
44/// @name out/outln/err/errln
45/// Print to `std::cout`/`std::cerr` via `std::format`; the `*ln` variants conclude with `std::endl`.
46///@{
47// clang-format off
48template<class... Args> void err (format::format_string<Args...> fmt, Args&&... args) { std::cerr << format::format(fmt, std::forward<Args>(args)...); }
49template<class... Args> void out (format::format_string<Args...> fmt, Args&&... args) { std::cout << format::format(fmt, std::forward<Args>(args)...); }
50template<class... Args> void errln(format::format_string<Args...> fmt, Args&&... args) { std::cerr << format::format(fmt, std::forward<Args>(args)...) << std::endl; }
51template<class... Args> void outln(format::format_string<Args...> fmt, Args&&... args) { std::cout << format::format(fmt, std::forward<Args>(args)...) << std::endl; }
52// clang-format on
53
54/// Keeps track of indentation level during output
55class Tab {
56public:
57 Tab(const Tab&) = default;
58 Tab(std::string_view tab = {"\t"}, size_t indent = 0)
59 : tab_(tab)
60 , indent_(indent) {}
61
62 /// @name Getters
63 ///@{
64 size_t indent() const { return indent_; }
65 std::string_view tab() const { return tab_; }
66 ///@}
67
68 /// @name Setters
69 ///@{
70 Tab& operator=(size_t indent) {
71 indent_ = indent;
72 return *this;
73 }
74 Tab& operator=(std::string tab) {
75 tab_ = tab;
76 return *this;
77 }
78 ///@}
79
80 // clang-format off
81 /// @name Indent/Dedent
82 ///@{
83 Tab& operator++() { ++indent_; return *this; }
84 Tab& operator--() { assert(indent_ > 0); --indent_; return *this; }
85 Tab& operator+=(size_t indent) { indent_ += indent; return *this; }
86 Tab& operator-=(size_t indent) { assert(indent_ > 0); indent_ -= indent; return *this; }
87 Tab operator++(int) { auto res = *this; ++indent_; return res; }
88 Tab operator--(int) { assert(indent_ > 0); auto res = *this; --indent_; return res; }
89 Tab operator+(size_t indent) const { return {tab_, indent_ + indent}; }
90 Tab operator-(size_t indent) const { assert(indent_ > 0); return {tab_, indent_ - indent}; }
91 ///@}
92 // clang-format on
93
94 friend std::ostream& operator<<(std::ostream& os, Tab tab) {
95 for (size_t i = 0; i != tab.indent_; ++i)
96 os << tab.tab_;
97 return os;
98 }
99
100private:
101 std::string_view tab_;
102 size_t indent_ = 0;
103};
104
105} // namespace fe
106
107#ifndef DOXYGEN
108template<>
109struct fe::format::formatter<fe::Pos> : fe::ostream_formatter {};
110template<>
111struct fe::format::formatter<fe::Loc> : fe::ostream_formatter {};
112template<>
113struct fe::format::formatter<fe::Sym> : fe::ostream_formatter {};
114template<>
115struct fe::format::formatter<fe::Tab> : fe::ostream_formatter {};
116template<>
117struct fe::format::formatter<fe::utf8::Char32> : fe::ostream_formatter {};
118#endif
Keeps track of indentation level during output.
Definition format.h:55
Tab operator-(size_t indent) const
Definition format.h:90
Tab & operator--()
Definition format.h:84
Tab & operator-=(size_t indent)
Definition format.h:86
friend std::ostream & operator<<(std::ostream &os, Tab tab)
Definition format.h:94
Tab(std::string_view tab={"\t"}, size_t indent=0)
Definition format.h:58
size_t indent() const
Definition format.h:64
Tab operator+(size_t indent) const
Definition format.h:89
Tab operator++(int)
Definition format.h:87
Tab & operator+=(size_t indent)
Definition format.h:85
Tab & operator=(std::string tab)
Definition format.h:74
Tab & operator=(size_t indent)
Definition format.h:70
Tab(const Tab &)=default
Tab & operator++()
Definition format.h:83
Tab operator--(int)
Definition format.h:88
std::string_view tab() const
Definition format.h:65
Definition arena.h:10
void err(format::format_string< Args... > fmt, Args &&... args)
Definition format.h:48
void out(format::format_string< Args... > fmt, Args &&... args)
Definition format.h:49
void errln(format::format_string< Args... > fmt, Args &&... args)
Definition format.h:50
void outln(format::format_string< Args... > fmt, Args &&... args)
Definition format.h:51
Make types that support ostream operators available for std::format.
Definition format.h:29
O format(const T &value, format::basic_format_context< O, Char > &ctx) const
Definition format.h:31